Skip to main content

reth_stages_types/
id.rs

1use alloc::vec::Vec;
2#[cfg(feature = "std")]
3use std::{collections::HashMap, sync::OnceLock};
4
5/// Stage IDs for all known stages.
6///
7/// For custom stages, use [`StageId::Other`]
8#[expect(missing_docs)]
9#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
10pub enum StageId {
11    #[deprecated(
12        note = "Static Files are generated outside of the pipeline and do not require a separate stage"
13    )]
14    StaticFile,
15    #[deprecated(
16        note = "MerkleChangeSets stage has been removed; kept for DB checkpoint compatibility"
17    )]
18    MerkleChangeSets,
19    Era,
20    Headers,
21    Bodies,
22    SenderRecovery,
23    Execution,
24    PruneSenderRecovery,
25    MerkleUnwind,
26    AccountHashing,
27    StorageHashing,
28    MerkleExecute,
29    TransactionLookup,
30    IndexStorageHistory,
31    IndexAccountHistory,
32    Prune,
33    Finish,
34    /// Other custom stage with a provided string identifier.
35    Other(&'static str),
36}
37
38/// One-time-allocated stage ids encoded as raw Vecs, useful for database
39/// clients to reference them for queries instead of encoding anew per query
40/// (sad heap allocation required).
41#[cfg(feature = "std")]
42static ENCODED_STAGE_IDS: OnceLock<HashMap<StageId, Vec<u8>>> = OnceLock::new();
43
44impl StageId {
45    /// All supported Stages
46    pub const ALL: [Self; 15] = [
47        Self::Era,
48        Self::Headers,
49        Self::Bodies,
50        Self::SenderRecovery,
51        Self::Execution,
52        Self::PruneSenderRecovery,
53        Self::MerkleUnwind,
54        Self::AccountHashing,
55        Self::StorageHashing,
56        Self::MerkleExecute,
57        Self::TransactionLookup,
58        Self::IndexStorageHistory,
59        Self::IndexAccountHistory,
60        Self::Prune,
61        Self::Finish,
62    ];
63
64    /// Stages that require state.
65    pub const STATE_REQUIRED: [Self; 9] = [
66        Self::Execution,
67        Self::PruneSenderRecovery,
68        Self::MerkleUnwind,
69        Self::AccountHashing,
70        Self::StorageHashing,
71        Self::MerkleExecute,
72        Self::IndexStorageHistory,
73        Self::IndexAccountHistory,
74        Self::Prune,
75    ];
76
77    /// Return stage id formatted as string.
78    pub const fn as_str(&self) -> &str {
79        match self {
80            #[expect(deprecated)]
81            Self::StaticFile => "StaticFile",
82            #[expect(deprecated)]
83            Self::MerkleChangeSets => "MerkleChangeSets",
84            Self::Era => "Era",
85            Self::Headers => "Headers",
86            Self::Bodies => "Bodies",
87            Self::SenderRecovery => "SenderRecovery",
88            Self::Execution => "Execution",
89            Self::PruneSenderRecovery => "PruneSenderRecovery",
90            Self::MerkleUnwind => "MerkleUnwind",
91            Self::AccountHashing => "AccountHashing",
92            Self::StorageHashing => "StorageHashing",
93            Self::MerkleExecute => "MerkleExecute",
94            Self::TransactionLookup => "TransactionLookup",
95            Self::IndexAccountHistory => "IndexAccountHistory",
96            Self::IndexStorageHistory => "IndexStorageHistory",
97            Self::Prune => "Prune",
98            Self::Finish => "Finish",
99            Self::Other(s) => s,
100        }
101    }
102
103    /// Returns true if it's a downloading stage [`StageId::Headers`] or [`StageId::Bodies`]
104    pub const fn is_downloading_stage(&self) -> bool {
105        matches!(self, Self::Era | Self::Headers | Self::Bodies)
106    }
107
108    /// Returns `true` if it's [`TransactionLookup`](StageId::TransactionLookup) stage.
109    pub const fn is_tx_lookup(&self) -> bool {
110        matches!(self, Self::TransactionLookup)
111    }
112
113    /// Returns true indicating if it's the finish stage [`StageId::Finish`]
114    pub const fn is_finish(&self) -> bool {
115        matches!(self, Self::Finish)
116    }
117
118    /// Get a pre-encoded raw Vec, for example, to be used as the DB key for
119    /// `tables::StageCheckpoints` and `tables::StageCheckpointProgresses`
120    pub fn get_pre_encoded(&self) -> Option<&Vec<u8>> {
121        #[cfg(not(feature = "std"))]
122        {
123            None
124        }
125        #[cfg(feature = "std")]
126        ENCODED_STAGE_IDS
127            .get_or_init(|| {
128                let mut map = HashMap::with_capacity(Self::ALL.len());
129                for stage_id in Self::ALL {
130                    map.insert(stage_id, stage_id.to_string().into_bytes());
131                }
132                map
133            })
134            .get(self)
135    }
136}
137
138impl core::fmt::Display for StageId {
139    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
140        write!(f, "{}", self.as_str())
141    }
142}
143
144#[cfg(test)]
145mod tests {
146    use super::*;
147
148    #[test]
149    fn stage_id_as_string() {
150        assert_eq!(StageId::Era.to_string(), "Era");
151        assert_eq!(StageId::Headers.to_string(), "Headers");
152        assert_eq!(StageId::Bodies.to_string(), "Bodies");
153        assert_eq!(StageId::SenderRecovery.to_string(), "SenderRecovery");
154        assert_eq!(StageId::Execution.to_string(), "Execution");
155        assert_eq!(StageId::MerkleUnwind.to_string(), "MerkleUnwind");
156        assert_eq!(StageId::AccountHashing.to_string(), "AccountHashing");
157        assert_eq!(StageId::StorageHashing.to_string(), "StorageHashing");
158        assert_eq!(StageId::MerkleExecute.to_string(), "MerkleExecute");
159        assert_eq!(StageId::IndexAccountHistory.to_string(), "IndexAccountHistory");
160        assert_eq!(StageId::IndexStorageHistory.to_string(), "IndexStorageHistory");
161        assert_eq!(StageId::TransactionLookup.to_string(), "TransactionLookup");
162        assert_eq!(StageId::Finish.to_string(), "Finish");
163
164        assert_eq!(StageId::Other("Foo").to_string(), "Foo");
165    }
166
167    #[test]
168    fn is_downloading_stage() {
169        assert!(StageId::Headers.is_downloading_stage());
170        assert!(StageId::Bodies.is_downloading_stage());
171        assert!(StageId::Era.is_downloading_stage());
172
173        assert!(!StageId::Execution.is_downloading_stage());
174    }
175}