@@ -6,7 +6,7 @@ use std::{
66use alloy:: { hex, primitives:: B256 } ;
77use anyhow:: { Context , Result } ;
88use rig:: zk_ee:: utils:: Bytes32 ;
9- use ruint:: aliases:: B160 ;
9+ use ruint:: aliases:: { B160 , U256 } ;
1010
1111use crate :: rpc_client:: { Block , BlockMetadataResult , RpcClient , TransactionReceipt } ;
1212
@@ -16,6 +16,7 @@ pub struct LoadedBlockParams {
1616 pub block_metadata : BlockMetadataResult ,
1717 pub chain_id : u64 ,
1818 pub receipts : Vec < TransactionReceipt > ,
19+ pub historical_block_hashes : [ U256 ; 256 ] ,
1920}
2021
2122#[ derive( Debug , Clone , serde:: Serialize , serde:: Deserialize ) ]
@@ -39,6 +40,8 @@ struct DiskBlockParams {
3940 chain_id : u64 ,
4041 #[ serde( default ) ]
4142 receipts : Vec < TransactionReceipt > ,
43+ #[ serde( default ) ]
44+ historical_block_hashes : Vec < String > ,
4245}
4346
4447pub fn block_params_cache_path ( block_hash : B256 ) -> PathBuf {
@@ -73,20 +76,36 @@ pub fn load_or_fetch_block_params(
7376 cached. receipts. len( ) ,
7477 cached_block_tx_count
7578 ) ;
76- } else {
77- println ! (
78- "Loaded block params from disk cache: {:?} (block_number={}, chain_id={}, receipts={})" ,
79- cache_path,
80- cached. block. result. header. number,
81- cached. chain_id,
82- cached. receipts. len( )
79+ } else if cached. historical_block_hashes . len ( ) != 256 {
80+ eprintln ! (
81+ "Block params cache is stale (historical block hash count mismatch: expected 256, got {}), refetching" ,
82+ cached. historical_block_hashes. len( )
8383 ) ;
84- return Ok ( LoadedBlockParams {
85- block : cached. block ,
86- block_metadata : cached. block_metadata ,
87- chain_id : cached. chain_id ,
88- receipts : cached. receipts ,
89- } ) ;
84+ } else {
85+ match decode_historical_block_hashes ( & cached. historical_block_hashes ) {
86+ Ok ( historical_block_hashes) => {
87+ println ! (
88+ "Loaded block params from disk cache: {:?} (block_number={}, chain_id={}, receipts={}, historical_block_hashes={})" ,
89+ cache_path,
90+ cached. block. result. header. number,
91+ cached. chain_id,
92+ cached. receipts. len( ) ,
93+ cached. historical_block_hashes. len( )
94+ ) ;
95+ return Ok ( LoadedBlockParams {
96+ block : cached. block ,
97+ block_metadata : cached. block_metadata ,
98+ chain_id : cached. chain_id ,
99+ receipts : cached. receipts ,
100+ historical_block_hashes,
101+ } ) ;
102+ }
103+ Err ( err) => {
104+ eprintln ! (
105+ "Block params cache is stale (invalid historical block hashes), refetching: {err}"
106+ ) ;
107+ }
108+ }
90109 }
91110 }
92111 Ok ( None ) => {
@@ -108,6 +127,7 @@ pub fn load_or_fetch_block_params(
108127 let block_metadata = rpc_client. get_block_metadata ( block_number) ?;
109128 let chain_id = rpc_client. get_chain_id ( ) ?;
110129 let receipts = rpc_client. get_block_receipts ( block_number) ?. result ;
130+ let historical_block_hashes = fetch_historical_block_hashes ( rpc_client, block_number) ?;
111131
112132 if let Err ( err) = save_block_params_cache (
113133 cache_path,
@@ -116,15 +136,17 @@ pub fn load_or_fetch_block_params(
116136 & block_metadata,
117137 chain_id,
118138 & receipts,
139+ & historical_block_hashes,
119140 ) {
120141 eprintln ! ( "Failed to save block params cache: {err}" ) ;
121142 } else {
122143 println ! (
123- "Saved block params cache to disk: {:?} (block_number={}, chain_id={}, receipts={})" ,
144+ "Saved block params cache to disk: {:?} (block_number={}, chain_id={}, receipts={}, historical_block_hashes={} )" ,
124145 cache_path,
125146 block_number,
126147 chain_id,
127- receipts. len( )
148+ receipts. len( ) ,
149+ historical_block_hashes. len( )
128150 ) ;
129151 }
130152
@@ -133,6 +155,7 @@ pub fn load_or_fetch_block_params(
133155 block_metadata,
134156 chain_id,
135157 receipts,
158+ historical_block_hashes,
136159 } )
137160}
138161
@@ -264,6 +287,7 @@ fn save_block_params_cache(
264287 block_metadata : & BlockMetadataResult ,
265288 chain_id : u64 ,
266289 receipts : & [ TransactionReceipt ] ,
290+ historical_block_hashes : & [ U256 ; 256 ] ,
267291) -> Result < ( ) > {
268292 let cache_dir = cache_path
269293 . parent ( )
@@ -277,6 +301,7 @@ fn save_block_params_cache(
277301 block_metadata : block_metadata. clone ( ) ,
278302 chain_id,
279303 receipts : receipts. to_vec ( ) ,
304+ historical_block_hashes : encode_historical_block_hashes ( historical_block_hashes) ,
280305 } ;
281306
282307 std:: fs:: write ( cache_path, serde_json:: to_vec_pretty ( & payload) ?)
@@ -300,3 +325,59 @@ fn decode_bytes_hex(value: &str) -> Result<Vec<u8>> {
300325 hex:: decode ( stripped) . with_context ( || format ! ( "failed to decode hex value `{value}`" ) ) ?;
301326 Ok ( raw)
302327}
328+
329+ fn fetch_historical_block_hashes ( rpc_client : & RpcClient , block_number : u64 ) -> Result < [ U256 ; 256 ] > {
330+ let mut block_hashes = [ U256 :: ZERO ; 256 ] ;
331+ let mut loaded = 0usize ;
332+
333+ // Chain expects newest historical block hash at index 255.
334+ for depth in 1u64 ..=256 {
335+ println ! (
336+ "Fetching historical block hash for block #{}, depth {}" ,
337+ block_number - depth,
338+ depth
339+ ) ;
340+ let Some ( target_block_number) = block_number. checked_sub ( depth) else {
341+ break ;
342+ } ;
343+
344+ let idx = 256 - depth as usize ;
345+ match rpc_client. get_block_hash_by_number ( target_block_number) ? {
346+ Some ( hash) => {
347+ block_hashes[ idx] = U256 :: from_be_bytes ( hash. 0 ) ;
348+ loaded += 1 ;
349+ }
350+ None => {
351+ println ! (
352+ "RPC returned null for historical block #{target_block_number}; leaving remaining block hashes as zeroes"
353+ ) ;
354+ break ;
355+ }
356+ }
357+ }
358+
359+ println ! ( "Fetched {} historical block hashes from RPC" , loaded) ;
360+ Ok ( block_hashes)
361+ }
362+
363+ fn encode_historical_block_hashes ( hashes : & [ U256 ; 256 ] ) -> Vec < String > {
364+ hashes
365+ . iter ( )
366+ . map ( |hash| hex:: encode_prefixed ( hash. to_be_bytes :: < 32 > ( ) ) )
367+ . collect ( )
368+ }
369+
370+ fn decode_historical_block_hashes ( raw_hashes : & [ String ] ) -> Result < [ U256 ; 256 ] > {
371+ if raw_hashes. len ( ) != 256 {
372+ return Err ( anyhow:: anyhow!(
373+ "expected 256 historical block hashes, got {}" ,
374+ raw_hashes. len( )
375+ ) ) ;
376+ }
377+
378+ let mut hashes = [ U256 :: ZERO ; 256 ] ;
379+ for ( idx, raw_hash) in raw_hashes. iter ( ) . enumerate ( ) {
380+ hashes[ idx] = U256 :: from_be_bytes ( decode_fixed_hex :: < 32 > ( raw_hash) ?) ;
381+ }
382+ Ok ( hashes)
383+ }
0 commit comments