From c7ded108705704a474e1f8e681374cea209cccb1 Mon Sep 17 00:00:00 2001 From: Michael Sproul Date: Tue, 30 Jul 2024 23:25:55 +1000 Subject: [PATCH] Use blinded blocks for light client proofs (#6201) * Use blinded blocks for light client proofs --- beacon_node/beacon_chain/src/beacon_chain.rs | 7 +- .../src/light_client_server_cache.rs | 15 ++- consensus/types/src/beacon_block_body.rs | 94 ++++++------------- consensus/types/src/light_client_bootstrap.rs | 6 +- .../types/src/light_client_finality_update.rs | 6 +- consensus/types/src/light_client_header.rs | 41 +++++--- .../src/light_client_optimistic_update.rs | 4 +- consensus/types/src/light_client_update.rs | 6 +- 8 files changed, 72 insertions(+), 107 deletions(-) diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index c6ed979d681..4bc98a98da0 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -6766,12 +6766,7 @@ impl BeaconChain { &self, block_root: &Hash256, ) -> Result, ForkName)>, Error> { - let handle = self - .task_executor - .handle() - .ok_or(BeaconChainError::RuntimeShutdown)?; - - let Some(block) = handle.block_on(async { self.get_block(block_root).await })? else { + let Some(block) = self.get_blinded_block(block_root)? else { return Ok(None); }; diff --git a/beacon_node/beacon_chain/src/light_client_server_cache.rs b/beacon_node/beacon_chain/src/light_client_server_cache.rs index ca029057373..87513885f77 100644 --- a/beacon_node/beacon_chain/src/light_client_server_cache.rs +++ b/beacon_node/beacon_chain/src/light_client_server_cache.rs @@ -84,13 +84,12 @@ impl LightClientServerCache { let signature_slot = block_slot; let attested_block_root = block_parent_root; - let attested_block = - store - .get_full_block(attested_block_root)? - .ok_or(BeaconChainError::DBInconsistent(format!( - "Block not available {:?}", - attested_block_root - )))?; + let attested_block = store.get_blinded_block(attested_block_root)?.ok_or( + BeaconChainError::DBInconsistent(format!( + "Block not available {:?}", + attested_block_root + )), + )?; let cached_parts = self.get_or_compute_prev_block_cache( store.clone(), @@ -130,7 +129,7 @@ impl LightClientServerCache { if is_latest_finality & !cached_parts.finalized_block_root.is_zero() { // Immediately after checkpoint sync the finalized block may not be available yet. if let Some(finalized_block) = - store.get_full_block(&cached_parts.finalized_block_root)? + store.get_blinded_block(&cached_parts.finalized_block_root)? { *self.latest_finality_update.write() = Some(LightClientFinalityUpdate::new( &attested_block, diff --git a/consensus/types/src/beacon_block_body.rs b/consensus/types/src/beacon_block_body.rs index 363ba08f7d5..373e165e0bb 100644 --- a/consensus/types/src/beacon_block_body.rs +++ b/consensus/types/src/beacon_block_body.rs @@ -129,6 +129,11 @@ impl> BeaconBlockBody { pub fn execution_payload(&self) -> Result, Error> { self.to_ref().execution_payload() } + + /// Returns the name of the fork pertaining to `self`. + pub fn fork_name(&self) -> ForkName { + self.to_ref().fork_name() + } } impl<'a, E: EthSpec, Payload: AbstractExecPayload> BeaconBlockBodyRef<'a, E, Payload> { @@ -239,6 +244,28 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload> BeaconBlockBodyRef<'a, E, Ok(proof.into()) } + pub fn block_body_merkle_proof(&self, generalized_index: usize) -> Result, Error> { + let field_index = match generalized_index { + light_client_update::EXECUTION_PAYLOAD_INDEX => { + // Execution payload is a top-level field, subtract off the generalized indices + // for the internal nodes. Result should be 9, the field offset of the execution + // payload in the `BeaconBlockBody`: + // https://github.com/ethereum/consensus-specs/blob/dev/specs/deneb/beacon-chain.md#beaconblockbody + generalized_index + .checked_sub(NUM_BEACON_BLOCK_BODY_HASH_TREE_ROOT_LEAVES) + .ok_or(Error::IndexNotSupported(generalized_index))? + } + _ => return Err(Error::IndexNotSupported(generalized_index)), + }; + + let leaves = self.body_merkle_leaves(); + let depth = light_client_update::EXECUTION_PAYLOAD_PROOF_LEN; + let tree = merkle_proof::MerkleTree::create(&leaves, depth); + let (_, proof) = tree.generate_proof(field_index, depth)?; + + Ok(proof) + } + /// Return `true` if this block body has a non-zero number of blobs. pub fn has_blobs(self) -> bool { self.blob_kzg_commitments() @@ -832,73 +859,6 @@ impl From>> } } -impl BeaconBlockBody { - /// Returns the name of the fork pertaining to `self`. - pub fn fork_name(&self) -> ForkName { - self.to_ref().fork_name() - } - - pub fn block_body_merkle_proof(&self, generalized_index: usize) -> Result, Error> { - let field_index = match generalized_index { - light_client_update::EXECUTION_PAYLOAD_INDEX => { - // Execution payload is a top-level field, subtract off the generalized indices - // for the internal nodes. Result should be 9, the field offset of the execution - // payload in the `BeaconBlockBody`: - // https://github.com/ethereum/consensus-specs/blob/dev/specs/deneb/beacon-chain.md#beaconblockbody - generalized_index - .checked_sub(NUM_BEACON_BLOCK_BODY_HASH_TREE_ROOT_LEAVES) - .ok_or(Error::IndexNotSupported(generalized_index))? - } - _ => return Err(Error::IndexNotSupported(generalized_index)), - }; - - let attestations_root = if self.fork_name() > ForkName::Electra { - self.attestations_electra()?.tree_hash_root() - } else { - self.attestations_base()?.tree_hash_root() - }; - - let attester_slashings_root = if self.fork_name() > ForkName::Electra { - self.attester_slashings_electra()?.tree_hash_root() - } else { - self.attester_slashings_base()?.tree_hash_root() - }; - - let mut leaves = vec![ - self.randao_reveal().tree_hash_root(), - self.eth1_data().tree_hash_root(), - self.graffiti().tree_hash_root(), - self.proposer_slashings().tree_hash_root(), - attester_slashings_root, - attestations_root, - self.deposits().tree_hash_root(), - self.voluntary_exits().tree_hash_root(), - ]; - - if let Ok(sync_aggregate) = self.sync_aggregate() { - leaves.push(sync_aggregate.tree_hash_root()) - } - - if let Ok(execution_payload) = self.execution_payload() { - leaves.push(execution_payload.tree_hash_root()) - } - - if let Ok(bls_to_execution_changes) = self.bls_to_execution_changes() { - leaves.push(bls_to_execution_changes.tree_hash_root()) - } - - if let Ok(blob_kzg_commitments) = self.blob_kzg_commitments() { - leaves.push(blob_kzg_commitments.tree_hash_root()) - } - - let depth = light_client_update::EXECUTION_PAYLOAD_PROOF_LEN; - let tree = merkle_proof::MerkleTree::create(&leaves, depth); - let (_, proof) = tree.generate_proof(field_index, depth)?; - - Ok(proof) - } -} - /// Util method helpful for logging. pub fn format_kzg_commitments(commitments: &[KzgCommitment]) -> String { let commitment_strings: Vec = commitments.iter().map(|x| x.to_string()).collect(); diff --git a/consensus/types/src/light_client_bootstrap.rs b/consensus/types/src/light_client_bootstrap.rs index e3a85744ded..f06a94adce9 100644 --- a/consensus/types/src/light_client_bootstrap.rs +++ b/consensus/types/src/light_client_bootstrap.rs @@ -1,8 +1,8 @@ use crate::{ light_client_update::*, test_utils::TestRandom, BeaconState, ChainSpec, EthSpec, FixedVector, ForkName, ForkVersionDeserialize, Hash256, LightClientHeader, LightClientHeaderAltair, - LightClientHeaderCapella, LightClientHeaderDeneb, LightClientHeaderElectra, SignedBeaconBlock, - Slot, SyncCommittee, + LightClientHeaderCapella, LightClientHeaderDeneb, LightClientHeaderElectra, + SignedBlindedBeaconBlock, Slot, SyncCommittee, }; use derivative::Derivative; use serde::{Deserialize, Deserializer, Serialize}; @@ -114,7 +114,7 @@ impl LightClientBootstrap { pub fn from_beacon_state( beacon_state: &mut BeaconState, - block: &SignedBeaconBlock, + block: &SignedBlindedBeaconBlock, chain_spec: &ChainSpec, ) -> Result { let mut header = beacon_state.latest_block_header().clone(); diff --git a/consensus/types/src/light_client_finality_update.rs b/consensus/types/src/light_client_finality_update.rs index a9e24e03db1..e65b0572923 100644 --- a/consensus/types/src/light_client_finality_update.rs +++ b/consensus/types/src/light_client_finality_update.rs @@ -3,7 +3,7 @@ use crate::ChainSpec; use crate::{ light_client_update::*, test_utils::TestRandom, ForkName, ForkVersionDeserialize, LightClientHeaderAltair, LightClientHeaderCapella, LightClientHeaderDeneb, - LightClientHeaderElectra, SignedBeaconBlock, + LightClientHeaderElectra, SignedBlindedBeaconBlock, }; use derivative::Derivative; use serde::{Deserialize, Deserializer, Serialize}; @@ -73,8 +73,8 @@ pub struct LightClientFinalityUpdate { impl LightClientFinalityUpdate { pub fn new( - attested_block: &SignedBeaconBlock, - finalized_block: &SignedBeaconBlock, + attested_block: &SignedBlindedBeaconBlock, + finalized_block: &SignedBlindedBeaconBlock, finality_branch: FixedVector, sync_aggregate: SyncAggregate, signature_slot: Slot, diff --git a/consensus/types/src/light_client_header.rs b/consensus/types/src/light_client_header.rs index 1d6432ed6f3..1feb748fae1 100644 --- a/consensus/types/src/light_client_header.rs +++ b/consensus/types/src/light_client_header.rs @@ -4,7 +4,7 @@ use crate::ForkVersionDeserialize; use crate::{light_client_update::*, BeaconBlockBody}; use crate::{ test_utils::TestRandom, EthSpec, ExecutionPayloadHeaderCapella, ExecutionPayloadHeaderDeneb, - ExecutionPayloadHeaderElectra, FixedVector, Hash256, SignedBeaconBlock, + ExecutionPayloadHeaderElectra, FixedVector, Hash256, SignedBlindedBeaconBlock, }; use crate::{BeaconBlockHeader, ExecutionPayloadHeader}; use derivative::Derivative; @@ -72,7 +72,7 @@ pub struct LightClientHeader { impl LightClientHeader { pub fn block_to_light_client_header( - block: &SignedBeaconBlock, + block: &SignedBlindedBeaconBlock, chain_spec: &ChainSpec, ) -> Result { let header = match block @@ -139,7 +139,9 @@ impl LightClientHeader { } impl LightClientHeaderAltair { - pub fn block_to_light_client_header(block: &SignedBeaconBlock) -> Result { + pub fn block_to_light_client_header( + block: &SignedBlindedBeaconBlock, + ) -> Result { Ok(LightClientHeaderAltair { beacon: block.message().block_header(), _phantom_data: PhantomData, @@ -148,7 +150,9 @@ impl LightClientHeaderAltair { } impl LightClientHeaderCapella { - pub fn block_to_light_client_header(block: &SignedBeaconBlock) -> Result { + pub fn block_to_light_client_header( + block: &SignedBlindedBeaconBlock, + ) -> Result { let payload = block .message() .execution_payload()? @@ -163,8 +167,9 @@ impl LightClientHeaderCapella { .to_owned(), ); - let execution_branch = - beacon_block_body.block_body_merkle_proof(EXECUTION_PAYLOAD_INDEX)?; + let execution_branch = beacon_block_body + .to_ref() + .block_body_merkle_proof(EXECUTION_PAYLOAD_INDEX)?; return Ok(LightClientHeaderCapella { beacon: block.message().block_header(), @@ -176,13 +181,15 @@ impl LightClientHeaderCapella { } impl LightClientHeaderDeneb { - pub fn block_to_light_client_header(block: &SignedBeaconBlock) -> Result { - let payload = block + pub fn block_to_light_client_header( + block: &SignedBlindedBeaconBlock, + ) -> Result { + let header = block .message() .execution_payload()? - .execution_payload_deneb()?; + .execution_payload_deneb()? + .clone(); - let header = ExecutionPayloadHeaderDeneb::from(payload); let beacon_block_body = BeaconBlockBody::from( block .message() @@ -191,8 +198,9 @@ impl LightClientHeaderDeneb { .to_owned(), ); - let execution_branch = - beacon_block_body.block_body_merkle_proof(EXECUTION_PAYLOAD_INDEX)?; + let execution_branch = beacon_block_body + .to_ref() + .block_body_merkle_proof(EXECUTION_PAYLOAD_INDEX)?; Ok(LightClientHeaderDeneb { beacon: block.message().block_header(), @@ -204,7 +212,9 @@ impl LightClientHeaderDeneb { } impl LightClientHeaderElectra { - pub fn block_to_light_client_header(block: &SignedBeaconBlock) -> Result { + pub fn block_to_light_client_header( + block: &SignedBlindedBeaconBlock, + ) -> Result { let payload = block .message() .execution_payload()? @@ -219,8 +229,9 @@ impl LightClientHeaderElectra { .to_owned(), ); - let execution_branch = - beacon_block_body.block_body_merkle_proof(EXECUTION_PAYLOAD_INDEX)?; + let execution_branch = beacon_block_body + .to_ref() + .block_body_merkle_proof(EXECUTION_PAYLOAD_INDEX)?; Ok(LightClientHeaderElectra { beacon: block.message().block_header(), diff --git a/consensus/types/src/light_client_optimistic_update.rs b/consensus/types/src/light_client_optimistic_update.rs index 708f24e7701..f5b749be706 100644 --- a/consensus/types/src/light_client_optimistic_update.rs +++ b/consensus/types/src/light_client_optimistic_update.rs @@ -2,7 +2,7 @@ use super::{EthSpec, ForkName, ForkVersionDeserialize, LightClientHeader, Slot, use crate::test_utils::TestRandom; use crate::{ light_client_update::*, ChainSpec, LightClientHeaderAltair, LightClientHeaderCapella, - LightClientHeaderDeneb, LightClientHeaderElectra, SignedBeaconBlock, + LightClientHeaderDeneb, LightClientHeaderElectra, SignedBlindedBeaconBlock, }; use derivative::Derivative; use serde::{Deserialize, Deserializer, Serialize}; @@ -63,7 +63,7 @@ pub struct LightClientOptimisticUpdate { impl LightClientOptimisticUpdate { pub fn new( - attested_block: &SignedBeaconBlock, + attested_block: &SignedBlindedBeaconBlock, sync_aggregate: SyncAggregate, signature_slot: Slot, chain_spec: &ChainSpec, diff --git a/consensus/types/src/light_client_update.rs b/consensus/types/src/light_client_update.rs index 210fa0eeeb3..8a3eaff487f 100644 --- a/consensus/types/src/light_client_update.rs +++ b/consensus/types/src/light_client_update.rs @@ -3,7 +3,7 @@ use crate::light_client_header::LightClientHeaderElectra; use crate::{ beacon_state, test_utils::TestRandom, BeaconBlock, BeaconBlockHeader, BeaconState, ChainSpec, ForkName, ForkVersionDeserialize, LightClientHeaderAltair, LightClientHeaderCapella, - LightClientHeaderDeneb, SignedBeaconBlock, + LightClientHeaderDeneb, SignedBlindedBeaconBlock, }; use derivative::Derivative; use safe_arith::ArithError; @@ -156,8 +156,8 @@ impl LightClientUpdate { beacon_state: BeaconState, block: BeaconBlock, attested_state: &mut BeaconState, - attested_block: &SignedBeaconBlock, - finalized_block: &SignedBeaconBlock, + attested_block: &SignedBlindedBeaconBlock, + finalized_block: &SignedBlindedBeaconBlock, chain_spec: &ChainSpec, ) -> Result { let sync_aggregate = block.body().sync_aggregate()?;