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,
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);
};

View File

@@ -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(),
@@ -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,

View File

@@ -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> {
@@ -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()
@@ -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();

View File

@@ -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<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();

View File

@@ -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<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,

View File

@@ -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<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
@@ -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,
@@ -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()?
@@ -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(),
@@ -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()
@@ -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(),
@@ -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()?
@@ -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(),

View File

@@ -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<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,

View File

@@ -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<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()?;