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}