Хеширование заголовка «оффлайн» python

Я пытаюсь доказать, что TransactionsRoot и ReceiptsRoot действительно принадлежат определенному блоку. Чтобы я мог без web3 проверить, что все транзакции и квитанции действительно относятся к этому блоку.

Допустим, у меня есть этот блок:

'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': []}

Как мне убедиться, что информация о руте верна? Есть ли простой способ пересчитать/доказать, что txRoot находится в этом блоке и не был изменен?

заранее спасибо

Ответы (1)

Чтобы убедиться в правильности информации, поместите все поля в объект заголовка RLP, сгенерируйте хэш и сравните его с хэшем блока. Два из этих полей заголовка — это корневой хэш транзакции и корневой хэш состояния. Вы проверяете все поля одновременно.

В py-evm есть объект заголовка, который вы можете использовать или создать его минимальную версию, например:

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

Затем вы можете использовать BlockHeaderкласс для проверки правильности полей в заголовке. Создайте объект заголовка и убедитесь, что сгенерированный хеш такой же, как тот, который вы наблюдали:

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

В этом случае тест печатает:

Поздравляем, ваш хэш заголовка совпадает с корнем транзакции, корнем состояния и т. д.