From cb28918f1e2cb98836736498e57024a5f0ad168f Mon Sep 17 00:00:00 2001 From: Severiano Sisneros Date: Mon, 5 Aug 2024 16:22:55 -0700 Subject: [PATCH 01/11] feat(HeadState): Added function to compute block root inclusion proof Function can be used to compute an inclusion for a block header root in the hisorical_roots or historical_summaries in the beacon state. --- Cargo.toml | 1 + src/head_state.rs | 31 +++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 1079080e..c7f88e14 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,7 @@ types = { git = "https://github.com/suchapalaver/lighthouse.git", branch = "stab primitive-types = "0.12.2" serde = { version = "1.0", features = ["derive"] } tree_hash = "0.6.0" +merkle_proof = { git = "https://github.com/suchapalaver/lighthouse.git" } [dev-dependencies] insta = "1.39.0" diff --git a/src/head_state.rs b/src/head_state.rs index 60c6f6e6..e4056e51 100644 --- a/src/head_state.rs +++ b/src/head_state.rs @@ -1,8 +1,11 @@ +use merkle_proof::{MerkleTree, MerkleTreeError}; use primitive_types::H256; use serde::{Deserialize, Serialize}; use tree_hash::TreeHash; use types::{BeaconState, Error, EthSpec, MainnetEthSpec}; +const HISTORY_TREE_DEPTH: usize = 13; + #[derive(Clone, Debug, Deserialize, Serialize)] pub struct HeadState { version: String, @@ -38,6 +41,14 @@ impl HeadState { pub fn version(&self) -> &str { &self.version } + + pub fn compute_block_roots_proof(&self, index: usize) -> Result, MerkleTreeError> { + let leaves = self.data.block_roots().to_vec(); + let tree = MerkleTree::create(&leaves, HISTORY_TREE_DEPTH); + let (_, proof) = tree.generate_proof(index, HISTORY_TREE_DEPTH)?; + + Ok(proof) + } } #[cfg(test)] @@ -132,4 +143,24 @@ mod tests { "Merkle proof verification failed" ); } + + #[test] + fn test_inclusion_proofs_for_block_roots() { + let state = &STATE; + let index = 4096usize; + let block_root_at_index = state.data().block_roots().to_vec()[index]; + let block_roots_root = state.data().block_roots().tree_hash_root(); + let proof = state.compute_block_roots_proof(index).unwrap(); + + assert!( + verify_merkle_proof( + block_root_at_index, + &proof, + HISTORY_TREE_DEPTH, + index, + block_roots_root + ), + "Merkle proof verification failed" + ); + } } From b714fdd67b820a9dca714b235584024dbffa17ca Mon Sep 17 00:00:00 2001 From: Severiano Sisneros Date: Wed, 7 Aug 2024 16:18:51 -0700 Subject: [PATCH 02/11] fix: Fixed compute_block_roots_proof to prove against a HistoricalSummary root and perform an era check --- Cargo.toml | 5 +-- src/head_state.rs | 79 ++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 71 insertions(+), 13 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c7f88e14..6f299ed1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,9 +13,10 @@ types = { git = "https://github.com/suchapalaver/lighthouse.git", branch = "stab primitive-types = "0.12.2" serde = { version = "1.0", features = ["derive"] } tree_hash = "0.6.0" -merkle_proof = { git = "https://github.com/suchapalaver/lighthouse.git" } +merkle_proof = { git = "https://github.com/suchapalaver/lighthouse.git", branch = "stable" } [dev-dependencies] insta = "1.39.0" -merkle_proof = { git = "https://github.com/suchapalaver/lighthouse.git" } +merkle_proof = { git = "https://github.com/suchapalaver/lighthouse.git", branch = "stable" } serde_json = "1.0" + diff --git a/src/head_state.rs b/src/head_state.rs index e4056e51..42b3b55f 100644 --- a/src/head_state.rs +++ b/src/head_state.rs @@ -2,9 +2,10 @@ use merkle_proof::{MerkleTree, MerkleTreeError}; use primitive_types::H256; use serde::{Deserialize, Serialize}; use tree_hash::TreeHash; -use types::{BeaconState, Error, EthSpec, MainnetEthSpec}; +use types::{BeaconState, BeaconStateError as Error, EthSpec, MainnetEthSpec, historical_summary::HistoricalSummary}; const HISTORY_TREE_DEPTH: usize = 13; +const HISTORICAL_SUMMARY_TREE_DEPTH: usize = 14; #[derive(Clone, Debug, Deserialize, Serialize)] pub struct HeadState { @@ -42,15 +43,33 @@ impl HeadState { &self.version } - pub fn compute_block_roots_proof(&self, index: usize) -> Result, MerkleTreeError> { + pub fn compute_block_roots_proof(&self, index: usize) -> Result, Error> { + // This computation only makes sense if we have all of the leaves (BeaconBlock roots) to construct the HisoricalSummary Merkle tree. + // So we construct a new HistoricalSummary from the state and check that the tree root is in historical_summaries. + // This will only be true if the state is in the last slot of an era. + let historical_summary = HistoricalSummary::new(&self.data); + let historical_summaries= self.data.historical_summaries()?.to_vec(); + let latest_historical_summary = historical_summaries.last(); + if latest_historical_summary != Some(&historical_summary) { + return Err(Error::SlotOutOfBounds); + } + + // Construct the block_roots Merkle tree and generate the proof. let leaves = self.data.block_roots().to_vec(); let tree = MerkleTree::create(&leaves, HISTORY_TREE_DEPTH); - let (_, proof) = tree.generate_proof(index, HISTORY_TREE_DEPTH)?; + let (_, mut proof) = tree.generate_proof(index, HISTORY_TREE_DEPTH)?; + // We are going to verify this proof using the HistoricalSummary root, the two children nodes are the block_roots tree root and that state_roots tree root. + // So we append the state_roots tree root to the proof. + let state_roots_root = self.data.state_roots().tree_hash_root(); + proof.extend(vec![state_roots_root]); + Ok(proof) } } + + #[cfg(test)] mod tests { use std::cell::LazyCell; @@ -63,7 +82,7 @@ mod tests { }; const HEAD_STATE_JSON: &str = include_str!("../head-state.json"); - + const HISTORICAL_ROOTS_FIELD_INDEX: usize = 7; const HISTORICAL_SUMMARIES_FIELD_INDEX: usize = 27; @@ -73,6 +92,15 @@ mod tests { ) }); + const TRANSITION_STATE_JSON: &str = include_str!("../8790016-state.json"); + const TRANSITION_STATE: LazyCell> = LazyCell::new(|| { + serde_json::from_str(TRANSITION_STATE_JSON).expect( + "For this spike we are using a '8790016-state.json' file that has been shared among contributors", + ) + }); + + const CAPELLA_START_ERA: usize = 758; + #[test] fn test_inclusion_proofs_with_historical_and_state_roots() { let state = &STATE; @@ -146,19 +174,48 @@ mod tests { #[test] fn test_inclusion_proofs_for_block_roots() { - let state = &STATE; + // For this test, we want to prove that a block_root is included in a HistoricalSummary from the BeaconState historical_summaries List. + // A HistoricalSummary contains the roots of two Merkle trees, block_summary_root and state_summary root. + // We are interested in the block_summary tree, whose leaves consists of the BeaconBlockHeader roots for one epoch (8192 consecutive slots). + // For this test, we are using the state at slot 8790016, which is the last slot of epoch 1073, to build the proof. + // We chose this slot because it is the last slot of an epoch, and all of the BeaconBlockHeader roots needed to construct the HistoricalSummary for this epoch are available in state.block_roots. + let transition_state = &TRANSITION_STATE; + + // There are 8192 slots in an era. + let proof_era= transition_state.data().slot().as_usize() / 8192usize; + + // In this test we are using the historical_summaries (introduced in Capella) for verification, so we need to subtract the Capella start era to get the correct index. + let proof_era_index = proof_era - CAPELLA_START_ERA - 1; + + // We are going to prove that the block_root at index 4096 is included in the block_roots tree. + // This is an arbitrary choice just for test purposes. let index = 4096usize; - let block_root_at_index = state.data().block_roots().to_vec()[index]; - let block_roots_root = state.data().block_roots().tree_hash_root(); - let proof = state.compute_block_roots_proof(index).unwrap(); + let block_root_at_index = match transition_state.data().block_roots().get(index) { + Some(block_root) => block_root, + None => panic!("Block root not found") + }; + let proof = match transition_state.compute_block_roots_proof(index) { + Ok(proof) => proof, + Err(e) => panic!("Error generating block_roots proof: {:?}", e) + }; + + // To verify the proof, we use the state from a later slot. + // The HistoricalSummary used to generate this proof is included in the historical_summaries list of this state. + let state = &STATE; + // The verifier retrieves the block_summary_root for the historical_summary and verifies the proof against it. + let historical_summary= match state.data().historical_summaries().unwrap().get(proof_era_index){ + Some(historical_summary) => historical_summary, + None => panic!("HistoricalSummary not found") + }; + let historical_summary_root = historical_summary.tree_hash_root(); assert!( verify_merkle_proof( - block_root_at_index, + *block_root_at_index, &proof, - HISTORY_TREE_DEPTH, + HISTORICAL_SUMMARY_TREE_DEPTH, index, - block_roots_root + historical_summary_root ), "Merkle proof verification failed" ); From 1427e9675d21822ec70b6fb56960bf25ac5a89f5 Mon Sep 17 00:00:00 2001 From: Severiano Sisneros Date: Wed, 7 Aug 2024 16:46:53 -0700 Subject: [PATCH 03/11] fix(Cargo.toml): Using semiotic-ai lighthouse repo --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index f72def29..4b46c0d5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ types = { git = "https://github.com/semiotic-ai/lighthouse.git", branch = "stabl primitive-types = "0.12.2" serde = { version = "1.0", features = ["derive"] } tree_hash = "0.6.0" -merkle_proof = { git = "https://github.com/suchapalaver/lighthouse.git", branch = "stable" } +merkle_proof = { git = "https://github.com/semiotic-ai/lighthouse.git", branch = "stable" } [dev-dependencies] insta = "1.39.0" From 89842657d047af009884daf1952e85fa3489a455 Mon Sep 17 00:00:00 2001 From: Severiano Sisneros Date: Wed, 7 Aug 2024 16:49:21 -0700 Subject: [PATCH 04/11] refactor(beacon_state): Removed unused lib --- src/beacon_state.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/beacon_state.rs b/src/beacon_state.rs index db95276d..dda6882b 100644 --- a/src/beacon_state.rs +++ b/src/beacon_state.rs @@ -1,4 +1,4 @@ -use merkle_proof::{MerkleTree, MerkleTreeError}; +use merkle_proof::MerkleTree; use primitive_types::H256; use serde::{Deserialize, Serialize}; use tree_hash::TreeHash; From c0d1c4ec49de8e74c9c88f32a654f8dd9056d68d Mon Sep 17 00:00:00 2001 From: Severiano Sisneros Date: Wed, 7 Aug 2024 17:19:43 -0700 Subject: [PATCH 05/11] docs(beacon_state): Added documentation for tree depth constants and compute_block_roots_proof --- src/beacon_state.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/beacon_state.rs b/src/beacon_state.rs index dda6882b..e57f24ce 100644 --- a/src/beacon_state.rs +++ b/src/beacon_state.rs @@ -4,7 +4,12 @@ use serde::{Deserialize, Serialize}; use tree_hash::TreeHash; use types::{BeaconState, BeaconStateError as Error, EthSpec, MainnetEthSpec, historical_summary::HistoricalSummary}; +/// [`BeaconState`] `block_roots` vector has length `SLOTS_PER_HISTORICAL_ROOT` (See ), +/// the value of which is calculated uint64(2**13) (= 8,192) (See ) const HISTORY_TREE_DEPTH: usize = 13; + +/// The historical roots tree (pre-Capella) and the historical summaries tree (post-Capella) have the same depth. +/// Both tree's root has the block_roots tree root and the state_roots tree root as childen and so has one more layer than each of these trees. const HISTORICAL_SUMMARY_TREE_DEPTH: usize = 14; pub const HISTORICAL_ROOTS_FIELD_INDEX: usize = 7; @@ -45,7 +50,7 @@ impl HeadState { pub fn version(&self) -> &str { &self.version } - + /// Computes a Merkle inclusion proof of a `BeaconBlock` root using Merkle trees from either the [`historical_roots`](https://github.com/ethereum/annotated-spec/blob/master/phase0/beacon-chain.md#beaconstate) or [`historical_summaries`](https://github.com/ethereum/annotated-spec/blob/master/capella/beacon-chain.md#beaconstate) list. See the discusion [here](https://github.com/ethereum/annotated-spec/blob/master/phase0/beacon-chain.md#slots_per_historical_root) for more details about the `historical_roots` and [here](https://github.com/ethereum/annotated-spec/blob/master/capella/beacon-chain.md#historicalsummary) about `historical_summaries`. pub fn compute_block_roots_proof(&self, index: usize) -> Result, Error> { // This computation only makes sense if we have all of the leaves (BeaconBlock roots) to construct the HisoricalSummary Merkle tree. // So we construct a new HistoricalSummary from the state and check that the tree root is in historical_summaries. From c60177563626fad20ea5ccf8db97f879406e69a6 Mon Sep 17 00:00:00 2001 From: Severiano Sisneros Date: Thu, 8 Aug 2024 09:36:01 -0600 Subject: [PATCH 06/11] Update src/beacon_state.rs Co-authored-by: Joseph Livesey Signed-off-by: Severiano Sisneros --- src/beacon_state.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/beacon_state.rs b/src/beacon_state.rs index e57f24ce..492cb722 100644 --- a/src/beacon_state.rs +++ b/src/beacon_state.rs @@ -10,7 +10,7 @@ const HISTORY_TREE_DEPTH: usize = 13; /// The historical roots tree (pre-Capella) and the historical summaries tree (post-Capella) have the same depth. /// Both tree's root has the block_roots tree root and the state_roots tree root as childen and so has one more layer than each of these trees. -const HISTORICAL_SUMMARY_TREE_DEPTH: usize = 14; +pub const HISTORICAL_SUMMARY_TREE_DEPTH: usize = 14; pub const HISTORICAL_ROOTS_FIELD_INDEX: usize = 7; pub const HISTORICAL_SUMMARIES_FIELD_INDEX: usize = 27; From 048018b8a822a3bb080603ce063e1d100017d3b8 Mon Sep 17 00:00:00 2001 From: Severiano Sisneros Date: Thu, 8 Aug 2024 09:36:11 -0600 Subject: [PATCH 07/11] Update src/beacon_state.rs Co-authored-by: Joseph Livesey Signed-off-by: Severiano Sisneros --- src/beacon_state.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/beacon_state.rs b/src/beacon_state.rs index 492cb722..8398685d 100644 --- a/src/beacon_state.rs +++ b/src/beacon_state.rs @@ -6,7 +6,7 @@ use types::{BeaconState, BeaconStateError as Error, EthSpec, MainnetEthSpec, his /// [`BeaconState`] `block_roots` vector has length `SLOTS_PER_HISTORICAL_ROOT` (See ), /// the value of which is calculated uint64(2**13) (= 8,192) (See ) -const HISTORY_TREE_DEPTH: usize = 13; +pub const HISTORY_TREE_DEPTH: usize = 13; /// The historical roots tree (pre-Capella) and the historical summaries tree (post-Capella) have the same depth. /// Both tree's root has the block_roots tree root and the state_roots tree root as childen and so has one more layer than each of these trees. From 77ee118f2ebd3f67515ee7ae11ac1399663ac335 Mon Sep 17 00:00:00 2001 From: Severiano Sisneros Date: Thu, 8 Aug 2024 09:54:30 -0600 Subject: [PATCH 08/11] Apply suggestions from code review Correcting typos. Co-authored-by: Joseph Livesey Signed-off-by: Severiano Sisneros --- src/beacon_state.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/beacon_state.rs b/src/beacon_state.rs index 8398685d..b53344a0 100644 --- a/src/beacon_state.rs +++ b/src/beacon_state.rs @@ -50,9 +50,9 @@ impl HeadState { pub fn version(&self) -> &str { &self.version } - /// Computes a Merkle inclusion proof of a `BeaconBlock` root using Merkle trees from either the [`historical_roots`](https://github.com/ethereum/annotated-spec/blob/master/phase0/beacon-chain.md#beaconstate) or [`historical_summaries`](https://github.com/ethereum/annotated-spec/blob/master/capella/beacon-chain.md#beaconstate) list. See the discusion [here](https://github.com/ethereum/annotated-spec/blob/master/phase0/beacon-chain.md#slots_per_historical_root) for more details about the `historical_roots` and [here](https://github.com/ethereum/annotated-spec/blob/master/capella/beacon-chain.md#historicalsummary) about `historical_summaries`. + /// Computes a Merkle inclusion proof of a `BeaconBlock` root using Merkle trees from either the [`historical_roots`](https://github.com/ethereum/annotated-spec/blob/master/phase0/beacon-chain.md#beaconstate) or [`historical_summaries`](https://github.com/ethereum/annotated-spec/blob/master/capella/beacon-chain.md#beaconstate) list. See the discussion [here](https://github.com/ethereum/annotated-spec/blob/master/phase0/beacon-chain.md#slots_per_historical_root) for more details about the `historical_roots` and [here](https://github.com/ethereum/annotated-spec/blob/master/capella/beacon-chain.md#historicalsummary) about `historical_summaries`. pub fn compute_block_roots_proof(&self, index: usize) -> Result, Error> { - // This computation only makes sense if we have all of the leaves (BeaconBlock roots) to construct the HisoricalSummary Merkle tree. + // This computation only makes sense if we have all of the leaves (BeaconBlock roots) to construct the HistoricalSummary Merkle tree. // So we construct a new HistoricalSummary from the state and check that the tree root is in historical_summaries. // This will only be true if the state is in the last slot of an era. let historical_summary = HistoricalSummary::new(&self.data); From 6ac682e94c038a236b0ef05f2e75f300816effde Mon Sep 17 00:00:00 2001 From: Severiano Sisneros Date: Thu, 8 Aug 2024 09:08:01 -0700 Subject: [PATCH 09/11] refactor(beacon_state): Removed uneccessary consts from tests and added doc strings in lib --- src/beacon_state.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/beacon_state.rs b/src/beacon_state.rs index b53344a0..0ac946d6 100644 --- a/src/beacon_state.rs +++ b/src/beacon_state.rs @@ -12,7 +12,10 @@ pub const HISTORY_TREE_DEPTH: usize = 13; /// Both tree's root has the block_roots tree root and the state_roots tree root as childen and so has one more layer than each of these trees. pub const HISTORICAL_SUMMARY_TREE_DEPTH: usize = 14; +/// Index of `historical_roots` field in the BeaconState [struct](https://github.com/ethereum/annotated-spec/blob/master/phase0/beacon-chain.md#beaconstate). pub const HISTORICAL_ROOTS_FIELD_INDEX: usize = 7; + +/// Index of `historical_summaries` field in the (post-Capella) BeaconState [struct](https://github.com/ethereum/annotated-spec/blob/master/capella/beacon-chain.md#beaconstate). pub const HISTORICAL_SUMMARIES_FIELD_INDEX: usize = 27; #[derive(Clone, Debug, Deserialize, Serialize)] @@ -90,8 +93,6 @@ mod tests { }; const HEAD_STATE_JSON: &str = include_str!("../head-state.json"); - const HISTORICAL_ROOTS_FIELD_INDEX: usize = 7; - const HISTORICAL_SUMMARIES_FIELD_INDEX: usize = 27; const STATE: LazyCell> = LazyCell::new(|| { serde_json::from_str(HEAD_STATE_JSON).expect( From 0481078f3f4011d3f8606682ff71f136f02acf2b Mon Sep 17 00:00:00 2001 From: Severiano Sisneros Date: Thu, 8 Aug 2024 09:56:04 -0700 Subject: [PATCH 10/11] docs(tests): Documenting test_inclusion_proofs_for_block_roots with doc commment --- src/beacon_state.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/beacon_state.rs b/src/beacon_state.rs index 0ac946d6..5f2d81fd 100644 --- a/src/beacon_state.rs +++ b/src/beacon_state.rs @@ -181,12 +181,12 @@ mod tests { } #[test] + /// For this test, we want to prove that a block_root is included in a HistoricalSummary from the BeaconState historical_summaries List. + /// A HistoricalSummary contains the roots of two Merkle trees, block_summary_root and state_summary root. + /// We are interested in the block_summary tree, whose leaves consists of the BeaconBlockHeader roots for one epoch (8192 consecutive slots). + /// For this test, we are using the state at slot 8790016, which is the last slot of epoch 1073, to build the proof. + /// We chose this slot because it is the last slot of an epoch, and all of the BeaconBlockHeader roots needed to construct the HistoricalSummary for this epoch are available in state.block_roots. fn test_inclusion_proofs_for_block_roots() { - // For this test, we want to prove that a block_root is included in a HistoricalSummary from the BeaconState historical_summaries List. - // A HistoricalSummary contains the roots of two Merkle trees, block_summary_root and state_summary root. - // We are interested in the block_summary tree, whose leaves consists of the BeaconBlockHeader roots for one epoch (8192 consecutive slots). - // For this test, we are using the state at slot 8790016, which is the last slot of epoch 1073, to build the proof. - // We chose this slot because it is the last slot of an epoch, and all of the BeaconBlockHeader roots needed to construct the HistoricalSummary for this epoch are available in state.block_roots. let transition_state = &TRANSITION_STATE; // There are 8192 slots in an era. From 4dc0d4ede4b17d8f4c065644ba174b779d5759c9 Mon Sep 17 00:00:00 2001 From: Severiano Sisneros Date: Thu, 8 Aug 2024 09:58:06 -0700 Subject: [PATCH 11/11] style: ran cargo fmt --- src/beacon_state.rs | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/src/beacon_state.rs b/src/beacon_state.rs index 5f2d81fd..9c27de90 100644 --- a/src/beacon_state.rs +++ b/src/beacon_state.rs @@ -2,7 +2,10 @@ use merkle_proof::MerkleTree; use primitive_types::H256; use serde::{Deserialize, Serialize}; use tree_hash::TreeHash; -use types::{BeaconState, BeaconStateError as Error, EthSpec, MainnetEthSpec, historical_summary::HistoricalSummary}; +use types::{ + historical_summary::HistoricalSummary, BeaconState, BeaconStateError as Error, EthSpec, + MainnetEthSpec, +}; /// [`BeaconState`] `block_roots` vector has length `SLOTS_PER_HISTORICAL_ROOT` (See ), /// the value of which is calculated uint64(2**13) (= 8,192) (See ) @@ -12,7 +15,7 @@ pub const HISTORY_TREE_DEPTH: usize = 13; /// Both tree's root has the block_roots tree root and the state_roots tree root as childen and so has one more layer than each of these trees. pub const HISTORICAL_SUMMARY_TREE_DEPTH: usize = 14; -/// Index of `historical_roots` field in the BeaconState [struct](https://github.com/ethereum/annotated-spec/blob/master/phase0/beacon-chain.md#beaconstate). +/// Index of `historical_roots` field in the BeaconState [struct](https://github.com/ethereum/annotated-spec/blob/master/phase0/beacon-chain.md#beaconstate). pub const HISTORICAL_ROOTS_FIELD_INDEX: usize = 7; /// Index of `historical_summaries` field in the (post-Capella) BeaconState [struct](https://github.com/ethereum/annotated-spec/blob/master/capella/beacon-chain.md#beaconstate). @@ -59,7 +62,7 @@ impl HeadState { // So we construct a new HistoricalSummary from the state and check that the tree root is in historical_summaries. // This will only be true if the state is in the last slot of an era. let historical_summary = HistoricalSummary::new(&self.data); - let historical_summaries= self.data.historical_summaries()?.to_vec(); + let historical_summaries = self.data.historical_summaries()?.to_vec(); let latest_historical_summary = historical_summaries.last(); if latest_historical_summary != Some(&historical_summary) { return Err(Error::SlotOutOfBounds); @@ -74,13 +77,11 @@ impl HeadState { // So we append the state_roots tree root to the proof. let state_roots_root = self.data.state_roots().tree_hash_root(); proof.extend(vec![state_roots_root]); - + Ok(proof) } } - - #[cfg(test)] mod tests { use std::cell::LazyCell; @@ -185,13 +186,13 @@ mod tests { /// A HistoricalSummary contains the roots of two Merkle trees, block_summary_root and state_summary root. /// We are interested in the block_summary tree, whose leaves consists of the BeaconBlockHeader roots for one epoch (8192 consecutive slots). /// For this test, we are using the state at slot 8790016, which is the last slot of epoch 1073, to build the proof. - /// We chose this slot because it is the last slot of an epoch, and all of the BeaconBlockHeader roots needed to construct the HistoricalSummary for this epoch are available in state.block_roots. + /// We chose this slot because it is the last slot of an epoch, and all of the BeaconBlockHeader roots needed to construct the HistoricalSummary for this epoch are available in state.block_roots. fn test_inclusion_proofs_for_block_roots() { let transition_state = &TRANSITION_STATE; - + // There are 8192 slots in an era. - let proof_era= transition_state.data().slot().as_usize() / 8192usize; - + let proof_era = transition_state.data().slot().as_usize() / 8192usize; + // In this test we are using the historical_summaries (introduced in Capella) for verification, so we need to subtract the Capella start era to get the correct index. let proof_era_index = proof_era - CAPELLA_START_ERA - 1; @@ -200,11 +201,11 @@ mod tests { let index = 4096usize; let block_root_at_index = match transition_state.data().block_roots().get(index) { Some(block_root) => block_root, - None => panic!("Block root not found") + None => panic!("Block root not found"), }; let proof = match transition_state.compute_block_roots_proof(index) { Ok(proof) => proof, - Err(e) => panic!("Error generating block_roots proof: {:?}", e) + Err(e) => panic!("Error generating block_roots proof: {:?}", e), }; // To verify the proof, we use the state from a later slot. @@ -212,9 +213,14 @@ mod tests { let state = &STATE; // The verifier retrieves the block_summary_root for the historical_summary and verifies the proof against it. - let historical_summary= match state.data().historical_summaries().unwrap().get(proof_era_index){ + let historical_summary = match state + .data() + .historical_summaries() + .unwrap() + .get(proof_era_index) + { Some(historical_summary) => historical_summary, - None => panic!("HistoricalSummary not found") + None => panic!("HistoricalSummary not found"), }; let historical_summary_root = historical_summary.tree_hash_root(); assert!( @@ -223,7 +229,7 @@ mod tests { &proof, HISTORICAL_SUMMARY_TREE_DEPTH, index, - historical_summary_root + historical_summary_root ), "Merkle proof verification failed" );