1

I am trying to prove that the TransactionsRoot and the ReceiptsRoot do belong to a specific block. So that I can verify without web3 that all the transactions and receipts actually belong to this block.

Lets say I have this block:

'difficulty': 3963642329, 
'extraData': '0xd88301080f846765746888676f312e31302e31856c696e7578'), 
'gasLimit': 8000000, 
'gasUsed': 7987824, 
'hash': '0x47b8f62c1400dae65105d2f8e03824bfc58481c0b32f45788ad3378fbc05e9f6', 
'logsBloom': '0x0800012104000104c00400108000400000003000000040008400000002800100000a00000000000001010401040001000001002000000000020020080000240200000000012260010000084800420200040000100000030800802000112020001a200800020000000000500010100a00000000020401480000000010001048000011104800c002410000000010800000000014200040000400000000000000600020c00000004010080000000020100200000200000800001024c4000000080100004002004808000102920408810000002000008000000008000120400020008200d80000000010010000008028004000010000008220000200000100100800', 
'miner': '0x6A9ECfa04e99726eC105517AC7ae1aba550BeA6c', 
'mixHash': '0x0c0026c706351083c0a913e084dee16ca133b813baa6a174e4fb179d9f2ecc52', 
'nonce': '0xf245822d3412da7f', 
'number': 4156209, 
'parentHash': '0xad22d4d8f0e94032cb32e86027e0a5533d945ed95088264e91dd71e4fbaebeda', 
'receiptsRoot': '0xeb1e644436f93be8a9938dfe598cb7fd729f9d201b6f7c0695bee883b3ea6a5b', 
'sha3Uncles': '0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347', 
'size': 27324, 'stateRoot': '0x43e3325393fbc583a5a0b56e98073fb81e82d992b52406a79d662b690a4d2753', 
'timestamp': 1538483791, 
'totalDifficulty': 11844984547350924, 
'transactions': [.......], 
'transactionsRoot': '0x40c339f7715932ec591d8c0c588bacfaed9bddc7519a1e6e87cf45be639de810', 'uncles': []}

How could I make sure that the Information about the root is correct? Is there an easy way to recalculate/prove that the txRoot is in that block and has not been changed?

Thank you in advance

2

You make sure that the information is correct by putting all the fields in a Header RLP object, generating the hash, and comparing it against the block hash. Two of those header fields are the transaction root hash and the state root hash. You verify all fields at the same time.

There is a header object in py-evm that you could use, or you could build a minimal version of it, like:

from eth_utils import keccak
import rlp
from rlp.sedes import (
    BigEndianInt,
    big_endian_int,
    Binary,
    binary,
)

address = Binary.fixed_length(20, allow_empty=True)
hash32 = Binary.fixed_length(32)
int256 = BigEndianInt(256)
trie_root = Binary.fixed_length(32, allow_empty=True)

class BlockHeader(rlp.Serializable):
    fields = [
        ('parent_hash', hash32),
        ('uncles_hash', hash32),
        ('coinbase', address),
        ('state_root', trie_root),
        ('transaction_root', trie_root),
        ('receipt_root', trie_root),
        ('bloom', int256),
        ('difficulty', big_endian_int),
        ('block_number', big_endian_int),
        ('gas_limit', big_endian_int),
        ('gas_used', big_endian_int),
        ('timestamp', big_endian_int),
        ('extra_data', binary),
        ('mix_hash', binary),
        ('nonce', Binary(8, allow_empty=True))
    ]

    def hash(self) -> bytes:
        return keccak(rlp.encode(self))

Then you can use the BlockHeader class to test if the fields in the header are valid. Build a header object, and confirm that the generated hash is the same as the one you observed:

from eth_utils import to_bytes, to_hex

header = BlockHeader(
    parent_hash=to_bytes(0xad22d4d8f0e94032cb32e86027e0a5533d945ed95088264e91dd71e4fbaebeda),
    uncles_hash=to_bytes(0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347),
    coinbase=to_bytes(0x6A9ECfa04e99726eC105517AC7ae1aba550BeA6c),
    state_root=to_bytes(0x43e3325393fbc583a5a0b56e98073fb81e82d992b52406a79d662b690a4d2753),
    transaction_root=to_bytes(0x40c339f7715932ec591d8c0c588bacfaed9bddc7519a1e6e87cf45be639de810),
    receipt_root=to_bytes(0xeb1e644436f93be8a9938dfe598cb7fd729f9d201b6f7c0695bee883b3ea6a5b),
    bloom=0x0800012104000104c00400108000400000003000000040008400000002800100000a00000000000001010401040001000001002000000000020020080000240200000000012260010000084800420200040000100000030800802000112020001a200800020000000000500010100a00000000020401480000000010001048000011104800c002410000000010800000000014200040000400000000000000600020c00000004010080000000020100200000200000800001024c4000000080100004002004808000102920408810000002000008000000008000120400020008200d80000000010010000008028004000010000008220000200000100100800,
    difficulty=3963642329,
    block_number=4156209,
    gas_limit=8000000,
    gas_used=7987824,
    timestamp=1538483791,
    extra_data=to_bytes(0xd88301080f846765746888676f312e31302e31856c696e7578),
    mix_hash=to_bytes(0x0c0026c706351083c0a913e084dee16ca133b813baa6a174e4fb179d9f2ecc52),
    nonce=to_bytes(0xf245822d3412da7f),
)

if to_hex(header.hash()) == '0x47b8f62c1400dae65105d2f8e03824bfc58481c0b32f45788ad3378fbc05e9f6': 
    print("Congratulations, your header hash matches your transaction root, state root, etc.") 
else: 
    print("Sorry, your header hash does not match one of your header fields")

In this case, the test prints:

Congratulations, your header hash matches your transaction root, state root, etc.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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