From 441867ca722f41a06cc984cfd988d00c1391a447 Mon Sep 17 00:00:00 2001 From: mutatrum Date: Tue, 4 Nov 2025 11:14:43 +0100 Subject: [PATCH 01/20] Optimize construct_bm_job This PR eliminates several inefficient codepaths * Limit back and forth reversing of byte or word orders; * Remove merkle_root_be and prev_block_hash_be from bm_job; * All parameters are converted to binary once; * Stack allocation instead of malloc; * Remove unused functions; * Unroll byte and word reversal functions. --- components/asic/bm1366.c | 4 +- components/asic/bm1368.c | 4 +- components/asic/bm1370.c | 4 +- components/asic/bm1397.c | 2 +- components/stratum/include/mining.h | 10 +- components/stratum/include/utils.h | 12 +-- components/stratum/mining.c | 99 ++++++++--------- components/stratum/test/test_mining.c | 4 +- components/stratum/test/test_utils.c | 9 +- components/stratum/utils.c | 150 ++++---------------------- main/self_test/self_test.c | 28 ++--- main/tasks/create_jobs_task.c | 16 +-- 12 files changed, 108 insertions(+), 234 deletions(-) diff --git a/components/asic/bm1366.c b/components/asic/bm1366.c index eacd821c4..be36dec00 100644 --- a/components/asic/bm1366.c +++ b/components/asic/bm1366.c @@ -289,8 +289,8 @@ void BM1366_send_work(void * pvParameters, bm_job * next_bm_job) memcpy(&job.starting_nonce, &next_bm_job->starting_nonce, 4); memcpy(&job.nbits, &next_bm_job->target, 4); memcpy(&job.ntime, &next_bm_job->ntime, 4); - memcpy(job.merkle_root, next_bm_job->merkle_root_be, 32); - memcpy(job.prev_block_hash, next_bm_job->prev_block_hash_be, 32); + memcpy(job.merkle_root, next_bm_job->merkle_root, 32); + memcpy(job.prev_block_hash, next_bm_job->prev_block_hash, 32); memcpy(&job.version, &next_bm_job->version, 4); if (GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[job.job_id] != NULL) { diff --git a/components/asic/bm1368.c b/components/asic/bm1368.c index dba3b1187..18694656e 100644 --- a/components/asic/bm1368.c +++ b/components/asic/bm1368.c @@ -233,8 +233,8 @@ void BM1368_send_work(void * pvParameters, bm_job * next_bm_job) memcpy(&job.starting_nonce, &next_bm_job->starting_nonce, 4); memcpy(&job.nbits, &next_bm_job->target, 4); memcpy(&job.ntime, &next_bm_job->ntime, 4); - memcpy(job.merkle_root, next_bm_job->merkle_root_be, 32); - memcpy(job.prev_block_hash, next_bm_job->prev_block_hash_be, 32); + memcpy(job.merkle_root, next_bm_job->merkle_root, 32); + memcpy(job.prev_block_hash, next_bm_job->prev_block_hash, 32); memcpy(&job.version, &next_bm_job->version, 4); if (GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[job.job_id] != NULL) { diff --git a/components/asic/bm1370.c b/components/asic/bm1370.c index 38aa2e731..1ff6f838b 100644 --- a/components/asic/bm1370.c +++ b/components/asic/bm1370.c @@ -309,8 +309,8 @@ void BM1370_send_work(void * pvParameters, bm_job * next_bm_job) memcpy(&job.starting_nonce, &next_bm_job->starting_nonce, 4); memcpy(&job.nbits, &next_bm_job->target, 4); memcpy(&job.ntime, &next_bm_job->ntime, 4); - memcpy(job.merkle_root, next_bm_job->merkle_root_be, 32); - memcpy(job.prev_block_hash, next_bm_job->prev_block_hash_be, 32); + memcpy(job.merkle_root, next_bm_job->merkle_root, 32); + memcpy(job.prev_block_hash, next_bm_job->prev_block_hash, 32); memcpy(&job.version, &next_bm_job->version, 4); if (GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[job.job_id] != NULL) { diff --git a/components/asic/bm1397.c b/components/asic/bm1397.c index d02519504..487494d7a 100644 --- a/components/asic/bm1397.c +++ b/components/asic/bm1397.c @@ -332,7 +332,7 @@ void BM1397_send_work(void *pvParameters, bm_job *next_bm_job) memcpy(&job.starting_nonce, &next_bm_job->starting_nonce, 4); memcpy(&job.nbits, &next_bm_job->target, 4); memcpy(&job.ntime, &next_bm_job->ntime, 4); - memcpy(&job.merkle4, next_bm_job->merkle_root + 28, 4); + memcpy(&job.merkle4, next_bm_job->merkle_root, 4); memcpy(job.midstate, next_bm_job->midstate, 32); if (job.num_midstates == 4) diff --git a/components/stratum/include/mining.h b/components/stratum/include/mining.h index dc4f76538..be918f9fb 100644 --- a/components/stratum/include/mining.h +++ b/components/stratum/include/mining.h @@ -8,9 +8,7 @@ typedef struct uint32_t version; uint32_t version_mask; uint8_t prev_block_hash[32]; - uint8_t prev_block_hash_be[32]; uint8_t merkle_root[32]; - uint8_t merkle_root_be[32]; uint32_t ntime; uint32_t target; // aka difficulty, aka nbits uint32_t starting_nonce; @@ -27,12 +25,12 @@ typedef struct void free_bm_job(bm_job *job); -char *construct_coinbase_tx(const char *coinbase_1, const char *coinbase_2, - const char *extranonce, const char *extranonce_2); +void calculate_coinbase_tx_hash(const char *coinbase_1, const char *coinbase_2, + const char *extranonce, const char *extranonce_2, uint8_t dest[32]); -void calculate_merkle_root_hash(const char *coinbase_tx, const uint8_t merkle_branches[][32], const int num_merkle_branches, char dest[65]); +void calculate_merkle_root_hash(const uint8_t coinbase_tx_hash[32], const uint8_t merkle_branches[][32], const int num_merkle_branches, uint8_t dest[32]); -bm_job construct_bm_job(mining_notify *params, const char *merkle_root, const uint32_t version_mask, uint32_t difficulty); +bm_job construct_bm_job(mining_notify *params, const uint8_t merkle_root[32], const uint32_t version_mask, const uint32_t difficulty); double test_nonce_value(const bm_job *job, const uint32_t nonce, const uint32_t rolled_version); diff --git a/components/stratum/include/utils.h b/components/stratum/include/utils.h index e3a12fb86..5c94b501b 100644 --- a/components/stratum/include/utils.h +++ b/components/stratum/include/utils.h @@ -6,31 +6,23 @@ size_t bin2hex(const uint8_t *buf, size_t buflen, char *hex, size_t hexlen); -void flip80bytes(void *dest_p, const void *src_p); -void flip32bytes(void *dest_p, const void *src_p); - size_t hex2bin(const char *hex, uint8_t *bin, size_t bin_len); void print_hex(const uint8_t *b, size_t len, const size_t in_line, const char *prefix); -char *double_sha256(const char *hex_string); - void double_sha256_bin(const uint8_t *data, const size_t data_len, uint8_t dest[32]); -void single_sha256_bin(const uint8_t *data, const size_t data_len, uint8_t dest[32]); void midstate_sha256_bin(const uint8_t *data, const size_t data_len, uint8_t dest[32]); -void swap_endian_words(const char *hex, uint8_t *output); +void reverse_32bit_words(const uint8_t src[32], uint8_t dest[32]); -void reverse_bytes(uint8_t *data, size_t len); +void reverse_byte_order(const uint8_t src[32], uint8_t dest[32]); double le256todouble(const void *target); void prettyHex(unsigned char *buf, int len); -uint32_t flip32(uint32_t val); - double networkDifficulty(uint32_t nBits); void suffixString(uint64_t val, char * buf, size_t bufsiz, int sigdigits); diff --git a/components/stratum/mining.c b/components/stratum/mining.c index 82a50a8c6..15eab0522 100644 --- a/components/stratum/mining.c +++ b/components/stratum/mining.c @@ -13,39 +13,40 @@ void free_bm_job(bm_job *job) free(job); } -char *construct_coinbase_tx(const char *coinbase_1, const char *coinbase_2, - const char *extranonce, const char *extranonce_2) +void calculate_coinbase_tx_hash(const char *coinbase_1, const char *coinbase_2, const char *extranonce, const char *extranonce_2, uint8_t dest[32]) { - int coinbase_tx_len = strlen(coinbase_1) + strlen(coinbase_2) + strlen(extranonce) + strlen(extranonce_2) + 1; + size_t len1 = strlen(coinbase_1); + size_t len2 = strlen(extranonce); + size_t len3 = strlen(extranonce_2); + size_t len4 = strlen(coinbase_2); - char *coinbase_tx = malloc(coinbase_tx_len); - strcpy(coinbase_tx, coinbase_1); - strcat(coinbase_tx, extranonce); - strcat(coinbase_tx, extranonce_2); - strcat(coinbase_tx, coinbase_2); - coinbase_tx[coinbase_tx_len - 1] = '\0'; + size_t coinbase_tx_bin_len = (len1 + len2 + len3 + len4) / 2; - return coinbase_tx; + uint8_t coinbase_tx_bin[coinbase_tx_bin_len]; + + size_t bin_offset = 0; + bin_offset += hex2bin(coinbase_1, coinbase_tx_bin + bin_offset, coinbase_tx_bin_len - bin_offset); + bin_offset += hex2bin(extranonce, coinbase_tx_bin + bin_offset, coinbase_tx_bin_len - bin_offset); + bin_offset += hex2bin(extranonce_2, coinbase_tx_bin + bin_offset, coinbase_tx_bin_len - bin_offset); + bin_offset += hex2bin(coinbase_2, coinbase_tx_bin + bin_offset, coinbase_tx_bin_len - bin_offset); + + double_sha256_bin(coinbase_tx_bin, coinbase_tx_bin_len, dest); } -void calculate_merkle_root_hash(const char *coinbase_tx, const uint8_t merkle_branches[][32], const int num_merkle_branches, char dest[65]) +void calculate_merkle_root_hash(const uint8_t coinbase_tx_hash[32], const uint8_t merkle_branches[][32], const int num_merkle_branches, uint8_t dest[32]) { - size_t coinbase_tx_bin_len = strlen(coinbase_tx) / 2; - uint8_t coinbase_tx_bin[coinbase_tx_bin_len]; - hex2bin(coinbase_tx, coinbase_tx_bin, coinbase_tx_bin_len); - uint8_t both_merkles[64]; - double_sha256_bin(coinbase_tx_bin, coinbase_tx_bin_len, both_merkles); + memcpy(both_merkles, coinbase_tx_hash, 32); for (int i = 0; i < num_merkle_branches; i++) { memcpy(both_merkles + 32, merkle_branches[i], 32); double_sha256_bin(both_merkles, 64, both_merkles); } - bin2hex(both_merkles, 32, dest, 65); + memcpy(dest, both_merkles, 32); } // take a mining_notify struct with ascii hex strings and convert it to a bm_job struct -bm_job construct_bm_job(mining_notify *params, const char *merkle_root, const uint32_t version_mask, const uint32_t difficulty) +bm_job construct_bm_job(mining_notify *params, const uint8_t merkle_root[32], const uint32_t version_mask, const uint32_t difficulty) { bm_job new_job; @@ -54,45 +55,40 @@ bm_job construct_bm_job(mining_notify *params, const char *merkle_root, const ui new_job.ntime = params->ntime; new_job.starting_nonce = 0; new_job.pool_diff = difficulty; + reverse_32bit_words(merkle_root, new_job.merkle_root); - hex2bin(merkle_root, new_job.merkle_root, 32); + uint8_t prev_block_hash[32]; + hex2bin(params->prev_block_hash, prev_block_hash, 32); + reverse_byte_order(prev_block_hash, new_job.prev_block_hash); - // hex2bin(merkle_root, new_job.merkle_root_be, 32); - swap_endian_words(merkle_root, new_job.merkle_root_be); - reverse_bytes(new_job.merkle_root_be, 32); - - swap_endian_words(params->prev_block_hash, new_job.prev_block_hash); - - hex2bin(params->prev_block_hash, new_job.prev_block_hash_be, 32); - reverse_bytes(new_job.prev_block_hash_be, 32); - - ////make the midstate hash + // make the midstate hash uint8_t midstate_data[64]; // copy 68 bytes header data into midstate (and deal with endianess) - memcpy(midstate_data, &new_job.version, 4); // copy version - memcpy(midstate_data + 4, new_job.prev_block_hash, 32); // copy prev_block_hash - memcpy(midstate_data + 36, new_job.merkle_root, 28); // copy merkle_root + memcpy(midstate_data, &new_job.version, 4); // copy version + reverse_32bit_words(new_job.prev_block_hash, midstate_data + 4); + memcpy(midstate_data + 36, merkle_root, 28); // copy the original word order merkle_root - midstate_sha256_bin(midstate_data, 64, new_job.midstate); // make the midstate hash - reverse_bytes(new_job.midstate, 32); // reverse the midstate bytes for the BM job packet + uint8_t midstate[32]; + midstate_sha256_bin(midstate_data, 64, midstate); // make the midstate hash + reverse_32bit_words(midstate, new_job.midstate); // reverse the midstate words for the BM job packet if (version_mask != 0) { uint32_t rolled_version = increment_bitmask(new_job.version, version_mask); memcpy(midstate_data, &rolled_version, 4); - midstate_sha256_bin(midstate_data, 64, new_job.midstate1); - reverse_bytes(new_job.midstate1, 32); + midstate_sha256_bin(midstate_data, 64, midstate); + reverse_32bit_words(midstate, new_job.midstate1); rolled_version = increment_bitmask(rolled_version, version_mask); memcpy(midstate_data, &rolled_version, 4); - midstate_sha256_bin(midstate_data, 64, new_job.midstate2); - reverse_bytes(new_job.midstate2, 32); + midstate_sha256_bin(midstate_data, 64, midstate); + reverse_32bit_words(midstate, new_job.midstate2); rolled_version = increment_bitmask(rolled_version, version_mask); memcpy(midstate_data, &rolled_version, 4); - midstate_sha256_bin(midstate_data, 64, new_job.midstate3); - reverse_bytes(new_job.midstate3, 32); + midstate_sha256_bin(midstate_data, 64, midstate); + reverse_32bit_words(midstate, new_job.midstate3); new_job.num_midstates = 4; } else @@ -126,8 +122,7 @@ static const double truediffone = 2695953529101130949315647634472399133601089873 /* testing a nonce and return the diff - 0 means invalid */ double test_nonce_value(const bm_job *job, const uint32_t nonce, const uint32_t rolled_version) { - double d64, s64, ds; - unsigned char header[80]; + uint8_t header[80]; // // TODO: use the midstate hash instead of hashing the whole header // uint32_t rolled_version = job->version; @@ -137,24 +132,18 @@ double test_nonce_value(const bm_job *job, const uint32_t nonce, const uint32_t // copy data from job to header memcpy(header, &rolled_version, 4); - memcpy(header + 4, job->prev_block_hash, 32); - memcpy(header + 36, job->merkle_root, 32); + reverse_32bit_words(job->prev_block_hash, header + 4); + reverse_32bit_words(job->merkle_root, header + 36); memcpy(header + 68, &job->ntime, 4); memcpy(header + 72, &job->target, 4); memcpy(header + 76, &nonce, 4); - unsigned char hash_buffer[32]; - unsigned char hash_result[32]; - - // double hash the header - mbedtls_sha256(header, 80, hash_buffer, 0); - mbedtls_sha256(hash_buffer, 32, hash_result, 0); - - d64 = truediffone; - s64 = le256todouble(hash_result); - ds = d64 / s64; + uint8_t hash_result[32]; + double_sha256_bin(header, 80, hash_result); - return ds; + double d64 = truediffone; + double s64 = le256todouble(hash_result); + return d64 / s64; } uint32_t increment_bitmask(const uint32_t value, const uint32_t mask) diff --git a/components/stratum/test/test_mining.c b/components/stratum/test/test_mining.c index 89799df3f..fc0d2ebde 100644 --- a/components/stratum/test/test_mining.c +++ b/components/stratum/test/test_mining.c @@ -71,7 +71,7 @@ TEST_CASE("Validate bm job construction", "[mining]") uint8_t expected_midstate_bin[32]; hex2bin("91DFEA528A9F73683D0D495DD6DD7415E1CA21CB411759E3E05D7D5FF285314D", expected_midstate_bin, 32); // bytes are reversed for the midstate on the bm job command packet - reverse_bytes(expected_midstate_bin, 32); + reverse_byte_order(expected_midstate_bin, 32); TEST_ASSERT_EQUAL_UINT8_ARRAY(expected_midstate_bin, job.midstate, 32); } @@ -106,7 +106,7 @@ TEST_CASE("Validate version mask incrementing", "[mining]") // uint8_t expected_midstate_bin[32]; // hex2bin("5FD281AF6A1750EAEE502C04067738BD46C82FC22112FFE797CE7F035D276126", expected_midstate_bin, 32); // // bytes are reversed for the midstate on the bm job command packet -// reverse_bytes(expected_midstate_bin, 32); +// reverse_byte_order(expected_midstate_bin, 32); // TEST_ASSERT_EQUAL_UINT8_ARRAY(expected_midstate_bin, job.midstate, 32); // TEST_ASSERT_EQUAL_UINT32(0x1705ae3a, job.target); // TEST_ASSERT_EQUAL_UINT32(0x6470e2a1, job.ntime); diff --git a/components/stratum/test/test_utils.c b/components/stratum/test/test_utils.c index d71b828c3..80705736b 100644 --- a/components/stratum/test/test_utils.c +++ b/components/stratum/test/test_utils.c @@ -2,10 +2,13 @@ #include "utils.h" #include -TEST_CASE("Test double sha", "[utils]") +TEST_CASE("Test double_sha256_bin", "[utils]") { - const char *input = "68656c6c6f"; - char *output = double_sha256(input); + uint8_t hash[32]; + char output[65]; + const uint8_t *input = { 0x68, 0x65, 0x6c, 0x6c, 0x6f }; + double_sha256_bin(input, 5, result); + bin2hex(hash, 32, output, 65); TEST_ASSERT_EQUAL_STRING("9595c9df90075148eb06860365df33584b75bff782a510c6cd4883a419833d50", output); } diff --git a/components/stratum/utils.c b/components/stratum/utils.c index a11c0a32c..efc38cac9 100644 --- a/components/stratum/utils.c +++ b/components/stratum/utils.c @@ -17,60 +17,6 @@ static const uint8_t hex_val_table[256] = { ['A'] = 10, ['B'] = 11, ['C'] = 12, ['D'] = 13, ['E'] = 14, ['F'] = 15 }; -#ifndef bswap_16 -#define bswap_16(a) ((((uint16_t)(a) << 8) & 0xff00) | (((uint16_t)(a) >> 8) & 0xff)) -#endif - -#ifndef bswap_32 -#define bswap_32(a) ((((uint32_t)(a) << 24) & 0xff000000) | \ - (((uint32_t)(a) << 8) & 0xff0000) | \ - (((uint32_t)(a) >> 8) & 0xff00) | \ - (((uint32_t)(a) >> 24) & 0xff)) -#endif - -/* - * General byte order swapping functions. - */ -#define bswap16(x) __bswap16(x) -#define bswap32(x) __bswap32(x) -#define bswap64(x) __bswap64(x) - -uint32_t swab32(uint32_t v) -{ - return bswap_32(v); -} - -// takes 80 bytes and flips every 4 bytes -void flip80bytes(void *dest_p, const void *src_p) -{ - uint32_t *dest = dest_p; - const uint32_t *src = src_p; - int i; - - for (i = 0; i < 20; i++) - dest[i] = swab32(src[i]); -} - -void flip64bytes(void *dest_p, const void *src_p) -{ - uint32_t *dest = dest_p; - const uint32_t *src = src_p; - int i; - - for (i = 0; i < 16; i++) - dest[i] = swab32(src[i]); -} - -void flip32bytes(void *dest_p, const void *src_p) -{ - uint32_t *dest = dest_p; - const uint32_t *src = src_p; - int i; - - for (i = 0; i < 8; i++) - dest[i] = swab32(src[i]); -} - size_t bin2hex(const uint8_t *buf, size_t buflen, char *hex, size_t hexlen) { if (hexlen < buflen * 2) { @@ -126,24 +72,6 @@ void print_hex(const uint8_t *b, size_t len, fflush(stdout); } -char *double_sha256(const char *hex_string) -{ - size_t bin_len = strlen(hex_string) / 2; - uint8_t *bin = malloc(bin_len); - hex2bin(hex_string, bin, bin_len); - - unsigned char first_hash_output[32], second_hash_output[32]; - - mbedtls_sha256(bin, bin_len, first_hash_output, 0); - mbedtls_sha256(first_hash_output, 32, second_hash_output, 0); - - free(bin); - - char *output_hash = malloc(64 + 1); - bin2hex(second_hash_output, 32, output_hash, 65); - return output_hash; -} - void double_sha256_bin(const uint8_t *data, const size_t data_len, uint8_t dest[32]) { uint8_t first_hash_output[32]; @@ -152,24 +80,6 @@ void double_sha256_bin(const uint8_t *data, const size_t data_len, uint8_t dest[ mbedtls_sha256(first_hash_output, 32, dest, 0); } -void single_sha256_bin(const uint8_t *data, const size_t data_len, uint8_t dest[32]) -{ - // mbedtls_sha256(data, data_len, dest, 0); - - // Initialize SHA256 context - mbedtls_sha256_context sha256_ctx; - mbedtls_sha256_init(&sha256_ctx); - mbedtls_sha256_starts(&sha256_ctx, 0); - - // Compute first SHA256 hash of header - mbedtls_sha256_update(&sha256_ctx, data, 64); - unsigned char hash[32]; - mbedtls_sha256_finish(&sha256_ctx, hash); - - // Compute midstate from hash - memcpy(dest, hash, 32); -} - void midstate_sha256_bin(const uint8_t *data, const size_t data_len, uint8_t dest[32]) { mbedtls_sha256_context midstate; @@ -179,40 +89,34 @@ void midstate_sha256_bin(const uint8_t *data, const size_t data_len, uint8_t des mbedtls_sha256_starts(&midstate, 0); mbedtls_sha256_update(&midstate, data, 64); - // memcpy(dest, midstate.state, 32); - flip32bytes(dest, midstate.state); + memcpy(dest, midstate.state, 32); } -void swap_endian_words(const char *hex_words, uint8_t *output) +void reverse_32bit_words(const uint8_t src[32], uint8_t dest[32]) { - size_t hex_length = strlen(hex_words); - if (hex_length % 8 != 0) - { - fprintf(stderr, "Must be 4-byte word aligned\n"); - exit(EXIT_FAILURE); - } - - size_t binary_length = hex_length / 2; - - for (size_t i = 0; i < binary_length; i += 4) - { - for (int j = 0; j < 4; j++) - { - unsigned int byte_val; - sscanf(hex_words + (i + j) * 2, "%2x", &byte_val); - output[i + (3 - j)] = byte_val; - } - } + uint32_t *s = (uint32_t *)src; + uint32_t *d = (uint32_t *)dest; + + d[0] = s[7]; + d[1] = s[6]; + d[2] = s[5]; + d[3] = s[4]; + d[4] = s[3]; + d[5] = s[2]; + d[6] = s[1]; + d[7] = s[0]; } -void reverse_bytes(uint8_t *data, size_t len) +void reverse_byte_order(const uint8_t src[32], uint8_t dest[32]) { - for (int i = 0; i < len / 2; ++i) - { - uint8_t temp = data[i]; - data[i] = data[len - 1 - i]; - data[len - 1 - i] = temp; - } + dest[ 0] = src[31]; dest[ 1] = src[30]; dest[ 2] = src[29]; dest[ 3] = src[28]; + dest[ 4] = src[27]; dest[ 5] = src[26]; dest[ 6] = src[25]; dest[ 7] = src[24]; + dest[ 8] = src[23]; dest[ 9] = src[22]; dest[10] = src[21]; dest[11] = src[20]; + dest[12] = src[19]; dest[13] = src[18]; dest[14] = src[17]; dest[15] = src[16]; + dest[16] = src[15]; dest[17] = src[14]; dest[18] = src[13]; dest[19] = src[12]; + dest[20] = src[11]; dest[21] = src[10]; dest[22] = src[ 9]; dest[23] = src[ 8]; + dest[24] = src[ 7]; dest[25] = src[ 6]; dest[26] = src[ 5]; dest[27] = src[ 4]; + dest[28] = src[ 3]; dest[29] = src[ 2]; dest[30] = src[ 1]; dest[31] = src[ 0]; } // static const double truediffone = 26959535291011309493156476344723991336010898738574164086137773096960.0; @@ -252,16 +156,6 @@ void prettyHex(unsigned char *buf, int len) printf("%02X]", buf[len - 1]); } -uint32_t flip32(uint32_t val) -{ - uint32_t ret = 0; - ret |= (val & 0xFF) << 24; - ret |= (val & 0xFF00) << 8; - ret |= (val & 0xFF0000) >> 8; - ret |= (val & 0xFF000000) >> 24; - return ret; -} - /* Calculate the network difficulty from nBits */ double networkDifficulty(uint32_t nBits) { diff --git a/main/self_test/self_test.c b/main/self_test/self_test.c index 1fd20f880..f58baabcd 100644 --- a/main/self_test/self_test.c +++ b/main/self_test/self_test.c @@ -361,15 +361,20 @@ bool self_test(void * pvParameters) notify_message.target = 0x1705ae3a; notify_message.ntime = 0x647025b5; - const char * coinbase_tx = "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4b0389130cfab" - "e6d6d5cbab26a2599e92916edec" - "5657a94a0708ddb970f5c45b5d12905085617eff8e010000000000000031650707758de07b010000000000001cfd703" - "8212f736c7573682f0000000003" - "79ad0c2a000000001976a9147c154ed1dc59609e3d26abb2df2ea3d587cd8c4188ac00000000000000002c6a4c29525" - "34b424c4f434b3ae725d3994b81" - "1572c1f345deb98b56b465ef8e153ecbbd27fa37bf1b005161380000000000000000266a24aa21a9ed63b06a7946b19" - "0a3fda1d76165b25c9b883bcc66" - "21b040773050ee2a1bb18f1800000000"; + char extranonce_2_str[17]; + extranonce_2_generate(1, 8, extranonce_2_str); + + uint8_t coinbase_tx_hash[32]; + calculate_coinbase_tx_hash("01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4b0389130cfab" + "e6d6d5cbab26a2599e92916edec5657a94a0708ddb970f5c45b5d", + "31650707758de07b010000000000001cfd7038212f736c7573682f000000000379ad0c2a000000001976a9147c154ed" + "1dc59609e3d26abb2df2ea3d587cd8c4188ac00000000000000002c6a4c2952534b424c4f434b3ae725d3994b811572" + "c1f345deb98b56b465ef8e153ecbbd27fa37bf1b005161380000000000000000266a24aa21a9ed63b06a7946b190a3f" + "da1d76165b25c9b883bcc6621b040773050ee2a1bb18f1800000000", + "12905085617eff8e", + extranonce_2_str, + coinbase_tx_hash); + uint8_t merkles[13][32]; int num_merkles = 13; @@ -387,9 +392,8 @@ bool self_test(void * pvParameters) hex2bin("c4f5ab01913fc186d550c1a28f3f3e9ffaca2016b961a6a751f8cca0089df924", merkles[11], 32); hex2bin("cff737e1d00176dd6bbfa73071adbb370f227cfb5fba186562e4060fcec877e1", merkles[12], 32); - char merkle_root[65]; - - calculate_merkle_root_hash(coinbase_tx, merkles, num_merkles, merkle_root); + uint8_t merkle_root[32]; + calculate_merkle_root_hash(coinbase_tx_hash, merkles, num_merkles, merkle_root); bm_job job = construct_bm_job(¬ify_message, merkle_root, 0x1fffe000, 1000000); diff --git a/main/tasks/create_jobs_task.c b/main/tasks/create_jobs_task.c index 65d3857e5..75424627d 100644 --- a/main/tasks/create_jobs_task.c +++ b/main/tasks/create_jobs_task.c @@ -87,21 +87,17 @@ static void generate_work(GlobalState *GLOBAL_STATE, mining_notify *notification //print generated extranonce_2 //ESP_LOGI(TAG, "Generated extranonce_2: %s", extranonce_2_str); - char *coinbase_tx = construct_coinbase_tx(notification->coinbase_1, notification->coinbase_2, GLOBAL_STATE->extranonce_str, extranonce_2_str); - if (coinbase_tx == NULL) { - ESP_LOGE(TAG, "Failed to construct coinbase_tx"); - return; - } + uint8_t coinbase_tx_hash[32]; + calculate_coinbase_tx_hash(notification->coinbase_1, notification->coinbase_2, GLOBAL_STATE->extranonce_str, extranonce_2_str, coinbase_tx_hash); - char merkle_root[65]; - calculate_merkle_root_hash(coinbase_tx, (uint8_t(*)[32])notification->merkle_branches, notification->n_merkle_branches, merkle_root); + uint8_t merkle_root[32]; + calculate_merkle_root_hash(coinbase_tx_hash, (uint8_t(*)[32])notification->merkle_branches, notification->n_merkle_branches, merkle_root); bm_job next_job = construct_bm_job(notification, merkle_root, GLOBAL_STATE->version_mask, difficulty); bm_job *queued_next_job = malloc(sizeof(bm_job)); if (queued_next_job == NULL) { ESP_LOGE(TAG, "Failed to allocate memory for queued_next_job"); - free(coinbase_tx); return; } @@ -111,6 +107,4 @@ static void generate_work(GlobalState *GLOBAL_STATE, mining_notify *notification queued_next_job->version_mask = GLOBAL_STATE->version_mask; queue_enqueue(&GLOBAL_STATE->ASIC_jobs_queue, queued_next_job); - - free(coinbase_tx); -} \ No newline at end of file +} From fcda3540bf88206316567ba492a8802feb1edaf5 Mon Sep 17 00:00:00 2001 From: mutatrum Date: Tue, 4 Nov 2025 11:18:51 +0100 Subject: [PATCH 02/20] Restore comment --- components/stratum/mining.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/components/stratum/mining.c b/components/stratum/mining.c index 15eab0522..9d2a97b56 100644 --- a/components/stratum/mining.c +++ b/components/stratum/mining.c @@ -65,13 +65,13 @@ bm_job construct_bm_job(mining_notify *params, const uint8_t merkle_root[32], co uint8_t midstate_data[64]; // copy 68 bytes header data into midstate (and deal with endianess) - memcpy(midstate_data, &new_job.version, 4); // copy version - reverse_32bit_words(new_job.prev_block_hash, midstate_data + 4); - memcpy(midstate_data + 36, merkle_root, 28); // copy the original word order merkle_root + memcpy(midstate_data, &new_job.version, 4); // copy version + reverse_32bit_words(new_job.prev_block_hash, midstate_data + 4); // copy prev_block_hash in reverse word order + memcpy(midstate_data + 36, merkle_root, 28); // copy the original word order merkle_root uint8_t midstate[32]; - midstate_sha256_bin(midstate_data, 64, midstate); // make the midstate hash - reverse_32bit_words(midstate, new_job.midstate); // reverse the midstate words for the BM job packet + midstate_sha256_bin(midstate_data, 64, midstate); // make the midstate hash + reverse_32bit_words(midstate, new_job.midstate); // reverse the midstate words for the BM job packet if (version_mask != 0) { From 70f6886a00d4012429671ff5873a3928d55066f9 Mon Sep 17 00:00:00 2001 From: mutatrum Date: Tue, 4 Nov 2025 11:21:39 +0100 Subject: [PATCH 03/20] Fix test --- components/stratum/test/test_utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/stratum/test/test_utils.c b/components/stratum/test/test_utils.c index 80705736b..29a050a85 100644 --- a/components/stratum/test/test_utils.c +++ b/components/stratum/test/test_utils.c @@ -6,7 +6,7 @@ TEST_CASE("Test double_sha256_bin", "[utils]") { uint8_t hash[32]; char output[65]; - const uint8_t *input = { 0x68, 0x65, 0x6c, 0x6c, 0x6f }; + const char input[] = "hello"; double_sha256_bin(input, 5, result); bin2hex(hash, 32, output, 65); TEST_ASSERT_EQUAL_STRING("9595c9df90075148eb06860365df33584b75bff782a510c6cd4883a419833d50", output); From c91d9f6979c9ba2126b38bae86ca65300ebd1e1c Mon Sep 17 00:00:00 2001 From: mutatrum Date: Tue, 4 Nov 2025 11:27:41 +0100 Subject: [PATCH 04/20] More test fix --- components/stratum/test/test_utils.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/stratum/test/test_utils.c b/components/stratum/test/test_utils.c index 29a050a85..6ad72f47d 100644 --- a/components/stratum/test/test_utils.c +++ b/components/stratum/test/test_utils.c @@ -4,10 +4,10 @@ TEST_CASE("Test double_sha256_bin", "[utils]") { + const char input[] = "hello"; uint8_t hash[32]; + double_sha256_bin((uint8_t *)input, 5, hash); char output[65]; - const char input[] = "hello"; - double_sha256_bin(input, 5, result); bin2hex(hash, 32, output, 65); TEST_ASSERT_EQUAL_STRING("9595c9df90075148eb06860365df33584b75bff782a510c6cd4883a419833d50", output); } From 7bbf56758c75f715633d6cbdd895b973f23bf141 Mon Sep 17 00:00:00 2001 From: mutatrum Date: Tue, 4 Nov 2025 11:39:30 +0100 Subject: [PATCH 05/20] Fix some test_mining tests --- components/stratum/test/test_mining.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/components/stratum/test/test_mining.c b/components/stratum/test/test_mining.c index fc0d2ebde..4ac8c40a1 100644 --- a/components/stratum/test/test_mining.c +++ b/components/stratum/test/test_mining.c @@ -10,7 +10,10 @@ TEST_CASE("Check coinbase tx construction", "[mining]") const char *coinbase_2 = "072f736c7573682f000000000100f2052a010000001976a914d23fcdf86f7e756a64a7a9688ef9903327048ed988ac00000000"; const char *extranonce = "e9695791"; const char *extranonce_2 = "99999999"; - char *coinbase_tx = construct_coinbase_tx(coinbase_1, coinbase_2, extranonce, extranonce_2); + uint8_t coinbase_tx_hash[32]; + construct_coinbase_tx(coinbase_1, coinbase_2, extranonce, extranonce_2, coinbase_tx_hash); + char coinbase_tx[65]; + bin2hex(coinbase_tx_hash, 32, coinbase_tx, 65); TEST_ASSERT_EQUAL_STRING(coinbase_tx, "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff20020862062f503253482f04b8864e5008e969579199999999072f736c7573682f000000000100f2052a010000001976a914d23fcdf86f7e756a64a7a9688ef9903327048ed988ac00000000"); free(coinbase_tx); } @@ -18,7 +21,8 @@ TEST_CASE("Check coinbase tx construction", "[mining]") // Values calculated from esp-miner/components/stratum/test/verifiers/merklecalc.py TEST_CASE("Validate merkle root calculation", "[mining]") { - const char *coinbase_tx = "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff20020862062f503253482f04b8864e5008e969579199999999072f736c7573682f000000000100f2052a010000001976a914d23fcdf86f7e756a64a7a9688ef9903327048ed988ac00000000"; + uint8_t coinbase_tx_hash[32]; + hex2bin("01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff20020862062f503253482f04b8864e5008e969579199999999072f736c7573682f000000000100f2052a010000001976a914d23fcdf86f7e756a64a7a9688ef9903327048ed988ac00000000", coinbase_tx_hash); uint8_t merkles[12][32]; int num_merkles = 12; @@ -36,13 +40,14 @@ TEST_CASE("Validate merkle root calculation", "[mining]") hex2bin("03d287f655813e540ddb9c4e7aeb922478662b0f5d8e9d0cbd564b20146bab76", merkles[11], 32); char root_hash[65]; - calculate_merkle_root_hash(coinbase_tx, merkles, num_merkles, root_hash); + calculate_merkle_root_hash(coinbase_tx_hash, merkles, num_merkles, root_hash); TEST_ASSERT_EQUAL_STRING("adbcbc21e20388422198a55957aedfa0e61be0b8f2b87d7c08510bb9f099a893", root_hash); } TEST_CASE("Validate another merkle root calculation", "[mining]") { - const char *coinbase_tx = "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff2503777d07062f503253482f0405b8c75208f800880e000000000b2f436f696e48756e74722f0000000001603f352a010000001976a914c633315d376c20a973a758f7422d67f7bfed9c5888ac00000000"; + uint8_t coinbase_tx_hash[32]; + hex2bin("01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff2503777d07062f503253482f0405b8c75208f800880e000000000b2f436f696e48756e74722f0000000001603f352a010000001976a914c633315d376c20a973a758f7422d67f7bfed9c5888ac00000000", coinbase_tx_hash); uint8_t merkles[5][32]; int num_merkles = 5; @@ -53,7 +58,7 @@ TEST_CASE("Validate another merkle root calculation", "[mining]") hex2bin("2d0b54af60fad4ae59ec02031f661d026f2bb95e2eeb1e6657a35036c017c595", merkles[4], 32); char root_hash[65]; - calculate_merkle_root_hash(coinbase_tx, merkles, num_merkles, root_hash); + calculate_merkle_root_hash(coinbase_tx_hash, merkles, num_merkles, root_hash); TEST_ASSERT_EQUAL_STRING("5cc58f5e84aafc740d521b92a7bf72f4e56c4cc3ad1c2159f1d094f97ac34eee", root_hash); } From 00231f30b4fdf40563eb1fbe17a0cdeeba76f036 Mon Sep 17 00:00:00 2001 From: mutatrum Date: Tue, 4 Nov 2025 11:50:23 +0100 Subject: [PATCH 06/20] Slowly fixing more tests --- components/stratum/test/test_mining.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/components/stratum/test/test_mining.c b/components/stratum/test/test_mining.c index 4ac8c40a1..4b6b213b8 100644 --- a/components/stratum/test/test_mining.c +++ b/components/stratum/test/test_mining.c @@ -11,18 +11,17 @@ TEST_CASE("Check coinbase tx construction", "[mining]") const char *extranonce = "e9695791"; const char *extranonce_2 = "99999999"; uint8_t coinbase_tx_hash[32]; - construct_coinbase_tx(coinbase_1, coinbase_2, extranonce, extranonce_2, coinbase_tx_hash); + calculate_coinbase_tx_hash(coinbase_1, coinbase_2, extranonce, extranonce_2, coinbase_tx_hash); char coinbase_tx[65]; bin2hex(coinbase_tx_hash, 32, coinbase_tx, 65); TEST_ASSERT_EQUAL_STRING(coinbase_tx, "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff20020862062f503253482f04b8864e5008e969579199999999072f736c7573682f000000000100f2052a010000001976a914d23fcdf86f7e756a64a7a9688ef9903327048ed988ac00000000"); - free(coinbase_tx); } // Values calculated from esp-miner/components/stratum/test/verifiers/merklecalc.py TEST_CASE("Validate merkle root calculation", "[mining]") { uint8_t coinbase_tx_hash[32]; - hex2bin("01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff20020862062f503253482f04b8864e5008e969579199999999072f736c7573682f000000000100f2052a010000001976a914d23fcdf86f7e756a64a7a9688ef9903327048ed988ac00000000", coinbase_tx_hash); + hex2bin("01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff20020862062f503253482f04b8864e5008e969579199999999072f736c7573682f000000000100f2052a010000001976a914d23fcdf86f7e756a64a7a9688ef9903327048ed988ac00000000", coinbase_tx_hash, 32); uint8_t merkles[12][32]; int num_merkles = 12; @@ -39,15 +38,17 @@ TEST_CASE("Validate merkle root calculation", "[mining]") hex2bin("463c19427286342120039a83218fa87ce45448e246895abac11fff0036076758", merkles[10], 32); hex2bin("03d287f655813e540ddb9c4e7aeb922478662b0f5d8e9d0cbd564b20146bab76", merkles[11], 32); + uint32_t root_hash_bin[32]; + calculate_merkle_root_hash(coinbase_tx_hash, merkles, num_merkles, root_hash_bin); char root_hash[65]; - calculate_merkle_root_hash(coinbase_tx_hash, merkles, num_merkles, root_hash); + bin2hex(root_hash_bin, 32, root_hash, 65); TEST_ASSERT_EQUAL_STRING("adbcbc21e20388422198a55957aedfa0e61be0b8f2b87d7c08510bb9f099a893", root_hash); } TEST_CASE("Validate another merkle root calculation", "[mining]") { uint8_t coinbase_tx_hash[32]; - hex2bin("01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff2503777d07062f503253482f0405b8c75208f800880e000000000b2f436f696e48756e74722f0000000001603f352a010000001976a914c633315d376c20a973a758f7422d67f7bfed9c5888ac00000000", coinbase_tx_hash); + hex2bin("01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff2503777d07062f503253482f0405b8c75208f800880e000000000b2f436f696e48756e74722f0000000001603f352a010000001976a914c633315d376c20a973a758f7422d67f7bfed9c5888ac00000000", coinbase_tx_hash, 32); uint8_t merkles[5][32]; int num_merkles = 5; @@ -57,8 +58,10 @@ TEST_CASE("Validate another merkle root calculation", "[mining]") hex2bin("9f64f3b0d9edddb14be6f71c3ac2e80455916e207ffc003316c6a515452aa7b4", merkles[3], 32); hex2bin("2d0b54af60fad4ae59ec02031f661d026f2bb95e2eeb1e6657a35036c017c595", merkles[4], 32); + uint32_t root_hash_bin[32]; + calculate_merkle_root_hash(coinbase_tx_hash, merkles, num_merkles, root_hash_bin); char root_hash[65]; - calculate_merkle_root_hash(coinbase_tx_hash, merkles, num_merkles, root_hash); + bin2hex(root_hash_bin, 32, root_hash, 65); TEST_ASSERT_EQUAL_STRING("5cc58f5e84aafc740d521b92a7bf72f4e56c4cc3ad1c2159f1d094f97ac34eee", root_hash); } @@ -70,7 +73,8 @@ TEST_CASE("Validate bm job construction", "[mining]") notify_message.version = 0x20000004; notify_message.target = 0x1705dd01; notify_message.ntime = 0x64658bd8; - const char *merkle_root = "cd1be82132ef0d12053dcece1fa0247fcfdb61d4dbd3eb32ea9ef9b4c604a846"; + const uint8_t merkle_root[32]; + hex2bin("cd1be82132ef0d12053dcece1fa0247fcfdb61d4dbd3eb32ea9ef9b4c604a846", merke_root, 32); bm_job job = construct_bm_job(¬ify_message, merkle_root, 0, 1000); uint8_t expected_midstate_bin[32]; @@ -151,7 +155,8 @@ TEST_CASE("Test nonce diff checking", "[mining test_nonce][not-on-qemu]") notify_message.version = 0x20000004; notify_message.target = 0x1705ae3a; notify_message.ntime = 0x646ff1a9; - const char *merkle_root = "6d0359c451434605c52a5a9ce074340be47c2c63840731f9edf1db3f26b1cdd9a9f16f64"; + const uint8_t merkle_root[32]; + hex2bin("6d0359c451434605c52a5a9ce074340be47c2c63840731f9edf1db3f26b1cdd9a9f16f64", merkle_root, 32); bm_job job = construct_bm_job(¬ify_message, merkle_root, 0, 1000); uint32_t nonce = 0x276E8947; From 3a982e03f4e92d45904f974da5f478ce053a0ca8 Mon Sep 17 00:00:00 2001 From: mutatrum Date: Tue, 4 Nov 2025 12:02:36 +0100 Subject: [PATCH 07/20] One more time --- components/stratum/test/test_mining.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/components/stratum/test/test_mining.c b/components/stratum/test/test_mining.c index 4b6b213b8..611360d46 100644 --- a/components/stratum/test/test_mining.c +++ b/components/stratum/test/test_mining.c @@ -38,7 +38,7 @@ TEST_CASE("Validate merkle root calculation", "[mining]") hex2bin("463c19427286342120039a83218fa87ce45448e246895abac11fff0036076758", merkles[10], 32); hex2bin("03d287f655813e540ddb9c4e7aeb922478662b0f5d8e9d0cbd564b20146bab76", merkles[11], 32); - uint32_t root_hash_bin[32]; + uint8_t root_hash_bin[32]; calculate_merkle_root_hash(coinbase_tx_hash, merkles, num_merkles, root_hash_bin); char root_hash[65]; bin2hex(root_hash_bin, 32, root_hash, 65); @@ -58,7 +58,7 @@ TEST_CASE("Validate another merkle root calculation", "[mining]") hex2bin("9f64f3b0d9edddb14be6f71c3ac2e80455916e207ffc003316c6a515452aa7b4", merkles[3], 32); hex2bin("2d0b54af60fad4ae59ec02031f661d026f2bb95e2eeb1e6657a35036c017c595", merkles[4], 32); - uint32_t root_hash_bin[32]; + uint8_t root_hash_bin[32]; calculate_merkle_root_hash(coinbase_tx_hash, merkles, num_merkles, root_hash_bin); char root_hash[65]; bin2hex(root_hash_bin, 32, root_hash, 65); @@ -73,15 +73,16 @@ TEST_CASE("Validate bm job construction", "[mining]") notify_message.version = 0x20000004; notify_message.target = 0x1705dd01; notify_message.ntime = 0x64658bd8; - const uint8_t merkle_root[32]; + uint8_t merkle_root[32]; hex2bin("cd1be82132ef0d12053dcece1fa0247fcfdb61d4dbd3eb32ea9ef9b4c604a846", merke_root, 32); bm_job job = construct_bm_job(¬ify_message, merkle_root, 0, 1000); uint8_t expected_midstate_bin[32]; hex2bin("91DFEA528A9F73683D0D495DD6DD7415E1CA21CB411759E3E05D7D5FF285314D", expected_midstate_bin, 32); // bytes are reversed for the midstate on the bm job command packet - reverse_byte_order(expected_midstate_bin, 32); - TEST_ASSERT_EQUAL_UINT8_ARRAY(expected_midstate_bin, job.midstate, 32); + uint8_t expected_midstate_bin_reversed[32]; + reverse_byte_order(expected_midstate_bin, expected_midstate_bin_reversed); + TEST_ASSERT_EQUAL_UINT8_ARRAY(expected_midstate_bin_reversed, job.midstate, 32); } TEST_CASE("Validate version mask incrementing", "[mining]") @@ -155,7 +156,7 @@ TEST_CASE("Test nonce diff checking", "[mining test_nonce][not-on-qemu]") notify_message.version = 0x20000004; notify_message.target = 0x1705ae3a; notify_message.ntime = 0x646ff1a9; - const uint8_t merkle_root[32]; + uint8_t merkle_root[32]; hex2bin("6d0359c451434605c52a5a9ce074340be47c2c63840731f9edf1db3f26b1cdd9a9f16f64", merkle_root, 32); bm_job job = construct_bm_job(¬ify_message, merkle_root, 0, 1000); @@ -172,7 +173,13 @@ TEST_CASE("Test nonce diff checking 2", "[mining test_nonce][not-on-qemu]") notify_message.target = 0x1705ae3a; notify_message.ntime = 0x647025b5; - const char *coinbase_tx = "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4b0389130cfabe6d6d5cbab26a2599e92916edec5657a94a0708ddb970f5c45b5d12905085617eff8e010000000000000031650707758de07b010000000000001cfd7038212f736c7573682f000000000379ad0c2a000000001976a9147c154ed1dc59609e3d26abb2df2ea3d587cd8c4188ac00000000000000002c6a4c2952534b424c4f434b3ae725d3994b811572c1f345deb98b56b465ef8e153ecbbd27fa37bf1b005161380000000000000000266a24aa21a9ed63b06a7946b190a3fda1d76165b25c9b883bcc6621b040773050ee2a1bb18f1800000000"; + const uint8_t coinbase_tx_hash[32]; + calculate_coinbase_tx_hash( + "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4b0389130cfabe6d6d5cbab26a2599e92916edec5657a94a0708ddb970f5c45b5d12905085617eff8e", + "31650707758de07b010000000000001cfd7038212f736c7573682f000000000379ad0c2a000000001976a9147c154ed1dc59609e3d26abb2df2ea3d587cd8c4188ac00000000000000002c6a4c2952534b424c4f434b3ae725d3994b811572c1f345deb98b56b465ef8e153ecbbd27fa37bf1b005161380000000000000000266a24aa21a9ed63b06a7946b190a3fda1d76165b25c9b883bcc6621b040773050ee2a1bb18f1800000000", + "01000000", + "00000000", + coinbase_tx_hash); uint8_t merkles[13][32]; int num_merkles = 13; @@ -190,8 +197,10 @@ TEST_CASE("Test nonce diff checking 2", "[mining test_nonce][not-on-qemu]") hex2bin("c4f5ab01913fc186d550c1a28f3f3e9ffaca2016b961a6a751f8cca0089df924", merkles[11], 32); hex2bin("cff737e1d00176dd6bbfa73071adbb370f227cfb5fba186562e4060fcec877e1", merkles[12], 32); + uint8_t merkle_root_hash[32]; + calculate_merkle_root_hash(coinbase_tx_hash, merkles, num_merkles, merkle_root_hash); char merkle_root[65]; - calculate_merkle_root_hash(coinbase_tx, merkles, num_merkles, merkle_root); + bin2hex(merkle_root_hash, 32, merkle_root, 65); TEST_ASSERT_EQUAL_STRING("5bdc1968499c3393873edf8e07a1c3a50a97fc3a9d1a376bbf77087dd63778eb", merkle_root); bm_job job = construct_bm_job(¬ify_message, merkle_root, 0, 1000); From 54e33f05b7529dfbe5ce45eff9604a7916d470fb Mon Sep 17 00:00:00 2001 From: mutatrum Date: Tue, 4 Nov 2025 12:06:49 +0100 Subject: [PATCH 08/20] Maybe the last one? --- components/stratum/test/test_mining.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/stratum/test/test_mining.c b/components/stratum/test/test_mining.c index 611360d46..43caf5e68 100644 --- a/components/stratum/test/test_mining.c +++ b/components/stratum/test/test_mining.c @@ -74,7 +74,7 @@ TEST_CASE("Validate bm job construction", "[mining]") notify_message.target = 0x1705dd01; notify_message.ntime = 0x64658bd8; uint8_t merkle_root[32]; - hex2bin("cd1be82132ef0d12053dcece1fa0247fcfdb61d4dbd3eb32ea9ef9b4c604a846", merke_root, 32); + hex2bin("cd1be82132ef0d12053dcece1fa0247fcfdb61d4dbd3eb32ea9ef9b4c604a846", merkle_root, 32); bm_job job = construct_bm_job(¬ify_message, merkle_root, 0, 1000); uint8_t expected_midstate_bin[32]; @@ -173,7 +173,7 @@ TEST_CASE("Test nonce diff checking 2", "[mining test_nonce][not-on-qemu]") notify_message.target = 0x1705ae3a; notify_message.ntime = 0x647025b5; - const uint8_t coinbase_tx_hash[32]; + uint8_t coinbase_tx_hash[32]; calculate_coinbase_tx_hash( "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4b0389130cfabe6d6d5cbab26a2599e92916edec5657a94a0708ddb970f5c45b5d12905085617eff8e", "31650707758de07b010000000000001cfd7038212f736c7573682f000000000379ad0c2a000000001976a9147c154ed1dc59609e3d26abb2df2ea3d587cd8c4188ac00000000000000002c6a4c2952534b424c4f434b3ae725d3994b811572c1f345deb98b56b465ef8e153ecbbd27fa37bf1b005161380000000000000000266a24aa21a9ed63b06a7946b190a3fda1d76165b25c9b883bcc6621b040773050ee2a1bb18f1800000000", @@ -203,7 +203,7 @@ TEST_CASE("Test nonce diff checking 2", "[mining test_nonce][not-on-qemu]") bin2hex(merkle_root_hash, 32, merkle_root, 65); TEST_ASSERT_EQUAL_STRING("5bdc1968499c3393873edf8e07a1c3a50a97fc3a9d1a376bbf77087dd63778eb", merkle_root); - bm_job job = construct_bm_job(¬ify_message, merkle_root, 0, 1000); + bm_job job = construct_bm_job(¬ify_message, merkle_root_hash, 0, 1000); uint32_t nonce = 0x0a029ed1; double diff = test_nonce_value(&job, nonce, 0); From 8c6ce753a3e07b7d05f2541c7758ed8ad3b1ba8d Mon Sep 17 00:00:00 2001 From: mutatrum Date: Tue, 4 Nov 2025 12:25:46 +0100 Subject: [PATCH 09/20] So close --- components/stratum/test/test_mining.c | 37 +++++++++++++++++++-------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/components/stratum/test/test_mining.c b/components/stratum/test/test_mining.c index 43caf5e68..b04d2fb4b 100644 --- a/components/stratum/test/test_mining.c +++ b/components/stratum/test/test_mining.c @@ -6,22 +6,34 @@ TEST_CASE("Check coinbase tx construction", "[mining]") { - const char *coinbase_1 = "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff20020862062f503253482f04b8864e5008"; - const char *coinbase_2 = "072f736c7573682f000000000100f2052a010000001976a914d23fcdf86f7e756a64a7a9688ef9903327048ed988ac00000000"; - const char *extranonce = "e9695791"; - const char *extranonce_2 = "99999999"; + const char *coinbase_1 = "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff20020862062f503253482f04b8864e5008e969579199999999072f736c7573682f0000000001"; + const char *coinbase_2 = "1976a914d23fcdf86f7e756a64a7a9688ef9903327048ed988ac00000000"; + const char *extranonce = "00f2052a"; + const char *extranonce_2 = "01000000"; uint8_t coinbase_tx_hash[32]; calculate_coinbase_tx_hash(coinbase_1, coinbase_2, extranonce, extranonce_2, coinbase_tx_hash); - char coinbase_tx[65]; - bin2hex(coinbase_tx_hash, 32, coinbase_tx, 65); - TEST_ASSERT_EQUAL_STRING(coinbase_tx, "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff20020862062f503253482f04b8864e5008e969579199999999072f736c7573682f000000000100f2052a010000001976a914d23fcdf86f7e756a64a7a9688ef9903327048ed988ac00000000"); + + char expected_coinbase_tx[] = "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff20020862062f503253482f04b8864e5008e969579199999999072f736c7573682f000000000100f2052a010000001976a914d23fcdf86f7e756a64a7a9688ef9903327048ed988ac00000000"; + size_t expected_coinbase_tx_len = strlen(expected_coinbase_tx) / 2; + uint8_t expected_coinbase_tx_bin[expected_coinbase_tx_len]; + hex2bin(expected_coinbase_tx, expected_coinbase_tx_bin, expected_coinbase_tx_len); + + uint8_t expected_coinbase_tx_hash[32]; + double_sha256_bin(expected_coinbase_tx_bin, expected_coinbase_tx_len, expected_coinbase_tx_hash); + + TEST_ASSERT_EQUAL_UINT8_ARRAY(expected_coinbase_tx_hash, coinbase_tx_hash, 32); } // Values calculated from esp-miner/components/stratum/test/verifiers/merklecalc.py TEST_CASE("Validate merkle root calculation", "[mining]") { + const char *coinbase_1 = "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff20020862062f503253482f04b8864e5008e969579199999999072f736c7573682f0000000001"; + const char *coinbase_2 = "1976a914d23fcdf86f7e756a64a7a9688ef9903327048ed988ac00000000"; + const char *extranonce = "00f2052a"; + const char *extranonce_2 = "01000000"; uint8_t coinbase_tx_hash[32]; - hex2bin("01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff20020862062f503253482f04b8864e5008e969579199999999072f736c7573682f000000000100f2052a010000001976a914d23fcdf86f7e756a64a7a9688ef9903327048ed988ac00000000", coinbase_tx_hash, 32); + calculate_coinbase_tx_hash(coinbase_1, coinbase_2, extranonce, extranonce_2, coinbase_tx_hash); + uint8_t merkles[12][32]; int num_merkles = 12; @@ -47,8 +59,13 @@ TEST_CASE("Validate merkle root calculation", "[mining]") TEST_CASE("Validate another merkle root calculation", "[mining]") { - uint8_t coinbase_tx_hash[32]; - hex2bin("01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff2503777d07062f503253482f0405b8c75208f800880e000000000b2f436f696e48756e74722f0000000001603f352a010000001976a914c633315d376c20a973a758f7422d67f7bfed9c5888ac00000000", coinbase_tx_hash, 32); + const char *coinbase_1 = "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff2503777d07062f503253482f0405b8c75208f800880e000000000b2f436f696e48756e74722f0000000001"; + const char *coinbase_2 = "1976a914c633315d376c20a973a758f7422d67f7bfed9c5888ac00000000"; + const char *extranonce = "603f352a"; + const char *extranonce_2 = "01000000"; + uint8_t coinbase_tx_hash[32]; + calculate_coinbase_tx_hash(coinbase_1, coinbase_2, extranonce, extranonce_2, coinbase_tx_hash); + uint8_t merkles[5][32]; int num_merkles = 5; From 285e4058a4363e6abbf44f7e4eee78ec94ad3056 Mon Sep 17 00:00:00 2001 From: mutatrum Date: Tue, 4 Nov 2025 12:27:00 +0100 Subject: [PATCH 10/20] Revert coinbase tx construction setup --- components/stratum/test/test_mining.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/components/stratum/test/test_mining.c b/components/stratum/test/test_mining.c index b04d2fb4b..46ef307ce 100644 --- a/components/stratum/test/test_mining.c +++ b/components/stratum/test/test_mining.c @@ -6,10 +6,10 @@ TEST_CASE("Check coinbase tx construction", "[mining]") { - const char *coinbase_1 = "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff20020862062f503253482f04b8864e5008e969579199999999072f736c7573682f0000000001"; - const char *coinbase_2 = "1976a914d23fcdf86f7e756a64a7a9688ef9903327048ed988ac00000000"; - const char *extranonce = "00f2052a"; - const char *extranonce_2 = "01000000"; + const char *coinbase_1 = "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff20020862062f503253482f04b8864e5008"; + const char *coinbase_2 = "072f736c7573682f000000000100f2052a010000001976a914d23fcdf86f7e756a64a7a9688ef9903327048ed988ac00000000"; + const char *extranonce = "e9695791"; + const char *extranonce_2 = "99999999"; uint8_t coinbase_tx_hash[32]; calculate_coinbase_tx_hash(coinbase_1, coinbase_2, extranonce, extranonce_2, coinbase_tx_hash); From 3eb619ba9e6b40e6561c6087830d78ec2d958116 Mon Sep 17 00:00:00 2001 From: mutatrum Date: Tue, 4 Nov 2025 12:29:38 +0100 Subject: [PATCH 11/20] Missing include --- components/stratum/test/test_mining.c | 1 + 1 file changed, 1 insertion(+) diff --git a/components/stratum/test/test_mining.c b/components/stratum/test/test_mining.c index 46ef307ce..519fa1594 100644 --- a/components/stratum/test/test_mining.c +++ b/components/stratum/test/test_mining.c @@ -3,6 +3,7 @@ #include "utils.h" #include +#include '' TEST_CASE("Check coinbase tx construction", "[mining]") { From b468cc64d440f47c4013620f8678f7a6f204aa83 Mon Sep 17 00:00:00 2001 From: mutatrum Date: Tue, 4 Nov 2025 12:30:23 +0100 Subject: [PATCH 12/20] Fix --- components/stratum/test/test_mining.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/stratum/test/test_mining.c b/components/stratum/test/test_mining.c index 519fa1594..0bb597e7b 100644 --- a/components/stratum/test/test_mining.c +++ b/components/stratum/test/test_mining.c @@ -3,7 +3,7 @@ #include "utils.h" #include -#include '' +#include TEST_CASE("Check coinbase tx construction", "[mining]") { From 4721f8d063e5dcab8b4a920c950fd345c62a841c Mon Sep 17 00:00:00 2001 From: mutatrum Date: Tue, 4 Nov 2025 12:59:29 +0100 Subject: [PATCH 13/20] Add tests for utils --- components/stratum/test/test_utils.c | 41 ++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/components/stratum/test/test_utils.c b/components/stratum/test/test_utils.c index 6ad72f47d..5abb19f74 100644 --- a/components/stratum/test/test_utils.c +++ b/components/stratum/test/test_utils.c @@ -32,3 +32,44 @@ TEST_CASE("Test bin2hex", "[utils]") bin2hex(bin, 5, hex_string, 11); TEST_ASSERT_EQUAL_STRING("48454c4c4f", hex_string); } + +TEST_CASE("reverse_32bit_words", "[utils]") +{ + uint8_t input[32]; + for (int i = 0; i < 32; i++) input[i] = i; + + uint8_t actual[32]; + reverse_32bit_words(input, actual); + + uint8_t expected[32] = {28, 29, 30, 31, 24, 25, 26, 27, + 20, 21, 22, 23, 16, 17, 18, 19, + 12, 13, 14, 15, 8, 9, 10, 11, + 4, 5, 6, 7, 0, 1, 2, 3}; + TEST_ASSERT_EQUAL_UINT8_ARRAY(expected, actual, 32); +} + +TEST_CASE("reverse_byte_order", "[utils]") +{ + uint8_t input[32]; + for (int i = 0; i < 32; i++) input[i] = i; + + uint8_t actual[32]; + reverse_byte_order(input, actual); + + uint8_t expected[32] = {31, 30, 29, 28, 27, 26, 25, 24, + 23, 22, 21, 20, 19, 18, 17, 16, + 15, 14, 13, 12, 11, 10, 9, 8, + 7, 6, 5, 4, 3, 2, 1, 0}; + TEST_ASSERT_EQUAL_UINT8_ARRAY(expected, actual, 32); +} + +TEST_CASE("networkDifficulty", "[utils]") +{ + uint32_t nBits = 0x1701cdfb; + + double actual = networkDifficulty(nBits); + + double expected = 155973032196071.9; + + TEST_ASSERT_EQUAL_DOUBLE(expected, actual); +} From e959cd79acbc1b9a5fd46b0a8bc8f8a96239f800 Mon Sep 17 00:00:00 2001 From: mutatrum Date: Tue, 4 Nov 2025 14:37:05 +0100 Subject: [PATCH 14/20] Don'y copy new bm_job --- components/stratum/include/mining.h | 2 +- components/stratum/mining.c | 38 ++++++++++++--------------- components/stratum/test/test_mining.c | 12 ++++++--- main/self_test/self_test.c | 3 ++- main/tasks/create_jobs_task.c | 18 ++++++------- 5 files changed, 37 insertions(+), 36 deletions(-) diff --git a/components/stratum/include/mining.h b/components/stratum/include/mining.h index be918f9fb..4e8f75524 100644 --- a/components/stratum/include/mining.h +++ b/components/stratum/include/mining.h @@ -30,7 +30,7 @@ void calculate_coinbase_tx_hash(const char *coinbase_1, const char *coinbase_2, void calculate_merkle_root_hash(const uint8_t coinbase_tx_hash[32], const uint8_t merkle_branches[][32], const int num_merkle_branches, uint8_t dest[32]); -bm_job construct_bm_job(mining_notify *params, const uint8_t merkle_root[32], const uint32_t version_mask, const uint32_t difficulty); +void construct_bm_job(mining_notify *params, const uint8_t merkle_root[32], const uint32_t version_mask, const uint32_t difficulty, bm_job* new_job); double test_nonce_value(const bm_job *job, const uint32_t nonce, const uint32_t rolled_version); diff --git a/components/stratum/mining.c b/components/stratum/mining.c index 9d2a97b56..63e3b2472 100644 --- a/components/stratum/mining.c +++ b/components/stratum/mining.c @@ -46,57 +46,53 @@ void calculate_merkle_root_hash(const uint8_t coinbase_tx_hash[32], const uint8_ } // take a mining_notify struct with ascii hex strings and convert it to a bm_job struct -bm_job construct_bm_job(mining_notify *params, const uint8_t merkle_root[32], const uint32_t version_mask, const uint32_t difficulty) +void construct_bm_job(mining_notify *params, const uint8_t merkle_root[32], const uint32_t version_mask, const uint32_t difficulty, bm_job *new_job) { - bm_job new_job; - - new_job.version = params->version; - new_job.target = params->target; - new_job.ntime = params->ntime; - new_job.starting_nonce = 0; - new_job.pool_diff = difficulty; - reverse_32bit_words(merkle_root, new_job.merkle_root); + new_job->version = params->version; + new_job->target = params->target; + new_job->ntime = params->ntime; + new_job->starting_nonce = 0; + new_job->pool_diff = difficulty; + reverse_32bit_words(merkle_root, new_job->merkle_root); uint8_t prev_block_hash[32]; hex2bin(params->prev_block_hash, prev_block_hash, 32); - reverse_byte_order(prev_block_hash, new_job.prev_block_hash); + reverse_byte_order(prev_block_hash, new_job->prev_block_hash); // make the midstate hash uint8_t midstate_data[64]; // copy 68 bytes header data into midstate (and deal with endianess) - memcpy(midstate_data, &new_job.version, 4); // copy version - reverse_32bit_words(new_job.prev_block_hash, midstate_data + 4); // copy prev_block_hash in reverse word order + memcpy(midstate_data, &new_job->version, 4); // copy version + reverse_32bit_words(new_job->prev_block_hash, midstate_data + 4); // copy prev_block_hash in reverse word order memcpy(midstate_data + 36, merkle_root, 28); // copy the original word order merkle_root uint8_t midstate[32]; midstate_sha256_bin(midstate_data, 64, midstate); // make the midstate hash - reverse_32bit_words(midstate, new_job.midstate); // reverse the midstate words for the BM job packet + reverse_32bit_words(midstate, new_job->midstate); // reverse the midstate words for the BM job packet if (version_mask != 0) { - uint32_t rolled_version = increment_bitmask(new_job.version, version_mask); + uint32_t rolled_version = increment_bitmask(new_job->version, version_mask); memcpy(midstate_data, &rolled_version, 4); midstate_sha256_bin(midstate_data, 64, midstate); - reverse_32bit_words(midstate, new_job.midstate1); + reverse_32bit_words(midstate, new_job->midstate1); rolled_version = increment_bitmask(rolled_version, version_mask); memcpy(midstate_data, &rolled_version, 4); midstate_sha256_bin(midstate_data, 64, midstate); - reverse_32bit_words(midstate, new_job.midstate2); + reverse_32bit_words(midstate, new_job->midstate2); rolled_version = increment_bitmask(rolled_version, version_mask); memcpy(midstate_data, &rolled_version, 4); midstate_sha256_bin(midstate_data, 64, midstate); - reverse_32bit_words(midstate, new_job.midstate3); - new_job.num_midstates = 4; + reverse_32bit_words(midstate, new_job->midstate3); + new_job->num_midstates = 4; } else { - new_job.num_midstates = 1; + new_job->num_midstates = 1; } - - return new_job; } void extranonce_2_generate(uint64_t extranonce_2, uint32_t length, char dest[static length * 2 + 1]) diff --git a/components/stratum/test/test_mining.c b/components/stratum/test/test_mining.c index 0bb597e7b..34564cf8d 100644 --- a/components/stratum/test/test_mining.c +++ b/components/stratum/test/test_mining.c @@ -93,7 +93,8 @@ TEST_CASE("Validate bm job construction", "[mining]") notify_message.ntime = 0x64658bd8; uint8_t merkle_root[32]; hex2bin("cd1be82132ef0d12053dcece1fa0247fcfdb61d4dbd3eb32ea9ef9b4c604a846", merkle_root, 32); - bm_job job = construct_bm_job(¬ify_message, merkle_root, 0, 1000); + bm_job job = { 0 }; + construct_bm_job(¬ify_message, merkle_root, 0, 1000, &job); uint8_t expected_midstate_bin[32]; hex2bin("91DFEA528A9F73683D0D495DD6DD7415E1CA21CB411759E3E05D7D5FF285314D", expected_midstate_bin, 32); @@ -129,7 +130,8 @@ TEST_CASE("Validate version mask incrementing", "[mining]") // char * coinbase_tx = construct_coinbase_tx(params->coinbase_1, params->coinbase_2, "336508070fca95", "0000000000000000"); // char merkle_root[65] // calculate_merkle_root_hash(coinbase_tx, (uint8_t(*)[32])params->merkle_branches, params->n_merkle_branches, merkle_root); -// bm_job job = construct_bm_job(params, merkle_root, 1000); +// bm_job job = { 0 }; +// construct_bm_job(params, merkle_root, 1000, &job); // uint8_t expected_midstate_bin[32]; // hex2bin("5FD281AF6A1750EAEE502C04067738BD46C82FC22112FFE797CE7F035D276126", expected_midstate_bin, 32); @@ -176,7 +178,8 @@ TEST_CASE("Test nonce diff checking", "[mining test_nonce][not-on-qemu]") notify_message.ntime = 0x646ff1a9; uint8_t merkle_root[32]; hex2bin("6d0359c451434605c52a5a9ce074340be47c2c63840731f9edf1db3f26b1cdd9a9f16f64", merkle_root, 32); - bm_job job = construct_bm_job(¬ify_message, merkle_root, 0, 1000); + bm_job job = { 0 }; + construct_bm_job(¬ify_message, merkle_root, 0, 1000, &job); uint32_t nonce = 0x276E8947; double diff = test_nonce_value(&job, nonce, 0); @@ -221,7 +224,8 @@ TEST_CASE("Test nonce diff checking 2", "[mining test_nonce][not-on-qemu]") bin2hex(merkle_root_hash, 32, merkle_root, 65); TEST_ASSERT_EQUAL_STRING("5bdc1968499c3393873edf8e07a1c3a50a97fc3a9d1a376bbf77087dd63778eb", merkle_root); - bm_job job = construct_bm_job(¬ify_message, merkle_root_hash, 0, 1000); + bm_job job = { 0 }; + construct_bm_job(¬ify_message, merkle_root_hash, 0, 1000, &job); uint32_t nonce = 0x0a029ed1; double diff = test_nonce_value(&job, nonce, 0); diff --git a/main/self_test/self_test.c b/main/self_test/self_test.c index f58baabcd..2ba5124e8 100644 --- a/main/self_test/self_test.c +++ b/main/self_test/self_test.c @@ -395,7 +395,8 @@ bool self_test(void * pvParameters) uint8_t merkle_root[32]; calculate_merkle_root_hash(coinbase_tx_hash, merkles, num_merkles, merkle_root); - bm_job job = construct_bm_job(¬ify_message, merkle_root, 0x1fffe000, 1000000); + bm_job job = {0}; + construct_bm_job(¬ify_message, merkle_root, 0x1fffe000, 1000000, &job); ESP_LOGI(TAG, "Sending work"); diff --git a/main/tasks/create_jobs_task.c b/main/tasks/create_jobs_task.c index 75424627d..876848a1a 100644 --- a/main/tasks/create_jobs_task.c +++ b/main/tasks/create_jobs_task.c @@ -93,18 +93,18 @@ static void generate_work(GlobalState *GLOBAL_STATE, mining_notify *notification uint8_t merkle_root[32]; calculate_merkle_root_hash(coinbase_tx_hash, (uint8_t(*)[32])notification->merkle_branches, notification->n_merkle_branches, merkle_root); - bm_job next_job = construct_bm_job(notification, merkle_root, GLOBAL_STATE->version_mask, difficulty); + bm_job *new_job = malloc(sizeof(bm_job)); - bm_job *queued_next_job = malloc(sizeof(bm_job)); - if (queued_next_job == NULL) { - ESP_LOGE(TAG, "Failed to allocate memory for queued_next_job"); + if (new_job == NULL) { + ESP_LOGE(TAG, "Failed to allocate memory for new job"); return; } - memcpy(queued_next_job, &next_job, sizeof(bm_job)); - queued_next_job->extranonce2 = strdup(extranonce_2_str); - queued_next_job->jobid = strdup(notification->job_id); - queued_next_job->version_mask = GLOBAL_STATE->version_mask; + construct_bm_job(notification, merkle_root, GLOBAL_STATE->version_mask, difficulty, new_job); - queue_enqueue(&GLOBAL_STATE->ASIC_jobs_queue, queued_next_job); + new_job->extranonce2 = strdup(extranonce_2_str); + new_job->jobid = strdup(notification->job_id); + new_job->version_mask = GLOBAL_STATE->version_mask; + + queue_enqueue(&GLOBAL_STATE->ASIC_jobs_queue, new_job); } From 39e5a6975a99db13d5b7033fcab3aaf7aa6dc527 Mon Sep 17 00:00:00 2001 From: mutatrum Date: Tue, 4 Nov 2025 14:38:08 +0100 Subject: [PATCH 15/20] Revert variable rename --- main/tasks/create_jobs_task.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/main/tasks/create_jobs_task.c b/main/tasks/create_jobs_task.c index 876848a1a..299925ff0 100644 --- a/main/tasks/create_jobs_task.c +++ b/main/tasks/create_jobs_task.c @@ -93,18 +93,18 @@ static void generate_work(GlobalState *GLOBAL_STATE, mining_notify *notification uint8_t merkle_root[32]; calculate_merkle_root_hash(coinbase_tx_hash, (uint8_t(*)[32])notification->merkle_branches, notification->n_merkle_branches, merkle_root); - bm_job *new_job = malloc(sizeof(bm_job)); + bm_job *queued_next_job = malloc(sizeof(bm_job)); - if (new_job == NULL) { + if (queued_next_job == NULL) { ESP_LOGE(TAG, "Failed to allocate memory for new job"); return; } - construct_bm_job(notification, merkle_root, GLOBAL_STATE->version_mask, difficulty, new_job); + construct_bm_job(notification, merkle_root, GLOBAL_STATE->version_mask, difficulty, queued_next_job); - new_job->extranonce2 = strdup(extranonce_2_str); - new_job->jobid = strdup(notification->job_id); - new_job->version_mask = GLOBAL_STATE->version_mask; + queued_next_job->extranonce2 = strdup(extranonce_2_str); + queued_next_job->jobid = strdup(notification->job_id); + queued_next_job->version_mask = GLOBAL_STATE->version_mask; - queue_enqueue(&GLOBAL_STATE->ASIC_jobs_queue, new_job); + queue_enqueue(&GLOBAL_STATE->ASIC_jobs_queue, queued_next_job); } From 8756c1024e73a84c886d7a002b38889f994628a9 Mon Sep 17 00:00:00 2001 From: mutatrum Date: Wed, 5 Nov 2025 12:14:53 +0100 Subject: [PATCH 16/20] Swawp endianness instead of full 32 byte order --- components/stratum/include/utils.h | 2 +- components/stratum/mining.c | 13 +++++++------ components/stratum/test/test_utils.c | 28 ++++++++++++++++++---------- components/stratum/utils.c | 22 ++++++++++++---------- 4 files changed, 38 insertions(+), 27 deletions(-) diff --git a/components/stratum/include/utils.h b/components/stratum/include/utils.h index 5c94b501b..4fd9502af 100644 --- a/components/stratum/include/utils.h +++ b/components/stratum/include/utils.h @@ -17,7 +17,7 @@ void midstate_sha256_bin(const uint8_t *data, const size_t data_len, uint8_t des void reverse_32bit_words(const uint8_t src[32], uint8_t dest[32]); -void reverse_byte_order(const uint8_t src[32], uint8_t dest[32]); +void reverse_endianness_per_word(uint8_t data[32]); double le256todouble(const void *target); diff --git a/components/stratum/mining.c b/components/stratum/mining.c index 63e3b2472..2c80cfae8 100644 --- a/components/stratum/mining.c +++ b/components/stratum/mining.c @@ -57,19 +57,20 @@ void construct_bm_job(mining_notify *params, const uint8_t merkle_root[32], cons uint8_t prev_block_hash[32]; hex2bin(params->prev_block_hash, prev_block_hash, 32); - reverse_byte_order(prev_block_hash, new_job->prev_block_hash); + reverse_endianness_per_word(prev_block_hash); + reverse_32bit_words(prev_block_hash, new_job->prev_block_hash); // make the midstate hash uint8_t midstate_data[64]; // copy 68 bytes header data into midstate (and deal with endianess) - memcpy(midstate_data, &new_job->version, 4); // copy version - reverse_32bit_words(new_job->prev_block_hash, midstate_data + 4); // copy prev_block_hash in reverse word order - memcpy(midstate_data + 36, merkle_root, 28); // copy the original word order merkle_root + memcpy(midstate_data, &new_job->version, 4); // copy version + memcpy(midstate_data + 4, prev_block_hash, 32); // copy prev_block_hash + memcpy(midstate_data + 36, merkle_root, 28); // copy merkle_root uint8_t midstate[32]; - midstate_sha256_bin(midstate_data, 64, midstate); // make the midstate hash - reverse_32bit_words(midstate, new_job->midstate); // reverse the midstate words for the BM job packet + midstate_sha256_bin(midstate_data, 64, midstate); // make the midstate hash + reverse_32bit_words(midstate, new_job->midstate); // reverse the midstate words for the BM job packet if (version_mask != 0) { diff --git a/components/stratum/test/test_utils.c b/components/stratum/test/test_utils.c index 5abb19f74..1cf0ffedc 100644 --- a/components/stratum/test/test_utils.c +++ b/components/stratum/test/test_utils.c @@ -41,25 +41,33 @@ TEST_CASE("reverse_32bit_words", "[utils]") uint8_t actual[32]; reverse_32bit_words(input, actual); - uint8_t expected[32] = {28, 29, 30, 31, 24, 25, 26, 27, - 20, 21, 22, 23, 16, 17, 18, 19, - 12, 13, 14, 15, 8, 9, 10, 11, - 4, 5, 6, 7, 0, 1, 2, 3}; + uint8_t expected[32] = {28, 29, 30, 31, + 24, 25, 26, 27, + 20, 21, 22, 23, + 16, 17, 18, 19, + 12, 13, 14, 15, + 8, 9, 10, 11, + 4, 5, 6, 7, + 0, 1, 2, 3}; TEST_ASSERT_EQUAL_UINT8_ARRAY(expected, actual, 32); } -TEST_CASE("reverse_byte_order", "[utils]") +TEST_CASE("reverse_endianness_per_word", "[utils]") { uint8_t input[32]; for (int i = 0; i < 32; i++) input[i] = i; uint8_t actual[32]; - reverse_byte_order(input, actual); + reverse_endianness_per_word(input, actual); - uint8_t expected[32] = {31, 30, 29, 28, 27, 26, 25, 24, - 23, 22, 21, 20, 19, 18, 17, 16, - 15, 14, 13, 12, 11, 10, 9, 8, - 7, 6, 5, 4, 3, 2, 1, 0}; + uint8_t expected[32] = { 3, 2, 1, 0, + 7, 6, 5, 4, + 11, 10, 9, 8, + 15, 14, 13, 12, + 19, 18, 17, 16, + 23, 22, 21, 20, + 27, 26, 25, 24, + 31, 30, 29, 28}; TEST_ASSERT_EQUAL_UINT8_ARRAY(expected, actual, 32); } diff --git a/components/stratum/utils.c b/components/stratum/utils.c index efc38cac9..ee2dfb98a 100644 --- a/components/stratum/utils.c +++ b/components/stratum/utils.c @@ -94,7 +94,7 @@ void midstate_sha256_bin(const uint8_t *data, const size_t data_len, uint8_t des void reverse_32bit_words(const uint8_t src[32], uint8_t dest[32]) { - uint32_t *s = (uint32_t *)src; + const uint32_t *s = (const uint32_t *)src; uint32_t *d = (uint32_t *)dest; d[0] = s[7]; @@ -107,16 +107,18 @@ void reverse_32bit_words(const uint8_t src[32], uint8_t dest[32]) d[7] = s[0]; } -void reverse_byte_order(const uint8_t src[32], uint8_t dest[32]) +void reverse_endianness_per_word(uint8_t data[32]) { - dest[ 0] = src[31]; dest[ 1] = src[30]; dest[ 2] = src[29]; dest[ 3] = src[28]; - dest[ 4] = src[27]; dest[ 5] = src[26]; dest[ 6] = src[25]; dest[ 7] = src[24]; - dest[ 8] = src[23]; dest[ 9] = src[22]; dest[10] = src[21]; dest[11] = src[20]; - dest[12] = src[19]; dest[13] = src[18]; dest[14] = src[17]; dest[15] = src[16]; - dest[16] = src[15]; dest[17] = src[14]; dest[18] = src[13]; dest[19] = src[12]; - dest[20] = src[11]; dest[21] = src[10]; dest[22] = src[ 9]; dest[23] = src[ 8]; - dest[24] = src[ 7]; dest[25] = src[ 6]; dest[26] = src[ 5]; dest[27] = src[ 4]; - dest[28] = src[ 3]; dest[29] = src[ 2]; dest[30] = src[ 1]; dest[31] = src[ 0]; + uint32_t *d = (uint32_t *)data; + + d[0] = __builtin_bswap32(d[0]); + d[1] = __builtin_bswap32(d[1]); + d[2] = __builtin_bswap32(d[2]); + d[3] = __builtin_bswap32(d[3]); + d[4] = __builtin_bswap32(d[4]); + d[5] = __builtin_bswap32(d[5]); + d[6] = __builtin_bswap32(d[6]); + d[7] = __builtin_bswap32(d[7]); } // static const double truediffone = 26959535291011309493156476344723991336010898738574164086137773096960.0; From 5c188baf1554e0f247a517be9dd26700a751d928 Mon Sep 17 00:00:00 2001 From: mutatrum Date: Wed, 5 Nov 2025 12:17:30 +0100 Subject: [PATCH 17/20] Fix compile error in test_mining.c --- components/stratum/test/test_mining.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/stratum/test/test_mining.c b/components/stratum/test/test_mining.c index 34564cf8d..14b03a493 100644 --- a/components/stratum/test/test_mining.c +++ b/components/stratum/test/test_mining.c @@ -100,7 +100,7 @@ TEST_CASE("Validate bm job construction", "[mining]") hex2bin("91DFEA528A9F73683D0D495DD6DD7415E1CA21CB411759E3E05D7D5FF285314D", expected_midstate_bin, 32); // bytes are reversed for the midstate on the bm job command packet uint8_t expected_midstate_bin_reversed[32]; - reverse_byte_order(expected_midstate_bin, expected_midstate_bin_reversed); + reverse_32bit_words(expected_midstate_bin, expected_midstate_bin_reversed); TEST_ASSERT_EQUAL_UINT8_ARRAY(expected_midstate_bin_reversed, job.midstate, 32); } @@ -136,7 +136,7 @@ TEST_CASE("Validate version mask incrementing", "[mining]") // uint8_t expected_midstate_bin[32]; // hex2bin("5FD281AF6A1750EAEE502C04067738BD46C82FC22112FFE797CE7F035D276126", expected_midstate_bin, 32); // // bytes are reversed for the midstate on the bm job command packet -// reverse_byte_order(expected_midstate_bin, 32); +// reverse_32bit_words(expected_midstate_bin, 32); // TEST_ASSERT_EQUAL_UINT8_ARRAY(expected_midstate_bin, job.midstate, 32); // TEST_ASSERT_EQUAL_UINT32(0x1705ae3a, job.target); // TEST_ASSERT_EQUAL_UINT32(0x6470e2a1, job.ntime); From f2bf7cd9e9f584c101fe7b504d46f1f272aba9a3 Mon Sep 17 00:00:00 2001 From: mutatrum Date: Wed, 5 Nov 2025 12:21:09 +0100 Subject: [PATCH 18/20] Fix test_utils --- components/stratum/test/test_utils.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/components/stratum/test/test_utils.c b/components/stratum/test/test_utils.c index 1cf0ffedc..2bf148ceb 100644 --- a/components/stratum/test/test_utils.c +++ b/components/stratum/test/test_utils.c @@ -54,11 +54,10 @@ TEST_CASE("reverse_32bit_words", "[utils]") TEST_CASE("reverse_endianness_per_word", "[utils]") { - uint8_t input[32]; - for (int i = 0; i < 32; i++) input[i] = i; + uint8_t data[32]; + for (int i = 0; i < 32; i++) data[i] = i; - uint8_t actual[32]; - reverse_endianness_per_word(input, actual); + reverse_endianness_per_word(data); uint8_t expected[32] = { 3, 2, 1, 0, 7, 6, 5, 4, @@ -68,7 +67,7 @@ TEST_CASE("reverse_endianness_per_word", "[utils]") 23, 22, 21, 20, 27, 26, 25, 24, 31, 30, 29, 28}; - TEST_ASSERT_EQUAL_UINT8_ARRAY(expected, actual, 32); + TEST_ASSERT_EQUAL_UINT8_ARRAY(expected, data, 32); } TEST_CASE("networkDifficulty", "[utils]") From 7f31e6a5921f1465f4c5f27b6777dc01e20a89e4 Mon Sep 17 00:00:00 2001 From: mutatrum Date: Wed, 5 Nov 2025 12:31:55 +0100 Subject: [PATCH 19/20] Fix mining test --- components/stratum/test/test_mining.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/components/stratum/test/test_mining.c b/components/stratum/test/test_mining.c index 14b03a493..8b0d6e634 100644 --- a/components/stratum/test/test_mining.c +++ b/components/stratum/test/test_mining.c @@ -99,9 +99,8 @@ TEST_CASE("Validate bm job construction", "[mining]") uint8_t expected_midstate_bin[32]; hex2bin("91DFEA528A9F73683D0D495DD6DD7415E1CA21CB411759E3E05D7D5FF285314D", expected_midstate_bin, 32); // bytes are reversed for the midstate on the bm job command packet - uint8_t expected_midstate_bin_reversed[32]; - reverse_32bit_words(expected_midstate_bin, expected_midstate_bin_reversed); - TEST_ASSERT_EQUAL_UINT8_ARRAY(expected_midstate_bin_reversed, job.midstate, 32); + reverse_endianness_per_word(expected_midstate_bin); + TEST_ASSERT_EQUAL_UINT8_ARRAY(expected_midstate_bin, job.midstate, 32); } TEST_CASE("Validate version mask incrementing", "[mining]") From bb51b7e4395d98a816b112cfd25fb073ace25fda Mon Sep 17 00:00:00 2001 From: mutatrum Date: Wed, 5 Nov 2025 12:43:03 +0100 Subject: [PATCH 20/20] Fix --- components/stratum/test/test_mining.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/components/stratum/test/test_mining.c b/components/stratum/test/test_mining.c index 8b0d6e634..dbe06f698 100644 --- a/components/stratum/test/test_mining.c +++ b/components/stratum/test/test_mining.c @@ -99,8 +99,10 @@ TEST_CASE("Validate bm job construction", "[mining]") uint8_t expected_midstate_bin[32]; hex2bin("91DFEA528A9F73683D0D495DD6DD7415E1CA21CB411759E3E05D7D5FF285314D", expected_midstate_bin, 32); // bytes are reversed for the midstate on the bm job command packet - reverse_endianness_per_word(expected_midstate_bin); - TEST_ASSERT_EQUAL_UINT8_ARRAY(expected_midstate_bin, job.midstate, 32); + uint8_t expected_midstate_bin_reversed[32]; + reverse_32bit_words(expected_midstate_bin, expected_midstate_bin_reversed); + reverse_endianness_per_word(expected_midstate_bin_reversed); + TEST_ASSERT_EQUAL_UINT8_ARRAY(expected_midstate_bin_reversed, job.midstate, 32); } TEST_CASE("Validate version mask incrementing", "[mining]")