diff --git a/beacon_node/beacon_chain/src/execution_payload.rs b/beacon_node/beacon_chain/src/execution_payload.rs index b8fbbc3c32..631a0180dd 100644 --- a/beacon_node/beacon_chain/src/execution_payload.rs +++ b/beacon_node/beacon_chain/src/execution_payload.rs @@ -113,7 +113,12 @@ impl PayloadNotifier { if let Some(precomputed_status) = self.payload_verification_status { Ok(precomputed_status) } 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( .ok_or(ExecutionPayloadError::NoExecutionConnection)?; 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 { Ok(status) => match status { diff --git a/beacon_node/beacon_chain/src/payload_envelope_verification/execution_pending_envelope.rs b/beacon_node/beacon_chain/src/payload_envelope_verification/execution_pending_envelope.rs index 956e6ffb8f..7dffd1c09c 100644 --- a/beacon_node/beacon_chain/src/payload_envelope_verification/execution_pending_envelope.rs +++ b/beacon_node/beacon_chain/src/payload_envelope_verification/execution_pending_envelope.rs @@ -1,8 +1,10 @@ use task_executor::JoinHandle; 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. pub type PayloadVerificationHandle = @@ -20,7 +22,7 @@ pub type PayloadVerificationHandle = /// due to finality or some other event. A `ExecutionPendingEnvelope` should be imported into the /// `BeaconChain` immediately after it is instantiated. pub struct ExecutionPendingEnvelope { - pub block: MaybeAvailableBlock, + pub block: MaybeAvailableEnvelope, pub import_data: PayloadEnvelopeImportData, - pub payload_verification_handle: PayloadVerificationHandle, -} \ No newline at end of file + pub payload_verification_handle: PayloadVerificationHandle, +} diff --git a/beacon_node/beacon_chain/src/payload_envelope_verification/gossip_verified_envelope.rs b/beacon_node/beacon_chain/src/payload_envelope_verification/gossip_verified_envelope.rs index 2bd5a6c3d7..580c6e9234 100644 --- a/beacon_node/beacon_chain/src/payload_envelope_verification/gossip_verified_envelope.rs +++ b/beacon_node/beacon_chain/src/payload_envelope_verification/gossip_verified_envelope.rs @@ -1,12 +1,19 @@ use std::sync::Arc; use educe::Educe; +use slot_clock::SlotClock; use state_processing::{VerifySignatures, envelope_processing::process_execution_payload_envelope}; use tracing::debug; -use types::{EthSpec, SignedBeaconBlock, SignedExecutionPayloadEnvelope}; +use types::{EthSpec, SignedBeaconBlock, SignedExecutionPayloadEnvelope, consts::gloas::BUILDER_INDEX_SELF_BUILD}; 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 @@ -29,7 +36,7 @@ impl GossipVerifiedEnvelope { let beacon_block_root = envelope.beacon_block_root; // 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 // 2. Blocks we've seen that are invalid (REJECT). @@ -41,14 +48,16 @@ impl GossipVerifiedEnvelope { 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); // TODO(EIP-7732): check that we haven't seen another valid `SignedExecutionPayloadEnvelope` // 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 .get_full_block(&beacon_block_root)? .ok_or_else(|| { @@ -61,11 +70,14 @@ impl GossipVerifiedEnvelope { .signed_execution_payload_bid()? .message; - // TODO(EIP-7732): Gossip rules for the beacon block contain the following: - // https://github.com/ethereum/consensus-specs/blob/master/specs/phase0/p2p-interface.md#beacon_block - // [IGNORE] The block is not from a future slot (with a MAXIMUM_GOSSIP_CLOCK_DISPARITY allowance) - // [IGNORE] The block is from a slot greater than the latest finalized slot - // should these kinds of checks be included for envelopes as well? + // check that the envelopes slot isnt from a slot prior + // to the latest finalized slot. + if envelope.slot < latest_finalized_slot { + return Err(EnvelopeError::PriorToFinalization { + payload_slot: envelope.slot, + latest_finalized_slot, + }); + } // check that the slot of the envelope matches the slot of the parent block if envelope.slot != block.slot() { @@ -119,17 +131,22 @@ impl GossipVerifiedEnvelope { )?; 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 index = if builder_index == BUILDER_INDEX_SELF_BUILD { + block.message().proposer_index() + } else { + builder_index + }; 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 builder_pubkey = pubkey_cache - .get(builder_index as usize) - .ok_or_else(|| EnvelopeError::UnknownValidator { builder_index })?; + let pubkey = pubkey_cache + .get(index as usize) + .ok_or_else(|| EnvelopeError::UnknownValidator { builder_index: index })?; signed_envelope.verify_signature( - builder_pubkey, + pubkey, &fork, chain.genesis_validators_root, &chain.spec, @@ -161,9 +178,17 @@ impl IntoExecutionPendingEnvelope for GossipVerifiedEnve let signed_envelope = self.signed_envelope; let envelope = &signed_envelope.message; let payload = &envelope.payload; - + // 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 let payload_notifier = diff --git a/beacon_node/beacon_chain/src/payload_envelope_verification/mod.rs b/beacon_node/beacon_chain/src/payload_envelope_verification/mod.rs index 4a739e74c5..b166e90fa1 100644 --- a/beacon_node/beacon_chain/src/payload_envelope_verification/mod.rs +++ b/beacon_node/beacon_chain/src/payload_envelope_verification/mod.rs @@ -17,6 +17,9 @@ //! |--------------- //! | //! ▼ +//! SignatureVerifiedEnvelope +//! | +//! ▼ //! ExecutionPendingEnvelope //! | //! await @@ -28,15 +31,25 @@ use std::sync::Arc; -use state_processing::{BlockProcessingError, ConsensusContext, envelope_processing::EnvelopeProcessingError}; +use state_processing::{ + BlockProcessingError, ConsensusContext, envelope_processing::EnvelopeProcessingError, +}; 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 gossip_verified_envelope; mod payload_notifier; +mod signature_verified_envelope; pub trait IntoExecutionPendingEnvelope: Sized { fn into_execution_pending_envelope( @@ -115,6 +128,12 @@ pub enum EnvelopeError { committed_bid: 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 BeaconChainError(Arc), // Some Beacon State error diff --git a/beacon_node/beacon_chain/src/payload_envelope_verification/payload_notifier.rs b/beacon_node/beacon_chain/src/payload_envelope_verification/payload_notifier.rs index 15fec7e21d..6bbdd971a5 100644 --- a/beacon_node/beacon_chain/src/payload_envelope_verification/payload_notifier.rs +++ b/beacon_node/beacon_chain/src/payload_envelope_verification/payload_notifier.rs @@ -2,12 +2,19 @@ use std::sync::Arc; use execution_layer::NewPayloadRequest; 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 types::{BeaconState, ExecutionPayloadBid, Hash256, SignedBeaconBlock, SignedExecutionPayloadEnvelope}; - -use crate::{BeaconChain, BeaconChainTypes, BlockError, ExecutionPayloadError, NotifyExecutionLayer, execution_payload::notify_new_payload}; +use types::{ + BeaconState, ExecutionPayloadBid, Hash256, SignedBeaconBlock, SignedExecutionPayloadEnvelope, +}; +use crate::{ + BeaconChain, BeaconChainTypes, BlockError, ExecutionPayloadError, NotifyExecutionLayer, + execution_payload::notify_new_payload, +}; /// Used to await the result of executing payload with a remote EE. pub struct PayloadNotifier { @@ -24,7 +31,7 @@ impl PayloadNotifier { state: &BeaconState, notify_execution_layer: NotifyExecutionLayer, ) -> Result { - let payload_verification_status = { + let payload_verification_status = { // Perform the initial stages of payload verification. // // We will duplicate these checks again during `per_block_processing`, however these @@ -32,11 +39,7 @@ impl PayloadNotifier { // the block as optimistically imported. This is particularly relevant in the case // where we do not send the block to the EL at all. let payload_message = &envelope.message; - partially_verify_payload_envelope( - state, - &envelope, - &chain.spec, - ).unwrap(); // TODO(gloas) unwrap + partially_verify_payload_envelope(state, &envelope, &chain.spec).unwrap(); // TODO(gloas) unwrap match notify_execution_layer { NotifyExecutionLayer::No if chain.config.optimistic_finalized_sync => { @@ -71,7 +74,12 @@ impl PayloadNotifier { Ok(precomputed_status) } else { // 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 } } -} \ No newline at end of file +} diff --git a/beacon_node/beacon_chain/src/payload_envelope_verification/signature_verified_envelope.rs b/beacon_node/beacon_chain/src/payload_envelope_verification/signature_verified_envelope.rs new file mode 100644 index 0000000000..cd430daf5b --- /dev/null +++ b/beacon_node/beacon_chain/src/payload_envelope_verification/signature_verified_envelope.rs @@ -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 { + envelope: SignedExecutionPayloadEnvelope, + block_root: Hash256, + state: Option>, + consensus_context: ConsensusContext, +} + + +impl SignatureVerifiedEnvelope { + pub fn new( + envelope: Arc>, + state: &mut BeaconState, + block_root: Hash256, + chain: &BeaconChain, + ) -> Result { + 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!() + } +} \ No newline at end of file diff --git a/beacon_node/execution_layer/src/engine_api/new_payload_request.rs b/beacon_node/execution_layer/src/engine_api/new_payload_request.rs index b88dd7ca3a..145d171bbc 100644 --- a/beacon_node/execution_layer/src/engine_api/new_payload_request.rs +++ b/beacon_node/execution_layer/src/engine_api/new_payload_request.rs @@ -4,7 +4,8 @@ use crate::versioned_hashes::verify_versioned_hashes; use state_processing::per_block_processing::deneb::kzg_commitment_to_versioned_hash; use superstruct::superstruct; use types::{ - BeaconBlockRef, BeaconStateError, EthSpec, ExecutionBlockHash, ExecutionPayload, ExecutionPayloadEnvelope, ExecutionPayloadRef, Hash256, VersionedHash + BeaconBlockRef, BeaconStateError, EthSpec, ExecutionBlockHash, ExecutionPayload, + ExecutionPayloadEnvelope, ExecutionPayloadRef, Hash256, VersionedHash, }; use types::{ ExecutionPayloadBellatrix, ExecutionPayloadCapella, ExecutionPayloadDeneb, diff --git a/consensus/state_processing/src/envelope_processing.rs b/consensus/state_processing/src/envelope_processing.rs index 2f511846a5..0cdb6caaef 100644 --- a/consensus/state_processing/src/envelope_processing.rs +++ b/consensus/state_processing/src/envelope_processing.rs @@ -277,7 +277,6 @@ pub fn process_execution_payload_envelope( Ok(()) } - /// Performs *partial* verification of the `payload envelope`. pub fn partially_verify_payload_envelope( state: &BeaconState, @@ -286,7 +285,7 @@ pub fn partially_verify_payload_envelope( ) -> Result<(), EnvelopeProcessingError> { let envelope = &signed_envelope.message; let payload = &signed_envelope.message.payload; - + // Verify consistency with the beacon block let latest_block_header_root = state.latest_block_header().tree_hash_root(); envelope_verify!(