1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
use crate::MINIMUM_PRUNING_DISTANCE;
use derive_more::Display;
use reth_codecs::{add_arbitrary_tests, Compact};
use serde::{Deserialize, Serialize};
use thiserror::Error;

/// Segment of the data that can be pruned.
#[derive(
    Debug,
    Display,
    Clone,
    Copy,
    Eq,
    PartialEq,
    Ord,
    PartialOrd,
    Hash,
    Serialize,
    Deserialize,
    Compact,
)]
#[cfg_attr(test, derive(arbitrary::Arbitrary))]
#[add_arbitrary_tests(compact)]
pub enum PruneSegment {
    /// Prune segment responsible for the `TransactionSenders` table.
    SenderRecovery,
    /// Prune segment responsible for the `TransactionHashNumbers` table.
    TransactionLookup,
    /// Prune segment responsible for all rows in `Receipts` table.
    Receipts,
    /// Prune segment responsible for some rows in `Receipts` table filtered by logs.
    ContractLogs,
    /// Prune segment responsible for the `AccountChangeSets` and `AccountsHistory` tables.
    AccountHistory,
    /// Prune segment responsible for the `StorageChangeSets` and `StoragesHistory` tables.
    StorageHistory,
    /// Prune segment responsible for the `CanonicalHeaders`, `Headers` and
    /// `HeaderTerminalDifficulties` tables.
    Headers,
    /// Prune segment responsible for the `Transactions` table.
    Transactions,
}

impl PruneSegment {
    /// Returns minimum number of blocks to left in the database for this segment.
    pub const fn min_blocks(&self, purpose: PrunePurpose) -> u64 {
        match self {
            Self::SenderRecovery | Self::TransactionLookup | Self::Headers | Self::Transactions => {
                0
            }
            Self::Receipts if purpose.is_static_file() => 0,
            Self::ContractLogs | Self::AccountHistory | Self::StorageHistory => {
                MINIMUM_PRUNING_DISTANCE
            }
            Self::Receipts => MINIMUM_PRUNING_DISTANCE,
        }
    }
}

/// Prune purpose.
#[derive(Debug, Clone, Copy)]
pub enum PrunePurpose {
    /// Prune data according to user configuration.
    User,
    /// Prune data according to highest `static_files` to delete the data from database.
    StaticFile,
}

impl PrunePurpose {
    /// Returns true if the purpose is [`PrunePurpose::User`].
    pub const fn is_user(self) -> bool {
        matches!(self, Self::User)
    }

    /// Returns true if the purpose is [`PrunePurpose::StaticFile`].
    pub const fn is_static_file(self) -> bool {
        matches!(self, Self::StaticFile)
    }
}

/// `PruneSegment` error type.
#[derive(Debug, Error, PartialEq, Eq, Clone)]
pub enum PruneSegmentError {
    /// Invalid configuration of a prune segment.
    #[error("the configuration provided for {0} is invalid")]
    Configuration(PruneSegment),
    /// Receipts have been pruned
    #[error("receipts have been pruned")]
    ReceiptsPruned,
}

#[cfg(test)]
impl Default for PruneSegment {
    fn default() -> Self {
        Self::SenderRecovery
    }
}