mirror of
https://github.com/sigp/lighthouse.git
synced 2026-05-30 12:47:05 +00:00
Refactor for Organization
This commit is contained in:
@@ -17,9 +17,6 @@
|
|||||||
//! |---------------
|
//! |---------------
|
||||||
//! |
|
//! |
|
||||||
//! ▼
|
//! ▼
|
||||||
//! SignatureVerifiedEnvelope
|
|
||||||
//! |
|
|
||||||
//! ▼
|
|
||||||
//! ExecutionPendingEnvelope
|
//! ExecutionPendingEnvelope
|
||||||
//! |
|
//! |
|
||||||
//! await
|
//! await
|
||||||
@@ -35,27 +32,16 @@ use crate::envelope_verification_types::{EnvelopeImportData, MaybeAvailableEnvel
|
|||||||
use crate::execution_payload::PayloadNotifier;
|
use crate::execution_payload::PayloadNotifier;
|
||||||
use crate::{BeaconChain, BeaconChainError, BeaconChainTypes};
|
use crate::{BeaconChain, BeaconChainError, BeaconChainTypes};
|
||||||
use derivative::Derivative;
|
use derivative::Derivative;
|
||||||
use safe_arith::ArithError;
|
|
||||||
use slot_clock::SlotClock;
|
use slot_clock::SlotClock;
|
||||||
use state_processing::envelope_processing::{EnvelopeProcessingError, envelope_processing};
|
use state_processing::envelope_processing::{EnvelopeProcessingError, envelope_processing};
|
||||||
use state_processing::per_block_processing::compute_timestamp_at_slot;
|
|
||||||
use state_processing::{BlockProcessingError, VerifySignatures};
|
use state_processing::{BlockProcessingError, VerifySignatures};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tree_hash::TreeHash;
|
use tracing::{debug, instrument};
|
||||||
use types::{
|
use types::{
|
||||||
BeaconState, BeaconStateError, ExecutionBlockHash, Hash256, SignedBeaconBlock,
|
BeaconState, BeaconStateError, EthSpec, ExecutionBlockHash, Hash256, SignedBeaconBlock,
|
||||||
SignedExecutionPayloadEnvelope, Slot,
|
SignedExecutionPayloadEnvelope, Slot,
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO(gloas): don't use this redefinition..
|
|
||||||
macro_rules! envelope_verify {
|
|
||||||
($condition: expr, $result: expr) => {
|
|
||||||
if !$condition {
|
|
||||||
return Err($result);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum EnvelopeError {
|
pub enum EnvelopeError {
|
||||||
/// The envelope's block root is unknown.
|
/// The envelope's block root is unknown.
|
||||||
@@ -64,74 +50,33 @@ pub enum EnvelopeError {
|
|||||||
},
|
},
|
||||||
/// The signature is invalid.
|
/// The signature is invalid.
|
||||||
BadSignature,
|
BadSignature,
|
||||||
/// Envelope doesn't match latest beacon block header
|
|
||||||
LatestBlockHeaderMismatch {
|
|
||||||
envelope_root: Hash256,
|
|
||||||
block_header_root: Hash256,
|
|
||||||
},
|
|
||||||
/// The builder index doesn't match the committed bid
|
/// The builder index doesn't match the committed bid
|
||||||
BuilderIndexMismatch {
|
BuilderIndexMismatch {
|
||||||
committed_bid: u64,
|
committed_bid: u64,
|
||||||
envelope: u64,
|
envelope: u64,
|
||||||
},
|
},
|
||||||
/// The blob KZG commitments root doesn't match the committed bid
|
|
||||||
BlobKzgCommitmentsRootMismatch {
|
|
||||||
committed_bid: Hash256,
|
|
||||||
envelope: Hash256,
|
|
||||||
},
|
|
||||||
/// The withdrawals root doesn't match the state's latest withdrawals root
|
|
||||||
WithdrawalsRootMismatch {
|
|
||||||
state: Hash256,
|
|
||||||
envelope: Hash256,
|
|
||||||
},
|
|
||||||
// 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 {
|
|
||||||
state: Hash256,
|
|
||||||
envelope: Hash256,
|
|
||||||
},
|
|
||||||
// The timestamp didn't match the payload
|
|
||||||
TimestampMismatch {
|
|
||||||
state: u64,
|
|
||||||
envelope: u64,
|
|
||||||
},
|
|
||||||
// Blob committments exceeded the maximum
|
|
||||||
BlobLimitExceeded {
|
|
||||||
max: usize,
|
|
||||||
envelope: usize,
|
|
||||||
},
|
|
||||||
// Invalid state root
|
|
||||||
InvalidStateRoot {
|
|
||||||
state: Hash256,
|
|
||||||
envelope: Hash256,
|
|
||||||
},
|
|
||||||
// The slot doesn't match the parent block
|
// The slot doesn't match the parent block
|
||||||
SlotMismatch {
|
SlotMismatch {
|
||||||
parent_block: Slot,
|
parent_block: Slot,
|
||||||
envelope: Slot,
|
envelope: Slot,
|
||||||
},
|
},
|
||||||
|
// The validator index is unknown
|
||||||
|
UnknownValidator {
|
||||||
|
builder_index: u64,
|
||||||
|
},
|
||||||
|
// The block hash doesn't match the committed bid
|
||||||
|
BlockHashMismatch {
|
||||||
|
committed_bid: ExecutionBlockHash,
|
||||||
|
envelope: ExecutionBlockHash,
|
||||||
|
},
|
||||||
// Some Beacon Chain Error
|
// Some Beacon Chain Error
|
||||||
BeaconChainError(Arc<BeaconChainError>),
|
BeaconChainError(Arc<BeaconChainError>),
|
||||||
// Some Beacon State error
|
// Some Beacon State error
|
||||||
BeaconStateError(BeaconStateError),
|
BeaconStateError(BeaconStateError),
|
||||||
// Some ArithError
|
|
||||||
ArithError(ArithError),
|
|
||||||
// Some BlockProcessingError (for electra operations)
|
// Some BlockProcessingError (for electra operations)
|
||||||
BlockProcessingError(BlockProcessingError),
|
BlockProcessingError(BlockProcessingError),
|
||||||
|
// Some EnvelopeProcessingError
|
||||||
|
EnvelopeProcessingError(EnvelopeProcessingError),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<BeaconChainError> for EnvelopeError {
|
impl From<BeaconChainError> for EnvelopeError {
|
||||||
@@ -146,24 +91,120 @@ impl From<BeaconStateError> for EnvelopeError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ArithError> for EnvelopeError {
|
/// Pull errors up from EnvelopeProcessingError to EnvelopeError
|
||||||
fn from(e: ArithError) -> Self {
|
|
||||||
EnvelopeError::ArithError(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<EnvelopeProcessingError> for EnvelopeError {
|
impl From<EnvelopeProcessingError> for EnvelopeError {
|
||||||
fn from(e: EnvelopeProcessingError) -> Self {
|
fn from(e: EnvelopeProcessingError) -> Self {
|
||||||
match e {
|
match e {
|
||||||
EnvelopeProcessingError::BadSignature => EnvelopeError::BadSignature,
|
EnvelopeProcessingError::BadSignature => EnvelopeError::BadSignature,
|
||||||
EnvelopeProcessingError::BeaconStateError(e) => EnvelopeError::BeaconStateError(e),
|
EnvelopeProcessingError::BeaconStateError(e) => EnvelopeError::BeaconStateError(e),
|
||||||
|
EnvelopeProcessingError::BlockHashMismatch {
|
||||||
|
committed_bid,
|
||||||
|
envelope,
|
||||||
|
} => EnvelopeError::BlockHashMismatch {
|
||||||
|
committed_bid,
|
||||||
|
envelope,
|
||||||
|
},
|
||||||
EnvelopeProcessingError::BlockProcessingError(e) => {
|
EnvelopeProcessingError::BlockProcessingError(e) => {
|
||||||
EnvelopeError::BlockProcessingError(e)
|
EnvelopeError::BlockProcessingError(e)
|
||||||
}
|
}
|
||||||
|
e => EnvelopeError::EnvelopeProcessingError(e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This snapshot is to be used for verifying a envelope of the block.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct EnvelopeProcessingSnapshot<E: EthSpec> {
|
||||||
|
/// This state is equivalent to the `self.beacon_block.state_root()` before applying the envelope.
|
||||||
|
pub pre_state: BeaconState<E>,
|
||||||
|
pub state_root: Hash256,
|
||||||
|
pub beacon_block_root: Hash256,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
|
#[instrument(skip_all, level = "debug", fields(beacon_block_root = %envelope.beacon_block_root()))]
|
||||||
|
fn load_snapshot<T: BeaconChainTypes>(
|
||||||
|
envelope: &SignedExecutionPayloadEnvelope<T::EthSpec>,
|
||||||
|
chain: &BeaconChain<T>,
|
||||||
|
) -> Result<EnvelopeProcessingSnapshot<T::EthSpec>, EnvelopeError> {
|
||||||
|
// Reject any block if its parent is not known to fork choice.
|
||||||
|
//
|
||||||
|
// A block that is not in fork choice is either:
|
||||||
|
//
|
||||||
|
// - Not yet imported: we should reject this block because we should only import a child
|
||||||
|
// after its parent has been fully imported.
|
||||||
|
// - Pre-finalized: if the parent block is _prior_ to finalization, we should ignore it
|
||||||
|
// 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 beacon_block_root = envelope.beacon_block_root();
|
||||||
|
if !chain
|
||||||
|
.canonical_head
|
||||||
|
.fork_choice_read_lock()
|
||||||
|
.contains_block(&beacon_block_root)
|
||||||
|
{
|
||||||
|
return Err(EnvelopeError::BlockRootUnknown {
|
||||||
|
block_root: beacon_block_root,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let fork_choice_read_lock = chain.canonical_head.fork_choice_read_lock();
|
||||||
|
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(gloas): add metrics here
|
||||||
|
|
||||||
|
let result = {
|
||||||
|
// Load the parent block's state from the database, returning an error if it is not found.
|
||||||
|
// It is an error because if we know the parent block we should also know the parent state.
|
||||||
|
// Retrieve any state that is advanced through to at most `block.slot()`: this is
|
||||||
|
// particularly important if `block` descends from the finalized/split block, but at a slot
|
||||||
|
// prior to the finalized slot (which is invalid and inaccessible in our DB schema).
|
||||||
|
let (parent_state_root, state) = chain
|
||||||
|
.store
|
||||||
|
// TODO(gloas): the state doesn't need to be advanced here because we're applying an envelope
|
||||||
|
// but this function does use a lot of caches that could be more efficient. Is there
|
||||||
|
// a better way to do this?
|
||||||
|
.get_advanced_hot_state(
|
||||||
|
beacon_block_root,
|
||||||
|
proto_beacon_block.slot,
|
||||||
|
proto_beacon_block.state_root,
|
||||||
|
)
|
||||||
|
.map_err(|e| EnvelopeError::BeaconChainError(Arc::new(e.into())))?
|
||||||
|
.ok_or_else(|| {
|
||||||
|
BeaconChainError::DBInconsistent(format!(
|
||||||
|
"Missing state for parent block {beacon_block_root:?}",
|
||||||
|
))
|
||||||
|
})?;
|
||||||
|
|
||||||
|
if state.slot() == proto_beacon_block.slot {
|
||||||
|
// Sanity check.
|
||||||
|
if parent_state_root != proto_beacon_block.state_root {
|
||||||
|
return Err(BeaconChainError::DBInconsistent(format!(
|
||||||
|
"Parent state at slot {} has the wrong state root: {:?} != {:?}",
|
||||||
|
state.slot(),
|
||||||
|
parent_state_root,
|
||||||
|
proto_beacon_block.state_root,
|
||||||
|
))
|
||||||
|
.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(EnvelopeProcessingSnapshot {
|
||||||
|
pre_state: state,
|
||||||
|
state_root: parent_state_root,
|
||||||
|
beacon_block_root,
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
/// 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
|
||||||
/// the p2p network.
|
/// the p2p network.
|
||||||
#[derive(Derivative)]
|
#[derive(Derivative)]
|
||||||
@@ -171,7 +212,7 @@ impl From<EnvelopeProcessingError> for EnvelopeError {
|
|||||||
pub struct GossipVerifiedEnvelope<T: BeaconChainTypes> {
|
pub struct GossipVerifiedEnvelope<T: BeaconChainTypes> {
|
||||||
pub signed_envelope: Arc<SignedExecutionPayloadEnvelope<T::EthSpec>>,
|
pub signed_envelope: Arc<SignedExecutionPayloadEnvelope<T::EthSpec>>,
|
||||||
pub parent_block: Arc<SignedBeaconBlock<T::EthSpec>>,
|
pub parent_block: Arc<SignedBeaconBlock<T::EthSpec>>,
|
||||||
pub pre_state: Box<BeaconState<T::EthSpec>>,
|
pub parent: Option<Box<EnvelopeProcessingSnapshot<T::EthSpec>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: BeaconChainTypes> GossipVerifiedEnvelope<T> {
|
impl<T: BeaconChainTypes> GossipVerifiedEnvelope<T> {
|
||||||
@@ -181,29 +222,43 @@ impl<T: BeaconChainTypes> GossipVerifiedEnvelope<T> {
|
|||||||
) -> Result<Self, EnvelopeError> {
|
) -> Result<Self, EnvelopeError> {
|
||||||
let envelope = signed_envelope.message();
|
let envelope = signed_envelope.message();
|
||||||
let payload = envelope.payload();
|
let payload = envelope.payload();
|
||||||
let block_root = envelope.beacon_block_root();
|
let beacon_block_root = envelope.beacon_block_root();
|
||||||
|
|
||||||
|
// check that we've seen the parent block of this envelope and that it passes validation
|
||||||
// TODO(gloas): this check would fail if the block didn't pass validation right?
|
// TODO(gloas): this check would fail if the block didn't pass validation right?
|
||||||
|
|
||||||
// check that we've seen the parent block of this envelope
|
|
||||||
let fork_choice_read_lock = chain.canonical_head.fork_choice_read_lock();
|
let fork_choice_read_lock = chain.canonical_head.fork_choice_read_lock();
|
||||||
if !fork_choice_read_lock.contains_block(&block_root) {
|
let Some(parent_proto_block) = fork_choice_read_lock.get_block(&beacon_block_root) else {
|
||||||
return Err(EnvelopeError::BlockRootUnknown { block_root });
|
return Err(EnvelopeError::BlockRootUnknown {
|
||||||
}
|
block_root: beacon_block_root,
|
||||||
|
});
|
||||||
|
};
|
||||||
drop(fork_choice_read_lock);
|
drop(fork_choice_read_lock);
|
||||||
|
|
||||||
|
// TODO(gloas): check that we haven't seen another valid `SignedExecutionPayloadEnvelope`
|
||||||
|
// for this block root from this builder - envelope status table check
|
||||||
|
|
||||||
|
// TODO(gloas): this should probably 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 parent_block = chain
|
let parent_block = chain
|
||||||
.get_full_block(&block_root)?
|
.get_full_block(&beacon_block_root)?
|
||||||
.ok_or_else(|| EnvelopeError::from(BeaconChainError::MissingBeaconBlock(block_root)))
|
.ok_or_else(|| {
|
||||||
|
EnvelopeError::from(BeaconChainError::MissingBeaconBlock(beacon_block_root))
|
||||||
|
})
|
||||||
.map(Arc::new)?;
|
.map(Arc::new)?;
|
||||||
let execution_bid = &parent_block
|
let execution_bid = &parent_block
|
||||||
.message()
|
.message()
|
||||||
.body()
|
.body()
|
||||||
.signed_execution_bid()?
|
.signed_execution_payload_bid()?
|
||||||
.message;
|
.message;
|
||||||
|
|
||||||
// TODO(gloas): check we're within the bounds of the slot (probably)
|
// TODO(gloas): Gossip rules for the beacon block contain the following:
|
||||||
// I think a timestamp check like this is on the beacon block but need to check.
|
// 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 slot of the envelope matches the slot of the parent block
|
||||||
if envelope.slot() != parent_block.slot() {
|
if envelope.slot() != parent_block.slot() {
|
||||||
return Err(EnvelopeError::SlotMismatch {
|
return Err(EnvelopeError::SlotMismatch {
|
||||||
parent_block: parent_block.slot(),
|
parent_block: parent_block.slot(),
|
||||||
@@ -211,9 +266,6 @@ impl<T: BeaconChainTypes> GossipVerifiedEnvelope<T> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(gloas): check that we haven't seen another valid `SignedExecutionPayloadEnvelope`
|
|
||||||
// for this block root from this builder - envelope status table check
|
|
||||||
|
|
||||||
// builder index matches committed bid
|
// builder index matches committed bid
|
||||||
if envelope.builder_index() != execution_bid.builder_index {
|
if envelope.builder_index() != execution_bid.builder_index {
|
||||||
return Err(EnvelopeError::BuilderIndexMismatch {
|
return Err(EnvelopeError::BuilderIndexMismatch {
|
||||||
@@ -230,29 +282,59 @@ impl<T: BeaconChainTypes> GossipVerifiedEnvelope<T> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(gloas): expensive load here.. check this
|
// TODO(gloas): check these assumptions.. exactly what the most efficient way to verify the signatures
|
||||||
let parent_state = chain
|
// in this case isn't clear. There are questions about the proposer cache, the pubkey cache,
|
||||||
// TODO(gloas): may need a get_block_state to get the right state here..
|
// and so on.
|
||||||
.get_state(
|
|
||||||
&parent_block.message().state_root(),
|
|
||||||
Some(parent_block.slot()),
|
|
||||||
true,
|
|
||||||
)?
|
|
||||||
.ok_or_else(|| {
|
|
||||||
EnvelopeError::from(BeaconChainError::MissingBeaconState(
|
|
||||||
parent_block.message().state_root(),
|
|
||||||
))
|
|
||||||
})?;
|
|
||||||
|
|
||||||
// verify the signature
|
// get the fork from the cache so we can verify the signature
|
||||||
if !signed_envelope.verify_signature(&parent_state, &chain.spec)? {
|
let block_slot = envelope.slot();
|
||||||
|
let block_epoch = block_slot.epoch(T::EthSpec::slots_per_epoch());
|
||||||
|
let proposer_shuffling_decision_block =
|
||||||
|
parent_proto_block.proposer_shuffling_root_for_child_block(block_epoch, &chain.spec);
|
||||||
|
let mut opt_parent = None;
|
||||||
|
let envelope_ref = signed_envelope.as_ref();
|
||||||
|
let proposer = chain.with_proposer_cache::<_, EnvelopeError>(
|
||||||
|
proposer_shuffling_decision_block,
|
||||||
|
block_epoch,
|
||||||
|
|proposers| proposers.get_slot::<T::EthSpec>(block_slot),
|
||||||
|
|| {
|
||||||
|
debug!(
|
||||||
|
%beacon_block_root,
|
||||||
|
block_hash = %envelope_ref.block_hash(),
|
||||||
|
"Proposer shuffling cache miss for envelope verification"
|
||||||
|
);
|
||||||
|
// The proposer index was *not* cached and we must load the parent in order to
|
||||||
|
// determine the proposer index.
|
||||||
|
let snapshot = load_snapshot(envelope_ref, chain)?;
|
||||||
|
opt_parent = Some(Box::new(snapshot.clone()));
|
||||||
|
Ok((snapshot.state_root, snapshot.pre_state))
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
let fork = proposer.fork;
|
||||||
|
|
||||||
|
let signature_is_valid = {
|
||||||
|
let pubkey_cache = chain.validator_pubkey_cache.read();
|
||||||
|
let builder_pubkey = pubkey_cache
|
||||||
|
.get(envelope.builder_index() as usize)
|
||||||
|
.ok_or_else(|| EnvelopeError::UnknownValidator {
|
||||||
|
builder_index: envelope.builder_index(),
|
||||||
|
})?;
|
||||||
|
signed_envelope.verify_signature(
|
||||||
|
&builder_pubkey,
|
||||||
|
&fork,
|
||||||
|
chain.genesis_validators_root,
|
||||||
|
&chain.spec,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
if !signature_is_valid {
|
||||||
return Err(EnvelopeError::BadSignature);
|
return Err(EnvelopeError::BadSignature);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
signed_envelope,
|
signed_envelope,
|
||||||
parent_block,
|
parent_block,
|
||||||
pre_state: Box::new(parent_state),
|
parent: opt_parent,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -285,103 +367,6 @@ impl<T: BeaconChainTypes> IntoExecutionPendingEnvelope<T> for GossipVerifiedEnve
|
|||||||
let envelope = signed_envelope.message();
|
let envelope = signed_envelope.message();
|
||||||
let payload = &envelope.payload();
|
let payload = &envelope.payload();
|
||||||
|
|
||||||
// verify signature already done
|
|
||||||
let mut state = *self.pre_state;
|
|
||||||
|
|
||||||
// all state modifications are done in envelope_processing (called at the bottom of this function)
|
|
||||||
// so here perform the consistency check with the beacon block on a copy of the latest block header
|
|
||||||
// and let it be modified later in envelope_processing
|
|
||||||
let previous_state_root = state.canonical_root()?;
|
|
||||||
if state.latest_block_header().state_root == Hash256::default() {
|
|
||||||
let mut copy_of_latest_block_header = state.latest_block_header().clone();
|
|
||||||
copy_of_latest_block_header.state_root = previous_state_root;
|
|
||||||
|
|
||||||
// Verify consistency with the beacon block
|
|
||||||
if !envelope.beacon_block_root() == copy_of_latest_block_header.tree_hash_root() {
|
|
||||||
return Err(EnvelopeError::LatestBlockHeaderMismatch {
|
|
||||||
envelope_root: envelope.beacon_block_root(),
|
|
||||||
block_header_root: copy_of_latest_block_header.tree_hash_root(),
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// the check about the slots matching is already done in the GossipVerifiedEnvelope
|
|
||||||
|
|
||||||
// Verify consistency with the committed bid
|
|
||||||
let committed_bid = state.latest_execution_bid()?;
|
|
||||||
// builder index match already verified
|
|
||||||
if committed_bid.blob_kzg_commitments_root
|
|
||||||
!= envelope.blob_kzg_commitments().tree_hash_root()
|
|
||||||
{
|
|
||||||
return Err(EnvelopeError::BlobKzgCommitmentsRootMismatch {
|
|
||||||
committed_bid: committed_bid.blob_kzg_commitments_root,
|
|
||||||
envelope: envelope.blob_kzg_commitments().tree_hash_root(),
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Verify the withdrawals root
|
|
||||||
envelope_verify!(
|
|
||||||
payload.withdrawals()?.tree_hash_root() == *state.latest_withdrawals_root()?,
|
|
||||||
EnvelopeError::WithdrawalsRootMismatch {
|
|
||||||
state: *state.latest_withdrawals_root()?,
|
|
||||||
envelope: payload.withdrawals()?.tree_hash_root(),
|
|
||||||
}
|
|
||||||
.into()
|
|
||||||
);
|
|
||||||
|
|
||||||
// Verify the gas limit
|
|
||||||
envelope_verify!(
|
|
||||||
payload.gas_limit() == committed_bid.gas_limit,
|
|
||||||
EnvelopeError::GasLimitMismatch {
|
|
||||||
committed_bid: committed_bid.gas_limit,
|
|
||||||
envelope: payload.gas_limit(),
|
|
||||||
}
|
|
||||||
.into()
|
|
||||||
);
|
|
||||||
// Verify the block hash already done in the GossipVerifiedEnvelope
|
|
||||||
|
|
||||||
// Verify consistency of the parent hash with respect to the previous execution payload
|
|
||||||
envelope_verify!(
|
|
||||||
payload.parent_hash() == *state.latest_block_hash()?,
|
|
||||||
EnvelopeError::ParentHashMismatch {
|
|
||||||
state: *state.latest_block_hash()?,
|
|
||||||
envelope: payload.parent_hash(),
|
|
||||||
}
|
|
||||||
.into()
|
|
||||||
);
|
|
||||||
|
|
||||||
// Verify prev_randao
|
|
||||||
envelope_verify!(
|
|
||||||
payload.prev_randao() == *state.get_randao_mix(state.current_epoch())?,
|
|
||||||
EnvelopeError::PrevRandaoMismatch {
|
|
||||||
state: *state.get_randao_mix(state.current_epoch())?,
|
|
||||||
envelope: payload.prev_randao(),
|
|
||||||
}
|
|
||||||
.into()
|
|
||||||
);
|
|
||||||
|
|
||||||
// Verify the timestamp
|
|
||||||
let state_timestamp = compute_timestamp_at_slot(&state, state.slot(), chain.spec.as_ref())?;
|
|
||||||
envelope_verify!(
|
|
||||||
payload.timestamp() == state_timestamp,
|
|
||||||
EnvelopeError::TimestampMismatch {
|
|
||||||
state: state_timestamp,
|
|
||||||
envelope: payload.timestamp(),
|
|
||||||
}
|
|
||||||
.into()
|
|
||||||
);
|
|
||||||
|
|
||||||
// Verify the commitments are under limit
|
|
||||||
let max_blobs = chain.spec.max_blobs_per_block(state.current_epoch()) as usize;
|
|
||||||
envelope_verify!(
|
|
||||||
envelope.blob_kzg_commitments().len() <= max_blobs,
|
|
||||||
EnvelopeError::BlobLimitExceeded {
|
|
||||||
max: max_blobs,
|
|
||||||
envelope: envelope.blob_kzg_commitments().len(),
|
|
||||||
}
|
|
||||||
.into()
|
|
||||||
);
|
|
||||||
|
|
||||||
// Verify the execution payload is valid
|
// Verify the execution payload is valid
|
||||||
let payload_notifier =
|
let payload_notifier =
|
||||||
PayloadNotifier::from_envelope(chain.clone(), envelope, notify_execution_layer)?;
|
PayloadNotifier::from_envelope(chain.clone(), envelope, notify_execution_layer)?;
|
||||||
@@ -390,7 +375,7 @@ impl<T: BeaconChainTypes> IntoExecutionPendingEnvelope<T> for GossipVerifiedEnve
|
|||||||
|
|
||||||
let payload_verification_future = async move {
|
let payload_verification_future = async move {
|
||||||
let chain = payload_notifier.chain.clone();
|
let chain = payload_notifier.chain.clone();
|
||||||
// TODO:(gloas): timing
|
// TODO:(gloas): timing metrics
|
||||||
if let Some(started_execution) = chain.slot_clock.now_duration() {
|
if let Some(started_execution) = chain.slot_clock.now_duration() {
|
||||||
chain.block_times_cache.write().set_time_started_execution(
|
chain.block_times_cache.write().set_time_started_execution(
|
||||||
block_root,
|
block_root,
|
||||||
@@ -417,23 +402,23 @@ impl<T: BeaconChainTypes> IntoExecutionPendingEnvelope<T> for GossipVerifiedEnve
|
|||||||
)
|
)
|
||||||
.ok_or(BeaconChainError::RuntimeShutdown)?;
|
.ok_or(BeaconChainError::RuntimeShutdown)?;
|
||||||
|
|
||||||
|
let parent = if let Some(snapshot) = self.parent {
|
||||||
|
*snapshot
|
||||||
|
} else {
|
||||||
|
load_snapshot(signed_envelope.as_ref(), chain)?
|
||||||
|
};
|
||||||
|
let mut state = parent.pre_state;
|
||||||
|
|
||||||
// All the state modifications are done in envelope_processing
|
// All the state modifications are done in envelope_processing
|
||||||
envelope_processing(
|
envelope_processing(
|
||||||
&mut state,
|
&mut state,
|
||||||
|
Some(parent.state_root),
|
||||||
&signed_envelope,
|
&signed_envelope,
|
||||||
|
// verify signature already done for GossipVerifiedEnvelope
|
||||||
VerifySignatures::False,
|
VerifySignatures::False,
|
||||||
&chain.spec,
|
&chain.spec,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// TODO(gloas): if verify
|
|
||||||
envelope_verify!(
|
|
||||||
state.canonical_root()? == envelope.state_root(),
|
|
||||||
EnvelopeError::InvalidStateRoot {
|
|
||||||
state: state.canonical_root()?,
|
|
||||||
envelope: envelope.state_root(),
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(ExecutionPendingEnvelope {
|
Ok(ExecutionPendingEnvelope {
|
||||||
signed_envelope: MaybeAvailableEnvelope::AvailabilityPending {
|
signed_envelope: MaybeAvailableEnvelope::AvailabilityPending {
|
||||||
block_hash: payload.block_hash(),
|
block_hash: payload.block_hash(),
|
||||||
|
|||||||
@@ -1,18 +1,91 @@
|
|||||||
use crate::BlockProcessingError;
|
use crate::BlockProcessingError;
|
||||||
use crate::VerifySignatures;
|
use crate::VerifySignatures;
|
||||||
|
use crate::per_block_processing::compute_timestamp_at_slot;
|
||||||
use crate::per_block_processing::process_operations::{
|
use crate::per_block_processing::process_operations::{
|
||||||
process_consolidation_requests, process_deposit_requests, process_withdrawal_requests,
|
process_consolidation_requests, process_deposit_requests, process_withdrawal_requests,
|
||||||
};
|
};
|
||||||
|
use safe_arith::{ArithError, SafeArith};
|
||||||
|
use tree_hash::TreeHash;
|
||||||
use types::{
|
use types::{
|
||||||
BeaconState, BeaconStateError, ChainSpec, EthSpec, Hash256, SignedExecutionPayloadEnvelope,
|
BeaconState, BeaconStateError, BuilderPendingPayment, ChainSpec, EthSpec, ExecutionBlockHash,
|
||||||
|
Hash256, SignedExecutionPayloadEnvelope, Slot,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
// TODO(gloas): don't use this redefinition..
|
||||||
|
macro_rules! envelope_verify {
|
||||||
|
($condition: expr, $result: expr) => {
|
||||||
|
if !$condition {
|
||||||
|
return Err($result);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
pub enum EnvelopeProcessingError {
|
pub enum EnvelopeProcessingError {
|
||||||
/// Bad Signature
|
/// Bad Signature
|
||||||
BadSignature,
|
BadSignature,
|
||||||
BeaconStateError(BeaconStateError),
|
BeaconStateError(BeaconStateError),
|
||||||
BlockProcessingError(BlockProcessingError),
|
BlockProcessingError(BlockProcessingError),
|
||||||
|
ArithError(ArithError),
|
||||||
|
/// Envelope doesn't match latest beacon block header
|
||||||
|
LatestBlockHeaderMismatch {
|
||||||
|
envelope_root: Hash256,
|
||||||
|
block_header_root: Hash256,
|
||||||
|
},
|
||||||
|
/// Envelope doesn't match latest beacon block slot
|
||||||
|
SlotMismatch {
|
||||||
|
envelope_slot: Slot,
|
||||||
|
parent_state_slot: Slot,
|
||||||
|
},
|
||||||
|
/// The withdrawals root doesn't match the state's latest withdrawals root
|
||||||
|
WithdrawalsRootMismatch {
|
||||||
|
state: Hash256,
|
||||||
|
envelope: Hash256,
|
||||||
|
},
|
||||||
|
// 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 blob KZG commitments root doesn't match the committed bid
|
||||||
|
BlobKzgCommitmentsRootMismatch {
|
||||||
|
committed_bid: Hash256,
|
||||||
|
envelope: Hash256,
|
||||||
|
},
|
||||||
|
// The previous randao didn't match the payload
|
||||||
|
PrevRandaoMismatch {
|
||||||
|
state: Hash256,
|
||||||
|
envelope: Hash256,
|
||||||
|
},
|
||||||
|
// The timestamp didn't match the payload
|
||||||
|
TimestampMismatch {
|
||||||
|
state: u64,
|
||||||
|
envelope: u64,
|
||||||
|
},
|
||||||
|
// Blob committments exceeded the maximum
|
||||||
|
BlobLimitExceeded {
|
||||||
|
max: usize,
|
||||||
|
envelope: usize,
|
||||||
|
},
|
||||||
|
// Invalid state root
|
||||||
|
InvalidStateRoot {
|
||||||
|
state: Hash256,
|
||||||
|
envelope: Hash256,
|
||||||
|
},
|
||||||
|
// BitFieldError
|
||||||
|
BitFieldError(ssz::BitfieldError),
|
||||||
|
// Some kind of error calculating the builder payment index
|
||||||
|
BuilderPaymentIndexOutOfBounds(usize),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<BeaconStateError> for EnvelopeProcessingError {
|
impl From<BeaconStateError> for EnvelopeProcessingError {
|
||||||
@@ -27,39 +100,185 @@ impl From<BlockProcessingError> for EnvelopeProcessingError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<ArithError> for EnvelopeProcessingError {
|
||||||
|
fn from(e: ArithError) -> Self {
|
||||||
|
EnvelopeProcessingError::ArithError(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Processes a `SignedExecutionPayloadEnvelope`
|
/// Processes a `SignedExecutionPayloadEnvelope`
|
||||||
///
|
///
|
||||||
/// This function does all the state modifications inside `process_execution_payload()`
|
/// This function does all the state modifications inside `process_execution_payload()`
|
||||||
pub fn envelope_processing<E: EthSpec>(
|
pub fn envelope_processing<E: EthSpec>(
|
||||||
state: &mut BeaconState<E>,
|
state: &mut BeaconState<E>,
|
||||||
|
parent_state_root: Option<Hash256>,
|
||||||
signed_envelope: &SignedExecutionPayloadEnvelope<E>,
|
signed_envelope: &SignedExecutionPayloadEnvelope<E>,
|
||||||
verify_signatures: VerifySignatures,
|
verify_signatures: VerifySignatures,
|
||||||
spec: &ChainSpec,
|
spec: &ChainSpec,
|
||||||
) -> Result<(), EnvelopeProcessingError> {
|
) -> Result<(), EnvelopeProcessingError> {
|
||||||
if verify_signatures.is_true() {
|
if verify_signatures.is_true() {
|
||||||
// Verify Signed Envelope Signature
|
// Verify Signed Envelope Signature
|
||||||
if !signed_envelope.verify_signature(&state, spec)? {
|
// TODO(gloas): there is probably a more efficient way to do this..
|
||||||
|
if !signed_envelope.verify_signature_with_state(&state, spec)? {
|
||||||
return Err(EnvelopeProcessingError::BadSignature);
|
return Err(EnvelopeProcessingError::BadSignature);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cache latest block header state root
|
|
||||||
let previous_state_root = state.canonical_root()?;
|
|
||||||
if state.latest_block_header().state_root == Hash256::default() {
|
|
||||||
state.latest_block_header_mut().state_root = previous_state_root;
|
|
||||||
}
|
|
||||||
|
|
||||||
// process electra operations
|
|
||||||
let envelope = signed_envelope.message();
|
let envelope = signed_envelope.message();
|
||||||
let payload = envelope.payload();
|
let payload = envelope.payload();
|
||||||
let execution_requests = envelope.execution_requests();
|
let execution_requests = envelope.execution_requests();
|
||||||
|
|
||||||
|
// Cache latest block header state root
|
||||||
|
if state.latest_block_header().state_root == Hash256::default() {
|
||||||
|
let previous_state_root = parent_state_root
|
||||||
|
.map(Ok)
|
||||||
|
.unwrap_or_else(|| state.canonical_root())?;
|
||||||
|
state.latest_block_header_mut().state_root = previous_state_root;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify consistency with the beacon block
|
||||||
|
envelope_verify!(
|
||||||
|
envelope.beacon_block_root() == state.latest_block_header().tree_hash_root(),
|
||||||
|
EnvelopeProcessingError::LatestBlockHeaderMismatch {
|
||||||
|
envelope_root: envelope.beacon_block_root(),
|
||||||
|
block_header_root: state.latest_block_header().tree_hash_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()?;
|
||||||
|
// builder index match already verified
|
||||||
|
if committed_bid.blob_kzg_commitments_root != envelope.blob_kzg_commitments().tree_hash_root() {
|
||||||
|
return Err(EnvelopeProcessingError::BlobKzgCommitmentsRootMismatch {
|
||||||
|
committed_bid: committed_bid.blob_kzg_commitments_root,
|
||||||
|
envelope: envelope.blob_kzg_commitments().tree_hash_root(),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Verify the withdrawals root
|
||||||
|
envelope_verify!(
|
||||||
|
payload.withdrawals()?.tree_hash_root() == *state.latest_withdrawals_root()?,
|
||||||
|
EnvelopeProcessingError::WithdrawalsRootMismatch {
|
||||||
|
state: *state.latest_withdrawals_root()?,
|
||||||
|
envelope: payload.withdrawals()?.tree_hash_root(),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Verify the gas limit
|
||||||
|
envelope_verify!(
|
||||||
|
payload.gas_limit() == committed_bid.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 prev_randao
|
||||||
|
envelope_verify!(
|
||||||
|
payload.prev_randao() == *state.get_randao_mix(state.current_epoch())?,
|
||||||
|
EnvelopeProcessingError::PrevRandaoMismatch {
|
||||||
|
state: *state.get_randao_mix(state.current_epoch())?,
|
||||||
|
envelope: payload.prev_randao(),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
);
|
||||||
|
|
||||||
|
// Verify the 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(),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
);
|
||||||
|
|
||||||
|
// Verify the commitments are under limit
|
||||||
|
let max_blobs = spec.max_blobs_per_block(state.current_epoch()) as usize;
|
||||||
|
envelope_verify!(
|
||||||
|
envelope.blob_kzg_commitments().len() <= max_blobs,
|
||||||
|
EnvelopeProcessingError::BlobLimitExceeded {
|
||||||
|
max: max_blobs,
|
||||||
|
envelope: envelope.blob_kzg_commitments().len(),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
);
|
||||||
|
|
||||||
|
// process electra operations
|
||||||
process_deposit_requests(state, &execution_requests.deposits, spec)?;
|
process_deposit_requests(state, &execution_requests.deposits, spec)?;
|
||||||
process_withdrawal_requests(state, &execution_requests.withdrawals, spec)?;
|
process_withdrawal_requests(state, &execution_requests.withdrawals, spec)?;
|
||||||
process_consolidation_requests(state, &execution_requests.consolidations, spec)?;
|
process_consolidation_requests(state, &execution_requests.consolidations, spec)?;
|
||||||
|
|
||||||
// cache the latest block hash and full slot
|
// queue the builder payment
|
||||||
|
let payment_index = E::slots_per_epoch()
|
||||||
|
.safe_add(state.slot().as_u64().safe_rem(E::slots_per_epoch())?)?
|
||||||
|
as usize;
|
||||||
|
let mut payment = state
|
||||||
|
.builder_pending_payments()?
|
||||||
|
.get(payment_index)
|
||||||
|
.ok_or_else(|| EnvelopeProcessingError::BuilderPaymentIndexOutOfBounds(payment_index))?
|
||||||
|
.clone();
|
||||||
|
let amount = payment.withdrawal.amount;
|
||||||
|
if amount > 0 {
|
||||||
|
let exit_queue_epoch = state.compute_exit_epoch_and_update_churn(amount, spec)?;
|
||||||
|
payment.withdrawal.withdrawable_epoch =
|
||||||
|
exit_queue_epoch.safe_add(spec.min_validator_withdrawability_delay)?;
|
||||||
|
state
|
||||||
|
.builder_pending_withdrawals_mut()?
|
||||||
|
.push(payment.withdrawal)
|
||||||
|
.map_err(|e| EnvelopeProcessingError::BeaconStateError(e.into()))?;
|
||||||
|
}
|
||||||
|
*state
|
||||||
|
.builder_pending_payments_mut()?
|
||||||
|
.get_mut(payment_index)
|
||||||
|
.ok_or_else(|| EnvelopeProcessingError::BuilderPaymentIndexOutOfBounds(payment_index))? =
|
||||||
|
BuilderPendingPayment::default();
|
||||||
|
|
||||||
|
// cache the execution payload hash
|
||||||
|
let availability_index = state
|
||||||
|
.slot()
|
||||||
|
.safe_rem(E::slots_per_historical_root() as u64)?
|
||||||
|
.as_usize();
|
||||||
|
state
|
||||||
|
.execution_payload_availability_mut()?
|
||||||
|
.set(availability_index, true)
|
||||||
|
.map_err(|e| EnvelopeProcessingError::BitFieldError(e))?;
|
||||||
*state.latest_block_hash_mut()? = payload.block_hash();
|
*state.latest_block_hash_mut()? = payload.block_hash();
|
||||||
|
|
||||||
todo!("the rest of process_execution_payload()");
|
// verify the state root
|
||||||
//Ok(())
|
envelope_verify!(
|
||||||
|
envelope.state_root() == state.canonical_root()?,
|
||||||
|
EnvelopeProcessingError::InvalidStateRoot {
|
||||||
|
state: state.canonical_root()?,
|
||||||
|
envelope: envelope.state_root(),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,6 +69,10 @@ impl<'a, E: EthSpec> ExecutionPayloadEnvelopeRef<'a, E> {
|
|||||||
Self::NextFork(envelope) => ExecutionPayloadRef::Gloas(&envelope.payload),
|
Self::NextFork(envelope) => ExecutionPayloadRef::Gloas(&envelope.payload),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn block_hash(&self) -> ExecutionBlockHash {
|
||||||
|
self.payload().block_hash()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'de, E: EthSpec> ContextDeserialize<'de, ForkName> for ExecutionPayloadEnvelope<E> {
|
impl<'de, E: EthSpec> ContextDeserialize<'de, ForkName> for ExecutionPayloadEnvelope<E> {
|
||||||
|
|||||||
@@ -75,11 +75,28 @@ impl<E: EthSpec> SignedExecutionPayloadEnvelope<E> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn slot(&self) -> Slot {
|
||||||
|
self.message().slot()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn epoch(&self) -> Epoch {
|
||||||
|
self.slot().epoch(E::slots_per_epoch())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn beacon_block_root(&self) -> Hash256 {
|
||||||
|
self.message().beacon_block_root()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn block_hash(&self) -> ExecutionBlockHash {
|
||||||
|
self.message().block_hash()
|
||||||
|
}
|
||||||
|
|
||||||
/// Verify `self.signature`.
|
/// Verify `self.signature`.
|
||||||
///
|
///
|
||||||
/// The `parent_state` is the post-state of the beacon block with
|
/// The `parent_state` is the post-state of the beacon block with
|
||||||
/// block_root = self.message.beacon_block_root
|
/// block_root = self.message.beacon_block_root
|
||||||
pub fn verify_signature(
|
/// todo(gloas): maybe delete this function later
|
||||||
|
pub fn verify_signature_with_state(
|
||||||
&self,
|
&self,
|
||||||
parent_state: &BeaconState<E>,
|
parent_state: &BeaconState<E>,
|
||||||
spec: &ChainSpec,
|
spec: &ChainSpec,
|
||||||
@@ -104,6 +121,29 @@ impl<E: EthSpec> SignedExecutionPayloadEnvelope<E> {
|
|||||||
|
|
||||||
Ok(self.signature().verify(&pubkey, message))
|
Ok(self.signature().verify(&pubkey, message))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Verify `self.signature`.
|
||||||
|
///
|
||||||
|
/// If the root of `block.message` is already known it can be passed in via `object_root_opt`.
|
||||||
|
/// Otherwise, it will be computed locally.
|
||||||
|
pub fn verify_signature(
|
||||||
|
&self,
|
||||||
|
pubkey: &PublicKey,
|
||||||
|
fork: &Fork,
|
||||||
|
genesis_validators_root: Hash256,
|
||||||
|
spec: &ChainSpec,
|
||||||
|
) -> bool {
|
||||||
|
let domain = spec.get_domain(
|
||||||
|
self.epoch(),
|
||||||
|
Domain::BeaconProposer,
|
||||||
|
fork,
|
||||||
|
genesis_validators_root,
|
||||||
|
);
|
||||||
|
|
||||||
|
let message = self.message().signing_root(domain);
|
||||||
|
|
||||||
|
self.signature().verify(pubkey, message)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'de, E: EthSpec> ContextDeserialize<'de, ForkName> for SignedExecutionPayloadEnvelope<E> {
|
impl<'de, E: EthSpec> ContextDeserialize<'de, ForkName> for SignedExecutionPayloadEnvelope<E> {
|
||||||
|
|||||||
Reference in New Issue
Block a user