@@ -397,6 +397,71 @@ impl<P: Preset> Storage<P> {
397397 Ok ( ( ) )
398398 }
399399
400+ pub ( crate ) fn prune_old_blocks_and_states ( & self , up_to_slot : Slot ) -> Result < ( ) > {
401+ let mut block_roots_to_remove = vec ! [ ] ;
402+ let mut keys_to_remove = vec ! [ ] ;
403+
404+ let results = self
405+ . database
406+ . iterator_descending ( ..=BlockRootBySlot ( up_to_slot. saturating_sub ( 1 ) ) . to_string ( ) ) ?;
407+
408+ for result in results {
409+ let ( key_bytes, value_bytes) = result?;
410+
411+ if !BlockRootBySlot :: has_prefix ( & key_bytes) {
412+ break ;
413+ }
414+
415+ block_roots_to_remove. push ( H256 :: from_ssz_default ( value_bytes) ?) ;
416+ keys_to_remove. push ( key_bytes. into_owned ( ) ) ;
417+ }
418+
419+ for block_root in block_roots_to_remove {
420+ let key = FinalizedBlockByRoot ( block_root) . to_string ( ) ;
421+ self . database . delete ( key) ?;
422+
423+ let key = UnfinalizedBlockByRoot ( block_root) . to_string ( ) ;
424+ self . database . delete ( key) ?;
425+
426+ let key = StateByBlockRoot ( block_root) . to_string ( ) ;
427+ self . database . delete ( key) ?;
428+ }
429+
430+ for key in keys_to_remove {
431+ self . database . delete ( key) ?;
432+ }
433+
434+ Ok ( ( ) )
435+ }
436+
437+ pub ( crate ) fn prune_old_state_roots ( & self , up_to_slot : Slot ) -> Result < ( ) > {
438+ let mut keys_to_remove = vec ! [ ] ;
439+
440+ let results = self
441+ . database
442+ . iterator_ascending ( SlotByStateRoot ( H256 :: zero ( ) ) . to_string ( ) ..) ?;
443+
444+ for result in results {
445+ let ( key_bytes, value_bytes) = result?;
446+
447+ if !SlotByStateRoot :: has_prefix ( & key_bytes) {
448+ break ;
449+ }
450+
451+ let slot = Slot :: from_ssz_default ( value_bytes) ?;
452+
453+ if slot < up_to_slot {
454+ keys_to_remove. push ( key_bytes. into_owned ( ) ) ;
455+ }
456+ }
457+
458+ for key in keys_to_remove {
459+ self . database . delete ( key) ?;
460+ }
461+
462+ Ok ( ( ) )
463+ }
464+
400465 pub ( crate ) fn checkpoint_state_slot ( & self ) -> Result < Option < Slot > > {
401466 if let Some ( StateCheckpoint { head_slot, .. } ) = self . load_state_checkpoint ( ) ? {
402467 return Ok ( Some ( head_slot) ) ;
@@ -704,6 +769,18 @@ impl<P: Preset> Storage<P> {
704769
705770#[ cfg( test) ]
706771impl < P : Preset > Storage < P > {
772+ pub fn block_root_by_slot_count ( & self ) -> Result < usize > {
773+ let results = self
774+ . database
775+ . iterator_ascending ( BlockRootBySlot ( 0 ) . to_string ( ) ..) ?;
776+
777+ itertools:: process_results ( results, |pairs| {
778+ pairs
779+ . take_while ( |( key_bytes, _) | BlockRootBySlot :: has_prefix ( key_bytes) )
780+ . count ( )
781+ } )
782+ }
783+
707784 pub fn finalized_block_count ( & self ) -> Result < usize > {
708785 let results = self
709786 . database
@@ -719,10 +796,34 @@ impl<P: Preset> Storage<P> {
719796 } )
720797 }
721798
799+ pub fn unfinalized_block_count ( & self ) -> Result < usize > {
800+ let results = self
801+ . database
802+ . iterator_ascending ( UnfinalizedBlockByRoot ( H256 :: zero ( ) ) . to_string ( ) ..) ?;
803+
804+ itertools:: process_results ( results, |pairs| {
805+ pairs
806+ . take_while ( |( key_bytes, _) | UnfinalizedBlockByRoot :: has_prefix ( key_bytes) )
807+ . count ( )
808+ } )
809+ }
810+
811+ pub fn slot_by_state_root_count ( & self ) -> Result < usize > {
812+ let results = self
813+ . database
814+ . iterator_ascending ( SlotByStateRoot ( H256 :: zero ( ) ) . to_string ( ) ..) ?;
815+
816+ itertools:: process_results ( results, |pairs| {
817+ pairs
818+ . take_while ( |( key_bytes, _) | SlotByStateRoot :: has_prefix ( key_bytes) )
819+ . count ( )
820+ } )
821+ }
822+
722823 pub fn slot_by_blob_id_count ( & self ) -> Result < usize > {
723824 let results = self
724825 . database
725- . iterator_ascending ( ( H256 :: zero ( ) ) . to_string ( ) ..) ?;
826+ . iterator_ascending ( SlotBlobId ( 0 , H256 :: zero ( ) , 0 ) . to_string ( ) ..) ?;
726827
727828 itertools:: process_results ( results, |pairs| {
728829 pairs
@@ -731,14 +832,26 @@ impl<P: Preset> Storage<P> {
731832 } )
732833 }
733834
835+ pub fn state_count ( & self ) -> Result < usize > {
836+ let results = self
837+ . database
838+ . iterator_ascending ( StateByBlockRoot ( H256 :: zero ( ) ) . to_string ( ) ..) ?;
839+
840+ itertools:: process_results ( results, |pairs| {
841+ pairs
842+ . take_while ( |( key_bytes, _) | StateByBlockRoot :: has_prefix ( key_bytes) )
843+ . count ( )
844+ } )
845+ }
846+
734847 pub fn blob_sidecar_by_blob_id_count ( & self ) -> Result < usize > {
735848 let results = self
736849 . database
737- . iterator_ascending ( ( H256 :: zero ( ) ) . to_string ( ) ..) ?;
850+ . iterator_ascending ( BlobSidecarByBlobId ( H256 :: zero ( ) , 0 ) . to_string ( ) ..) ?;
738851
739852 itertools:: process_results ( results, |pairs| {
740853 pairs
741- . filter ( |( key_bytes, _) | BlobSidecarByBlobId :: has_prefix ( key_bytes) )
854+ . take_while ( |( key_bytes, _) | BlobSidecarByBlobId :: has_prefix ( key_bytes) )
742855 . count ( )
743856 } )
744857 }
@@ -931,10 +1044,70 @@ pub fn serialize(key: impl Display, value: impl SszWrite) -> Result<(String, Vec
9311044mod tests {
9321045 use bytesize:: ByteSize ;
9331046 use tempfile:: TempDir ;
934- use types:: preset:: Mainnet ;
1047+ use types:: {
1048+ phase0:: containers:: SignedBeaconBlock as Phase0SignedBeaconBlock , preset:: Mainnet ,
1049+ } ;
9351050
9361051 use super :: * ;
9371052
1053+ #[ test]
1054+ fn test_prune_old_blocks_and_states ( ) -> Result < ( ) > {
1055+ let database = Database :: persistent ( "test_db" , TempDir :: new ( ) ?, ByteSize :: mib ( 10 ) , false ) ?;
1056+ let block = SignedBeaconBlock :: < Mainnet > :: Phase0 ( Phase0SignedBeaconBlock :: default ( ) ) ;
1057+
1058+ database. put_batch ( vec ! [
1059+ // Slot 1
1060+ serialize( BlockRootBySlot ( 1 ) , H256 :: repeat_byte( 1 ) ) ?,
1061+ serialize( FinalizedBlockByRoot ( H256 :: repeat_byte( 1 ) ) , & block) ?,
1062+ serialize( UnfinalizedBlockByRoot ( H256 :: repeat_byte( 1 ) ) , & block) ?,
1063+ serialize( SlotByStateRoot ( H256 :: repeat_byte( 1 ) ) , 1_u64 ) ?,
1064+ serialize( StateByBlockRoot ( H256 :: repeat_byte( 1 ) ) , 1_u64 ) ?,
1065+ // Slot 3
1066+ serialize( BlockRootBySlot ( 3 ) , H256 :: repeat_byte( 3 ) ) ?,
1067+ serialize( FinalizedBlockByRoot ( H256 :: repeat_byte( 3 ) ) , & block) ?,
1068+ // Slot 5
1069+ serialize( BlockRootBySlot ( 5 ) , H256 :: repeat_byte( 5 ) ) ?,
1070+ serialize( UnfinalizedBlockByRoot ( H256 :: repeat_byte( 5 ) ) , & block) ?,
1071+ //Slot 6
1072+ serialize( BlockRootBySlot ( 6 ) , H256 :: repeat_byte( 6 ) ) ?,
1073+ serialize( UnfinalizedBlockByRoot ( H256 :: repeat_byte( 6 ) ) , & block) ?,
1074+ serialize( SlotByStateRoot ( H256 :: repeat_byte( 6 ) ) , 6_u64 ) ?,
1075+ serialize( StateByBlockRoot ( H256 :: repeat_byte( 6 ) ) , 6_u64 ) ?,
1076+ // Slot 10, test case that "10" < "3" is not true
1077+ serialize( BlockRootBySlot ( 10 ) , H256 :: repeat_byte( 10 ) ) ?,
1078+ serialize( UnfinalizedBlockByRoot ( H256 :: repeat_byte( 10 ) ) , & block) ?,
1079+ serialize( SlotByStateRoot ( H256 :: repeat_byte( 10 ) ) , 10_u64 ) ?,
1080+ serialize( StateByBlockRoot ( H256 :: repeat_byte( 10 ) ) , 10_u64 ) ?,
1081+ ] ) ?;
1082+
1083+ let storage = Storage :: < Mainnet > :: new (
1084+ Arc :: new ( Config :: mainnet ( ) ) ,
1085+ database,
1086+ nonzero ! ( 64_u64 ) ,
1087+ true ,
1088+ ) ;
1089+
1090+ assert_eq ! ( storage. finalized_block_count( ) ?, 2 ) ;
1091+ assert_eq ! ( storage. unfinalized_block_count( ) ?, 4 ) ;
1092+ assert_eq ! ( storage. block_root_by_slot_count( ) ?, 5 ) ;
1093+ assert_eq ! ( storage. slot_by_state_root_count( ) ?, 3 ) ;
1094+ assert_eq ! ( storage. state_count( ) ?, 3 ) ;
1095+
1096+ storage. prune_old_blocks_and_states ( 5 ) ?;
1097+
1098+ assert_eq ! ( storage. finalized_block_count( ) ?, 0 ) ;
1099+ assert_eq ! ( storage. unfinalized_block_count( ) ?, 3 ) ;
1100+ assert_eq ! ( storage. block_root_by_slot_count( ) ?, 3 ) ;
1101+ assert_eq ! ( storage. slot_by_state_root_count( ) ?, 3 ) ;
1102+ assert_eq ! ( storage. state_count( ) ?, 2 ) ;
1103+
1104+ storage. prune_old_state_roots ( 5 ) ?;
1105+
1106+ assert_eq ! ( storage. slot_by_state_root_count( ) ?, 2 ) ;
1107+
1108+ Ok ( ( ) )
1109+ }
1110+
9381111 #[ test]
9391112 #[ expect( clippy:: similar_names) ]
9401113 fn test_prune_old_blob_sidecars ( ) -> Result < ( ) > {
0 commit comments