mirror of
https://github.com/sigp/lighthouse.git
synced 2026-05-30 12:47:05 +00:00
Co-Authored-By: Josh King <josh@sigmaprime.io> Co-Authored-By: Jimmy Chen <jchen.tc@gmail.com> Co-Authored-By: Michael Sproul <michael@sigmaprime.io>
235 lines
8.1 KiB
Rust
235 lines
8.1 KiB
Rust
use crate::VerifySignatures;
|
|
use crate::per_block_processing::compute_timestamp_at_slot;
|
|
use safe_arith::ArithError;
|
|
use tree_hash::TreeHash;
|
|
use types::{
|
|
BeaconState, BeaconStateError, BuilderIndex, ChainSpec, EthSpec, ExecutionBlockHash, Hash256,
|
|
SignedExecutionPayloadEnvelope, Slot,
|
|
};
|
|
|
|
macro_rules! envelope_verify {
|
|
($condition: expr, $result: expr) => {
|
|
if !$condition {
|
|
return Err($result);
|
|
}
|
|
};
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub enum EnvelopeProcessingError {
|
|
/// Bad Signature
|
|
BadSignature,
|
|
BeaconStateError(BeaconStateError),
|
|
ArithError(ArithError),
|
|
/// Envelope doesn't match latest beacon block header
|
|
LatestBlockHeaderMismatch {
|
|
envelope_root: Hash256,
|
|
block_header_root: Hash256,
|
|
},
|
|
/// Envelope's `parent_beacon_block_root` doesn't match the parent root of the latest
|
|
/// block header.
|
|
ParentBeaconBlockRootMismatch {
|
|
envelope: Hash256,
|
|
state: Hash256,
|
|
},
|
|
/// Envelope doesn't match latest beacon block slot
|
|
SlotMismatch {
|
|
envelope_slot: Slot,
|
|
parent_state_slot: Slot,
|
|
},
|
|
/// The payload withdrawals don't match the state's payload withdrawals.
|
|
WithdrawalsRootMismatch {
|
|
state: Hash256,
|
|
payload: Hash256,
|
|
},
|
|
// The builder index doesn't match the committed bid.
|
|
BuilderIndexMismatch {
|
|
committed_bid: BuilderIndex,
|
|
envelope: BuilderIndex,
|
|
},
|
|
// The gas limit doesn't match the committed bid
|
|
GasLimitMismatch {
|
|
committed_bid: u64,
|
|
envelope: u64,
|
|
},
|
|
// The block hash doesn't match the committed bid
|
|
BlockHashMismatch {
|
|
committed_bid: ExecutionBlockHash,
|
|
envelope: ExecutionBlockHash,
|
|
},
|
|
// The parent hash doesn't match the previous execution payload
|
|
ParentHashMismatch {
|
|
state: ExecutionBlockHash,
|
|
envelope: ExecutionBlockHash,
|
|
},
|
|
// The previous randao didn't match the payload
|
|
PrevRandaoMismatch {
|
|
committed_bid: Hash256,
|
|
envelope: Hash256,
|
|
},
|
|
// The timestamp didn't match the payload
|
|
TimestampMismatch {
|
|
state: u64,
|
|
envelope: u64,
|
|
},
|
|
// The execution requests root doesn't match the committed bid
|
|
ExecutionRequestsRootMismatch {
|
|
committed_bid: Hash256,
|
|
envelope: Hash256,
|
|
},
|
|
/// The envelope was deemed invalid by the execution engine.
|
|
ExecutionInvalid,
|
|
}
|
|
|
|
impl From<BeaconStateError> for EnvelopeProcessingError {
|
|
fn from(e: BeaconStateError) -> Self {
|
|
EnvelopeProcessingError::BeaconStateError(e)
|
|
}
|
|
}
|
|
|
|
impl From<ArithError> for EnvelopeProcessingError {
|
|
fn from(e: ArithError) -> Self {
|
|
EnvelopeProcessingError::ArithError(e)
|
|
}
|
|
}
|
|
|
|
/// Verifies a `SignedExecutionPayloadEnvelope` against the beacon state.
|
|
///
|
|
/// This function performs pure verification with no state mutation. The execution requests
|
|
/// from the envelope are deferred to be processed in the next block via
|
|
/// `process_parent_execution_payload`.
|
|
///
|
|
/// `block_state_root` should be the post-block state root (used to fill in the block header
|
|
/// for beacon_block_root verification). If `None`, the latest_block_header must already have
|
|
/// its state_root filled in.
|
|
pub fn verify_execution_payload_envelope<E: EthSpec>(
|
|
state: &BeaconState<E>,
|
|
signed_envelope: &SignedExecutionPayloadEnvelope<E>,
|
|
verify_signatures: VerifySignatures,
|
|
block_state_root: Hash256,
|
|
spec: &ChainSpec,
|
|
) -> Result<(), EnvelopeProcessingError> {
|
|
if verify_signatures.is_true() && !signed_envelope.verify_signature_with_state(state, spec)? {
|
|
return Err(EnvelopeProcessingError::BadSignature);
|
|
}
|
|
|
|
let envelope = &signed_envelope.message;
|
|
let payload = &envelope.payload;
|
|
|
|
// Verify consistency with the beacon block.
|
|
// Use a copy of the header with state_root filled in, matching the spec's approach.
|
|
let mut header = state.latest_block_header().clone();
|
|
if header.state_root == Hash256::default() {
|
|
// The caller must provide the post-block state root so we can compute
|
|
// the block header root without mutating state.
|
|
header.state_root = block_state_root;
|
|
}
|
|
let latest_block_header_root = header.tree_hash_root();
|
|
envelope_verify!(
|
|
envelope.beacon_block_root == latest_block_header_root,
|
|
EnvelopeProcessingError::LatestBlockHeaderMismatch {
|
|
envelope_root: envelope.beacon_block_root,
|
|
block_header_root: latest_block_header_root,
|
|
}
|
|
);
|
|
envelope_verify!(
|
|
envelope.parent_beacon_block_root == state.latest_block_header().parent_root,
|
|
EnvelopeProcessingError::ParentBeaconBlockRootMismatch {
|
|
envelope: envelope.parent_beacon_block_root,
|
|
state: state.latest_block_header().parent_root,
|
|
}
|
|
);
|
|
envelope_verify!(
|
|
envelope.slot() == state.slot(),
|
|
EnvelopeProcessingError::SlotMismatch {
|
|
envelope_slot: envelope.slot(),
|
|
parent_state_slot: state.slot(),
|
|
}
|
|
);
|
|
|
|
// Verify consistency with the committed bid
|
|
let committed_bid = state.latest_execution_payload_bid()?;
|
|
envelope_verify!(
|
|
envelope.builder_index == committed_bid.builder_index,
|
|
EnvelopeProcessingError::BuilderIndexMismatch {
|
|
committed_bid: committed_bid.builder_index,
|
|
envelope: envelope.builder_index,
|
|
}
|
|
);
|
|
envelope_verify!(
|
|
committed_bid.prev_randao == payload.prev_randao,
|
|
EnvelopeProcessingError::PrevRandaoMismatch {
|
|
committed_bid: committed_bid.prev_randao,
|
|
envelope: payload.prev_randao,
|
|
}
|
|
);
|
|
|
|
// Verify consistency with expected withdrawals
|
|
// NOTE: we don't bother hashing here except in case of error, because we can just compare for
|
|
// equality directly. This equality check could be more straight-forward if the types were
|
|
// changed to match (currently we are comparing VariableList to List). This could happen
|
|
// coincidentally when we adopt ProgressiveList.
|
|
envelope_verify!(
|
|
payload.withdrawals.len() == state.payload_expected_withdrawals()?.len()
|
|
&& payload
|
|
.withdrawals
|
|
.iter()
|
|
.eq(state.payload_expected_withdrawals()?.iter()),
|
|
EnvelopeProcessingError::WithdrawalsRootMismatch {
|
|
state: state.payload_expected_withdrawals()?.tree_hash_root(),
|
|
payload: payload.withdrawals.tree_hash_root(),
|
|
}
|
|
);
|
|
|
|
// Verify the gas limit
|
|
envelope_verify!(
|
|
committed_bid.gas_limit == payload.gas_limit,
|
|
EnvelopeProcessingError::GasLimitMismatch {
|
|
committed_bid: committed_bid.gas_limit,
|
|
envelope: payload.gas_limit,
|
|
}
|
|
);
|
|
|
|
// Verify the block hash
|
|
envelope_verify!(
|
|
committed_bid.block_hash == payload.block_hash,
|
|
EnvelopeProcessingError::BlockHashMismatch {
|
|
committed_bid: committed_bid.block_hash,
|
|
envelope: payload.block_hash,
|
|
}
|
|
);
|
|
|
|
// Verify consistency of the parent hash with respect to the previous execution payload
|
|
envelope_verify!(
|
|
payload.parent_hash == *state.latest_block_hash()?,
|
|
EnvelopeProcessingError::ParentHashMismatch {
|
|
state: *state.latest_block_hash()?,
|
|
envelope: payload.parent_hash,
|
|
}
|
|
);
|
|
|
|
// Verify timestamp
|
|
let state_timestamp = compute_timestamp_at_slot(state, state.slot(), spec)?;
|
|
envelope_verify!(
|
|
payload.timestamp == state_timestamp,
|
|
EnvelopeProcessingError::TimestampMismatch {
|
|
state: state_timestamp,
|
|
envelope: payload.timestamp,
|
|
}
|
|
);
|
|
|
|
// Verify execution requests root matches committed bid
|
|
let execution_requests_root = envelope.execution_requests.tree_hash_root();
|
|
envelope_verify!(
|
|
execution_requests_root == committed_bid.execution_requests_root,
|
|
EnvelopeProcessingError::ExecutionRequestsRootMismatch {
|
|
committed_bid: committed_bid.execution_requests_root,
|
|
envelope: execution_requests_root,
|
|
}
|
|
);
|
|
|
|
// TODO(gloas): newPayload happens here in the spec, ensure we wire that up correctly
|
|
|
|
Ok(())
|
|
}
|