Skip to main content

reth_snap_sync/
generation.rs

1//! Identifies one attempt at downloading state.
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}
20
21impl SnapGeneration {
22    /// Creates a generation anchored to the given pivot, before any range is downloaded.
23    pub const fn new(target: BlockNumHash, state_root: B256) -> Self {
24        Self { target, state_root }
25    }
26
27    /// Pivot block this generation is anchored to.
28    pub const fn target(&self) -> BlockNumHash {
29        self.target
30    }
31
32    /// State root that downloaded ranges authenticate against.
33    pub const fn state_root(&self) -> B256 {
34        self.state_root
35    }
36
37    /// Returns how far the canonical head has moved past this generation's anchor.
38    pub const fn lag(&self, head: u64) -> u64 {
39        head.saturating_sub(self.target.number)
40    }
41
42    /// Returns whether the block this generation is anchored to is still canonical.
43    ///
44    /// Separate from whether it is worth finishing: an orphaned anchor is recoverable from the
45    /// abandoned branch's lists.
46    pub fn is_canonical(&self, provider: &impl HeaderProvider) -> Result<bool, SnapSyncError> {
47        let header = provider.sealed_header(self.target.number)?;
48        Ok(header.is_some_and(|header| header.hash() == self.target.hash))
49    }
50}