Skip to main content

reth_snap_sync/
generation.rs

1//! Identifies one attempt at downloading state, and how far it has progressed.
2
3use crate::SnapSyncError;
4use alloy_eips::BlockNumHash;
5use alloy_primitives::B256;
6use reth_storage_api::HeaderProvider;
7
8/// One attempt at downloading state, anchored to the pivot block it targets.
9///
10/// The anchor is kept as both a number-hash pair and a state root: the hash decides whether the
11/// attempt is still on the canonical chain, and the root is what downloaded ranges authenticate
12/// against.
13#[derive(Clone, Copy, Debug, Eq, PartialEq)]
14pub struct SnapGeneration {
15    // Pivot block this attempt is anchored to.
16    target: BlockNumHash,
17    // Root downloaded ranges authenticate against.
18    state_root: B256,
19    // Stage reached so far.
20    phase: SnapPhase,
21}
22
23impl SnapGeneration {
24    /// Creates a generation anchored to the given pivot, before any range is downloaded.
25    pub const fn new(target: BlockNumHash, state_root: B256) -> Self {
26        Self { target, state_root, phase: SnapPhase::Accounts }
27    }
28
29    /// Pivot block this generation is anchored to.
30    pub const fn target(&self) -> BlockNumHash {
31        self.target
32    }
33
34    /// State root that downloaded ranges authenticate against.
35    pub const fn state_root(&self) -> B256 {
36        self.state_root
37    }
38
39    /// Stage this generation has reached.
40    pub const fn phase(&self) -> SnapPhase {
41        self.phase
42    }
43
44    /// Returns how far the canonical head has moved past this generation's anchor.
45    pub const fn lag(&self, head: u64) -> u64 {
46        head.saturating_sub(self.target.number)
47    }
48
49    /// Returns whether the block this generation is anchored to is still canonical.
50    ///
51    /// Separate from whether it is worth finishing: an orphaned anchor is recoverable from the
52    /// abandoned branch's lists.
53    pub fn is_canonical(&self, provider: &impl HeaderProvider) -> Result<bool, SnapSyncError> {
54        let header = provider.sealed_header(self.target.number)?;
55        Ok(header.is_some_and(|header| header.hash() == self.target.hash))
56    }
57
58    /// Returns this generation moved to `phase`.
59    #[cfg(test)]
60    pub(crate) const fn with_phase(mut self, phase: SnapPhase) -> Self {
61        self.phase = phase;
62        self
63    }
64}
65
66/// The stage a [`SnapGeneration`] has reached.
67#[derive(Clone, Copy, Debug, Eq, PartialEq)]
68pub enum SnapPhase {
69    /// Account, storage and bytecode ranges are being downloaded.
70    Accounts,
71    /// Authenticated block access lists are being applied.
72    BlockAccessLists,
73    /// The final state trie is being rebuilt and checked.
74    Trie,
75}