@@ -934,11 +934,11 @@ impl Store {
934934 . map_or ( finalized_slot, |header| {
935935 header. expect ( "Failed to get block header" ) . slot
936936 } ) ;
937- let pruned_proofs = self
937+ let pruned_below_slot = self
938938 . prune_old_block_proofs ( finalized_slot, tip_slot)
939939 . expect ( "prune old block proofs" ) ;
940- if pruned_proofs > 0 {
941- info ! ( pruned_proofs , "Pruned old finalized block proofs" ) ;
940+ if pruned_below_slot > 0 {
941+ info ! ( pruned_below_slot , "Pruned old finalized block proofs" ) ;
942942 }
943943 Ok ( ( ) )
944944 }
@@ -1103,41 +1103,37 @@ impl Store {
11031103 /// reverted, so their proofs are not needed for fork choice, re-org
11041104 /// safety, or re-aggregation once outside the window.
11051105 ///
1106- /// Returns the number of proofs pruned.
1106+ /// Returns the exclusive slot below which proofs were dropped, or 0 when
1107+ /// nothing was pruned. This is a range delete, so the count of removed keys
1108+ /// is not known without reading the table back.
11071109 pub fn prune_old_block_proofs (
11081110 & mut self ,
11091111 finalized_slot : u64 ,
11101112 tip_slot : u64 ,
1111- ) -> Result < usize , Error > {
1113+ ) -> Result < u64 , Error > {
11121114 let cutoff = tip_slot. saturating_sub ( BLOCK_PROOF_PRUNING_RANGE ) ;
11131115 // Only prune when the whole window is finalized; never touch
1114- // non-finalized proofs.
1115- if cutoff > finalized_slot {
1116+ // non-finalized proofs. A zero cutoff covers nothing.
1117+ if cutoff > finalized_slot || cutoff == 0 {
11161118 return Ok ( 0 ) ;
11171119 }
11181120
1119- let view = self . backend . begin_read ( ) . expect ( "read view" ) ;
1120-
1121- // Keys are slot||root in big-endian slot order, so iteration ascends by
1122- // slot: take entries below the cutoff and stop at the first one past it.
1123- let keys_to_delete: Vec < Vec < u8 > > = view
1124- . prefix_iterator ( Table :: BlockProof , & [ ] )
1125- . expect ( "iterator" )
1126- . filter_map ( |res| res. ok ( ) )
1127- . map ( |( key, _) | key. to_vec ( ) )
1128- . take_while ( |key| decode_slot_root_key ( key) . 0 < cutoff)
1129- . collect ( ) ;
1130- drop ( view) ;
1121+ // Keys are slot||root in big-endian slot order, so the cutoff's bare
1122+ // slot prefix is an exact upper bound: keys below the cutoff sort
1123+ // before it, and keys at the cutoff sort after it (they extend it with
1124+ // a root). A single range delete drops them all without reading the
1125+ // table (and without walking the tombstones left by earlier prunes).
1126+ let mut batch = self . backend . begin_write ( ) . expect ( "write batch" ) ;
1127+ batch
1128+ . delete_range (
1129+ Table :: BlockProof ,
1130+ & 0u64 . to_be_bytes ( ) ,
1131+ & cutoff. to_be_bytes ( ) ,
1132+ )
1133+ . expect ( "delete finalized block proofs" ) ;
1134+ batch. commit ( ) . expect ( "commit" ) ;
11311135
1132- let count = keys_to_delete. len ( ) ;
1133- if count > 0 {
1134- let mut batch = self . backend . begin_write ( ) . expect ( "write batch" ) ;
1135- batch
1136- . delete_batch ( Table :: BlockProof , keys_to_delete)
1137- . expect ( "delete finalized block proofs" ) ;
1138- batch. commit ( ) . expect ( "commit" ) ;
1139- }
1140- Ok ( count)
1136+ Ok ( cutoff)
11411137 }
11421138
11431139 /// Get the block header by root.
@@ -1980,12 +1976,12 @@ mod tests {
19801976 // tip = range + 10, finalized = range + 5, so cutoff = tip - range = 10.
19811977 let tip_slot = BLOCK_PROOF_PRUNING_RANGE + 10 ;
19821978 let finalized_slot = BLOCK_PROOF_PRUNING_RANGE + 5 ;
1983- let pruned = store
1979+ let pruned_below_slot = store
19841980 . prune_old_block_proofs ( finalized_slot, tip_slot)
19851981 . expect ( "prune" ) ;
19861982
19871983 // cutoff = 10: slots 0..9 pruned, slots 10..12 kept (within the window).
1988- assert_eq ! ( pruned , 10 ) ;
1984+ assert_eq ! ( pruned_below_slot , 10 ) ;
19891985 assert_eq ! ( count_entries( backend. as_ref( ) , Table :: BlockProof ) , 3 ) ;
19901986
19911987 // Oldest proofs are gone, but headers, bodies, and roots stay queryable.
@@ -2015,10 +2011,10 @@ mod tests {
20152011 // cutoff = tip - range > finalized → prune nothing.
20162012 let tip_slot = BLOCK_PROOF_PRUNING_RANGE + 100 ;
20172013 let finalized_slot = 5 ;
2018- let pruned = store
2014+ let pruned_below_slot = store
20192015 . prune_old_block_proofs ( finalized_slot, tip_slot)
20202016 . expect ( "prune" ) ;
2021- assert_eq ! ( pruned , 0 ) ;
2017+ assert_eq ! ( pruned_below_slot , 0 ) ;
20222018 assert_eq ! ( count_entries( backend. as_ref( ) , Table :: BlockProof ) , 10 ) ;
20232019 }
20242020
@@ -2033,8 +2029,8 @@ mod tests {
20332029
20342030 // Early chain: tip < BLOCK_PROOF_PRUNING_RANGE → cutoff saturates to 0,
20352031 // so nothing is old enough to prune even though slots are finalized.
2036- let pruned = store. prune_old_block_proofs ( 9 , 9 ) . expect ( "prune" ) ;
2037- assert_eq ! ( pruned , 0 ) ;
2032+ let pruned_below_slot = store. prune_old_block_proofs ( 9 , 9 ) . expect ( "prune" ) ;
2033+ assert_eq ! ( pruned_below_slot , 0 ) ;
20382034 assert_eq ! ( count_entries( backend. as_ref( ) , Table :: BlockProof ) , 10 ) ;
20392035 }
20402036
0 commit comments