mirror of
https://github.com/sigp/lighthouse.git
synced 2026-07-01 11:54:40 +00:00
Implement gloas block gossip verification changes (#8878)
Co-Authored-By: Eitan Seri-Levi <eserilev@ucsc.edu> Co-Authored-By: Eitan Seri- Levi <eserilev@gmail.com> Co-Authored-By: Michael Sproul <michaelsproul@users.noreply.github.com>
This commit is contained in:
@@ -3378,11 +3378,19 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.data_availability_checker.put_pre_execution_block(
|
// Gloas blocks dont need to be inserted into the DA cache
|
||||||
block_root,
|
// they are always available.
|
||||||
unverified_block.block_cloned(),
|
if !unverified_block
|
||||||
block_source,
|
.block()
|
||||||
)?;
|
.fork_name_unchecked()
|
||||||
|
.gloas_enabled()
|
||||||
|
{
|
||||||
|
self.data_availability_checker.put_pre_execution_block(
|
||||||
|
block_root,
|
||||||
|
unverified_block.block_cloned(),
|
||||||
|
block_source,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
// Start the Prometheus timer.
|
// Start the Prometheus timer.
|
||||||
let _full_timer = metrics::start_timer(&metrics::BLOCK_PROCESSING_TIMES);
|
let _full_timer = metrics::start_timer(&metrics::BLOCK_PROCESSING_TIMES);
|
||||||
|
|||||||
@@ -51,7 +51,9 @@
|
|||||||
use crate::beacon_snapshot::PreProcessingSnapshot;
|
use crate::beacon_snapshot::PreProcessingSnapshot;
|
||||||
use crate::blob_verification::GossipBlobError;
|
use crate::blob_verification::GossipBlobError;
|
||||||
use crate::block_verification_types::{AsBlock, BlockImportData, RpcBlock};
|
use crate::block_verification_types::{AsBlock, BlockImportData, RpcBlock};
|
||||||
use crate::data_availability_checker::{AvailabilityCheckError, MaybeAvailableBlock};
|
use crate::data_availability_checker::{
|
||||||
|
AvailabilityCheckError, AvailableBlock, AvailableBlockData, MaybeAvailableBlock,
|
||||||
|
};
|
||||||
use crate::data_column_verification::GossipDataColumnError;
|
use crate::data_column_verification::GossipDataColumnError;
|
||||||
use crate::execution_payload::{
|
use crate::execution_payload::{
|
||||||
AllowOptimisticImport, NotifyExecutionLayer, PayloadNotifier,
|
AllowOptimisticImport, NotifyExecutionLayer, PayloadNotifier,
|
||||||
@@ -334,6 +336,15 @@ pub enum BlockError {
|
|||||||
max_blobs_at_epoch: usize,
|
max_blobs_at_epoch: usize,
|
||||||
block: usize,
|
block: usize,
|
||||||
},
|
},
|
||||||
|
/// The bid's parent_block_root does not match the block's parent_root.
|
||||||
|
///
|
||||||
|
/// ## Peer scoring
|
||||||
|
///
|
||||||
|
/// The block is invalid and the peer should be penalized.
|
||||||
|
BidParentRootMismatch {
|
||||||
|
bid_parent_root: Hash256,
|
||||||
|
block_parent_root: Hash256,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Which specific signature(s) are invalid in a SignedBeaconBlock
|
/// Which specific signature(s) are invalid in a SignedBeaconBlock
|
||||||
@@ -887,15 +898,15 @@ impl<T: BeaconChainTypes> GossipVerifiedBlock<T> {
|
|||||||
|
|
||||||
// Do not gossip blocks that claim to contain more blobs than the max allowed
|
// Do not gossip blocks that claim to contain more blobs than the max allowed
|
||||||
// at the given block epoch.
|
// at the given block epoch.
|
||||||
if let Ok(commitments) = block.message().body().blob_kzg_commitments() {
|
if let Some(blob_kzg_commitments_len) = block.message().blob_kzg_commitments_len() {
|
||||||
let max_blobs_at_epoch = chain
|
let max_blobs_at_epoch = chain
|
||||||
.spec
|
.spec
|
||||||
.max_blobs_per_block(block.slot().epoch(T::EthSpec::slots_per_epoch()))
|
.max_blobs_per_block(block.slot().epoch(T::EthSpec::slots_per_epoch()))
|
||||||
as usize;
|
as usize;
|
||||||
if commitments.len() > max_blobs_at_epoch {
|
if blob_kzg_commitments_len > max_blobs_at_epoch {
|
||||||
return Err(BlockError::InvalidBlobCount {
|
return Err(BlockError::InvalidBlobCount {
|
||||||
max_blobs_at_epoch,
|
max_blobs_at_epoch,
|
||||||
block: commitments.len(),
|
block: blob_kzg_commitments_len,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -932,6 +943,24 @@ impl<T: BeaconChainTypes> GossipVerifiedBlock<T> {
|
|||||||
let block_epoch = block.slot().epoch(T::EthSpec::slots_per_epoch());
|
let block_epoch = block.slot().epoch(T::EthSpec::slots_per_epoch());
|
||||||
let (parent_block, block) =
|
let (parent_block, block) =
|
||||||
verify_parent_block_is_known::<T>(&fork_choice_read_lock, block)?;
|
verify_parent_block_is_known::<T>(&fork_choice_read_lock, block)?;
|
||||||
|
|
||||||
|
// [New in Gloas]: Verify bid.parent_block_root matches block.parent_root.
|
||||||
|
if let Ok(bid) = block.message().body().signed_execution_payload_bid()
|
||||||
|
&& bid.message.parent_block_root != block.message().parent_root()
|
||||||
|
{
|
||||||
|
return Err(BlockError::BidParentRootMismatch {
|
||||||
|
bid_parent_root: bid.message.parent_block_root,
|
||||||
|
block_parent_root: block.message().parent_root(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(gloas) The following validation can only be completed once fork choice has been implemented:
|
||||||
|
// The block's parent execution payload (defined by bid.parent_block_hash) has been seen
|
||||||
|
// (via gossip or non-gossip sources) (a client MAY queue blocks for processing
|
||||||
|
// once the parent payload is retrieved). If execution_payload verification of block's execution
|
||||||
|
// payload parent by an execution node is complete, verify the block's execution payload
|
||||||
|
// parent (defined by bid.parent_block_hash) passes all validation.
|
||||||
|
|
||||||
drop(fork_choice_read_lock);
|
drop(fork_choice_read_lock);
|
||||||
|
|
||||||
// Track the number of skip slots between the block and its parent.
|
// Track the number of skip slots between the block and its parent.
|
||||||
@@ -1038,8 +1067,15 @@ impl<T: BeaconChainTypes> GossipVerifiedBlock<T> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate the block's execution_payload (if any).
|
// [New in Gloas]: Skip payload validation checks. The payload now arrives separately
|
||||||
validate_execution_payload_for_gossip(&parent_block, block.message(), chain)?;
|
// via `ExecutionPayloadEnvelope`.
|
||||||
|
if !chain
|
||||||
|
.spec
|
||||||
|
.fork_name_at_slot::<T::EthSpec>(block.slot())
|
||||||
|
.gloas_enabled()
|
||||||
|
{
|
||||||
|
validate_execution_payload_for_gossip(&parent_block, block.message(), chain)?;
|
||||||
|
}
|
||||||
|
|
||||||
// Beacon API block_gossip events
|
// Beacon API block_gossip events
|
||||||
if let Some(event_handler) = chain.event_handler.as_ref()
|
if let Some(event_handler) = chain.event_handler.as_ref()
|
||||||
@@ -1211,15 +1247,35 @@ impl<T: BeaconChainTypes> SignatureVerifiedBlock<T> {
|
|||||||
|
|
||||||
let result = info_span!("signature_verify").in_scope(|| signature_verifier.verify());
|
let result = info_span!("signature_verify").in_scope(|| signature_verifier.verify());
|
||||||
match result {
|
match result {
|
||||||
Ok(_) => Ok(Self {
|
Ok(_) => {
|
||||||
block: MaybeAvailableBlock::AvailabilityPending {
|
// gloas blocks are always available.
|
||||||
|
let maybe_available = if chain
|
||||||
|
.spec
|
||||||
|
.fork_name_at_slot::<T::EthSpec>(block.slot())
|
||||||
|
.gloas_enabled()
|
||||||
|
{
|
||||||
|
MaybeAvailableBlock::Available(
|
||||||
|
AvailableBlock::new(
|
||||||
|
block,
|
||||||
|
AvailableBlockData::NoData,
|
||||||
|
&chain.data_availability_checker,
|
||||||
|
chain.spec.clone(),
|
||||||
|
)
|
||||||
|
.map_err(BlockError::AvailabilityCheck)?,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
MaybeAvailableBlock::AvailabilityPending {
|
||||||
|
block_root: from.block_root,
|
||||||
|
block,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Ok(Self {
|
||||||
|
block: maybe_available,
|
||||||
block_root: from.block_root,
|
block_root: from.block_root,
|
||||||
block,
|
parent: Some(parent),
|
||||||
},
|
consensus_context,
|
||||||
block_root: from.block_root,
|
})
|
||||||
parent: Some(parent),
|
}
|
||||||
consensus_context,
|
|
||||||
}),
|
|
||||||
Err(_) => Err(BlockError::InvalidSignature(
|
Err(_) => Err(BlockError::InvalidSignature(
|
||||||
InvalidSignature::BlockBodySignatures,
|
InvalidSignature::BlockBodySignatures,
|
||||||
)),
|
)),
|
||||||
|
|||||||
@@ -62,7 +62,10 @@ impl<T: BeaconChainTypes> PayloadNotifier<T> {
|
|||||||
state: &BeaconState<T::EthSpec>,
|
state: &BeaconState<T::EthSpec>,
|
||||||
notify_execution_layer: NotifyExecutionLayer,
|
notify_execution_layer: NotifyExecutionLayer,
|
||||||
) -> Result<Self, BlockError> {
|
) -> Result<Self, BlockError> {
|
||||||
let payload_verification_status = if is_execution_enabled(state, block.message().body()) {
|
let payload_verification_status = if block.fork_name_unchecked().gloas_enabled() {
|
||||||
|
// Gloas blocks don't contain an execution payload.
|
||||||
|
Some(PayloadVerificationStatus::Irrelevant)
|
||||||
|
} else if is_execution_enabled(state, block.message().body()) {
|
||||||
// Perform the initial stages of payload verification.
|
// Perform the initial stages of payload verification.
|
||||||
//
|
//
|
||||||
// We will duplicate these checks again during `per_block_processing`, however these
|
// We will duplicate these checks again during `per_block_processing`, however these
|
||||||
@@ -294,6 +297,12 @@ pub fn validate_execution_payload_for_gossip<T: BeaconChainTypes>(
|
|||||||
block: BeaconBlockRef<'_, T::EthSpec>,
|
block: BeaconBlockRef<'_, T::EthSpec>,
|
||||||
chain: &BeaconChain<T>,
|
chain: &BeaconChain<T>,
|
||||||
) -> Result<(), BlockError> {
|
) -> Result<(), BlockError> {
|
||||||
|
// Gloas blocks don't have an execution payload in the block body.
|
||||||
|
// Bid-related validations are handled in gossip block verification.
|
||||||
|
if block.fork_name_unchecked().gloas_enabled() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
// Only apply this validation if this is a Bellatrix beacon block.
|
// Only apply this validation if this is a Bellatrix beacon block.
|
||||||
if let Ok(execution_payload) = block.body().execution_payload() {
|
if let Ok(execution_payload) = block.body().execution_payload() {
|
||||||
// This logic should match `is_execution_enabled`. We use only the execution block hash of
|
// This logic should match `is_execution_enabled`. We use only the execution block hash of
|
||||||
|
|||||||
@@ -1356,7 +1356,8 @@ impl<T: BeaconChainTypes> NetworkBeaconProcessor<T> {
|
|||||||
| Err(e @ BlockError::ParentExecutionPayloadInvalid { .. })
|
| Err(e @ BlockError::ParentExecutionPayloadInvalid { .. })
|
||||||
| Err(e @ BlockError::KnownInvalidExecutionPayload(_))
|
| Err(e @ BlockError::KnownInvalidExecutionPayload(_))
|
||||||
| Err(e @ BlockError::GenesisBlock)
|
| Err(e @ BlockError::GenesisBlock)
|
||||||
| Err(e @ BlockError::InvalidBlobCount { .. }) => {
|
| Err(e @ BlockError::InvalidBlobCount { .. })
|
||||||
|
| Err(e @ BlockError::BidParentRootMismatch { .. }) => {
|
||||||
warn!(error = %e, "Could not verify block for gossip. Rejecting the block");
|
warn!(error = %e, "Could not verify block for gossip. Rejecting the block");
|
||||||
self.propagate_validation_result(message_id, peer_id, MessageAcceptance::Reject);
|
self.propagate_validation_result(message_id, peer_id, MessageAcceptance::Reject);
|
||||||
self.gossip_penalize_peer(
|
self.gossip_penalize_peer(
|
||||||
@@ -1490,19 +1491,23 @@ impl<T: BeaconChainTypes> NetworkBeaconProcessor<T> {
|
|||||||
|
|
||||||
// Block is gossip valid. Attempt to fetch blobs from the EL using versioned hashes derived
|
// Block is gossip valid. Attempt to fetch blobs from the EL using versioned hashes derived
|
||||||
// from kzg commitments, without having to wait for all blobs to be sent from the peers.
|
// from kzg commitments, without having to wait for all blobs to be sent from the peers.
|
||||||
let publish_blobs = true;
|
// TODO(gloas) we'll want to use this same optimization, but we need to refactor the
|
||||||
let self_clone = self.clone();
|
// `fetch_and_process_engine_blobs` flow to support gloas.
|
||||||
let block_clone = block.clone();
|
if !block.fork_name_unchecked().gloas_enabled() {
|
||||||
let current_span = Span::current();
|
let publish_blobs = true;
|
||||||
self.executor.spawn(
|
let self_clone = self.clone();
|
||||||
async move {
|
let block_clone = block.clone();
|
||||||
self_clone
|
let current_span = Span::current();
|
||||||
.fetch_engine_blobs_and_publish(block_clone, block_root, publish_blobs)
|
self.executor.spawn(
|
||||||
.await
|
async move {
|
||||||
}
|
self_clone
|
||||||
.instrument(current_span),
|
.fetch_engine_blobs_and_publish(block_clone, block_root, publish_blobs)
|
||||||
"fetch_blobs_gossip",
|
.await
|
||||||
);
|
}
|
||||||
|
.instrument(current_span),
|
||||||
|
"fetch_blobs_gossip",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
let result = self
|
let result = self
|
||||||
.chain
|
.chain
|
||||||
|
|||||||
@@ -309,6 +309,26 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload<E>> BeaconBlockRef<'a, E, Payl
|
|||||||
pub fn execution_payload(&self) -> Result<Payload::Ref<'a>, BeaconStateError> {
|
pub fn execution_payload(&self) -> Result<Payload::Ref<'a>, BeaconStateError> {
|
||||||
self.body().execution_payload()
|
self.body().execution_payload()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn blob_kzg_commitments_len(&self) -> Option<usize> {
|
||||||
|
match self {
|
||||||
|
BeaconBlockRef::Base(_) => None,
|
||||||
|
BeaconBlockRef::Altair(_) => None,
|
||||||
|
BeaconBlockRef::Bellatrix(_) => None,
|
||||||
|
BeaconBlockRef::Capella(_) => None,
|
||||||
|
BeaconBlockRef::Deneb(block) => Some(block.body.blob_kzg_commitments.len()),
|
||||||
|
BeaconBlockRef::Electra(block) => Some(block.body.blob_kzg_commitments.len()),
|
||||||
|
BeaconBlockRef::Fulu(block) => Some(block.body.blob_kzg_commitments.len()),
|
||||||
|
BeaconBlockRef::Gloas(block) => Some(
|
||||||
|
block
|
||||||
|
.body
|
||||||
|
.signed_execution_payload_bid
|
||||||
|
.message
|
||||||
|
.blob_kzg_commitments
|
||||||
|
.len(),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, E: EthSpec, Payload: AbstractExecPayload<E>> BeaconBlockRefMut<'a, E, Payload> {
|
impl<'a, E: EthSpec, Payload: AbstractExecPayload<E>> BeaconBlockRefMut<'a, E, Payload> {
|
||||||
|
|||||||
Reference in New Issue
Block a user