I am trying to understand how Monero hashes blocks.
I understand there is something called a "block hashing blob" that is combined with a nonce, but how can I get the block hashing blob for a specific block?
I tried the Monero Daemon JSON API get_block
, which has a field blob
in the return value (Python):
from Crypto.Hash import keccak
hash_blob = daemon.get_block(1)["blob"]
k = keccak.new(digest_bits=256)
hash_bin = bytes.fromhex(hash_blob)
k.update(hash_bin)
print(k.hexdigest())
The hash blob returned for get_block(1)["blob"]
is:
0100d186c49a05418015bb9ae982a1975da7d79277c2705727a56894ba0fb246adaabb1f4632e345fc7c30013d01ff0109c0a710025f391ad90e8b64ef432a0a28d0d9d699189b9c1322248ddbdb699c101a3cd9c3c0a8a5040233b81ac838467f7c59079e80517be1a45de51248a9bd841bf783e0aca7b2d5e2808ece1c023dc61a8cab11504ef1a36c51affeb7eed222cd09c98bf5045e489c23b409c9bc80c2d72f022caa4a9af327b36df136599a104278cf44342b0732bb5ad8c4c3582531add94b80a8d6b90702f9edf7d361176a29d1ce53e890e6ebc1e721d9719d273b69f1eb15d96025c6348088aca3cf02022e5ba472765cb2297f51f1a47aaf5f358cf48e16593c25bfc1880578014a65ed8090cad2c60e021b82a36cde1c9a6103d99ea6ebfb9f82b2547cef8934d8e87cf5e20c098ede9c80e08d84ddcb0102b37974cac8678446a230fb3e1b0ec06d56666bf0bf43dd64ff096a01f5aa2fda80c0caf384a30202a0c492751cb53389c9228f68b1ec1be831fb774a285f06c4ee02053858486e8221012a9fca96074c5216f9622c58c5c95024e53ff579d128913548363cb14d7f637400
and running the above code for it prints:
e26f21cfccf0ac4297647c879be976ed427e97ce02745dbbd6385decc8af6b53
querying the deamon for block 1, as in get_block(1)["header"]["hash"]
, I get hash:
771fbcd656ec1464d3a02ead5e18644030007a0fc664c0a964d30922821a8148
So, obviously this is quite different. get_block_template
seems to produce something that could be combined with a nonce to build a valid hash, but this seems to be only for new blocks.
How do I calculate the hashes for an existing block? Some pseudocode or similar is fine, I tried to read some of the Monero C code, but it jumps around and my C/C++ is a bit limited, so couldn't quite figure it out.
I understand the block hashing blob would need things like coinbase transaction, merkle tree root, nonce, etc. But I also understand I need to combine them in a very specific way to get the exact correct hash. So first to build the block hashing blob, then to combine it with nonce..
An example for a block would be great but anything helps..
EDIT: I modified the daemon to add the block hashing blob to the get_block RPC method. With this I get the block hashing blob for block 1 as:
0100d186c49a05418015bb9ae982a1975da7d79277c2705727a56894ba0fb246adaabb1f4632e345fc7c3052578a3816ec18ca6db2ec4f594b7c8a778caa4c52d2c1705bcbab9798a9ea7b01
However, calling cn_slow_hash
from pycryptonight on this does not give the correct hash:
pycryptonight.cn_slow_hash(binascii.unhexlify(hashblob), x)
Where x
is the hash variant, I tried values 0-4. The block hash in the get_block(1)
is 771fbcd656ec1464d3a02ead5e18644030007a0fc664c0a964d30922821a8148
but the value returned by variant 0 for above is 5aeebb3de73859d92f3f82fdb97286d81264ecb72a42e4b9f1e6d62eb682d7c0
.
If I run the same for height 1407480 as in question Can't seem to reconstruct hashing blob for old block, I get the same hashing blob as mentioned in that question (0606f8e7a8ce05a5449f2dc32fff0730d58751fac5a2b9d58c59622f8a8d58d18e9886eddcdb01bb8c00006b4c34591fb7dd7d6664881f7c7e675aae7709d0acca033c6226727125c2127a17
), but hashing it does not give the same hash as given for the block. Just like in that question, not able to get the correct hash.. But also do not understand how the author of that question fixed it.
What could be wrong with the hashing I use here?