0

What inputs go into the RLP and Keccak function to calculate the block header hash?

I looked up the header struct. Which of those values are fed into the RLP, Keccak? Were nonce and mixed hash left out? Are there any test cases or example templates for reference?

0

1 Answer 1

9

Below are the steps to calculate blockHash, given a blockNumber:

Step1. eth.getBlock(400000)

Output:{ difficulty: '6022643743806', extraData: '0xd583010202844765746885676f312e35856c696e7578', gasLimit: 3141592, gasUsed: 0, hash: '0x5d15649e25d8f3e2c0374946078539d200710afc977cdfc6a977bd23f20fa8e8', logsBloom: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', miner: '0x2a65Aca4D5fC5B5C859090a6c34d164135398226', mixHash: '0x3fbea7af642a4e20cd93a945a1f5e23bd72fc5261153e09102cf718980aeff38', nonce: '0x6af23caae95692ef', number: 400000, parentHash: '0x1e77d8f1267348b516ebc4f4da1e2aa59f85f0cbd853949500ffac8bfc38ba14', receiptsRoot: '0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421', sha3Uncles: '0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347', size: 539, stateRoot: '0x0b5e4386680f43c224c5c037efc0b645c8e1c3f6b30da0eec07272b4e6f8cd89', timestamp: 1445130204, totalDifficulty: '2014130882275463845', transactions: [], transactionsRoot: '0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421', uncles: [] }

Hash in the above object refers to the blockHash which we are trying to validate. This is the actual output which will be used later to compare the test results with.

Step2. Remove some of the elements from the above object, keep only those that are inputs into a blockHeader, and reorder it as below:

[['ParentHash','0x1e77d8f1267348b516ebc4f4da1e2aa59f85f0cbd853949500ffac8bfc38ba14'], ['UncleHash','0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347'], ['Coinbase','0x2a65Aca4D5fC5B5C859090a6c34d164135398226'], ['Root','0x0b5e4386680f43c224c5c037efc0b645c8e1c3f6b30da0eec07272b4e6f8cd89'], ['TxHash','0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421'], ['ReceiptHash','0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421'], ['Bloom','0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'], ['Difficulty',6022643743806], ['Number','0x400000'], ['GasLimit',3141592], ['GasUsed',0], ['Time',1445130204], ['Extra','0xd583010202844765746885676f312e35856c696e7578'], ['MixDigest','0x3fbea7af642a4e20cd93a945a1f5e23bd72fc5261153e09102cf718980aeff38'], ['Nonce','0x6af23caae95692ef']]

Step3. Convert values with numbers to Hex

console.log(web3.utils.toHex(gasLimit));
console.log(web3.utils.toHex(gasUsed));
console.log(web3.utils.toHex(time));
console.log(web3.utils.toHex(difficulty));
console.log(web3.utils.toHex(number));

Step4. For elements with value as 0, use 0x and not 0x0

Example: for block 400000, the value for gasUsed is 0. So the value used for gasUsed should be 0x and not 0x0

Step5. After changing the numbers to Hex and handing values with 0, we can go ahead and remove all the keys listed in Step2 and restructure the array as below:

[ '0x1e77d8f1267348b516ebc4f4da1e2aa59f85f0cbd853949500ffac8bfc38ba14', '0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347', '0x2a65aca4d5fc5b5c859090a6c34d164135398226', '0x0b5e4386680f43c224c5c037efc0b645c8e1c3f6b30da0eec07272b4e6f8cd89', '0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421', '0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421', '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', '0x57a418a7c3e', '0x61a80', '0x2fefd8', '0x', '0x5622efdc', '0xd583010202844765746885676f312e35856c696e7578', '0x3fbea7af642a4e20cd93a945a1f5e23bd72fc5261153e09102cf718980aeff38', '0x6af23caae95692ef' ]

Step6. The above array of values can now be fed into a rlp.encode function

Output: 0xf90213a01e77d8f1267348b516ebc4f4da1e2aa59f85f0cbd853949500ffac8bfc38ba14a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347942a65aca4d5fc5b5c859090a6c34d164135398226a00b5e4386680f43c224c5c037efc0b645c8e1c3f6b30da0eec07272b4e6f8cd89a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000086057a418a7c3e83061a80832fefd880845622efdc96d583010202844765746885676f312e35856c696e7578a03fbea7af642a4e20cd93a945a1f5e23bd72fc5261153e09102cf718980aeff38886af23caae95692ef

Step7. Pass the above RLP through a keccak256 function. Below is the output:

TestOutput: 0x5d15649e25d8f3e2c0374946078539d200710afc977cdfc6a977bd23f20fa8e8

ActualOutput: 0x5d15649e25d8f3e2c0374946078539d200710afc977cdfc6a977bd23f20fa8e8

Conclusion: Use eth.getBlock(). Take the object it returns as output. Remove unwanted elements and keep only those that are inputs to a blockHeader. Convert numbers to Hex and handle values with 0s. Restructure the object to form an array of strings. Pass this array into a rlp.encode function. Take the rlp output and apply a keccak256 hash on it.

Links: https://github.com/ethereum/go-ethereum/blob/master/core/types/block.go#L69

1
  • If I run the RLP encoding through keccak-256 I don't get the same hash. Mar 24, 2021 at 13:23

Not the answer you're looking for? Browse other questions tagged or ask your own question.