#include #include #include #include #include #include "../miner.h" #include "../sha256/sha256_backend.h" #include "../utils.h" static inline void write_u32_le(uint8_t *dst, uint32_t v) { dst[0] = (uint8_t)(v & 0xFFU); dst[1] = (uint8_t)((v >> 8) & 0xFFU); dst[2] = (uint8_t)((v >> 16) & 0xFFU); dst[3] = (uint8_t)((v >> 24) & 0xFFU); } static void sha256d_from_header76_nonce(const uint8_t header76[76], uint32_t nonce, uint8_t out[32]) { uint8_t header80[80]; uint8_t block1[64]; uint8_t block2[64]; sha256_state_t init_state; sha256_state_t st1; sha256_state_t st2; memcpy(header80, header76, 76); write_u32_le(header80 + 76, nonce); sha256_state_init(&init_state); st1 = init_state; sha256_transform_fast(&st1, header80); memset(block1, 0, sizeof(block1)); memcpy(block1, header80 + 64, 16); block1[16] = 0x80; block1[62] = 0x02; block1[63] = 0x80; sha256_transform_fast(&st1, block1); memset(block2, 0, sizeof(block2)); sha256_state_to_digest(&st1, block2); block2[32] = 0x80; block2[62] = 0x01; block2[63] = 0x00; st2 = init_state; sha256_transform_fast(&st2, block2); sha256_state_to_digest(&st2, out); } static void digest_rev(const uint8_t digest[32], uint8_t rev[32]) { int i; for (i = 0; i < 32; i++) { rev[i] = digest[31 - i]; } } static int find_record_nonce( const uint8_t header76[76], int parity, uint32_t min_nonce, uint32_t max_nonce, uint32_t *out_nonce, uint8_t out_target_be[32] ) { uint8_t best[32]; uint32_t n; memset(best, 0xFF, sizeof(best)); for (n = 0; n <= max_nonce; n++) { uint8_t digest[32]; uint8_t rev[32]; sha256d_from_header76_nonce(header76, n, digest); digest_rev(digest, rev); if (memcmp(rev, best, 32) < 0) { memcpy(best, rev, 32); if (n >= min_nonce && ((int)(n & 1U) == parity)) { *out_nonce = n; memcpy(out_target_be, rev, 32); return 1; } } } return 0; } static int run_case(uint32_t batch, int parity) { uint8_t header76[76]; uint8_t target_be[32]; uint8_t expected_digest[32]; MineResult out; atomic_int stop_flag; uint32_t expected_nonce; char *target_hex; int rc; int i; for (i = 0; i < 76; i++) { header76[i] = (uint8_t)((i * 29 + 11) & 0xFF); } if (!find_record_nonce(header76, parity, 4U, 150000U, &expected_nonce, target_be)) { fprintf(stderr, "[test_miner_regression] no record nonce found for parity=%d\n", parity); return 0; } target_hex = bytes_to_hex(target_be, 32); if (target_hex == NULL) { return 0; } atomic_init(&stop_flag, 0); rc = mine_block( header76, target_hex, "incremental", batch, 0, &stop_flag, NULL, NULL, &out ); free(target_hex); if (rc == 0 || out.found == 0) { fprintf(stderr, "[test_miner_regression] mine_block failed for batch=%u\n", batch); return 0; } if (out.nonce != expected_nonce) { fprintf(stderr, "[test_miner_regression] nonce mismatch batch=%u expected=%u got=%u\n", batch, expected_nonce, out.nonce); return 0; } sha256d_from_header76_nonce(header76, out.nonce, expected_digest); if (memcmp(expected_digest, out.digest, 32) != 0) { fprintf(stderr, "[test_miner_regression] digest mismatch for nonce=%u\n", out.nonce); return 0; } return 1; } static int test_easy_target_finds_zero(void) { uint8_t header76[76]; char *target_hex = NULL; MineResult out; atomic_int stop_flag; int i; for (i = 0; i < 76; i++) { header76[i] = (uint8_t)((i * 7 + 3) & 0xFF); } target_hex = bytes_to_hex((const uint8_t[32]){ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF }, 32); if (target_hex == NULL) { return 0; } atomic_init(&stop_flag, 0); if (!mine_block(header76, target_hex, "incremental", 1, 0, &stop_flag, NULL, NULL, &out)) { free(target_hex); return 0; } free(target_hex); return out.found == 1 && out.nonce == 0U; } static int test_wrap_arithmetic(void) { uint32_t start = 0xFFFFFFFEU; uint32_t n0 = start + 0U; uint32_t n1 = start + 1U; uint32_t n2 = start + 2U; uint32_t n3 = start + 3U; return n0 == 0xFFFFFFFEU && n1 == 0xFFFFFFFFU && n2 == 0x00000000U && n3 == 0x00000001U; } int main(void) { if (!test_easy_target_finds_zero()) { fprintf(stderr, "test_easy_target_finds_zero: FAIL\n"); return 1; } if (!run_case(5U, 1)) { fprintf(stderr, "run_case(batch=5, parity=1): FAIL\n"); return 1; } if (!run_case(6U, 0)) { fprintf(stderr, "run_case(batch=6, parity=0): FAIL\n"); return 1; } if (!test_wrap_arithmetic()) { fprintf(stderr, "test_wrap_arithmetic: FAIL\n"); return 1; } printf("test_miner_regression: OK\n"); return 0; }