reth_prune_types/
segment.rs

1#![allow(deprecated)] // necessary to all defining deprecated `PruneSegment` variants
2
3use crate::MINIMUM_PRUNING_DISTANCE;
4use derive_more::Display;
5use strum::{EnumIter, IntoEnumIterator};
6use thiserror::Error;
7
8/// Segment of the data that can be pruned.
9///
10/// VERY IMPORTANT NOTE: new variants must be added to the end of this enum, and old variants which
11/// are no longer used must not be removed from this enum. The variant index is encoded directly
12/// when writing to the `PruneCheckpoint` table, so changing the order here will corrupt the table.
13#[derive(Debug, Display, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash, EnumIter)]
14#[cfg_attr(test, derive(arbitrary::Arbitrary))]
15#[cfg_attr(any(test, feature = "reth-codec"), derive(reth_codecs::Compact))]
16#[cfg_attr(any(test, feature = "reth-codec"), reth_codecs::add_arbitrary_tests(compact))]
17#[cfg_attr(any(test, feature = "serde"), derive(serde::Serialize, serde::Deserialize))]
18pub enum PruneSegment {
19    /// Prune segment responsible for the `TransactionSenders` table.
20    SenderRecovery,
21    /// Prune segment responsible for the `TransactionHashNumbers` table.
22    TransactionLookup,
23    /// Prune segment responsible for all rows in `Receipts` table.
24    Receipts,
25    /// Prune segment responsible for some rows in `Receipts` table filtered by logs.
26    ContractLogs,
27    /// Prune segment responsible for the `AccountChangeSets` and `AccountsHistory` tables.
28    AccountHistory,
29    /// Prune segment responsible for the `StorageChangeSets` and `StoragesHistory` tables.
30    StorageHistory,
31    #[deprecated = "Variant indexes cannot be changed"]
32    #[strum(disabled)]
33    /// Prune segment responsible for the `CanonicalHeaders`, `Headers` tables.
34    Headers,
35    #[deprecated = "Variant indexes cannot be changed"]
36    #[strum(disabled)]
37    /// Prune segment responsible for the `Transactions` table.
38    Transactions,
39    /// Prune segment responsible for all rows in `AccountsTrieChangeSets` and
40    /// `StoragesTrieChangeSets` table.
41    MerkleChangeSets,
42    /// Prune segment responsible for bodies (transactions in static files).
43    Bodies,
44}
45
46#[cfg(test)]
47#[allow(clippy::derivable_impls)]
48impl Default for PruneSegment {
49    fn default() -> Self {
50        Self::SenderRecovery
51    }
52}
53
54impl PruneSegment {
55    /// Returns an iterator over all variants of [`PruneSegment`].
56    ///
57    /// Excludes deprecated variants that are no longer used, but can still be found in the
58    /// database.
59    pub fn variants() -> impl Iterator<Item = Self> {
60        Self::iter()
61    }
62
63    /// Returns minimum number of blocks to keep in the database for this segment.
64    pub const fn min_blocks(&self, purpose: PrunePurpose) -> u64 {
65        match self {
66            Self::SenderRecovery | Self::TransactionLookup => 0,
67            Self::Receipts if purpose.is_static_file() => 0,
68            Self::ContractLogs |
69            Self::AccountHistory |
70            Self::StorageHistory |
71            Self::MerkleChangeSets |
72            Self::Bodies |
73            Self::Receipts => MINIMUM_PRUNING_DISTANCE,
74            #[expect(deprecated)]
75            #[expect(clippy::match_same_arms)]
76            Self::Headers | Self::Transactions => 0,
77        }
78    }
79
80    /// Returns true if this is [`Self::AccountHistory`].
81    pub const fn is_account_history(&self) -> bool {
82        matches!(self, Self::AccountHistory)
83    }
84
85    /// Returns true if this is [`Self::StorageHistory`].
86    pub const fn is_storage_history(&self) -> bool {
87        matches!(self, Self::StorageHistory)
88    }
89}
90
91/// Prune purpose.
92#[derive(Debug, Clone, Copy)]
93pub enum PrunePurpose {
94    /// Prune data according to user configuration.
95    User,
96    /// Prune data according to highest `static_files` to delete the data from database.
97    StaticFile,
98}
99
100impl PrunePurpose {
101    /// Returns true if the purpose is [`PrunePurpose::User`].
102    pub const fn is_user(self) -> bool {
103        matches!(self, Self::User)
104    }
105
106    /// Returns true if the purpose is [`PrunePurpose::StaticFile`].
107    pub const fn is_static_file(self) -> bool {
108        matches!(self, Self::StaticFile)
109    }
110}
111
112/// `PruneSegment` error type.
113#[derive(Debug, Error, PartialEq, Eq, Clone)]
114pub enum PruneSegmentError {
115    /// Invalid configuration of a prune segment.
116    #[error("the configuration provided for {0} is invalid")]
117    Configuration(PruneSegment),
118}
119
120#[cfg(test)]
121mod tests {
122    use super::*;
123
124    #[test]
125    fn test_prune_segment_iter_excludes_deprecated() {
126        let segments: Vec<PruneSegment> = PruneSegment::variants().collect();
127
128        // Verify deprecated variants are not included derived iter
129        #[expect(deprecated)]
130        {
131            assert!(!segments.contains(&PruneSegment::Headers));
132            assert!(!segments.contains(&PruneSegment::Transactions));
133        }
134    }
135}