Skip to content

Commit

Permalink
Use blinded blocks for light client proofs (#6201)
Browse files Browse the repository at this point in the history
* Use blinded blocks for light client proofs
  • Loading branch information
michaelsproul authored Jul 30, 2024
1 parent 96b00ef commit c7ded10
Show file tree
Hide file tree
Showing 8 changed files with 72 additions and 107 deletions.
7 changes: 1 addition & 6 deletions beacon_node/beacon_chain/src/beacon_chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6766,12 +6766,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
&self,
block_root: &Hash256,
) -> Result<Option<(LightClientBootstrap<T::EthSpec>, 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);
};

Expand Down
15 changes: 7 additions & 8 deletions beacon_node/beacon_chain/src/light_client_server_cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,13 +84,12 @@ impl<T: BeaconChainTypes> LightClientServerCache<T> {
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(),
Expand Down Expand Up @@ -130,7 +129,7 @@ impl<T: BeaconChainTypes> LightClientServerCache<T> {
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,
Expand Down
94 changes: 27 additions & 67 deletions consensus/types/src/beacon_block_body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,11 @@ impl<E: EthSpec, Payload: AbstractExecPayload<E>> BeaconBlockBody<E, Payload> {
pub fn execution_payload(&self) -> Result<Payload::Ref<'_>, 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<E>> BeaconBlockBodyRef<'a, E, Payload> {
Expand Down Expand Up @@ -239,6 +244,28 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload<E>> BeaconBlockBodyRef<'a, E,
Ok(proof.into())
}

pub fn block_body_merkle_proof(&self, generalized_index: usize) -> Result<Vec<Hash256>, 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()
Expand Down Expand Up @@ -832,73 +859,6 @@ impl<E: EthSpec> From<BeaconBlockBody<E, FullPayload<E>>>
}
}

impl<E: EthSpec> BeaconBlockBody<E> {
/// 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<Vec<Hash256>, 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<String> = commitments.iter().map(|x| x.to_string()).collect();
Expand Down
6 changes: 3 additions & 3 deletions consensus/types/src/light_client_bootstrap.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand Down Expand Up @@ -114,7 +114,7 @@ impl<E: EthSpec> LightClientBootstrap<E> {

pub fn from_beacon_state(
beacon_state: &mut BeaconState<E>,
block: &SignedBeaconBlock<E>,
block: &SignedBlindedBeaconBlock<E>,
chain_spec: &ChainSpec,
) -> Result<Self, Error> {
let mut header = beacon_state.latest_block_header().clone();
Expand Down
6 changes: 3 additions & 3 deletions consensus/types/src/light_client_finality_update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -73,8 +73,8 @@ pub struct LightClientFinalityUpdate<E: EthSpec> {

impl<E: EthSpec> LightClientFinalityUpdate<E> {
pub fn new(
attested_block: &SignedBeaconBlock<E>,
finalized_block: &SignedBeaconBlock<E>,
attested_block: &SignedBlindedBeaconBlock<E>,
finalized_block: &SignedBlindedBeaconBlock<E>,
finality_branch: FixedVector<Hash256, FinalizedRootProofLen>,
sync_aggregate: SyncAggregate<E>,
signature_slot: Slot,
Expand Down
41 changes: 26 additions & 15 deletions consensus/types/src/light_client_header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -72,7 +72,7 @@ pub struct LightClientHeader<E: EthSpec> {

impl<E: EthSpec> LightClientHeader<E> {
pub fn block_to_light_client_header(
block: &SignedBeaconBlock<E>,
block: &SignedBlindedBeaconBlock<E>,
chain_spec: &ChainSpec,
) -> Result<Self, Error> {
let header = match block
Expand Down Expand Up @@ -139,7 +139,9 @@ impl<E: EthSpec> LightClientHeader<E> {
}

impl<E: EthSpec> LightClientHeaderAltair<E> {
pub fn block_to_light_client_header(block: &SignedBeaconBlock<E>) -> Result<Self, Error> {
pub fn block_to_light_client_header(
block: &SignedBlindedBeaconBlock<E>,
) -> Result<Self, Error> {
Ok(LightClientHeaderAltair {
beacon: block.message().block_header(),
_phantom_data: PhantomData,
Expand All @@ -148,7 +150,9 @@ impl<E: EthSpec> LightClientHeaderAltair<E> {
}

impl<E: EthSpec> LightClientHeaderCapella<E> {
pub fn block_to_light_client_header(block: &SignedBeaconBlock<E>) -> Result<Self, Error> {
pub fn block_to_light_client_header(
block: &SignedBlindedBeaconBlock<E>,
) -> Result<Self, Error> {
let payload = block
.message()
.execution_payload()?
Expand All @@ -163,8 +167,9 @@ impl<E: EthSpec> LightClientHeaderCapella<E> {
.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(),
Expand All @@ -176,13 +181,15 @@ impl<E: EthSpec> LightClientHeaderCapella<E> {
}

impl<E: EthSpec> LightClientHeaderDeneb<E> {
pub fn block_to_light_client_header(block: &SignedBeaconBlock<E>) -> Result<Self, Error> {
let payload = block
pub fn block_to_light_client_header(
block: &SignedBlindedBeaconBlock<E>,
) -> Result<Self, Error> {
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()
Expand All @@ -191,8 +198,9 @@ impl<E: EthSpec> LightClientHeaderDeneb<E> {
.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(),
Expand All @@ -204,7 +212,9 @@ impl<E: EthSpec> LightClientHeaderDeneb<E> {
}

impl<E: EthSpec> LightClientHeaderElectra<E> {
pub fn block_to_light_client_header(block: &SignedBeaconBlock<E>) -> Result<Self, Error> {
pub fn block_to_light_client_header(
block: &SignedBlindedBeaconBlock<E>,
) -> Result<Self, Error> {
let payload = block
.message()
.execution_payload()?
Expand All @@ -219,8 +229,9 @@ impl<E: EthSpec> LightClientHeaderElectra<E> {
.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(),
Expand Down
4 changes: 2 additions & 2 deletions consensus/types/src/light_client_optimistic_update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -63,7 +63,7 @@ pub struct LightClientOptimisticUpdate<E: EthSpec> {

impl<E: EthSpec> LightClientOptimisticUpdate<E> {
pub fn new(
attested_block: &SignedBeaconBlock<E>,
attested_block: &SignedBlindedBeaconBlock<E>,
sync_aggregate: SyncAggregate<E>,
signature_slot: Slot,
chain_spec: &ChainSpec,
Expand Down
6 changes: 3 additions & 3 deletions consensus/types/src/light_client_update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -156,8 +156,8 @@ impl<E: EthSpec> LightClientUpdate<E> {
beacon_state: BeaconState<E>,
block: BeaconBlock<E>,
attested_state: &mut BeaconState<E>,
attested_block: &SignedBeaconBlock<E>,
finalized_block: &SignedBeaconBlock<E>,
attested_block: &SignedBlindedBeaconBlock<E>,
finalized_block: &SignedBlindedBeaconBlock<E>,
chain_spec: &ChainSpec,
) -> Result<Self, Error> {
let sync_aggregate = block.body().sync_aggregate()?;
Expand Down

0 comments on commit c7ded10

Please sign in to comment.