@@ -235,6 +235,72 @@ The following methods are available on the ``web3.eth`` namespace.
235
235
]
236
236
})
237
237
238
+ * Merkle proof verification using py-trie.
239
+
240
+ The following example verifies that the values returned in the AttributeDict are included in the state of given trie ``root ``.
241
+
242
+ .. code-block :: python
243
+
244
+ from eth_utils import (
245
+ keccak,
246
+ )
247
+ import rlp
248
+ from rlp.sedes import (
249
+ Binary,
250
+ big_endian_int,
251
+ )
252
+ from trie import (
253
+ HexaryTrie,
254
+ )
255
+ from web3._utils.encoding import (
256
+ pad_bytes,
257
+ )
258
+
259
+ def format_proof_nodes (proof ):
260
+ trie_proof = []
261
+ for rlp_node in proof:
262
+ trie_proof.append(rlp.decode(bytes (rlp_node)))
263
+ return trie_proof
264
+
265
+ def verify_eth_getProof (proof , root ):
266
+ trie_root = Binary.fixed_length(32 , allow_empty = True )
267
+ hash32 = Binary.fixed_length(32 )
268
+
269
+ class _Account (rlp .Serializable ):
270
+ fields = [
271
+ (' nonce' , big_endian_int),
272
+ (' balance' , big_endian_int),
273
+ (' storage' , trie_root),
274
+ (' code_hash' , hash32)
275
+ ]
276
+ acc = _Account(
277
+ proof.nonce, proof.balance, proof.storageHash, proof.codeHash
278
+ )
279
+ rlp_account = rlp.encode(acc)
280
+ trie_key = keccak(bytes .fromhex(proof.address[2 :]))
281
+
282
+ assert rlp_account == HexaryTrie.get_from_proof(
283
+ root, trie_key, format_proof_nodes(proof.accountProof)
284
+ ), " Failed to verify account proof {} " .format(proof.address)
285
+
286
+ for storage_proof in proof.storageProof:
287
+ trie_key = keccak(pad_bytes(b ' \x00 ' , 32 , storage_proof.key))
288
+ root = proof.storageHash
289
+ if storage_proof.value == b ' \x00 ' :
290
+ rlp_value = b ' '
291
+ else :
292
+ rlp_value = rlp.encode(storage_proof.value)
293
+
294
+ assert rlp_value == HexaryTrie.get_from_proof(
295
+ root, trie_key, format_proof_nodes(storage_proof.proof)
296
+ ), " Failed to verify storage proof {} " .format(storage_proof.key)
297
+
298
+ return True
299
+
300
+ block = w3.eth.getBlock(3391 )
301
+ proof = w3.eth.getProof(' 0x6c8f2a135f6ed072de4503bd7c4999a1a17f824b' , [0 , 1 ], 3391 )
302
+ assert verify_eth_getProof(proof, block.stateRoot)
303
+
238
304
239
305
.. py :method :: Eth.getCode(account, block_identifier = eth.defaultBlock)
240
306
0 commit comments