From 24010c3fe85e3e238d747b5e905dd04f18682df0 Mon Sep 17 00:00:00 2001 From: johnny9 <985648+johnny9@users.noreply.github.com> Date: Sat, 20 May 2023 21:52:34 -0400 Subject: [PATCH] bm1397: update midstate construction test with proper values Midstate test has been updated with known working values from a bm1397 job command. Additional adjustment was also made to the bm_job construction method that changed the endianess of the merkle root. --- components/stratum/mining.c | 2 +- components/stratum/test/test_mining.c | 16 ++-- components/stratum/test/verifiers/bm1397.py | 92 +++++++++++++++++++ .../stratum/test/verifiers/midstatecalc.py | 32 ------- 4 files changed, 102 insertions(+), 40 deletions(-) create mode 100644 components/stratum/test/verifiers/bm1397.py delete mode 100644 components/stratum/test/verifiers/midstatecalc.py diff --git a/components/stratum/mining.c b/components/stratum/mining.c index 730c7a05..9963383b 100644 --- a/components/stratum/mining.c +++ b/components/stratum/mining.c @@ -64,7 +64,7 @@ bm_job construct_bm_job(uint32_t version, const char * prev_block_hash, const ch memcpy(midstate_data, &version, 4); //copy version swap_endian_words(prev_block_hash, midstate_data + 4); //copy prev_block_hash - swap_endian_words(merkle_root, midstate_data + 36); //copy merkle_root + memcpy(midstate_data + 36, merkle_root_bin, 28); //copy merkle_root // printf("midstate_data: "); // prettyHex(midstate_data, 64); // printf("\n"); diff --git a/components/stratum/test/test_mining.c b/components/stratum/test/test_mining.c index c45ac9b8..e6a6922e 100644 --- a/components/stratum/test/test_mining.c +++ b/components/stratum/test/test_mining.c @@ -55,18 +55,20 @@ TEST_CASE("Validate another merkle root calculation", "[mining]") free(root_hash); } -// Values calculated from esp-miner/components/stratum/test/verifiers/midstatecalc.py +// Values calculated from esp-miner/components/stratum/test/verifiers/bm1397.py TEST_CASE("Validate bm job construction", "[mining]") { - const char * merkle_root = "adbcbc21e20388422198a55957aedfa0e61be0b8f2b87d7c08510bb9f099a893"; - const char * prev_block_hash = "ef4b9a48c7986466de4adc002f7337a6e121bc43000376ea0000000000000000"; + const char * merkle_root = "cd1be82132ef0d12053dcece1fa0247fcfdb61d4dbd3eb32ea9ef9b4c604a846"; + const char * prev_block_hash = "bf44fd3513dc7b837d60e5c628b572b448d204a8000007490000000000000000"; uint32_t version = 0x20000004; - uint32_t target = 0x1705c739; - uint32_t ntime = 0x64495522; + uint32_t target = 0x1705dd01; + uint32_t ntime = 0x64658bd8; bm_job job = construct_bm_job(version, prev_block_hash, merkle_root, ntime, target); - TEST_ASSERT_EQUAL_UINT32(job.merkle_root_end, 0x93a899f0); + TEST_ASSERT_EQUAL_UINT32(job.merkle_root_end, 0x46a804c6); uint8_t expected_midstate_bin[32]; - hex2bin("ac9643f83aa1e1d8de56d0f59a41ea3b3eac45b62ae043bd933a7413c0a1fe58", 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); TEST_ASSERT_EQUAL_UINT8_ARRAY(expected_midstate_bin, job.midstate, 32); } \ No newline at end of file diff --git a/components/stratum/test/verifiers/bm1397.py b/components/stratum/test/verifiers/bm1397.py new file mode 100644 index 00000000..dd4240d8 --- /dev/null +++ b/components/stratum/test/verifiers/bm1397.py @@ -0,0 +1,92 @@ +import hashlib +import binascii + + +""" +The following is the reference stratum notify string as well as the bytes/values for the resulting data that gets sent to a bm1397 + + + {"id":null,"method":"mining.notify","params":["1f9a56282c","bf44fd3513dc7b837d60e5c628b572b448d204a8000007490000000000000000","01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4b03e60e0cfabe6d6d7595fc426909f3a63c563a88773a618ec42cc51188ed0632b69f1c3053a8f8180100000000000000","2c28569a1f2f736c7573682f0000000003a1f3a22b000000001976a9147c154ed1dc59609e3d26abb2df2ea3d587cd8c4188ac00000000000000002c6a4c2952534b424c4f434b3a799d4c611eff5765ba06d2c58ad71b5734d677cea10942664b2a712d005108ae0000000000000000266a24aa21a9ed5c4d2056e3eef09b05d95897adec38c5c3f460a919e95f87e15664957c70305a00000000", + ["4ea53a030256c37391b891b0d5060537df63944ce3fcd45121215596376bb3db","22cd1dde2c1b083237bbadd62ed1d51ee455265b7defe04dc8bcae7e5acacb33","60c781a8b02c07544cb3a91de3b4d7a13f9939c8579f3ac92fa28e802ace1b39", + "d89820b36568adc0705d71d639e69ccb7c168a1051697846cf5d98e5725ee4e3","73f0f773a3b6097388984f934ba1b01afc771c33db6df126cd6971cfea9f8f49","420958bbb39f6b8ad30e5b45b38a3825bf76f619b7dbb73a0366605ff882e91d", + "75f9ef87931104db956c88d65198596049af51017af4685c4548f2c31ec75b6d","70dd7189d5b927ac10a750062e5ab9f8b83fb784068e1c80d0df919bcf22e1b2","b34f2440b2b4609e44594885a397086339f4a2d880fb2d50ac585f757b895832", + "4c62d861fb259a743d1e2787eeac5bdd22a9883b5cc0b025843cff9441ea6b74","62522d5d8e2ff9d721a9a4b91931ec61069fff7c8ad23119718c068a035b9b1b","a0e7cf5509d9d0d87ff9a4f6332f76a243de01f4e93289b290e937e7fd03224f"], + "20000004","1705dd01","64658bd8",true]} + +header: [20 00 00 04 BF 44 FD 35 13 DC 7B 83 7D 60 E5 C6 28 B5 72 B4 48 D2 04 A8 00 00 07 49 00 00 00 00 00 00 00 00 21 E8 1B CD 12 0D EF 32 CE CE 3D 05 7F 24 A0 1F D4 61 DB CF 32 EB D3 DB B4 F9 9E EA 46 A8 04 C6 64 65 8B D8 17 05 DD 01 00 00 00 00 00 00 00 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00] +nonce1: 1165060344b679 +nonce2: 0 +nonce2_len: 8 +ntime: 64658bd8 +midstate: [91 DF EA 52 8A 9F 73 68 3D 0D 49 5D D6 DD 74 15 E1 CA 21 CB 41 17 59 E3 E0 5D 7D 5F F2 85 31 4D] +job cmd: [55 AA 21 96 04 04 00 00 00 00 01 DD 05 17 D8 8B 65 64 C6 04 A8 46 4D 31 85 F2 5F 7D 5D E0 E3 59 17 41 CB 21 CA E1 15 74 DD D6 5D 49 0D 3D 68 73 9F 8A 52 EA DF 91 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 6B 1D] +""" + + +def double_sha256(data): + return hashlib.sha256(hashlib.sha256(data).digest()).digest() + + +def merkle_root(coinbase_tx_hash, merkle_branches): + current_hash = bytes.fromhex(coinbase_tx_hash) + for branch in merkle_branches: + branch_hash = bytes.fromhex(branch) + # Concatenate the hashes and compute the double SHA-256 hash + current_hash = double_sha256(current_hash + branch_hash) + return current_hash.hex() + + +def swap_endian_words(hex_words): + '''Swaps the endianness of a hexadecimal string of words and returns as another hexadecimal string.''' + + message = binascii.unhexlify(hex_words) + if len(message) % 4 != 0: + raise ValueError('Must be 4-byte word aligned') + swapped_bytes = [message[4 * i: 4 * i + 4][::-1] for i in range(0, len(message) // 4)] + return ''.join([binascii.hexlify(word).decode('utf-8') for word in swapped_bytes]) + +coinbase_tx = "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4b03e60e0cfabe6d6d7595fc426909f3a63c563a88773a618ec42cc51188ed0632b69f1c3053a8f81801000000000000001165060344b67900000000000000002c28569a1f2f736c7573682f0000000003a1f3a22b000000001976a9147c154ed1dc59609e3d26abb2df2ea3d587cd8c4188ac00000000000000002c6a4c2952534b424c4f434b3a799d4c611eff5765ba06d2c58ad71b5734d677cea10942664b2a712d005108ae0000000000000000266a24aa21a9ed5c4d2056e3eef09b05d95897adec38c5c3f460a919e95f87e15664957c70305a00000000" +coinbase_tx_hash = double_sha256(bytes.fromhex(coinbase_tx)).hex() +merkle_branches = [ + "4ea53a030256c37391b891b0d5060537df63944ce3fcd45121215596376bb3db", + "22cd1dde2c1b083237bbadd62ed1d51ee455265b7defe04dc8bcae7e5acacb33", + "60c781a8b02c07544cb3a91de3b4d7a13f9939c8579f3ac92fa28e802ace1b39", + "d89820b36568adc0705d71d639e69ccb7c168a1051697846cf5d98e5725ee4e3", + "73f0f773a3b6097388984f934ba1b01afc771c33db6df126cd6971cfea9f8f49", + "420958bbb39f6b8ad30e5b45b38a3825bf76f619b7dbb73a0366605ff882e91d", + "75f9ef87931104db956c88d65198596049af51017af4685c4548f2c31ec75b6d", + "70dd7189d5b927ac10a750062e5ab9f8b83fb784068e1c80d0df919bcf22e1b2", + "b34f2440b2b4609e44594885a397086339f4a2d880fb2d50ac585f757b895832", + "4c62d861fb259a743d1e2787eeac5bdd22a9883b5cc0b025843cff9441ea6b74", + "62522d5d8e2ff9d721a9a4b91931ec61069fff7c8ad23119718c068a035b9b1b", + "a0e7cf5509d9d0d87ff9a4f6332f76a243de01f4e93289b290e937e7fd03224f" +] + + +print("Merkle root:", merkle_root(coinbase_tx_hash, merkle_branches)) +# cd1be82132ef0d12053dcece1fa0247fcfdb61d4dbd3eb32ea9ef9b4c604a846 +# last 4 bytes of merkle is C6 04 A8 46 + +version = b'\x20\x00\x00\x04' # little-endian encoding of version 1 +prev_block_hash = bytes.fromhex(swap_endian_words("bf44fd3513dc7b837d60e5c628b572b448d204a8000007490000000000000000")) +# merkle calculated above +merkle_root = bytes.fromhex(('cd1be82132ef0d12053dcece1fa0247fcfdb61d4dbd3eb32ea9ef9b4c604a846')) +timestamp = b'\x64\x65\x8b\xd8' # little-endian encoding of Unix timestamp 64658bd8 +difficulty_target = b'\x17\x05\xdd\x01' # little-endian encoding of difficulty 1705dd01 +nonce = b'\x00\x00\x00\x00' # example nonce value + +block_header = version + prev_block_hash + merkle_root + timestamp + difficulty_target + nonce +print(block_header.hex()) +#20000004bf44fd3513dc7b837d60e5c628b572b448d204a800000749000000000000000021e81bcd120def32cece3d057f24a01fd461dbcf32ebd3dbb4f99eea46a804c664658bd81705dd0100000000 +#[20 00 00 04 BF 44 FD 35 13 DC 7B 83 7D 60 E5 C6 28 B5 72 B4 48 D2 04 A8 00 00 07 49 00 00 00 00 00 00 00 00 21 E8 1B CD 12 0D EF 32 CE CE 3D 05 7F 24 A0 1F D4 61 DB CF 32 EB D3 DB B4 F9 9E EA ] +# output: 0400002035fd44bf837bdc13c6e5607db472b528a804d248490700000000000000000000cd1be82132ef0d12053dcece1fa0247fcfdb61d4dbd3eb32ea9ef9b4c604a846d88b656401dd7830351700000000 + +first_64_bytes = block_header[:64] +print(first_64_bytes.hex()) + +# The midstate is not a completed sha256 instead it is a reult of a single "update" +# expected midstate: [91 DF EA 52 8A 9F 73 68 3D 0D 49 5D D6 DD 74 15 E1 CA 21 CB 41 17 59 E3 E0 5D 7D 5F F2 85 31 4D] + + + + diff --git a/components/stratum/test/verifiers/midstatecalc.py b/components/stratum/test/verifiers/midstatecalc.py deleted file mode 100644 index e253d119..00000000 --- a/components/stratum/test/verifiers/midstatecalc.py +++ /dev/null @@ -1,32 +0,0 @@ -import hashlib -import binascii - - -def swap_endian_words(hex_words): - '''Swaps the endianness of a hexadecimal string of words and returns as another hexadecimal string.''' - - message = binascii.unhexlify(hex_words) - if len(message) % 4 != 0: - raise ValueError('Must be 4-byte word aligned') - swapped_bytes = [message[4 * i: 4 * i + 4][::-1] for i in range(0, len(message) // 4)] - return ''.join([binascii.hexlify(word).decode('utf-8') for word in swapped_bytes]) - - -version = b'\x04\x00\x00\x20' # little-endian encoding of version 1 -prev_block_hash = bytes.fromhex(swap_endian_words("ef4b9a48c7986466de4adc002f7337a6e121bc43000376ea0000000000000000")) -merkle_root = bytes.fromhex('adbcbc21e20388422198a55957aedfa0e61be0b8f2b87d7c08510bb9f099a893') -timestamp = b'\x64\x49\x55\x22' # little-endian encoding of Unix timestamp 1683385928 -difficulty_target = b'\x39\xc7\x05\x17' # little-endian encoding of difficulty -nonce = b'\x00\x00\x00\x00' # example nonce value - -block_header = version + prev_block_hash + merkle_root + timestamp + difficulty_target + nonce -print(block_header.hex()) -# output: 04000020ef4b9a48c7986466de4adc002f7337a6e121bc43000376ea0000000000000000adbcbc21e20388422198a55957aedfa0e61be0b8f2b87d7c08510bb9f099a8936449552239c7051700000000 - -first_64_bytes = block_header[:64] -print(first_64_bytes.hex()) -print(len(first_64_bytes)) -block_hash = hashlib.sha256(first_64_bytes).digest() -print(block_hash.hex()) -# output: ce9aa3d9ff4cf2c5897fe7caaacf56bfd7fc7ac01d89f8d88f6501d4597344b9 -