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.
This commit is contained in:
johnny9 2023-05-20 21:52:34 -04:00
parent 5d4733ec34
commit 24010c3fe8
4 changed files with 102 additions and 40 deletions

View File

@ -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");

View File

@ -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);
}

View File

@ -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]

View File

@ -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