Created
July 16, 2025 22:41
-
-
Save 0xClandestine/1b56a478c029a6d1935e00145a3d124b to your computer and use it in GitHub Desktop.
Block hash verification example
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| from web3 import Web3 | |
| import rlp | |
| from eth_utils import keccak, to_bytes, to_hex | |
| class BlockHeaderVerifier: | |
| def __init__(self, rpc_url=""): | |
| self.w3 = Web3(Web3.HTTPProvider(rpc_url)) | |
| def get_block_header_fields(self, block): | |
| """Extract and format block header fields for RLP encoding""" | |
| # Convert address string to bytes | |
| miner_bytes = to_bytes(hexstr=block.miner) if isinstance(block.miner, str) else block.miner | |
| # Build header with proper types | |
| return [ | |
| block.parentHash, # 0. parentHash | |
| block.sha3Uncles, # 1. ommersHash (sha3Uncles) | |
| miner_bytes, # 2. beneficiary (miner) | |
| block.stateRoot, # 3. stateRoot | |
| block.transactionsRoot, # 4. transactionsRoot | |
| block.receiptsRoot, # 5. receiptsRoot | |
| block.logsBloom, # 6. logsBloom | |
| block.difficulty, # 7. difficulty (0 for PoS) | |
| block.number, # 8. number | |
| block.gasLimit, # 9. gasLimit | |
| block.gasUsed, # 10. gasUsed | |
| block.timestamp, # 11. timestamp | |
| block.extraData, # 12. extraData | |
| block.mixHash, # 13. mixHash | |
| block.nonce, # 14. nonce | |
| block.baseFeePerGas, # 15. baseFeePerGas (EIP-1559) | |
| block.withdrawalsRoot, # 16. withdrawalsRoot (EIP-4895) | |
| block.blobGasUsed, # 17. blobGasUsed (EIP-4844) | |
| block.excessBlobGas, # 18. excessBlobGas (EIP-4844) | |
| block.parentBeaconBlockRoot, # 19. parentBeaconBlockRoot (EIP-4788) | |
| block.requestsHash # 20. requestsHash (EIP-7685) | |
| ] | |
| def decode_merkle_proof_nodes(self, proof_list): | |
| """Decode RPC proof nodes from hex strings to RLP items""" | |
| decoded_nodes = [] | |
| for node in proof_list: | |
| # Each node is an RLP-encoded hex string, decode it | |
| decoded_nodes.append(rlp.decode(bytes(node))) | |
| return decoded_nodes | |
| def get_account_proof(self, address, block_number, slots=[]): | |
| """Get RLP encoded account proof for a given address and block number""" | |
| # Get account proof from RPC | |
| proof = self.w3.eth.get_proof(address, slots, block_number) | |
| # Decode the account proof nodes | |
| account_proof = self.decode_merkle_proof_nodes(proof['accountProof']) | |
| # Decode storage proofs if any slots were requested | |
| # storage_proofs = [] | |
| # for slot_data in proof['storageProof']: | |
| # storage_proofs.append(self.decode_merkle_proof_nodes(slot_data['proof'])) | |
| # The proof structure is: [accountProof, storageProofs] | |
| # proof_rlp = rlp.encode([account_proof, storage_proofs]) | |
| proof_rlp = rlp.encode(account_proof) | |
| print(f"\nAccount proof RLP: 0x{proof_rlp.hex()}") | |
| print(f"Account balance: {Web3.from_wei(proof['balance'], 'ether')} ETH") | |
| print(f"Account nonce: {proof['nonce']}") | |
| print(f"Account code hash: {proof['codeHash'].hex()}") | |
| print(f"Account storage hash: {proof['storageHash'].hex()}") | |
| return proof_rlp | |
| def verify_block_header(self, block_number): | |
| """Verify block header hash for a given block number""" | |
| # Get block | |
| block = self.w3.eth.get_block(block_number) | |
| # Get header fields and encode | |
| header = self.get_block_header_fields(block) | |
| encoded = rlp.encode(header) | |
| computed_hash = keccak(encoded) | |
| # Check match | |
| if block.hash == computed_hash: | |
| print("✅ Success: ", block.hash.hex()) | |
| else: | |
| print("❌ Failed: ", computed_hash.hex()) | |
| print(f"\ncast keccak256 0x{encoded.hex()}") | |
| return block.hash == computed_hash | |
| # Example usage | |
| if __name__ == "__main__": | |
| verifier = BlockHeaderVerifier() | |
| verifier.verify_block_header(22841008) | |
| verifier.get_account_proof("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", 22841008) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment