Use blinded blocks for light client proofs (#6201)

* Use blinded blocks for light client proofs
This commit is contained in:
Michael Sproul
2024-07-30 23:25:55 +10:00
committed by GitHub
parent 96b00ef66c
commit c7ded10870
8 changed files with 72 additions and 107 deletions

View File

@@ -6766,12 +6766,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
&self, &self,
block_root: &Hash256, block_root: &Hash256,
) -> Result<Option<(LightClientBootstrap<T::EthSpec>, ForkName)>, Error> { ) -> Result<Option<(LightClientBootstrap<T::EthSpec>, ForkName)>, Error> {
let handle = self let Some(block) = self.get_blinded_block(block_root)? else {
.task_executor
.handle()
.ok_or(BeaconChainError::RuntimeShutdown)?;
let Some(block) = handle.block_on(async { self.get_block(block_root).await })? else {
return Ok(None); return Ok(None);
}; };

View File

@@ -84,13 +84,12 @@ impl<T: BeaconChainTypes> LightClientServerCache<T> {
let signature_slot = block_slot; let signature_slot = block_slot;
let attested_block_root = block_parent_root; let attested_block_root = block_parent_root;
let attested_block = let attested_block = store.get_blinded_block(attested_block_root)?.ok_or(
store BeaconChainError::DBInconsistent(format!(
.get_full_block(attested_block_root)?
.ok_or(BeaconChainError::DBInconsistent(format!(
"Block not available {:?}", "Block not available {:?}",
attested_block_root attested_block_root
)))?; )),
)?;
let cached_parts = self.get_or_compute_prev_block_cache( let cached_parts = self.get_or_compute_prev_block_cache(
store.clone(), store.clone(),
@@ -130,7 +129,7 @@ impl<T: BeaconChainTypes> LightClientServerCache<T> {
if is_latest_finality & !cached_parts.finalized_block_root.is_zero() { if is_latest_finality & !cached_parts.finalized_block_root.is_zero() {
// Immediately after checkpoint sync the finalized block may not be available yet. // Immediately after checkpoint sync the finalized block may not be available yet.
if let Some(finalized_block) = 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( *self.latest_finality_update.write() = Some(LightClientFinalityUpdate::new(
&attested_block, &attested_block,

View File

@@ -129,6 +129,11 @@ impl<E: EthSpec, Payload: AbstractExecPayload<E>> BeaconBlockBody<E, Payload> {
pub fn execution_payload(&self) -> Result<Payload::Ref<'_>, Error> { pub fn execution_payload(&self) -> Result<Payload::Ref<'_>, Error> {
self.to_ref().execution_payload() 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> { impl<'a, E: EthSpec, Payload: AbstractExecPayload<E>> BeaconBlockBodyRef<'a, E, Payload> {
@@ -239,6 +244,28 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload<E>> BeaconBlockBodyRef<'a, E,
Ok(proof.into()) 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. /// Return `true` if this block body has a non-zero number of blobs.
pub fn has_blobs(self) -> bool { pub fn has_blobs(self) -> bool {
self.blob_kzg_commitments() self.blob_kzg_commitments()
@@ -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. /// Util method helpful for logging.
pub fn format_kzg_commitments(commitments: &[KzgCommitment]) -> String { pub fn format_kzg_commitments(commitments: &[KzgCommitment]) -> String {
let commitment_strings: Vec<String> = commitments.iter().map(|x| x.to_string()).collect(); let commitment_strings: Vec<String> = commitments.iter().map(|x| x.to_string()).collect();

View File

@@ -1,8 +1,8 @@
use crate::{ use crate::{
light_client_update::*, test_utils::TestRandom, BeaconState, ChainSpec, EthSpec, FixedVector, light_client_update::*, test_utils::TestRandom, BeaconState, ChainSpec, EthSpec, FixedVector,
ForkName, ForkVersionDeserialize, Hash256, LightClientHeader, LightClientHeaderAltair, ForkName, ForkVersionDeserialize, Hash256, LightClientHeader, LightClientHeaderAltair,
LightClientHeaderCapella, LightClientHeaderDeneb, LightClientHeaderElectra, SignedBeaconBlock, LightClientHeaderCapella, LightClientHeaderDeneb, LightClientHeaderElectra,
Slot, SyncCommittee, SignedBlindedBeaconBlock, Slot, SyncCommittee,
}; };
use derivative::Derivative; use derivative::Derivative;
use serde::{Deserialize, Deserializer, Serialize}; use serde::{Deserialize, Deserializer, Serialize};
@@ -114,7 +114,7 @@ impl<E: EthSpec> LightClientBootstrap<E> {
pub fn from_beacon_state( pub fn from_beacon_state(
beacon_state: &mut BeaconState<E>, beacon_state: &mut BeaconState<E>,
block: &SignedBeaconBlock<E>, block: &SignedBlindedBeaconBlock<E>,
chain_spec: &ChainSpec, chain_spec: &ChainSpec,
) -> Result<Self, Error> { ) -> Result<Self, Error> {
let mut header = beacon_state.latest_block_header().clone(); let mut header = beacon_state.latest_block_header().clone();

View File

@@ -3,7 +3,7 @@ use crate::ChainSpec;
use crate::{ use crate::{
light_client_update::*, test_utils::TestRandom, ForkName, ForkVersionDeserialize, light_client_update::*, test_utils::TestRandom, ForkName, ForkVersionDeserialize,
LightClientHeaderAltair, LightClientHeaderCapella, LightClientHeaderDeneb, LightClientHeaderAltair, LightClientHeaderCapella, LightClientHeaderDeneb,
LightClientHeaderElectra, SignedBeaconBlock, LightClientHeaderElectra, SignedBlindedBeaconBlock,
}; };
use derivative::Derivative; use derivative::Derivative;
use serde::{Deserialize, Deserializer, Serialize}; use serde::{Deserialize, Deserializer, Serialize};
@@ -73,8 +73,8 @@ pub struct LightClientFinalityUpdate<E: EthSpec> {
impl<E: EthSpec> LightClientFinalityUpdate<E> { impl<E: EthSpec> LightClientFinalityUpdate<E> {
pub fn new( pub fn new(
attested_block: &SignedBeaconBlock<E>, attested_block: &SignedBlindedBeaconBlock<E>,
finalized_block: &SignedBeaconBlock<E>, finalized_block: &SignedBlindedBeaconBlock<E>,
finality_branch: FixedVector<Hash256, FinalizedRootProofLen>, finality_branch: FixedVector<Hash256, FinalizedRootProofLen>,
sync_aggregate: SyncAggregate<E>, sync_aggregate: SyncAggregate<E>,
signature_slot: Slot, signature_slot: Slot,

View File

@@ -4,7 +4,7 @@ use crate::ForkVersionDeserialize;
use crate::{light_client_update::*, BeaconBlockBody}; use crate::{light_client_update::*, BeaconBlockBody};
use crate::{ use crate::{
test_utils::TestRandom, EthSpec, ExecutionPayloadHeaderCapella, ExecutionPayloadHeaderDeneb, test_utils::TestRandom, EthSpec, ExecutionPayloadHeaderCapella, ExecutionPayloadHeaderDeneb,
ExecutionPayloadHeaderElectra, FixedVector, Hash256, SignedBeaconBlock, ExecutionPayloadHeaderElectra, FixedVector, Hash256, SignedBlindedBeaconBlock,
}; };
use crate::{BeaconBlockHeader, ExecutionPayloadHeader}; use crate::{BeaconBlockHeader, ExecutionPayloadHeader};
use derivative::Derivative; use derivative::Derivative;
@@ -72,7 +72,7 @@ pub struct LightClientHeader<E: EthSpec> {
impl<E: EthSpec> LightClientHeader<E> { impl<E: EthSpec> LightClientHeader<E> {
pub fn block_to_light_client_header( pub fn block_to_light_client_header(
block: &SignedBeaconBlock<E>, block: &SignedBlindedBeaconBlock<E>,
chain_spec: &ChainSpec, chain_spec: &ChainSpec,
) -> Result<Self, Error> { ) -> Result<Self, Error> {
let header = match block let header = match block
@@ -139,7 +139,9 @@ impl<E: EthSpec> LightClientHeader<E> {
} }
impl<E: EthSpec> LightClientHeaderAltair<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 { Ok(LightClientHeaderAltair {
beacon: block.message().block_header(), beacon: block.message().block_header(),
_phantom_data: PhantomData, _phantom_data: PhantomData,
@@ -148,7 +150,9 @@ impl<E: EthSpec> LightClientHeaderAltair<E> {
} }
impl<E: EthSpec> LightClientHeaderCapella<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 let payload = block
.message() .message()
.execution_payload()? .execution_payload()?
@@ -163,8 +167,9 @@ impl<E: EthSpec> LightClientHeaderCapella<E> {
.to_owned(), .to_owned(),
); );
let execution_branch = let execution_branch = beacon_block_body
beacon_block_body.block_body_merkle_proof(EXECUTION_PAYLOAD_INDEX)?; .to_ref()
.block_body_merkle_proof(EXECUTION_PAYLOAD_INDEX)?;
return Ok(LightClientHeaderCapella { return Ok(LightClientHeaderCapella {
beacon: block.message().block_header(), beacon: block.message().block_header(),
@@ -176,13 +181,15 @@ impl<E: EthSpec> LightClientHeaderCapella<E> {
} }
impl<E: EthSpec> LightClientHeaderDeneb<E> { impl<E: EthSpec> LightClientHeaderDeneb<E> {
pub fn block_to_light_client_header(block: &SignedBeaconBlock<E>) -> Result<Self, Error> { pub fn block_to_light_client_header(
let payload = block block: &SignedBlindedBeaconBlock<E>,
) -> Result<Self, Error> {
let header = block
.message() .message()
.execution_payload()? .execution_payload()?
.execution_payload_deneb()?; .execution_payload_deneb()?
.clone();
let header = ExecutionPayloadHeaderDeneb::from(payload);
let beacon_block_body = BeaconBlockBody::from( let beacon_block_body = BeaconBlockBody::from(
block block
.message() .message()
@@ -191,8 +198,9 @@ impl<E: EthSpec> LightClientHeaderDeneb<E> {
.to_owned(), .to_owned(),
); );
let execution_branch = let execution_branch = beacon_block_body
beacon_block_body.block_body_merkle_proof(EXECUTION_PAYLOAD_INDEX)?; .to_ref()
.block_body_merkle_proof(EXECUTION_PAYLOAD_INDEX)?;
Ok(LightClientHeaderDeneb { Ok(LightClientHeaderDeneb {
beacon: block.message().block_header(), beacon: block.message().block_header(),
@@ -204,7 +212,9 @@ impl<E: EthSpec> LightClientHeaderDeneb<E> {
} }
impl<E: EthSpec> LightClientHeaderElectra<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 let payload = block
.message() .message()
.execution_payload()? .execution_payload()?
@@ -219,8 +229,9 @@ impl<E: EthSpec> LightClientHeaderElectra<E> {
.to_owned(), .to_owned(),
); );
let execution_branch = let execution_branch = beacon_block_body
beacon_block_body.block_body_merkle_proof(EXECUTION_PAYLOAD_INDEX)?; .to_ref()
.block_body_merkle_proof(EXECUTION_PAYLOAD_INDEX)?;
Ok(LightClientHeaderElectra { Ok(LightClientHeaderElectra {
beacon: block.message().block_header(), beacon: block.message().block_header(),

View File

@@ -2,7 +2,7 @@ use super::{EthSpec, ForkName, ForkVersionDeserialize, LightClientHeader, Slot,
use crate::test_utils::TestRandom; use crate::test_utils::TestRandom;
use crate::{ use crate::{
light_client_update::*, ChainSpec, LightClientHeaderAltair, LightClientHeaderCapella, light_client_update::*, ChainSpec, LightClientHeaderAltair, LightClientHeaderCapella,
LightClientHeaderDeneb, LightClientHeaderElectra, SignedBeaconBlock, LightClientHeaderDeneb, LightClientHeaderElectra, SignedBlindedBeaconBlock,
}; };
use derivative::Derivative; use derivative::Derivative;
use serde::{Deserialize, Deserializer, Serialize}; use serde::{Deserialize, Deserializer, Serialize};
@@ -63,7 +63,7 @@ pub struct LightClientOptimisticUpdate<E: EthSpec> {
impl<E: EthSpec> LightClientOptimisticUpdate<E> { impl<E: EthSpec> LightClientOptimisticUpdate<E> {
pub fn new( pub fn new(
attested_block: &SignedBeaconBlock<E>, attested_block: &SignedBlindedBeaconBlock<E>,
sync_aggregate: SyncAggregate<E>, sync_aggregate: SyncAggregate<E>,
signature_slot: Slot, signature_slot: Slot,
chain_spec: &ChainSpec, chain_spec: &ChainSpec,

View File

@@ -3,7 +3,7 @@ use crate::light_client_header::LightClientHeaderElectra;
use crate::{ use crate::{
beacon_state, test_utils::TestRandom, BeaconBlock, BeaconBlockHeader, BeaconState, ChainSpec, beacon_state, test_utils::TestRandom, BeaconBlock, BeaconBlockHeader, BeaconState, ChainSpec,
ForkName, ForkVersionDeserialize, LightClientHeaderAltair, LightClientHeaderCapella, ForkName, ForkVersionDeserialize, LightClientHeaderAltair, LightClientHeaderCapella,
LightClientHeaderDeneb, SignedBeaconBlock, LightClientHeaderDeneb, SignedBlindedBeaconBlock,
}; };
use derivative::Derivative; use derivative::Derivative;
use safe_arith::ArithError; use safe_arith::ArithError;
@@ -156,8 +156,8 @@ impl<E: EthSpec> LightClientUpdate<E> {
beacon_state: BeaconState<E>, beacon_state: BeaconState<E>,
block: BeaconBlock<E>, block: BeaconBlock<E>,
attested_state: &mut BeaconState<E>, attested_state: &mut BeaconState<E>,
attested_block: &SignedBeaconBlock<E>, attested_block: &SignedBlindedBeaconBlock<E>,
finalized_block: &SignedBeaconBlock<E>, finalized_block: &SignedBlindedBeaconBlock<E>,
chain_spec: &ChainSpec, chain_spec: &ChainSpec,
) -> Result<Self, Error> { ) -> Result<Self, Error> {
let sync_aggregate = block.body().sync_aggregate()?; let sync_aggregate = block.body().sync_aggregate()?;