refactor(prune): derive EnumIter instead of explicit array of segments (#19465)

This commit is contained in:
Alexey Shekhirin
2025-11-03 15:28:14 +00:00
committed by GitHub
parent 7905fba953
commit 7438bdbdf6
5 changed files with 37 additions and 19 deletions

1
Cargo.lock generated
View File

@@ -9848,6 +9848,7 @@ dependencies = [
"reth-codecs",
"serde",
"serde_json",
"strum 0.27.2",
"thiserror 2.0.17",
"toml",
]

View File

@@ -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",

View File

@@ -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};

View File

@@ -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<Item = Self> {
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> = PruneSegment::variants().collect();
// Verify deprecated variants are not included derived iter
#[expect(deprecated)]
{
assert!(!segments.contains(&PruneSegment::Headers));
assert!(!segments.contains(&PruneSegment::Transactions));
}
}
}

View File

@@ -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<TX: DbTx + 'static, N: NodeTypes> PruneCheckpointReader for DatabaseProvide
}
fn get_prune_checkpoints(&self) -> ProviderResult<Vec<(PruneSegment, PruneCheckpoint)>> {
Ok(PRUNE_SEGMENTS
.iter()
Ok(PruneSegment::variants()
.filter_map(|segment| {
self.tx
.get::<tables::PruneCheckpoints>(*segment)
.get::<tables::PruneCheckpoints>(segment)
.transpose()
.map(|chk| chk.map(|chk| (*segment, chk)))
.map(|chk| chk.map(|chk| (segment, chk)))
})
.collect::<Result<_, _>>()?)
}