This commit is contained in:
Eitan Seri- Levi
2026-02-10 22:40:26 -08:00
parent 8204241b45
commit 22f3fd4ccf
8 changed files with 146 additions and 45 deletions

View File

@@ -113,7 +113,12 @@ impl<T: BeaconChainTypes> PayloadNotifier<T> {
if let Some(precomputed_status) = self.payload_verification_status { if let Some(precomputed_status) = self.payload_verification_status {
Ok(precomputed_status) Ok(precomputed_status)
} else { } else {
notify_new_payload(&self.chain, self.block.message().tree_hash_root(), self.block.message().try_into()?).await notify_new_payload(
&self.chain,
self.block.message().tree_hash_root(),
self.block.message().try_into()?,
)
.await
} }
} }
} }
@@ -138,7 +143,9 @@ pub async fn notify_new_payload<T: BeaconChainTypes>(
.ok_or(ExecutionPayloadError::NoExecutionConnection)?; .ok_or(ExecutionPayloadError::NoExecutionConnection)?;
let execution_block_hash = new_payload_request.execution_payload_ref().block_hash(); let execution_block_hash = new_payload_request.execution_payload_ref().block_hash();
let new_payload_response = execution_layer.notify_new_payload(new_payload_request.clone()).await; let new_payload_response = execution_layer
.notify_new_payload(new_payload_request.clone())
.await;
match new_payload_response { match new_payload_response {
Ok(status) => match status { Ok(status) => match status {

View File

@@ -1,8 +1,10 @@
use task_executor::JoinHandle; use task_executor::JoinHandle;
use types::{EthSpec, FullPayload}; use types::{EthSpec, FullPayload};
use crate::{BeaconChainTypes, PayloadVerificationOutcome, payload_envelope_verification::PayloadEnvelopeImportData}; use crate::{
BeaconChainTypes, PayloadVerificationOutcome,
payload_envelope_verification::{MaybeAvailableEnvelope, PayloadEnvelopeImportData},
};
/// Used to await the result of executing payload with an EE. /// Used to await the result of executing payload with an EE.
pub type PayloadVerificationHandle<E: EthSpec> = pub type PayloadVerificationHandle<E: EthSpec> =
@@ -20,7 +22,7 @@ pub type PayloadVerificationHandle<E: EthSpec> =
/// due to finality or some other event. A `ExecutionPendingEnvelope` should be imported into the /// due to finality or some other event. A `ExecutionPendingEnvelope` should be imported into the
/// `BeaconChain` immediately after it is instantiated. /// `BeaconChain` immediately after it is instantiated.
pub struct ExecutionPendingEnvelope<T: BeaconChainTypes> { pub struct ExecutionPendingEnvelope<T: BeaconChainTypes> {
pub block: MaybeAvailableBlock<T::EthSpec>, pub block: MaybeAvailableEnvelope<T::EthSpec>,
pub import_data: PayloadEnvelopeImportData<T::EthSpec>, pub import_data: PayloadEnvelopeImportData<T::EthSpec>,
pub payload_verification_handle: PayloadVerificationHandle<E>, pub payload_verification_handle: PayloadVerificationHandle<T::EthSpec>,
} }

View File

@@ -1,12 +1,19 @@
use std::sync::Arc; use std::sync::Arc;
use educe::Educe; use educe::Educe;
use slot_clock::SlotClock;
use state_processing::{VerifySignatures, envelope_processing::process_execution_payload_envelope}; use state_processing::{VerifySignatures, envelope_processing::process_execution_payload_envelope};
use tracing::debug; use tracing::debug;
use types::{EthSpec, SignedBeaconBlock, SignedExecutionPayloadEnvelope}; use types::{EthSpec, SignedBeaconBlock, SignedExecutionPayloadEnvelope, consts::gloas::BUILDER_INDEX_SELF_BUILD};
use crate::{ use crate::{
BeaconChain, BeaconChainError, BeaconChainTypes, NotifyExecutionLayer, PayloadVerificationOutcome, payload_envelope_verification::{EnvelopeError, EnvelopeImportData, EnvelopeProcessingSnapshot, ExecutionPendingEnvelope, IntoExecutionPendingEnvelope, MaybeAvailableEnvelope, load_snapshot, payload_notifier::PayloadNotifier} BeaconChain, BeaconChainError, BeaconChainTypes, NotifyExecutionLayer,
PayloadVerificationOutcome,
payload_envelope_verification::{
EnvelopeError, EnvelopeImportData, EnvelopeProcessingSnapshot, ExecutionPendingEnvelope,
IntoExecutionPendingEnvelope, MaybeAvailableEnvelope, load_snapshot,
payload_notifier::PayloadNotifier,
},
}; };
/// A wrapper around a `SignedExecutionPayloadEnvelope` that indicates it has been approved for re-gossiping on /// A wrapper around a `SignedExecutionPayloadEnvelope` that indicates it has been approved for re-gossiping on
@@ -29,7 +36,7 @@ impl<T: BeaconChainTypes> GossipVerifiedEnvelope<T> {
let beacon_block_root = envelope.beacon_block_root; let beacon_block_root = envelope.beacon_block_root;
// Check that we've seen the beacon block for this envelope and that it passes validation. // Check that we've seen the beacon block for this envelope and that it passes validation.
// TODO(EIP-7732): We need a block status table in order to differentiate between: // TODO(EIP-7732): We might need some type of status table in order to differentiate between:
// //
// 1. Blocks we haven't seen (IGNORE), and // 1. Blocks we haven't seen (IGNORE), and
// 2. Blocks we've seen that are invalid (REJECT). // 2. Blocks we've seen that are invalid (REJECT).
@@ -41,14 +48,16 @@ impl<T: BeaconChainTypes> GossipVerifiedEnvelope<T> {
block_root: beacon_block_root, block_root: beacon_block_root,
}); });
}; };
let latest_finalized_slot = fork_choice_read_lock
.finalized_checkpoint()
.epoch
.start_slot(T::EthSpec::slots_per_epoch());
drop(fork_choice_read_lock); drop(fork_choice_read_lock);
// TODO(EIP-7732): check that we haven't seen another valid `SignedExecutionPayloadEnvelope` // TODO(EIP-7732): check that we haven't seen another valid `SignedExecutionPayloadEnvelope`
// for this block root from this builder - envelope status table check // for this block root from this builder - envelope status table check
// TODO(EIP-7732): this could be obtained from the ProtoBlock instead of the DB
// but this means the ProtoBlock needs to include something like the ExecutionBid
// will need to answer this question later.
let block = chain let block = chain
.get_full_block(&beacon_block_root)? .get_full_block(&beacon_block_root)?
.ok_or_else(|| { .ok_or_else(|| {
@@ -61,11 +70,14 @@ impl<T: BeaconChainTypes> GossipVerifiedEnvelope<T> {
.signed_execution_payload_bid()? .signed_execution_payload_bid()?
.message; .message;
// TODO(EIP-7732): Gossip rules for the beacon block contain the following: // check that the envelopes slot isnt from a slot prior
// https://github.com/ethereum/consensus-specs/blob/master/specs/phase0/p2p-interface.md#beacon_block // to the latest finalized slot.
// [IGNORE] The block is not from a future slot (with a MAXIMUM_GOSSIP_CLOCK_DISPARITY allowance) if envelope.slot < latest_finalized_slot {
// [IGNORE] The block is from a slot greater than the latest finalized slot return Err(EnvelopeError::PriorToFinalization {
// should these kinds of checks be included for envelopes as well? payload_slot: envelope.slot,
latest_finalized_slot,
});
}
// check that the slot of the envelope matches the slot of the parent block // check that the slot of the envelope matches the slot of the parent block
if envelope.slot != block.slot() { if envelope.slot != block.slot() {
@@ -119,17 +131,22 @@ impl<T: BeaconChainTypes> GossipVerifiedEnvelope<T> {
)?; )?;
let fork = proposer.fork; let fork = proposer.fork;
// True builder index accounting for self-building.
let proposer_index = block.message().proposer_index();
let builder_index = envelope.builder_index; let builder_index = envelope.builder_index;
let index = if builder_index == BUILDER_INDEX_SELF_BUILD {
block.message().proposer_index()
} else {
builder_index
};
let signature_is_valid = { let signature_is_valid = {
// TODO(gloas) the builder pubkey wont be in the validator pubkey cache
// this will currently only work for local block building.
let pubkey_cache = chain.validator_pubkey_cache.read(); let pubkey_cache = chain.validator_pubkey_cache.read();
let builder_pubkey = pubkey_cache let pubkey = pubkey_cache
.get(builder_index as usize) .get(index as usize)
.ok_or_else(|| EnvelopeError::UnknownValidator { builder_index })?; .ok_or_else(|| EnvelopeError::UnknownValidator { builder_index: index })?;
signed_envelope.verify_signature( signed_envelope.verify_signature(
builder_pubkey, pubkey,
&fork, &fork,
chain.genesis_validators_root, chain.genesis_validators_root,
&chain.spec, &chain.spec,
@@ -163,7 +180,15 @@ impl<T: BeaconChainTypes> IntoExecutionPendingEnvelope<T> for GossipVerifiedEnve
let payload = &envelope.payload; let payload = &envelope.payload;
// TODO(gloas) unwrap // TODO(gloas) unwrap
let bid = chain.get_full_block(&envelope.beacon_block_root).unwrap().unwrap().message().body().signed_execution_payload_bid().unwrap().message; let bid = chain
.get_full_block(&envelope.beacon_block_root)
.unwrap()
.unwrap()
.message()
.body()
.signed_execution_payload_bid()
.unwrap()
.message;
// Verify the execution payload is valid // Verify the execution payload is valid
let payload_notifier = let payload_notifier =

View File

@@ -17,6 +17,9 @@
//! |--------------- //! |---------------
//! | //! |
//! ▼ //! ▼
//! SignatureVerifiedEnvelope
//! |
//! ▼
//! ExecutionPendingEnvelope //! ExecutionPendingEnvelope
//! | //! |
//! await //! await
@@ -28,15 +31,25 @@
use std::sync::Arc; use std::sync::Arc;
use state_processing::{BlockProcessingError, ConsensusContext, envelope_processing::EnvelopeProcessingError}; use state_processing::{
BlockProcessingError, ConsensusContext, envelope_processing::EnvelopeProcessingError,
};
use tracing::instrument; use tracing::instrument;
use types::{BeaconState, BeaconStateError, ChainSpec, DataColumnSidecarList, EthSpec, ExecutionBlockHash, Hash256, SignedBeaconBlock, SignedExecutionPayloadEnvelope, Slot}; use types::{
BeaconState, BeaconStateError, ChainSpec, DataColumnSidecarList, EthSpec, ExecutionBlockHash,
Hash256, SignedBeaconBlock, SignedExecutionPayloadEnvelope, Slot,
};
use crate::{BeaconChain, BeaconChainError, BeaconChainTypes, NotifyExecutionLayer, block_verification::PayloadVerificationHandle, payload_envelope_verification::gossip_verified_envelope::GossipVerifiedEnvelope}; use crate::{
BeaconChain, BeaconChainError, BeaconChainTypes, NotifyExecutionLayer,
block_verification::PayloadVerificationHandle,
payload_envelope_verification::gossip_verified_envelope::GossipVerifiedEnvelope,
};
pub mod execution_pending_envelope; pub mod execution_pending_envelope;
pub mod gossip_verified_envelope; pub mod gossip_verified_envelope;
mod payload_notifier; mod payload_notifier;
mod signature_verified_envelope;
pub trait IntoExecutionPendingEnvelope<T: BeaconChainTypes>: Sized { pub trait IntoExecutionPendingEnvelope<T: BeaconChainTypes>: Sized {
fn into_execution_pending_envelope( fn into_execution_pending_envelope(
@@ -115,6 +128,12 @@ pub enum EnvelopeError {
committed_bid: ExecutionBlockHash, committed_bid: ExecutionBlockHash,
envelope: ExecutionBlockHash, envelope: ExecutionBlockHash,
}, },
// The slot belongs to a block that is from a slot prior than
// the most recently finalized slot
PriorToFinalization {
payload_slot: Slot,
latest_finalized_slot: Slot,
},
// Some Beacon Chain Error // Some Beacon Chain Error
BeaconChainError(Arc<BeaconChainError>), BeaconChainError(Arc<BeaconChainError>),
// Some Beacon State error // Some Beacon State error

View File

@@ -2,12 +2,19 @@ use std::sync::Arc;
use execution_layer::NewPayloadRequest; use execution_layer::NewPayloadRequest;
use fork_choice::PayloadVerificationStatus; use fork_choice::PayloadVerificationStatus;
use state_processing::{envelope_processing::partially_verify_payload_envelope, per_block_processing::is_execution_enabled}; use state_processing::{
envelope_processing::partially_verify_payload_envelope,
per_block_processing::is_execution_enabled,
};
use tracing::warn; use tracing::warn;
use types::{BeaconState, ExecutionPayloadBid, Hash256, SignedBeaconBlock, SignedExecutionPayloadEnvelope}; use types::{
BeaconState, ExecutionPayloadBid, Hash256, SignedBeaconBlock, SignedExecutionPayloadEnvelope,
use crate::{BeaconChain, BeaconChainTypes, BlockError, ExecutionPayloadError, NotifyExecutionLayer, execution_payload::notify_new_payload}; };
use crate::{
BeaconChain, BeaconChainTypes, BlockError, ExecutionPayloadError, NotifyExecutionLayer,
execution_payload::notify_new_payload,
};
/// Used to await the result of executing payload with a remote EE. /// Used to await the result of executing payload with a remote EE.
pub struct PayloadNotifier<T: BeaconChainTypes> { pub struct PayloadNotifier<T: BeaconChainTypes> {
@@ -24,7 +31,7 @@ impl<T: BeaconChainTypes> PayloadNotifier<T> {
state: &BeaconState<T::EthSpec>, state: &BeaconState<T::EthSpec>,
notify_execution_layer: NotifyExecutionLayer, notify_execution_layer: NotifyExecutionLayer,
) -> Result<Self, ExecutionPayloadError> { ) -> Result<Self, ExecutionPayloadError> {
let payload_verification_status = { let payload_verification_status = {
// 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
@@ -32,11 +39,7 @@ impl<T: BeaconChainTypes> PayloadNotifier<T> {
// the block as optimistically imported. This is particularly relevant in the case // the block as optimistically imported. This is particularly relevant in the case
// where we do not send the block to the EL at all. // where we do not send the block to the EL at all.
let payload_message = &envelope.message; let payload_message = &envelope.message;
partially_verify_payload_envelope( partially_verify_payload_envelope(state, &envelope, &chain.spec).unwrap(); // TODO(gloas) unwrap
state,
&envelope,
&chain.spec,
).unwrap(); // TODO(gloas) unwrap
match notify_execution_layer { match notify_execution_layer {
NotifyExecutionLayer::No if chain.config.optimistic_finalized_sync => { NotifyExecutionLayer::No if chain.config.optimistic_finalized_sync => {
@@ -71,7 +74,12 @@ impl<T: BeaconChainTypes> PayloadNotifier<T> {
Ok(precomputed_status) Ok(precomputed_status)
} else { } else {
// tODO(gloas) fix zero // tODO(gloas) fix zero
notify_new_payload(&self.chain, Hash256::ZERO, self.envelope.message.try_into()?).await notify_new_payload(
&self.chain,
Hash256::ZERO,
self.envelope.message.try_into()?,
)
.await
} }
} }
} }

View File

@@ -0,0 +1,40 @@
use std::sync::Arc;
use state_processing::ConsensusContext;
use types::{BeaconState, Hash256, SignedExecutionPayloadEnvelope};
use crate::{BeaconChain, BeaconChainTypes, payload_envelope_verification::{EnvelopeError, MaybeAvailableEnvelope}};
/// A wrapper around a `SignedExecutionPayloadEnvelope` that indicates that all signatures (except the deposit
/// signatures) have been verified.
pub struct SignatureVerifiedEnvelope<T: BeaconChainTypes> {
envelope: SignedExecutionPayloadEnvelope<T::EthSpec>,
block_root: Hash256,
state: Option<BeaconState<T::EthSpec>>,
consensus_context: ConsensusContext<T::EthSpec>,
}
impl<T: BeaconChainTypes> SignatureVerifiedEnvelope<T> {
pub fn new(
envelope: Arc<SignedExecutionPayloadEnvelope<T::EthSpec>>,
state: &mut BeaconState<T::EthSpec>,
block_root: Hash256,
chain: &BeaconChain<T>,
) -> Result<Self, EnvelopeError> {
let is_signature_valid = envelope.verify_signature_with_state(state, &chain.spec)?;
if !is_signature_valid {
return Err(EnvelopeError::BadSignature)
}
Self {
envelope,
block_root,
state
}
todo!()
}
}

View File

@@ -4,7 +4,8 @@ use crate::versioned_hashes::verify_versioned_hashes;
use state_processing::per_block_processing::deneb::kzg_commitment_to_versioned_hash; use state_processing::per_block_processing::deneb::kzg_commitment_to_versioned_hash;
use superstruct::superstruct; use superstruct::superstruct;
use types::{ use types::{
BeaconBlockRef, BeaconStateError, EthSpec, ExecutionBlockHash, ExecutionPayload, ExecutionPayloadEnvelope, ExecutionPayloadRef, Hash256, VersionedHash BeaconBlockRef, BeaconStateError, EthSpec, ExecutionBlockHash, ExecutionPayload,
ExecutionPayloadEnvelope, ExecutionPayloadRef, Hash256, VersionedHash,
}; };
use types::{ use types::{
ExecutionPayloadBellatrix, ExecutionPayloadCapella, ExecutionPayloadDeneb, ExecutionPayloadBellatrix, ExecutionPayloadCapella, ExecutionPayloadDeneb,

View File

@@ -277,7 +277,6 @@ pub fn process_execution_payload_envelope<E: EthSpec>(
Ok(()) Ok(())
} }
/// Performs *partial* verification of the `payload envelope`. /// Performs *partial* verification of the `payload envelope`.
pub fn partially_verify_payload_envelope<E: EthSpec>( pub fn partially_verify_payload_envelope<E: EthSpec>(
state: &BeaconState<E>, state: &BeaconState<E>,