diff --git a/Cargo.lock b/Cargo.lock index 4f3ef5779b..7f9e6eaaa0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9848,6 +9848,7 @@ dependencies = [ "reth-codecs", "serde", "serde_json", + "strum 0.27.2", "thiserror 2.0.17", "toml", ] diff --git a/crates/prune/types/Cargo.toml b/crates/prune/types/Cargo.toml index b60621b331..30adbb14d9 100644 --- a/crates/prune/types/Cargo.toml +++ b/crates/prune/types/Cargo.toml @@ -16,6 +16,7 @@ reth-codecs = { workspace = true, optional = true } alloy-primitives.workspace = true derive_more.workspace = true +strum = { workspace = true, features = ["derive"] } thiserror.workspace = true modular-bitfield = { workspace = true, optional = true } @@ -42,6 +43,7 @@ std = [ "serde?/std", "serde_json/std", "thiserror/std", + "strum/std", ] test-utils = [ "std", diff --git a/crates/prune/types/src/lib.rs b/crates/prune/types/src/lib.rs index b42574cde2..a588693892 100644 --- a/crates/prune/types/src/lib.rs +++ b/crates/prune/types/src/lib.rs @@ -25,5 +25,5 @@ pub use pruner::{ PruneInterruptReason, PruneProgress, PrunedSegmentInfo, PrunerOutput, SegmentOutput, SegmentOutputCheckpoint, }; -pub use segment::{PrunePurpose, PruneSegment, PruneSegmentError, PRUNE_SEGMENTS}; +pub use segment::{PrunePurpose, PruneSegment, PruneSegmentError}; pub use target::{PruneModes, UnwindTargetPrunedError, MINIMUM_PRUNING_DISTANCE}; diff --git a/crates/prune/types/src/segment.rs b/crates/prune/types/src/segment.rs index aa0e893bb4..36e39fcb58 100644 --- a/crates/prune/types/src/segment.rs +++ b/crates/prune/types/src/segment.rs @@ -2,6 +2,7 @@ use crate::MINIMUM_PRUNING_DISTANCE; use derive_more::Display; +use strum::{EnumIter, IntoEnumIterator}; use thiserror::Error; /// Segment of the data that can be pruned. @@ -9,7 +10,7 @@ use thiserror::Error; /// VERY IMPORTANT NOTE: new variants must be added to the end of this enum, and old variants which /// are no longer used must not be removed from this enum. The variant index is encoded directly /// when writing to the `PruneCheckpoint` table, so changing the order here will corrupt the table. -#[derive(Debug, Display, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[derive(Debug, Display, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash, EnumIter)] #[cfg_attr(test, derive(arbitrary::Arbitrary))] #[cfg_attr(any(test, feature = "reth-codec"), derive(reth_codecs::Compact))] #[cfg_attr(any(test, feature = "reth-codec"), reth_codecs::add_arbitrary_tests(compact))] @@ -28,9 +29,11 @@ pub enum PruneSegment { /// Prune segment responsible for the `StorageChangeSets` and `StoragesHistory` tables. StorageHistory, #[deprecated = "Variant indexes cannot be changed"] + #[strum(disabled)] /// Prune segment responsible for the `CanonicalHeaders`, `Headers` tables. Headers, #[deprecated = "Variant indexes cannot be changed"] + #[strum(disabled)] /// Prune segment responsible for the `Transactions` table. Transactions, /// Prune segment responsible for all rows in `AccountsTrieChangeSets` and @@ -40,18 +43,6 @@ pub enum PruneSegment { Bodies, } -/// Array of [`PruneSegment`]s actively in use. -pub const PRUNE_SEGMENTS: [PruneSegment; 8] = [ - PruneSegment::SenderRecovery, - PruneSegment::TransactionLookup, - PruneSegment::Receipts, - PruneSegment::ContractLogs, - PruneSegment::AccountHistory, - PruneSegment::StorageHistory, - PruneSegment::MerkleChangeSets, - PruneSegment::Bodies, -]; - #[cfg(test)] #[allow(clippy::derivable_impls)] impl Default for PruneSegment { @@ -61,6 +52,14 @@ impl Default for PruneSegment { } impl PruneSegment { + /// Returns an iterator over all variants of [`PruneSegment`]. + /// + /// Excludes deprecated variants that are no longer used, but can still be found in the + /// database. + pub fn variants() -> impl Iterator { + Self::iter() + } + /// Returns minimum number of blocks to keep in the database for this segment. pub const fn min_blocks(&self, purpose: PrunePurpose) -> u64 { match self { @@ -117,3 +116,20 @@ pub enum PruneSegmentError { #[error("the configuration provided for {0} is invalid")] Configuration(PruneSegment), } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_prune_segment_iter_excludes_deprecated() { + let segments: Vec = PruneSegment::variants().collect(); + + // Verify deprecated variants are not included derived iter + #[expect(deprecated)] + { + assert!(!segments.contains(&PruneSegment::Headers)); + assert!(!segments.contains(&PruneSegment::Transactions)); + } + } +} diff --git a/crates/storage/provider/src/providers/database/provider.rs b/crates/storage/provider/src/providers/database/provider.rs index 9fa6500db1..a90b2c2e64 100644 --- a/crates/storage/provider/src/providers/database/provider.rs +++ b/crates/storage/provider/src/providers/database/provider.rs @@ -52,7 +52,7 @@ use reth_primitives_traits::{ Account, Block as _, BlockBody as _, Bytecode, RecoveredBlock, SealedHeader, StorageEntry, }; use reth_prune_types::{ - PruneCheckpoint, PruneMode, PruneModes, PruneSegment, MINIMUM_PRUNING_DISTANCE, PRUNE_SEGMENTS, + PruneCheckpoint, PruneMode, PruneModes, PruneSegment, MINIMUM_PRUNING_DISTANCE, }; use reth_stages_types::{StageCheckpoint, StageId}; use reth_static_file_types::StaticFileSegment; @@ -3024,13 +3024,12 @@ impl PruneCheckpointReader for DatabaseProvide } fn get_prune_checkpoints(&self) -> ProviderResult> { - Ok(PRUNE_SEGMENTS - .iter() + Ok(PruneSegment::variants() .filter_map(|segment| { self.tx - .get::(*segment) + .get::(segment) .transpose() - .map(|chk| chk.map(|chk| (*segment, chk))) + .map(|chk| chk.map(|chk| (segment, chk))) }) .collect::>()?) }