1- use std:: { collections:: HashMap , fmt :: Display } ;
1+ use std:: collections:: HashMap ;
22
33use alloy_consensus:: Header ;
44use alloy_eips:: eip4788:: BEACON_ROOTS_ADDRESS ;
@@ -15,9 +15,9 @@ use crate::AnchorType;
1515// https://eips.ethereum.org/EIPS/eip-4788
1616pub const HISTORY_BUFFER_LENGTH : U256 = uint ! ( 8191_ U256 ) ;
1717/// The generalized Merkle tree index of the `block_hash` field in the `BeaconBlock`.
18- const BLOCK_HASH_LEAF_INDEX : usize = 6444 ;
18+ pub const BLOCK_HASH_LEAF_INDEX : usize = 6444 ;
1919/// The generalized Merkle tree index of the `state_root` field in the `BeaconBlock`.
20- const STATE_ROOT_LEAF_INDEX : usize = 6434 ;
20+ pub const STATE_ROOT_LEAF_INDEX : usize = 6434 ;
2121
2222/// Ethereum anchoring system for verifying block execution against beacon chain roots.
2323///
@@ -58,12 +58,17 @@ impl Anchor {
5858 Anchor :: Header ( header_anchor) => ResolvedAnchor {
5959 id : U256 :: from ( header_anchor. header . number ) ,
6060 hash : header_anchor. header . hash_slow ( ) ,
61+ ty : AnchorType :: BlockHash ,
6162 } ,
62- Anchor :: Eip4788 ( beacon_anchor) | Anchor :: Consensus ( beacon_anchor ) => {
63+ Anchor :: Eip4788 ( beacon_anchor) => {
6364 let block_hash = beacon_anchor. inner . header . hash_slow ( ) ;
6465 let hash = beacon_anchor. anchor . beacon_root ( block_hash, BLOCK_HASH_LEAF_INDEX ) ;
6566
66- ResolvedAnchor { id : beacon_anchor. id ( ) . into ( ) , hash }
67+ ResolvedAnchor {
68+ id : U256 :: from ( beacon_anchor. id ( ) . as_timestamp ( ) . unwrap ( ) ) ,
69+ hash,
70+ ty : AnchorType :: Timestamp ,
71+ }
6772 }
6873 Anchor :: ChainedEip4788 ( chained_anchor) => {
6974 // Retrieve the execution block beacon root and timestamp
@@ -88,7 +93,17 @@ impl Anchor {
8893
8994 // If the full chain is valid, return the resolved anchor containing
9095 // the reference block beacon root and timestamp
91- ResolvedAnchor { id : timestamp, hash : beacon_root }
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+ }
92107 }
93108 }
94109 }
@@ -97,8 +112,8 @@ impl Anchor {
97112 pub fn ty ( & self ) -> AnchorType {
98113 match self {
99114 Anchor :: Header ( _) => AnchorType :: BlockHash ,
100- Anchor :: Eip4788 ( _) | Anchor :: ChainedEip4788 ( _) => AnchorType :: Eip4788 ,
101- Anchor :: Consensus ( _) => AnchorType :: Consensus ,
115+ Anchor :: Eip4788 ( _) | Anchor :: ChainedEip4788 ( _) => AnchorType :: Timestamp ,
116+ Anchor :: Consensus ( _) => AnchorType :: Slot ,
102117 }
103118 }
104119}
@@ -114,10 +129,11 @@ impl From<Header> for Anchor {
114129/// This structure represents the result of processing an anchor through its
115130/// verification chain, yielding a canonical identifier and cryptographic hash
116131/// that can be used for block validation.
117- #[ derive( Debug , Clone , Copy ) ]
132+ #[ derive( Debug , Clone ) ]
118133pub struct ResolvedAnchor {
119134 pub id : U256 ,
120135 pub hash : B256 ,
136+ pub ty : AnchorType ,
121137}
122138
123139/// A simple anchor that directly references an Ethereum execution block header.
@@ -214,18 +230,19 @@ impl BeaconAnchor {
214230 }
215231}
216232
217- /// Identifier for a beacon chain anchor, specifying how to locate the anchor in beacon chain history.
233+ /// Identifier for a beacon chain anchor, specifying how to locate the anchor in beacon chain
234+ /// history.
218235///
219236/// The beacon chain stores historical roots that can be accessed either by timestamp
220237/// (for EIP-4788 verification) or by slot number (for direct beacon chain verification).
221238/// This enum allows anchors to specify which indexing method should be used.
222239///
223240/// # Variants
224241///
225- /// - **Timestamp**: References a beacon root by its timestamp, used with EIP-4788
226- /// where beacon roots are stored in the execution layer indexed by timestamp
227- /// - **Slot**: References a beacon root by its slot number, used for direct beacon
228- /// chain verification where data is indexed by consensus slots
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
229246#[ derive( Debug , Clone , Serialize , Deserialize , PartialEq , Eq ) ]
230247pub enum BeaconAnchorId {
231248 Timestamp ( u64 ) ,
@@ -240,13 +257,12 @@ impl BeaconAnchorId {
240257 BeaconAnchorId :: Slot ( _) => None ,
241258 }
242259 }
243- }
244260
245- impl From < & BeaconAnchorId > for U256 {
246- fn from ( value : & BeaconAnchorId ) -> Self {
247- match value {
248- BeaconAnchorId :: Timestamp ( t ) => U256 :: from ( * t ) ,
249- BeaconAnchorId :: Slot ( s) => U256 :: from ( * s) ,
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) ,
250266 }
251267 }
252268}
@@ -277,13 +293,15 @@ pub struct ChainedBeaconAnchor {
277293}
278294
279295impl ChainedBeaconAnchor {
280- /// Creates a new chained beacon anchor linking an execution block through multiple state transitions.
296+ /// Creates a new chained beacon anchor linking an execution block through multiple state
297+ /// transitions.
281298 pub fn new ( inner : BeaconWithHeaderAnchor , state_anchors : Vec < BeaconStateAnchor > ) -> Self {
282299 Self { inner, state_anchors }
283300 }
284301}
285302
286- /// An anchor that combines beacon chain state with cryptographic proof for state transition verification.
303+ /// An anchor that combines beacon chain state with cryptographic proof for state transition
304+ /// verification.
287305///
288306/// This structure represents a single link in a chained verification process, containing
289307/// both a beacon chain state and the cryptographic proof needed to verify that state's
@@ -311,43 +329,6 @@ impl BeaconStateAnchor {
311329 }
312330}
313331
314- /// A field identifier for beacon block components that can be verified via Merkle proofs.
315- ///
316- /// This enum specifies which field of a beacon block should be used as the leaf value
317- /// in Merkle proof verification. Different anchor types require verification of different
318- /// beacon block fields to establish the cryptographic link between execution and consensus layers.
319- #[ derive( Debug , Clone , Copy ) ]
320- pub enum BeaconBlockField {
321- BlockHash ,
322- StateRoot ,
323- }
324-
325- impl Display for BeaconBlockField {
326- fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
327- match self {
328- BeaconBlockField :: BlockHash => write ! ( f, "block_hash" ) ,
329- BeaconBlockField :: StateRoot => write ! ( f, "state_root" ) ,
330- }
331- }
332- }
333-
334- impl PartialEq < BeaconBlockField > for usize {
335- fn eq ( & self , other : & BeaconBlockField ) -> bool {
336- let other = usize:: from ( other) ;
337-
338- * self == other
339- }
340- }
341-
342- impl From < & BeaconBlockField > for usize {
343- fn from ( value : & BeaconBlockField ) -> Self {
344- match value {
345- BeaconBlockField :: BlockHash => BLOCK_HASH_LEAF_INDEX ,
346- BeaconBlockField :: StateRoot => STATE_ROOT_LEAF_INDEX ,
347- }
348- }
349- }
350-
351332/// Rebuilds a Merkle tree root from a leaf value and its branch proof.
352333///
353334/// Given a leaf value, its generalized index in the tree, and the sibling hashes
@@ -369,6 +350,8 @@ pub fn rebuild_merkle_root(leaf: B256, generalized_index: usize, branch: &[B256]
369350 let mut index = generalized_index - ( 1 << depth) ;
370351 let mut hasher = Sha256 :: new ( ) ;
371352
353+ assert_eq ! ( branch. len( ) as u32 , depth) ;
354+
372355 for sibling in branch {
373356 // Determine if the current node is a left or right child
374357 let is_left = index % 2 == 0 ;
@@ -407,9 +390,12 @@ pub fn rebuild_merkle_root(leaf: B256, generalized_index: usize, branch: &[B256]
407390///
408391/// The beacon root hash stored at the given timestamp
409392pub fn get_beacon_root_from_state ( state : & EthereumState , timestamp : U256 ) -> B256 {
393+ assert ! ( !timestamp. is_zero( ) ) ;
410394 let db = TrieDB :: new ( state, HashMap :: default ( ) , HashMap :: default ( ) ) ;
411395 let timestamp_idx = timestamp % HISTORY_BUFFER_LENGTH ;
412396 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) ;
413399
414400 let root = db. storage_ref ( BEACON_ROOTS_ADDRESS , root_idx) . unwrap ( ) ;
415401
0 commit comments