sp1_cc_client_executor/
anchor.rs

1use std::collections::HashMap;
2
3use alloy_consensus::Header;
4use alloy_eips::eip4788::BEACON_ROOTS_ADDRESS;
5use alloy_primitives::{uint, B256, U256};
6use revm::DatabaseRef;
7use rsp_client_executor::io::TrieDB;
8use rsp_mpt::EthereumState;
9use serde::{Deserialize, Serialize};
10use serde_with::serde_as;
11use sha2::{Digest, Sha256};
12
13use crate::AnchorType;
14
15// https://eips.ethereum.org/EIPS/eip-4788
16pub const HISTORY_BUFFER_LENGTH: U256 = uint!(8191_U256);
17/// The generalized Merkle tree index of the `block_hash` field in the `BeaconBlock`.
18pub const BLOCK_HASH_LEAF_INDEX: usize = 6444;
19/// The generalized Merkle tree index of the `state_root` field in the `BeaconBlock`.
20pub const STATE_ROOT_LEAF_INDEX: usize = 6434;
21
22/// Ethereum anchoring system for verifying block execution against beacon chain roots.
23///
24/// This module provides structures and functionality for creating cryptographic anchors
25/// that link Ethereum execution blocks to their corresponding beacon chain state. These
26/// anchors enable verification of block validity through Merkle proofs and beacon root
27/// commitments stored via EIP-4788.
28///
29/// # Anchor Types
30///
31/// - **Header Anchor**: Direct reference to an execution block header
32/// - **EIP-4788 Anchor**: Links execution block to beacon chain via EIP-4788 beacon roots
33/// - **Chained EIP-4788 Anchor**: Multi-hop verification through state transitions
34/// - **Consensus Anchor**: Direct beacon chain consensus verification
35#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
36pub enum Anchor {
37    Header(HeaderAnchor),
38    Eip4788(BeaconWithHeaderAnchor),
39    ChainedEip4788(ChainedBeaconAnchor),
40    Consensus(BeaconWithHeaderAnchor),
41}
42
43impl Anchor {
44    /// Returns the execution block header for this anchor.
45    pub fn header(&self) -> &Header {
46        match self {
47            Anchor::Header(header_anchor) => &header_anchor.header,
48            Anchor::Eip4788(beacon_anchor) | Anchor::Consensus(beacon_anchor) => {
49                &beacon_anchor.inner.header
50            }
51            Anchor::ChainedEip4788(chained_anchor) => &chained_anchor.inner.inner.header,
52        }
53    }
54
55    /// Returns the resolved anchor containing the final identifier and hash after verification.
56    pub fn resolve(&self) -> ResolvedAnchor {
57        match self {
58            Anchor::Header(header_anchor) => ResolvedAnchor {
59                id: U256::from(header_anchor.header.number),
60                hash: header_anchor.header.hash_slow(),
61                ty: AnchorType::BlockHash,
62            },
63            Anchor::Eip4788(beacon_anchor) => {
64                let block_hash = beacon_anchor.inner.header.hash_slow();
65                let hash = beacon_anchor.anchor.beacon_root(block_hash, BLOCK_HASH_LEAF_INDEX);
66
67                ResolvedAnchor {
68                    id: U256::from(beacon_anchor.id().as_timestamp().unwrap()),
69                    hash,
70                    ty: AnchorType::Timestamp,
71                }
72            }
73            Anchor::ChainedEip4788(chained_anchor) => {
74                // Retrieve the execution block beacon root and timestamp
75                let mut beacon_root = chained_anchor.inner.beacon_root();
76                let mut timestamp = U256::from(chained_anchor.inner.id().as_timestamp().unwrap());
77
78                // Iterate over all the state anchors stating from the execution block
79                // to the reference block
80                for state_anchor in &chained_anchor.state_anchors {
81                    let state_root = state_anchor.state.state_root();
82                    let current_beacon_root =
83                        get_beacon_root_from_state(&state_anchor.state, timestamp);
84
85                    // Verify that the previous anchor is valid wrt the current state
86                    assert_eq!(current_beacon_root, beacon_root, "Beacon root should match");
87
88                    // Retrieve the beacon root and timestamp of the current state
89                    beacon_root =
90                        state_anchor.anchor.beacon_root(state_root, STATE_ROOT_LEAF_INDEX);
91                    timestamp = U256::from(state_anchor.anchor.id().as_timestamp().unwrap());
92                }
93
94                // If the full chain is valid, return the resolved anchor containing
95                // the reference block beacon root and timestamp
96                ResolvedAnchor { id: timestamp, hash: beacon_root, ty: AnchorType::Timestamp }
97            }
98            Anchor::Consensus(beacon_anchor) => {
99                let block_hash = beacon_anchor.inner.header.hash_slow();
100                let hash = beacon_anchor.anchor.beacon_root(block_hash, BLOCK_HASH_LEAF_INDEX);
101
102                ResolvedAnchor {
103                    id: U256::from(beacon_anchor.id().as_slot().unwrap()),
104                    hash,
105                    ty: AnchorType::Slot,
106                }
107            }
108        }
109    }
110
111    /// Returns the anchor type for this anchor.
112    pub fn ty(&self) -> AnchorType {
113        match self {
114            Anchor::Header(_) => AnchorType::BlockHash,
115            Anchor::Eip4788(_) | Anchor::ChainedEip4788(_) => AnchorType::Timestamp,
116            Anchor::Consensus(_) => AnchorType::Slot,
117        }
118    }
119}
120
121impl From<Header> for Anchor {
122    fn from(header: Header) -> Self {
123        Self::Header(HeaderAnchor { header })
124    }
125}
126
127/// A resolved anchor containing the final computed identifier and hash.
128///
129/// This structure represents the result of processing an anchor through its
130/// verification chain, yielding a canonical identifier and cryptographic hash
131/// that can be used for block validation.
132#[derive(Debug, Clone)]
133pub struct ResolvedAnchor {
134    pub id: U256,
135    pub hash: B256,
136    pub ty: AnchorType,
137}
138
139/// A simple anchor that directly references an Ethereum execution block header.
140///
141/// This is the most basic form of anchor that provides direct access to a block header
142/// without any additional cryptographic proofs or beacon chain integration. It's typically
143/// used when you have direct trust in the header data or when working with local/trusted
144/// block sources.
145#[serde_as]
146#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
147pub struct HeaderAnchor {
148    #[serde_as(as = "alloy_consensus::serde_bincode_compat::Header")]
149    header: Header,
150}
151
152/// An anchor that combines an execution block header with beacon chain verification.
153///
154/// This structure links an Ethereum execution block to the beacon chain through
155/// cryptographic proofs, enabling verification that the execution block is part
156/// of the canonical beacon chain. It's used for EIP-4788 based verification
157/// where beacon roots are stored in the execution layer.
158///
159/// The anchor contains:
160/// - An execution block header that can be verified
161/// - A beacon anchor with Merkle proofs linking the block to beacon chain state
162///
163/// This enables trustless verification of execution blocks by checking their
164/// inclusion in the beacon chain consensus without requiring direct access
165/// to beacon chain data.
166#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
167pub struct BeaconWithHeaderAnchor {
168    inner: HeaderAnchor,
169    anchor: BeaconAnchor,
170}
171
172impl BeaconWithHeaderAnchor {
173    /// Creates a new beacon anchor with header and beacon proof.
174    pub fn new(header: Header, anchor: BeaconAnchor) -> Self {
175        Self { inner: HeaderAnchor { header }, anchor }
176    }
177
178    /// Returns the Merkle proof for beacon chain verification.
179    pub fn proof(&self) -> &[B256] {
180        self.anchor.proof()
181    }
182
183    /// Returns the block identifier used for verification.
184    pub fn id(&self) -> &BeaconAnchorId {
185        self.anchor.id()
186    }
187
188    /// Returns the beacon root for this anchor computed from the execution block hash.
189    pub fn beacon_root(&self) -> B256 {
190        self.anchor.beacon_root(self.inner.header.hash_slow(), BLOCK_HASH_LEAF_INDEX)
191    }
192}
193
194impl From<BeaconWithHeaderAnchor> for BeaconAnchor {
195    fn from(value: BeaconWithHeaderAnchor) -> Self {
196        value.anchor
197    }
198}
199
200/// A beacon chain anchor that provides cryptographic proof linking data to beacon chain state.
201///
202/// This structure contains a Merkle proof and identifier that can be used to verify
203/// that a specific piece of data (like a block hash or state root) is correctly
204/// included in the beacon chain. The proof enables trustless verification without
205/// requiring access to the full beacon chain state.
206#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
207pub struct BeaconAnchor {
208    proof: Vec<B256>,
209    id: BeaconAnchorId,
210}
211
212impl BeaconAnchor {
213    /// Creates a new beacon anchor with the given proof and identifier.
214    pub fn new(proof: Vec<B256>, id: BeaconAnchorId) -> Self {
215        Self { proof, id }
216    }
217    /// Creates a new beacon anchor with the given proof and identifier.
218    pub fn proof(&self) -> &[B256] {
219        &self.proof
220    }
221
222    /// Returns the block identifier used for verification.
223    pub fn id(&self) -> &BeaconAnchorId {
224        &self.id
225    }
226
227    /// Reconstructs the beacon chain Merkle root from a leaf value and proof.
228    pub fn beacon_root(&self, leaf: B256, generalized_index: usize) -> B256 {
229        rebuild_merkle_root(leaf, generalized_index, &self.proof)
230    }
231}
232
233/// Identifier for a beacon chain anchor, specifying how to locate the anchor in beacon chain
234/// history.
235///
236/// The beacon chain stores historical roots that can be accessed either by timestamp
237/// (for EIP-4788 verification) or by slot number (for direct beacon chain verification).
238/// This enum allows anchors to specify which indexing method should be used.
239///
240/// # Variants
241///
242/// - **Timestamp**: References a beacon root by its timestamp, used with EIP-4788 where beacon
243///   roots are stored in the execution layer indexed by timestamp
244/// - **Slot**: References a beacon root by its slot number, used for direct beacon chain
245///   verification where data is indexed by consensus slots
246#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
247pub enum BeaconAnchorId {
248    Timestamp(u64),
249    Slot(u64),
250}
251
252impl BeaconAnchorId {
253    /// Returns timestamp if this is a Timestamp variant, None otherwise.
254    pub fn as_timestamp(&self) -> Option<u64> {
255        match self {
256            BeaconAnchorId::Timestamp(t) => Some(*t),
257            BeaconAnchorId::Slot(_) => None,
258        }
259    }
260
261    /// Returns timestamp if this is a Timestamp variant, None otherwise.
262    pub fn as_slot(&self) -> Option<u64> {
263        match self {
264            BeaconAnchorId::Timestamp(_) => None,
265            BeaconAnchorId::Slot(s) => Some(*s),
266        }
267    }
268}
269
270/// A chained anchor that enables verification through multiple beacon chain state transitions.
271///
272/// This structure extends the basic beacon anchor concept by allowing verification through
273/// a chain of state transitions. It's useful when you need to verify an execution block
274/// against a beacon chain state that's not directly accessible via EIP-4788, but can be
275/// reached through a series of intermediate states.
276///
277/// The chained anchor works by:
278/// 1. Starting with an execution block and its beacon root (via EIP-4788)
279/// 2. Following a chain of beacon chain state transitions through intermediate states
280/// 3. Ending at a reference beacon chain state that can be independently verified
281///
282/// Each step in the chain verifies:
283/// - The previous beacon root matches the current state's stored beacon root
284/// - The current state root is properly included in the next beacon chain state
285///
286/// This enables verification of execution blocks against historical beacon chain states
287/// that may not be directly accessible, creating a cryptographic chain of trust through
288/// intermediate consensus states.
289#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
290pub struct ChainedBeaconAnchor {
291    inner: BeaconWithHeaderAnchor,
292    state_anchors: Vec<BeaconStateAnchor>,
293}
294
295impl ChainedBeaconAnchor {
296    /// Creates a new chained beacon anchor linking an execution block through multiple state
297    /// transitions.
298    pub fn new(inner: BeaconWithHeaderAnchor, state_anchors: Vec<BeaconStateAnchor>) -> Self {
299        Self { inner, state_anchors }
300    }
301}
302
303/// An anchor that combines beacon chain state with cryptographic proof for state transition
304/// verification.
305///
306/// This structure represents a single link in a chained verification process, containing
307/// both a beacon chain state and the cryptographic proof needed to verify that state's
308/// inclusion in the beacon chain. It's used as a building block for `ChainedBeaconAnchor`
309/// to enable verification through multiple state transitions.
310///
311/// The anchor contains:
312/// - A complete Ethereum beacon chain state snapshot
313/// - A beacon anchor with Merkle proofs linking the state root to beacon chain consensus
314///
315/// This enables verification that a specific beacon chain state is legitimate and can
316/// be used as a trusted intermediate step in a chain of cryptographic proofs. Each
317/// `BeaconStateAnchor` in a chain verifies that its state root is properly included
318/// in the next beacon chain state, creating a verifiable path from an execution block
319/// to a reference beacon chain state.
320#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
321pub struct BeaconStateAnchor {
322    state: EthereumState,
323    anchor: BeaconAnchor,
324}
325
326impl BeaconStateAnchor {
327    pub fn new(state: EthereumState, anchor: BeaconAnchor) -> Self {
328        Self { state, anchor }
329    }
330}
331
332/// Rebuilds a Merkle tree root from a leaf value and its branch proof.
333///
334/// Given a leaf value, its generalized index in the tree, and the sibling hashes
335/// along the path to the root, this function reconstructs the Merkle root by
336/// iteratively hashing the current node with its sibling at each level.
337///
338/// # Arguments
339///
340/// * `leaf` - The leaf value to start reconstruction from
341/// * `generalized_index` - The generalized index of the leaf in the Merkle tree
342/// * `branch` - Slice of sibling hashes along the path from leaf to root
343///
344/// # Returns
345///
346/// The reconstructed Merkle root hash
347pub fn rebuild_merkle_root(leaf: B256, generalized_index: usize, branch: &[B256]) -> B256 {
348    let mut current_hash = leaf;
349    let depth = generalized_index.ilog2();
350    let mut index = generalized_index - (1 << depth);
351    let mut hasher = Sha256::new();
352
353    assert_eq!(branch.len() as u32, depth);
354
355    for sibling in branch {
356        // Determine if the current node is a left or right child
357        let is_left = index % 2 == 0;
358
359        // Combine the current hash with the sibling hash
360        if is_left {
361            // If current node is left child, hash(current + sibling)
362            hasher.update(current_hash);
363            hasher.update(sibling);
364        } else {
365            // If current node is right child, hash(sibling + current)
366            hasher.update(sibling);
367            hasher.update(current_hash);
368        }
369        current_hash.copy_from_slice(&hasher.finalize_reset());
370
371        // Move up to the parent level
372        index /= 2;
373    }
374
375    current_hash
376}
377
378/// Retrieves a beacon root from Ethereum state using EIP-4788 storage.
379///
380/// This function looks up a beacon root stored in the EIP-4788 beacon roots contract
381/// at the `BEACON_ROOTS_ADDRESS`. The beacon root is indexed by timestamp and retrieved
382/// from the circular buffer using modular arithmetic.
383///
384/// # Arguments
385///
386/// * `state` - The Ethereum state to query
387/// * `timestamp` - The timestamp to look up the beacon root for
388///
389/// # Returns
390///
391/// The beacon root hash stored at the given timestamp
392pub fn get_beacon_root_from_state(state: &EthereumState, timestamp: U256) -> B256 {
393    assert!(!timestamp.is_zero());
394    let db = TrieDB::new(state, HashMap::default(), HashMap::default());
395    let timestamp_idx = timestamp % HISTORY_BUFFER_LENGTH;
396    let root_idx = timestamp_idx + HISTORY_BUFFER_LENGTH;
397    let timestamp_in_storage = db.storage_ref(BEACON_ROOTS_ADDRESS, timestamp_idx).unwrap();
398    assert_eq!(timestamp, timestamp_in_storage);
399
400    let root = db.storage_ref(BEACON_ROOTS_ADDRESS, root_idx).unwrap();
401
402    root.into()
403}