@@ -25,6 +25,58 @@ use signet_storage_types::{
2525} ;
2626use std:: path:: Path ;
2727
28+ /// Write a single block's data into an open read-write transaction.
29+ ///
30+ /// Uses `MDBX_APPEND` / `MDBX_APPENDDUP` for block-number-keyed tables,
31+ /// skipping B-tree traversal. Blocks MUST be appended in ascending order.
32+ fn write_block_to_tx (
33+ tx : & signet_hot_mdbx:: Tx < signet_libmdbx:: Rw > ,
34+ data : BlockData ,
35+ ) -> Result < ( ) , MdbxColdError > {
36+ let block = data. block_number ( ) ;
37+
38+ tx. queue_append :: < ColdHeaders > ( & block, & data. header ) ?;
39+ // Hash-keyed indices use put (keys are not sequential)
40+ tx. queue_put :: < ColdBlockHashIndex > ( & data. header . hash ( ) , & block) ?;
41+
42+ // Store transactions, senders, and build hash index
43+ let tx_meta: Vec < _ > = data
44+ . transactions
45+ . iter ( )
46+ . enumerate ( )
47+ . map ( |( idx, recovered_tx) | {
48+ let tx_idx = idx as u64 ;
49+ let sender = recovered_tx. signer ( ) ;
50+ let tx_signed: & TransactionSigned = recovered_tx;
51+ tx. queue_append_dual :: < ColdTransactions > ( & block, & tx_idx, tx_signed) ?;
52+ tx. queue_append_dual :: < ColdTxSenders > ( & block, & tx_idx, & sender) ?;
53+ tx. queue_put :: < ColdTxHashIndex > ( tx_signed. hash ( ) , & TxLocation :: new ( block, tx_idx) ) ?;
54+ Ok ( ( * tx_signed. hash ( ) , sender) )
55+ } )
56+ . collect :: < Result < _ , MdbxColdError > > ( ) ?;
57+
58+ // Compute and store IndexedReceipts with precomputed metadata
59+ let mut first_log_index = 0u64 ;
60+ let mut prior_cumulative_gas = 0u64 ;
61+ for ( idx, ( receipt, ( tx_hash, sender) ) ) in data. receipts . into_iter ( ) . zip ( tx_meta) . enumerate ( ) {
62+ let gas_used = receipt. inner . cumulative_gas_used - prior_cumulative_gas;
63+ prior_cumulative_gas = receipt. inner . cumulative_gas_used ;
64+ let ir = IndexedReceipt { receipt, tx_hash, first_log_index, gas_used, sender } ;
65+ first_log_index += ir. receipt . inner . logs . len ( ) as u64 ;
66+ tx. queue_append_dual :: < ColdReceipts > ( & block, & ( idx as u64 ) , & ir) ?;
67+ }
68+
69+ for ( idx, event) in data. signet_events . iter ( ) . enumerate ( ) {
70+ tx. queue_append_dual :: < ColdSignetEvents > ( & block, & ( idx as u64 ) , event) ?;
71+ }
72+
73+ if let Some ( zh) = & data. zenith_header {
74+ tx. queue_append :: < ColdZenithHeaders > ( & block, zh) ?;
75+ }
76+
77+ Ok ( ( ) )
78+ }
79+
2880/// MDBX-based cold storage backend.
2981///
3082/// This backend stores historical blockchain data in an MDBX database.
@@ -68,57 +120,37 @@ impl MdbxColdBackend {
68120 fn create_tables ( & self ) -> Result < ( ) , MdbxColdError > {
69121 let tx = self . env . tx_rw ( ) ?;
70122
71- for ( name, dual_key_size, fixed_val_size, int_key) in [
72- (
73- ColdHeaders :: NAME ,
74- ColdHeaders :: DUAL_KEY_SIZE ,
75- ColdHeaders :: FIXED_VAL_SIZE ,
76- ColdHeaders :: INT_KEY ,
77- ) ,
123+ for ( name, dual_key_size, fixed_val_size) in [
124+ ( ColdHeaders :: NAME , ColdHeaders :: DUAL_KEY_SIZE , ColdHeaders :: FIXED_VAL_SIZE ) ,
78125 (
79126 ColdZenithHeaders :: NAME ,
80127 ColdZenithHeaders :: DUAL_KEY_SIZE ,
81128 ColdZenithHeaders :: FIXED_VAL_SIZE ,
82- ColdZenithHeaders :: INT_KEY ,
83129 ) ,
84130 (
85131 ColdBlockHashIndex :: NAME ,
86132 ColdBlockHashIndex :: DUAL_KEY_SIZE ,
87133 ColdBlockHashIndex :: FIXED_VAL_SIZE ,
88- ColdBlockHashIndex :: INT_KEY ,
89134 ) ,
90135 (
91136 ColdTxHashIndex :: NAME ,
92137 ColdTxHashIndex :: DUAL_KEY_SIZE ,
93138 ColdTxHashIndex :: FIXED_VAL_SIZE ,
94- ColdTxHashIndex :: INT_KEY ,
95139 ) ,
96140 (
97141 ColdTransactions :: NAME ,
98142 ColdTransactions :: DUAL_KEY_SIZE ,
99143 ColdTransactions :: FIXED_VAL_SIZE ,
100- ColdTransactions :: INT_KEY ,
101- ) ,
102- (
103- ColdTxSenders :: NAME ,
104- ColdTxSenders :: DUAL_KEY_SIZE ,
105- ColdTxSenders :: FIXED_VAL_SIZE ,
106- ColdTxSenders :: INT_KEY ,
107- ) ,
108- (
109- ColdReceipts :: NAME ,
110- ColdReceipts :: DUAL_KEY_SIZE ,
111- ColdReceipts :: FIXED_VAL_SIZE ,
112- ColdReceipts :: INT_KEY ,
113144 ) ,
145+ ( ColdTxSenders :: NAME , ColdTxSenders :: DUAL_KEY_SIZE , ColdTxSenders :: FIXED_VAL_SIZE ) ,
146+ ( ColdReceipts :: NAME , ColdReceipts :: DUAL_KEY_SIZE , ColdReceipts :: FIXED_VAL_SIZE ) ,
114147 (
115148 ColdSignetEvents :: NAME ,
116149 ColdSignetEvents :: DUAL_KEY_SIZE ,
117150 ColdSignetEvents :: FIXED_VAL_SIZE ,
118- ColdSignetEvents :: INT_KEY ,
119151 ) ,
120152 ] {
121- tx. queue_raw_create ( name, dual_key_size, fixed_val_size, int_key ) ?;
153+ tx. queue_raw_create ( name, dual_key_size, fixed_val_size) ?;
122154 }
123155
124156 tx. raw_commit ( ) ?;
@@ -292,9 +324,10 @@ impl MdbxColdBackend {
292324 end : BlockNumber ,
293325 ) -> Result < Vec < DbSignetEvent > , MdbxColdError > {
294326 let tx = self . env . tx ( ) ?;
327+ let mut cursor = tx. traverse_dual :: < ColdSignetEvents > ( ) ?;
295328 let mut events = Vec :: new ( ) ;
296329 for block in start..=end {
297- for item in tx . traverse_dual :: < ColdSignetEvents > ( ) ? . iter_k2 ( & block) ? {
330+ for item in cursor . iter_k2 ( & block) ? {
298331 events. push ( item?. 1 ) ;
299332 }
300333 }
@@ -335,49 +368,16 @@ impl MdbxColdBackend {
335368
336369 fn append_block_inner ( & self , data : BlockData ) -> Result < ( ) , MdbxColdError > {
337370 let tx = self . env . tx_rw ( ) ?;
338- let block = data. block_number ( ) ;
339-
340- // Store the sealed header (hash already cached)
341- tx. queue_put :: < ColdHeaders > ( & block, & data. header ) ?;
342- tx. queue_put :: < ColdBlockHashIndex > ( & data. header . hash ( ) , & block) ?;
343-
344- // Store transactions, senders, and build hash index
345- let tx_meta: Vec < _ > = data
346- . transactions
347- . iter ( )
348- . enumerate ( )
349- . map ( |( idx, recovered_tx) | {
350- let tx_idx = idx as u64 ;
351- let sender = recovered_tx. signer ( ) ;
352- let tx_signed: & TransactionSigned = recovered_tx;
353- tx. queue_put_dual :: < ColdTransactions > ( & block, & tx_idx, tx_signed) ?;
354- tx. queue_put_dual :: < ColdTxSenders > ( & block, & tx_idx, & sender) ?;
355- tx. queue_put :: < ColdTxHashIndex > ( tx_signed. hash ( ) , & TxLocation :: new ( block, tx_idx) ) ?;
356- Ok ( ( * tx_signed. hash ( ) , sender) )
357- } )
358- . collect :: < Result < _ , MdbxColdError > > ( ) ?;
359-
360- // Compute and store IndexedReceipts with precomputed metadata
361- let mut first_log_index = 0u64 ;
362- let mut prior_cumulative_gas = 0u64 ;
363- for ( idx, ( receipt, ( tx_hash, sender) ) ) in
364- data. receipts . into_iter ( ) . zip ( tx_meta) . enumerate ( )
365- {
366- let gas_used = receipt. inner . cumulative_gas_used - prior_cumulative_gas;
367- prior_cumulative_gas = receipt. inner . cumulative_gas_used ;
368- let ir = IndexedReceipt { receipt, tx_hash, first_log_index, gas_used, sender } ;
369- first_log_index += ir. receipt . inner . logs . len ( ) as u64 ;
370- tx. queue_put_dual :: < ColdReceipts > ( & block, & ( idx as u64 ) , & ir) ?;
371- }
372-
373- for ( idx, event) in data. signet_events . iter ( ) . enumerate ( ) {
374- tx. queue_put_dual :: < ColdSignetEvents > ( & block, & ( idx as u64 ) , event) ?;
375- }
371+ write_block_to_tx ( & tx, data) ?;
372+ tx. raw_commit ( ) ?;
373+ Ok ( ( ) )
374+ }
376375
377- if let Some ( zh) = & data. zenith_header {
378- tx. queue_put :: < ColdZenithHeaders > ( & block, zh) ?;
376+ fn append_blocks_inner ( & self , data : Vec < BlockData > ) -> Result < ( ) , MdbxColdError > {
377+ let tx = self . env . tx_rw ( ) ?;
378+ for block_data in data {
379+ write_block_to_tx ( & tx, block_data) ?;
379380 }
380-
381381 tx. raw_commit ( ) ?;
382382 Ok ( ( ) )
383383 }
@@ -412,20 +412,23 @@ impl MdbxColdBackend {
412412 }
413413
414414 // Delete each block's data
415- for ( block_num, sealed) in & headers_to_remove {
416- // Delete transaction hash indices
417- for item in tx. traverse_dual :: < ColdTransactions > ( ) ?. iter_k2 ( block_num) ? {
418- let ( _, tx_signed) = item?;
419- tx. queue_delete :: < ColdTxHashIndex > ( tx_signed. hash ( ) ) ?;
420- }
415+ {
416+ let mut tx_cursor = tx. traverse_dual :: < ColdTransactions > ( ) ?;
417+ for ( block_num, sealed) in & headers_to_remove {
418+ // Delete transaction hash indices
419+ for item in tx_cursor. iter_k2 ( block_num) ? {
420+ let ( _, tx_signed) = item?;
421+ tx. queue_delete :: < ColdTxHashIndex > ( tx_signed. hash ( ) ) ?;
422+ }
421423
422- tx. queue_delete :: < ColdHeaders > ( block_num) ?;
423- tx. queue_delete :: < ColdBlockHashIndex > ( & sealed. hash ( ) ) ?;
424- tx. clear_k1_for :: < ColdTransactions > ( block_num) ?;
425- tx. clear_k1_for :: < ColdTxSenders > ( block_num) ?;
426- tx. clear_k1_for :: < ColdReceipts > ( block_num) ?;
427- tx. clear_k1_for :: < ColdSignetEvents > ( block_num) ?;
428- tx. queue_delete :: < ColdZenithHeaders > ( block_num) ?;
424+ tx. queue_delete :: < ColdHeaders > ( block_num) ?;
425+ tx. queue_delete :: < ColdBlockHashIndex > ( & sealed. hash ( ) ) ?;
426+ tx. clear_k1_for :: < ColdTransactions > ( block_num) ?;
427+ tx. clear_k1_for :: < ColdTxSenders > ( block_num) ?;
428+ tx. clear_k1_for :: < ColdReceipts > ( block_num) ?;
429+ tx. clear_k1_for :: < ColdSignetEvents > ( block_num) ?;
430+ tx. queue_delete :: < ColdZenithHeaders > ( block_num) ?;
431+ }
429432 }
430433
431434 tx. raw_commit ( ) ?;
@@ -437,15 +440,28 @@ impl MdbxColdBackend {
437440 let mut results = Vec :: new ( ) ;
438441
439442 let from = filter. get_from_block ( ) . unwrap_or ( 0 ) ;
440- let to = filter. get_to_block ( ) . unwrap_or ( u64:: MAX ) ;
443+ let to = match filter. get_to_block ( ) {
444+ Some ( to) => to,
445+ None => {
446+ let mut cursor = tx. new_cursor :: < ColdHeaders > ( ) ?;
447+ let Some ( ( key, _) ) = cursor. last ( ) ? else {
448+ return Ok ( results) ;
449+ } ;
450+ BlockNumber :: decode_key ( & key) ?
451+ }
452+ } ;
453+
454+ let mut header_cursor = tx. traverse :: < ColdHeaders > ( ) ?;
455+ let mut receipt_cursor = tx. traverse_dual :: < ColdReceipts > ( ) ?;
456+
441457 for block_num in from..=to {
442- let Some ( sealed) = tx . traverse :: < ColdHeaders > ( ) ? . exact ( & block_num) ? else {
458+ let Some ( sealed) = header_cursor . exact ( & block_num) ? else {
443459 continue ;
444460 } ;
445461 let block_hash = sealed. hash ( ) ;
446462 let block_timestamp = sealed. timestamp ;
447463
448- for item in tx . traverse_dual :: < ColdReceipts > ( ) ? . iter_k2 ( & block_num) ? {
464+ for item in receipt_cursor . iter_k2 ( & block_num) ? {
449465 let ( tx_idx, ir) = item?;
450466 results. extend (
451467 ir. receipt
@@ -567,10 +583,7 @@ impl ColdStorage for MdbxColdBackend {
567583 }
568584
569585 async fn append_blocks ( & self , data : Vec < BlockData > ) -> ColdResult < ( ) > {
570- for block_data in data {
571- self . append_block_inner ( block_data) ?;
572- }
573- Ok ( ( ) )
586+ Ok ( self . append_blocks_inner ( data) ?)
574587 }
575588
576589 async fn truncate_above ( & self , block : BlockNumber ) -> ColdResult < ( ) > {
0 commit comments