@@ -4,29 +4,31 @@ use alloy::consensus::BlockHeader;
44use alloy:: network:: primitives:: HeaderResponse ;
55use alloy:: network:: { BlockResponse , ReceiptResponse } ;
66use alloy:: primitives:: { keccak256, Address , B256 , U256 } ;
7- use alloy:: rlp:: encode ;
7+ use alloy:: rlp;
88use alloy:: rpc:: types:: { BlockTransactions , Filter , FilterChanges , Log } ;
9+ use alloy_trie:: {
10+ proof:: verify_proof as mpt_verify_proof,
11+ root:: ordered_trie_root_with_encoder,
12+ { Nibbles , TrieAccount } ,
13+ } ;
914use constants:: { BLOB_BASE_FEE_UPDATE_FRACTION , MIN_BASE_FEE_PER_BLOB_GAS } ;
1015use eyre:: Result ;
1116use futures:: future:: try_join_all;
1217use revm:: primitives:: KECCAK_EMPTY ;
1318use tracing:: warn;
14- use triehash_ethereum:: ordered_trie_root;
1519
1620use crate :: network_spec:: NetworkSpec ;
1721use crate :: types:: BlockTag ;
1822
1923use self :: constants:: MAX_SUPPORTED_LOGS_NUMBER ;
2024use self :: errors:: ExecutionError ;
21- use self :: proof:: { encode_account, verify_proof} ;
2225use self :: rpc:: ExecutionRpc ;
2326use self :: state:: { FilterType , State } ;
2427use self :: types:: Account ;
2528
2629pub mod constants;
2730pub mod errors;
2831pub mod evm;
29- pub mod proof;
3032pub mod rpc;
3133pub mod state;
3234pub mod types;
@@ -69,48 +71,49 @@ impl<N: NetworkSpec, R: ExecutionRpc<N>> ExecutionClient<N, R> {
6971 . get_proof ( address, slots, block. header ( ) . number ( ) . into ( ) )
7072 . await ?;
7173
72- let account_path = keccak256 ( address) . to_vec ( ) ;
73- let account_encoded = encode_account ( & proof) ;
74+ // Verify the account proof
75+ let account_key = Nibbles :: unpack ( keccak256 ( proof. address ) ) ;
76+ let account = TrieAccount {
77+ nonce : proof. nonce ,
78+ balance : proof. balance ,
79+ storage_root : proof. storage_hash ,
80+ code_hash : proof. code_hash ,
81+ } ;
82+ let account_encoded = rlp:: encode ( account) ;
7483
75- let is_valid = verify_proof (
84+ mpt_verify_proof (
85+ block. header ( ) . state_root ( ) ,
86+ account_key,
87+ account_encoded. into ( ) ,
7688 & proof. account_proof ,
77- block. header ( ) . state_root ( ) . as_slice ( ) ,
78- & account_path,
79- & account_encoded,
80- ) ;
81-
82- if !is_valid {
83- return Err ( ExecutionError :: InvalidAccountProof ( address) . into ( ) ) ;
84- }
89+ )
90+ . map_err ( |_| ExecutionError :: InvalidAccountProof ( address) ) ?;
8591
92+ // Verify the storage proofs, collecting the slot values
8693 let mut slot_map = HashMap :: new ( ) ;
8794
8895 for storage_proof in proof. storage_proof {
8996 let key = storage_proof. key . as_b256 ( ) ;
9097 let key_hash = keccak256 ( key) ;
91- let value = encode ( storage_proof. value ) ;
98+ let key_nibbles = Nibbles :: unpack ( key_hash) ;
99+ let encoded_value = rlp:: encode ( storage_proof. value ) ;
92100
93- let is_valid = verify_proof (
101+ mpt_verify_proof (
102+ proof. storage_hash ,
103+ key_nibbles,
104+ encoded_value. into ( ) ,
94105 & storage_proof. proof ,
95- proof. storage_hash . as_slice ( ) ,
96- key_hash. as_slice ( ) ,
97- & value,
98- ) ;
99-
100- if !is_valid {
101- return Err ( ExecutionError :: InvalidStorageProof ( address, key) . into ( ) ) ;
102- }
106+ )
107+ . map_err ( |_| ExecutionError :: InvalidStorageProof ( address, key) ) ?;
103108
104109 slot_map. insert ( key, storage_proof. value ) ;
105110 }
106111
112+ // Verify the code hash
107113 let code = if proof. code_hash == KECCAK_EMPTY || proof. code_hash == B256 :: ZERO {
108114 Vec :: new ( )
109115 } else {
110- let code = self
111- . rpc
112- . get_code ( address, block. header ( ) . number ( ) . into ( ) )
113- . await ?;
116+ let code = self . rpc . get_code ( address, block. header ( ) . number ( ) ) . await ?;
114117 let code_hash = keccak256 ( & code) ;
115118
116119 if proof. code_hash != code_hash {
@@ -256,8 +259,7 @@ impl<N: NetworkSpec, R: ExecutionRpc<N>> ExecutionClient<N, R> {
256259 . ok_or ( eyre:: eyre!( ExecutionError :: NoReceiptsForBlock ( tag) ) ) ?;
257260
258261 let receipts_encoded = receipts. iter ( ) . map ( N :: encode_receipt) . collect :: < Vec < _ > > ( ) ;
259- let expected_receipt_root = ordered_trie_root ( receipts_encoded. clone ( ) ) ;
260- let expected_receipt_root = B256 :: from_slice ( & expected_receipt_root. to_fixed_bytes ( ) ) ;
262+ let expected_receipt_root = ordered_trie_root ( & receipts_encoded) ;
261263
262264 if expected_receipt_root != block. header ( ) . receipts_root ( )
263265 // Note: Some RPC providers return different response in `eth_getTransactionReceipt` vs `eth_getBlockReceipts`
@@ -286,7 +288,7 @@ impl<N: NetworkSpec, R: ExecutionRpc<N>> ExecutionClient<N, R> {
286288 return Ok ( None ) ;
287289 } ;
288290
289- let tag = BlockTag :: Number ( block. header ( ) . number ( ) . into ( ) ) ;
291+ let tag = BlockTag :: Number ( block. header ( ) . number ( ) ) ;
290292
291293 let receipts = self
292294 . rpc
@@ -295,8 +297,7 @@ impl<N: NetworkSpec, R: ExecutionRpc<N>> ExecutionClient<N, R> {
295297 . ok_or ( eyre:: eyre!( ExecutionError :: NoReceiptsForBlock ( tag) ) ) ?;
296298
297299 let receipts_encoded = receipts. iter ( ) . map ( N :: encode_receipt) . collect :: < Vec < _ > > ( ) ;
298- let expected_receipt_root = ordered_trie_root ( receipts_encoded) ;
299- let expected_receipt_root = B256 :: from_slice ( & expected_receipt_root. to_fixed_bytes ( ) ) ;
300+ let expected_receipt_root = ordered_trie_root ( & receipts_encoded) ;
300301
301302 if expected_receipt_root != block. header ( ) . receipts_root ( ) {
302303 return Err ( ExecutionError :: BlockReceiptsRootMismatch ( tag) . into ( ) ) ;
@@ -369,7 +370,7 @@ impl<N: NetworkSpec, R: ExecutionRpc<N>> ExecutionClient<N, R> {
369370 self . state
370371 . push_filter (
371372 filter_id,
372- FilterType :: NewBlock ( blocks. last ( ) . unwrap ( ) . header ( ) . number ( ) . into ( ) ) ,
373+ FilterType :: NewBlock ( blocks. last ( ) . unwrap ( ) . header ( ) . number ( ) ) ,
373374 )
374375 . await ;
375376 }
@@ -476,7 +477,10 @@ impl<N: NetworkSpec, R: ExecutionRpc<N>> ExecutionClient<N, R> {
476477 None
477478 } else {
478479 let tx_hash = logs[ 0 ] . transaction_hash . unwrap ( ) ;
479- let encoded_logs = logs. iter ( ) . map ( |l| encode ( & l. inner ) ) . collect :: < Vec < _ > > ( ) ;
480+ let encoded_logs = logs
481+ . iter ( )
482+ . map ( |l| rlp:: encode ( & l. inner ) )
483+ . collect :: < Vec < _ > > ( ) ;
480484 Some ( ( tx_hash, encoded_logs) )
481485 }
482486 } )
@@ -486,7 +490,7 @@ impl<N: NetworkSpec, R: ExecutionRpc<N>> ExecutionClient<N, R> {
486490 // Check if the receipt contains the desired log
487491 // Encoding logs for comparison
488492 let tx_hash = log. transaction_hash . unwrap ( ) ;
489- let log_encoded = encode ( & log. inner ) ;
493+ let log_encoded = rlp :: encode ( & log. inner ) ;
490494 let receipt_logs_encoded = receipts_logs_encoded. get ( & tx_hash) . unwrap ( ) ;
491495
492496 if !receipt_logs_encoded. contains ( & log_encoded) {
@@ -500,3 +504,13 @@ impl<N: NetworkSpec, R: ExecutionRpc<N>> ExecutionClient<N, R> {
500504 Ok ( ( ) )
501505 }
502506}
507+
508+ /// Compute a trie root of a collection of encoded items.
509+ /// Ref: https://github.com/alloy-rs/trie/blob/main/src/root.rs.
510+ fn ordered_trie_root ( items : & [ Vec < u8 > ] ) -> B256 {
511+ fn noop_encoder ( item : & Vec < u8 > , buffer : & mut Vec < u8 > ) {
512+ buffer. extend_from_slice ( item) ;
513+ }
514+
515+ ordered_trie_root_with_encoder ( items, noop_encoder)
516+ }
0 commit comments