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 877dcc2c2b..68d6e8605e 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 @@ -22,7 +22,7 @@ use crate::{ payload_envelope_verification::{ EnvelopeError, EnvelopeImportData, EnvelopeProcessingSnapshot, ExecutionPendingEnvelope, IntoExecutionPendingEnvelope, MaybeAvailableEnvelope, load_snapshot, - payload_notifier::PayloadNotifier, + load_snapshot_from_state_root, payload_notifier::PayloadNotifier, }, validator_pubkey_cache::ValidatorPubkeyCache, }; @@ -161,7 +161,6 @@ impl GossipVerifiedEnvelope { let (signature_is_valid, opt_snapshot) = if builder_index == BUILDER_INDEX_SELF_BUILD { // Fast path: self-built envelopes can be verified without loading the state. - let envelope_ref = signed_envelope.as_ref(); let mut opt_snapshot = None; let proposer = beacon_proposer_cache::with_proposer_cache( ctx.beacon_proposer_cache, @@ -174,7 +173,11 @@ impl GossipVerifiedEnvelope { %beacon_block_root, "Proposer shuffling cache miss for envelope verification" ); - let snapshot = load_snapshot(envelope_ref, ctx.canonical_head, ctx.store)?; + let snapshot = load_snapshot_from_state_root::( + beacon_block_root, + proto_block.state_root, + ctx.store, + )?; opt_snapshot = Some(Box::new(snapshot.clone())); Ok::<_, EnvelopeError>((snapshot.state_root, snapshot.pre_state)) }, @@ -205,7 +208,11 @@ impl GossipVerifiedEnvelope { } else { // TODO(gloas) if we implement a builder pubkey cache, we'll need to use it here. // External builder: must load the state to get the builder pubkey. - let snapshot = load_snapshot(signed_envelope.as_ref(), ctx.canonical_head, ctx.store)?; + let snapshot = load_snapshot_from_state_root::( + beacon_block_root, + proto_block.state_root, + ctx.store, + )?; let is_valid = signed_envelope.verify_signature_with_state(&snapshot.pre_state, ctx.spec)?; (is_valid, Some(Box::new(snapshot))) 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 9caff959d0..5e88d62ec1 100644 --- a/beacon_node/beacon_chain/src/payload_envelope_verification/mod.rs +++ b/beacon_node/beacon_chain/src/payload_envelope_verification/mod.rs @@ -291,35 +291,16 @@ impl From for EnvelopeError { } #[allow(clippy::type_complexity)] -#[instrument(skip_all, level = "debug", fields(beacon_block_root = %envelope.beacon_block_root()))] -pub(crate) fn load_snapshot( - envelope: &SignedExecutionPayloadEnvelope, - canonical_head: &CanonicalHead, +#[instrument(skip_all, level = "debug", fields(beacon_block_root = %beacon_block_root))] +/// Load state from store given a known state root and block root. +/// Use this when the proto block has already been looked up from fork choice. +pub(crate) fn load_snapshot_from_state_root( + beacon_block_root: Hash256, + block_state_root: Hash256, store: &BeaconStore, ) -> Result, EnvelopeError> { - // Reject any envelope if its block is not known to fork choice. - // - // A block that is not in fork choice is either: - // - // - Not yet imported: we should reject this envelope because we should only import it after its parent block - // has been fully imported. - // - Pre-finalized: if the parent block is _prior_ to finalization, we should ignore the envelope - // because it will revert finalization. Note that the finalized block is stored in fork - // choice, so we will not reject any child of the finalized block (this is relevant during - // genesis). - - let fork_choice_read_lock = canonical_head.fork_choice_read_lock(); - let beacon_block_root = envelope.beacon_block_root(); - let Some(proto_beacon_block) = fork_choice_read_lock.get_block(&beacon_block_root) else { - return Err(EnvelopeError::BlockRootUnknown { - block_root: beacon_block_root, - }); - }; - drop(fork_choice_read_lock); - // TODO(EIP-7732): add metrics here - let block_state_root = proto_beacon_block.state_root; // We can use `get_hot_state` here rather than `get_advanced_hot_state` because the envelope // must be from the same slot as its block (so no advance is required). let cache_state = true; @@ -339,6 +320,35 @@ pub(crate) fn load_snapshot( }) } +#[instrument(skip_all, level = "debug", fields(beacon_block_root = %envelope.beacon_block_root()))] +pub(crate) fn load_snapshot( + envelope: &SignedExecutionPayloadEnvelope, + canonical_head: &CanonicalHead, + store: &BeaconStore, +) -> Result, EnvelopeError> { + // Reject any envelope if its block is not known to fork choice. + // + // A block that is not in fork choice is either: + // + // - Not yet imported: we should reject this envelope because we should only import it after + // its parent block has been fully imported. + // - Pre-finalized: if the parent block is _prior_ to finalization, we should ignore the + // envelope because it will revert finalization. Note that the finalized block is stored in + // fork choice, so we will not reject any child of the finalized block (this is relevant + // during genesis). + + let fork_choice_read_lock = canonical_head.fork_choice_read_lock(); + let beacon_block_root = envelope.beacon_block_root(); + let Some(proto_beacon_block) = fork_choice_read_lock.get_block(&beacon_block_root) else { + return Err(EnvelopeError::BlockRootUnknown { + block_root: beacon_block_root, + }); + }; + drop(fork_choice_read_lock); + + load_snapshot_from_state_root::(beacon_block_root, proto_beacon_block.state_root, store) +} + impl IntoExecutionPendingEnvelope for Arc> {