mirror of
https://github.com/sigp/lighthouse.git
synced 2026-04-20 22:38:34 +00:00
Gloas payload bid consensus (#8801)
- [x] Consensus changes for execution payload bids - [x] EF tests for bids (and `block_header` -- no changes required). Co-Authored-By: Michael Sproul <michael@sigmaprime.io>
This commit is contained in:
@@ -1,12 +1,17 @@
|
||||
use crate::consensus_context::ConsensusContext;
|
||||
use errors::{BlockOperationError, BlockProcessingError, HeaderInvalid};
|
||||
use errors::{
|
||||
BlockOperationError, BlockProcessingError, ExecutionPayloadBidInvalid, HeaderInvalid,
|
||||
};
|
||||
use rayon::prelude::*;
|
||||
use safe_arith::{ArithError, SafeArith};
|
||||
use signature_sets::{block_proposal_signature_set, get_pubkey_from_state, randao_signature_set};
|
||||
use signature_sets::{
|
||||
block_proposal_signature_set, execution_payload_bid_signature_set,
|
||||
get_builder_pubkey_from_state, get_pubkey_from_state, randao_signature_set,
|
||||
};
|
||||
use std::borrow::Cow;
|
||||
use tree_hash::TreeHash;
|
||||
use typenum::Unsigned;
|
||||
use types::*;
|
||||
use types::{consts::gloas::BUILDER_INDEX_SELF_BUILD, *};
|
||||
|
||||
pub use self::verify_attester_slashing::{
|
||||
get_slashable_indices, get_slashable_indices_modular, verify_attester_slashing,
|
||||
@@ -522,3 +527,162 @@ pub fn compute_timestamp_at_slot<E: EthSpec>(
|
||||
.safe_mul(spec.get_slot_duration().as_secs())
|
||||
.and_then(|since_genesis| state.genesis_time().safe_add(since_genesis))
|
||||
}
|
||||
|
||||
pub fn can_builder_cover_bid<E: EthSpec>(
|
||||
state: &BeaconState<E>,
|
||||
builder_index: BuilderIndex,
|
||||
builder: &Builder,
|
||||
bid_amount: u64,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<bool, BlockProcessingError> {
|
||||
let builder_balance = builder.balance;
|
||||
let pending_withdrawals_amount =
|
||||
state.get_pending_balance_to_withdraw_for_builder(builder_index)?;
|
||||
let min_balance = spec
|
||||
.min_deposit_amount
|
||||
.safe_add(pending_withdrawals_amount)?;
|
||||
if builder_balance < min_balance {
|
||||
Ok(false)
|
||||
} else {
|
||||
Ok(builder_balance.safe_sub(min_balance)? >= bid_amount)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn process_execution_payload_bid<E: EthSpec, Payload: AbstractExecPayload<E>>(
|
||||
state: &mut BeaconState<E>,
|
||||
block: BeaconBlockRef<'_, E, Payload>,
|
||||
verify_signatures: VerifySignatures,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<(), BlockProcessingError> {
|
||||
// Verify the bid signature
|
||||
let signed_bid = block.body().signed_execution_payload_bid()?;
|
||||
|
||||
let bid = &signed_bid.message;
|
||||
let amount = bid.value;
|
||||
let builder_index = bid.builder_index;
|
||||
|
||||
// For self-builds, amount must be zero regardless of withdrawal credential prefix
|
||||
if builder_index == BUILDER_INDEX_SELF_BUILD {
|
||||
block_verify!(
|
||||
amount == 0,
|
||||
ExecutionPayloadBidInvalid::SelfBuildNonZeroAmount.into()
|
||||
);
|
||||
block_verify!(
|
||||
signed_bid.signature.is_infinity(),
|
||||
ExecutionPayloadBidInvalid::BadSignature.into()
|
||||
);
|
||||
} else {
|
||||
let builder = state.get_builder(builder_index)?;
|
||||
|
||||
// Verify that the builder is active
|
||||
block_verify!(
|
||||
builder.is_active_at_finalized_epoch(state.finalized_checkpoint().epoch, spec),
|
||||
ExecutionPayloadBidInvalid::BuilderNotActive(builder_index).into()
|
||||
);
|
||||
|
||||
// Verify that the builder has funds to cover the bid
|
||||
block_verify!(
|
||||
can_builder_cover_bid(state, builder_index, builder, amount, spec)?,
|
||||
ExecutionPayloadBidInvalid::InsufficientBalance {
|
||||
builder_index,
|
||||
builder_balance: builder.balance,
|
||||
bid_value: amount,
|
||||
}
|
||||
.into()
|
||||
);
|
||||
|
||||
if verify_signatures.is_true() {
|
||||
block_verify!(
|
||||
// We know this is NOT a self-build, so there MUST be a signature set (func does not
|
||||
// return None).
|
||||
execution_payload_bid_signature_set(
|
||||
state,
|
||||
|i| get_builder_pubkey_from_state(state, i),
|
||||
signed_bid,
|
||||
spec
|
||||
)?
|
||||
.ok_or(ExecutionPayloadBidInvalid::BadSignature)?
|
||||
.verify(),
|
||||
ExecutionPayloadBidInvalid::BadSignature.into()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Verify commitments are under limit
|
||||
let max_blobs_per_block = spec.max_blobs_per_block(state.current_epoch()) as usize;
|
||||
block_verify!(
|
||||
bid.blob_kzg_commitments.len() <= max_blobs_per_block,
|
||||
ExecutionPayloadBidInvalid::ExcessBlobCommitments {
|
||||
max: max_blobs_per_block,
|
||||
bid: bid.blob_kzg_commitments.len(),
|
||||
}
|
||||
.into()
|
||||
);
|
||||
|
||||
// Verify that the bid is for the current slot
|
||||
block_verify!(
|
||||
bid.slot == block.slot(),
|
||||
ExecutionPayloadBidInvalid::SlotMismatch {
|
||||
bid_slot: bid.slot,
|
||||
block_slot: block.slot(),
|
||||
}
|
||||
.into()
|
||||
);
|
||||
|
||||
// Verify that the bid is for the right parent block
|
||||
let latest_block_hash = state.latest_block_hash()?;
|
||||
block_verify!(
|
||||
bid.parent_block_hash == *latest_block_hash,
|
||||
ExecutionPayloadBidInvalid::ParentBlockHashMismatch {
|
||||
state_block_hash: *latest_block_hash,
|
||||
bid_parent_hash: bid.parent_block_hash,
|
||||
}
|
||||
.into()
|
||||
);
|
||||
|
||||
block_verify!(
|
||||
bid.parent_block_root == block.parent_root(),
|
||||
ExecutionPayloadBidInvalid::ParentBlockRootMismatch {
|
||||
block_parent_root: block.parent_root(),
|
||||
bid_parent_root: bid.parent_block_root,
|
||||
}
|
||||
.into()
|
||||
);
|
||||
|
||||
let expected_randao = *state.get_randao_mix(state.current_epoch())?;
|
||||
block_verify!(
|
||||
bid.prev_randao == expected_randao,
|
||||
ExecutionPayloadBidInvalid::PrevRandaoMismatch {
|
||||
expected: expected_randao,
|
||||
bid: bid.prev_randao,
|
||||
}
|
||||
.into()
|
||||
);
|
||||
|
||||
// Record the pending payment if there is some payment
|
||||
if amount > 0 {
|
||||
let pending_payment = BuilderPendingPayment {
|
||||
weight: 0,
|
||||
withdrawal: BuilderPendingWithdrawal {
|
||||
fee_recipient: bid.fee_recipient,
|
||||
amount,
|
||||
builder_index,
|
||||
},
|
||||
};
|
||||
|
||||
let payment_index = E::SlotsPerEpoch::to_usize()
|
||||
.safe_add(bid.slot.as_usize().safe_rem(E::SlotsPerEpoch::to_usize())?)?;
|
||||
|
||||
*state
|
||||
.builder_pending_payments_mut()?
|
||||
.get_mut(payment_index)
|
||||
.ok_or(BlockProcessingError::BeaconStateError(
|
||||
BeaconStateError::InvalidBuilderPendingPaymentsIndex(payment_index),
|
||||
))? = pending_payment;
|
||||
}
|
||||
|
||||
// Cache the execution bid
|
||||
*state.latest_execution_payload_bid_mut()? = bid.clone();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -99,6 +99,9 @@ pub enum BlockProcessingError {
|
||||
IncorrectExpectedWithdrawalsVariant,
|
||||
MissingLastWithdrawal,
|
||||
PendingAttestationInElectra,
|
||||
ExecutionPayloadBidInvalid {
|
||||
reason: ExecutionPayloadBidInvalid,
|
||||
},
|
||||
/// Builder payment index out of bounds (Gloas)
|
||||
BuilderPaymentIndexOutOfBounds(usize),
|
||||
}
|
||||
@@ -157,6 +160,12 @@ impl From<milhouse::Error> for BlockProcessingError {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ExecutionPayloadBidInvalid> for BlockProcessingError {
|
||||
fn from(reason: ExecutionPayloadBidInvalid) -> Self {
|
||||
Self::ExecutionPayloadBidInvalid { reason }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BlockOperationError<HeaderInvalid>> for BlockProcessingError {
|
||||
fn from(e: BlockOperationError<HeaderInvalid>) -> BlockProcessingError {
|
||||
match e {
|
||||
@@ -452,6 +461,38 @@ pub enum ExitInvalid {
|
||||
PendingWithdrawalInQueue(u64),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub enum ExecutionPayloadBidInvalid {
|
||||
/// The validator set a non-zero amount for a self-build.
|
||||
SelfBuildNonZeroAmount,
|
||||
/// The signature is invalid.
|
||||
BadSignature,
|
||||
/// The builder is not active.
|
||||
BuilderNotActive(u64),
|
||||
/// The builder has insufficient balance to cover the bid
|
||||
InsufficientBalance {
|
||||
builder_index: u64,
|
||||
builder_balance: u64,
|
||||
bid_value: u64,
|
||||
},
|
||||
/// Bid slot doesn't match block slot
|
||||
SlotMismatch { bid_slot: Slot, block_slot: Slot },
|
||||
/// The bid's parent block hash doesn't match the state's latest block hash
|
||||
ParentBlockHashMismatch {
|
||||
state_block_hash: ExecutionBlockHash,
|
||||
bid_parent_hash: ExecutionBlockHash,
|
||||
},
|
||||
/// The bid's parent block root doesn't match the block's parent root
|
||||
ParentBlockRootMismatch {
|
||||
block_parent_root: Hash256,
|
||||
bid_parent_root: Hash256,
|
||||
},
|
||||
/// The bid's prev randao doesn't match the state.
|
||||
PrevRandaoMismatch { expected: Hash256, bid: Hash256 },
|
||||
/// The bid contains more than the maximum number of kzg blob commitments.
|
||||
ExcessBlobCommitments { max: usize, bid: usize },
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub enum BlsExecutionChangeInvalid {
|
||||
/// The specified validator is not in the state's validator registry.
|
||||
|
||||
@@ -9,11 +9,12 @@ use tree_hash::TreeHash;
|
||||
use typenum::Unsigned;
|
||||
use types::{
|
||||
AbstractExecPayload, AttesterSlashingRef, BeaconBlockRef, BeaconState, BeaconStateError,
|
||||
ChainSpec, DepositData, Domain, Epoch, EthSpec, Fork, Hash256, InconsistentFork,
|
||||
BuilderIndex, ChainSpec, DepositData, Domain, Epoch, EthSpec, Fork, Hash256, InconsistentFork,
|
||||
IndexedAttestation, IndexedAttestationRef, ProposerSlashing, SignedAggregateAndProof,
|
||||
SignedBeaconBlock, SignedBeaconBlockHeader, SignedBlsToExecutionChange,
|
||||
SignedContributionAndProof, SignedRoot, SignedVoluntaryExit, SigningData, Slot, SyncAggregate,
|
||||
SyncAggregatorSelectionData,
|
||||
SignedContributionAndProof, SignedExecutionPayloadBid, SignedRoot, SignedVoluntaryExit,
|
||||
SigningData, Slot, SyncAggregate, SyncAggregatorSelectionData,
|
||||
consts::gloas::BUILDER_INDEX_SELF_BUILD,
|
||||
};
|
||||
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
@@ -28,6 +29,9 @@ pub enum Error {
|
||||
/// Attempted to find the public key of a validator that does not exist. You cannot distinguish
|
||||
/// between an error and an invalid block in this case.
|
||||
ValidatorUnknown(u64),
|
||||
/// Attempted to find the public key of a builder that does not exist. You cannot distinguish
|
||||
/// between an error and an invalid block in this case.
|
||||
BuilderUnknown(BuilderIndex),
|
||||
/// Attempted to find the public key of a validator that does not exist. You cannot distinguish
|
||||
/// between an error and an invalid block in this case.
|
||||
ValidatorPubkeyUnknown(PublicKeyBytes),
|
||||
@@ -53,7 +57,7 @@ impl From<BeaconStateError> for Error {
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper function to get a public key from a `state`.
|
||||
/// Helper function to get a validator public key from a `state`.
|
||||
pub fn get_pubkey_from_state<E>(
|
||||
state: &BeaconState<E>,
|
||||
validator_index: usize,
|
||||
@@ -71,6 +75,25 @@ where
|
||||
.map(Cow::Owned)
|
||||
}
|
||||
|
||||
/// Helper function to get a builder public key from a `state`.
|
||||
pub fn get_builder_pubkey_from_state<E>(
|
||||
state: &BeaconState<E>,
|
||||
builder_index: BuilderIndex,
|
||||
) -> Option<Cow<'_, PublicKey>>
|
||||
where
|
||||
E: EthSpec,
|
||||
{
|
||||
state
|
||||
.builders()
|
||||
.ok()?
|
||||
.get(builder_index as usize)
|
||||
.and_then(|b| {
|
||||
let pk: Option<PublicKey> = b.pubkey.decompress().ok();
|
||||
pk
|
||||
})
|
||||
.map(Cow::Owned)
|
||||
}
|
||||
|
||||
/// A signature set that is valid if a block was signed by the expected block producer.
|
||||
pub fn block_proposal_signature_set<'a, E, F, Payload: AbstractExecPayload<E>>(
|
||||
state: &'a BeaconState<E>,
|
||||
@@ -332,6 +355,41 @@ where
|
||||
Ok(SignatureSet::multiple_pubkeys(signature, pubkeys, message))
|
||||
}
|
||||
|
||||
pub fn execution_payload_bid_signature_set<'a, E, F>(
|
||||
state: &'a BeaconState<E>,
|
||||
get_builder_pubkey: F,
|
||||
signed_execution_payload_bid: &'a SignedExecutionPayloadBid<E>,
|
||||
spec: &'a ChainSpec,
|
||||
) -> Result<Option<SignatureSet<'a>>>
|
||||
where
|
||||
E: EthSpec,
|
||||
F: Fn(BuilderIndex) -> Option<Cow<'a, PublicKey>>,
|
||||
{
|
||||
let execution_payload_bid = &signed_execution_payload_bid.message;
|
||||
let builder_index = execution_payload_bid.builder_index;
|
||||
if builder_index == BUILDER_INDEX_SELF_BUILD {
|
||||
// No signatures to verify in case of a self-build, but consensus code MUST check that
|
||||
// the signature is the point at infinity.
|
||||
// See `process_execution_payload_bid`.
|
||||
return Ok(None);
|
||||
}
|
||||
let domain = spec.get_domain(
|
||||
state.current_epoch(),
|
||||
Domain::BeaconBuilder,
|
||||
&state.fork(),
|
||||
state.genesis_validators_root(),
|
||||
);
|
||||
|
||||
let pubkey = get_builder_pubkey(builder_index).ok_or(Error::BuilderUnknown(builder_index))?;
|
||||
let message = execution_payload_bid.signing_root(domain);
|
||||
|
||||
Ok(Some(SignatureSet::single_pubkey(
|
||||
&signed_execution_payload_bid.signature,
|
||||
pubkey,
|
||||
message,
|
||||
)))
|
||||
}
|
||||
|
||||
/// Returns the signature set for the given `attester_slashing` and corresponding `pubkeys`.
|
||||
pub fn attester_slashing_signature_sets<'a, E, F>(
|
||||
state: &'a BeaconState<E>,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::{Address, Epoch, ForkName};
|
||||
use crate::{Address, ChainSpec, Epoch, ForkName};
|
||||
use bls::PublicKeyBytes;
|
||||
use context_deserialize::context_deserialize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -24,3 +24,12 @@ pub struct Builder {
|
||||
pub deposit_epoch: Epoch,
|
||||
pub withdrawable_epoch: Epoch,
|
||||
}
|
||||
|
||||
impl Builder {
|
||||
/// Check if a builder is active in a state with `finalized_epoch`.
|
||||
///
|
||||
/// This implements `is_active_builder` from the spec.
|
||||
pub fn is_active_at_finalized_epoch(&self, finalized_epoch: Epoch, spec: &ChainSpec) -> bool {
|
||||
self.deposit_epoch < finalized_epoch && self.withdrawable_epoch == spec.far_future_epoch
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ use fixed_bytes::FixedBytesExtended;
|
||||
use int_to_bytes::{int_to_bytes4, int_to_bytes8};
|
||||
use metastruct::{NumFields, metastruct};
|
||||
use milhouse::{List, Vector};
|
||||
use safe_arith::{ArithError, SafeArith};
|
||||
use safe_arith::{ArithError, SafeArith, SafeArithIter};
|
||||
use serde::{Deserialize, Deserializer, Serialize};
|
||||
use ssz::{Decode, DecodeError, Encode, ssz_encode};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
@@ -218,6 +218,7 @@ pub enum BeaconStateError {
|
||||
envelope_epoch: Epoch,
|
||||
},
|
||||
InvalidIndicesCount,
|
||||
InvalidBuilderPendingPaymentsIndex(usize),
|
||||
InvalidExecutionPayloadAvailabilityIndex(usize),
|
||||
}
|
||||
|
||||
@@ -2749,6 +2750,30 @@ impl<E: EthSpec> BeaconState<E> {
|
||||
Ok(pending_balance)
|
||||
}
|
||||
|
||||
pub fn get_pending_balance_to_withdraw_for_builder(
|
||||
&self,
|
||||
builder_index: BuilderIndex,
|
||||
) -> Result<u64, BeaconStateError> {
|
||||
let pending_withdrawals_total = self
|
||||
.builder_pending_withdrawals()?
|
||||
.iter()
|
||||
.filter_map(|withdrawal| {
|
||||
(withdrawal.builder_index == builder_index).then_some(withdrawal.amount)
|
||||
})
|
||||
.safe_sum()?;
|
||||
let pending_payments_total = self
|
||||
.builder_pending_payments()?
|
||||
.iter()
|
||||
.filter_map(|payment| {
|
||||
(payment.withdrawal.builder_index == builder_index)
|
||||
.then_some(payment.withdrawal.amount)
|
||||
})
|
||||
.safe_sum()?;
|
||||
pending_withdrawals_total
|
||||
.safe_add(pending_payments_total)
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
// ******* Electra mutators *******
|
||||
|
||||
pub fn queue_excess_active_balance(
|
||||
|
||||
@@ -48,8 +48,6 @@ excluded_paths = [
|
||||
"tests/.*/eip7732",
|
||||
"tests/.*/eip7805",
|
||||
# TODO(gloas): remove these ignores as more Gloas operations are implemented
|
||||
"tests/.*/gloas/operations/block_header/.*",
|
||||
"tests/.*/gloas/operations/execution_payload_bid/.*",
|
||||
"tests/.*/gloas/operations/payload_attestation/.*",
|
||||
# TODO(EIP-7732): remove these ignores as Gloas consensus is implemented
|
||||
"tests/.*/gloas/epoch_processing/.*",
|
||||
|
||||
@@ -16,7 +16,7 @@ use state_processing::{
|
||||
per_block_processing::{
|
||||
VerifyBlockRoot, VerifySignatures,
|
||||
errors::BlockProcessingError,
|
||||
process_block_header, process_execution_payload,
|
||||
process_block_header, process_execution_payload, process_execution_payload_bid,
|
||||
process_operations::{
|
||||
altair_deneb, base, gloas, process_attester_slashings,
|
||||
process_bls_to_execution_changes, process_deposits, process_exits,
|
||||
@@ -51,6 +51,12 @@ pub struct WithdrawalsPayload<E: EthSpec> {
|
||||
payload: Option<ExecutionPayload<E>>,
|
||||
}
|
||||
|
||||
/// Newtype for testing execution payload bids.
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct ExecutionPayloadBidBlock<E: EthSpec> {
|
||||
block: BeaconBlock<E>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Operations<E: EthSpec, O: Operation<E>> {
|
||||
metadata: Metadata,
|
||||
@@ -459,6 +465,37 @@ impl<E: EthSpec> Operation<E> for SignedExecutionPayloadEnvelope<E> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EthSpec> Operation<E> for ExecutionPayloadBidBlock<E> {
|
||||
type Error = BlockProcessingError;
|
||||
|
||||
fn handler_name() -> String {
|
||||
"execution_payload_bid".into()
|
||||
}
|
||||
|
||||
fn filename() -> String {
|
||||
"block.ssz_snappy".into()
|
||||
}
|
||||
|
||||
fn is_enabled_for_fork(fork_name: ForkName) -> bool {
|
||||
fork_name.gloas_enabled()
|
||||
}
|
||||
|
||||
fn decode(path: &Path, _fork_name: ForkName, spec: &ChainSpec) -> Result<Self, Error> {
|
||||
ssz_decode_file_with(path, |bytes| BeaconBlock::from_ssz_bytes(bytes, spec))
|
||||
.map(|block| ExecutionPayloadBidBlock { block })
|
||||
}
|
||||
|
||||
fn apply_to(
|
||||
&self,
|
||||
state: &mut BeaconState<E>,
|
||||
spec: &ChainSpec,
|
||||
_: &Operations<E, Self>,
|
||||
) -> Result<(), BlockProcessingError> {
|
||||
process_execution_payload_bid(state, self.block.to_ref(), VerifySignatures::True, spec)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EthSpec> Operation<E> for WithdrawalsPayload<E> {
|
||||
type Error = BlockProcessingError;
|
||||
|
||||
|
||||
@@ -1139,11 +1139,13 @@ impl<E: EthSpec + TypeName, O: Operation<E>> Handler for OperationsHandler<E, O>
|
||||
&& (!fork_name.gloas_enabled()
|
||||
|| self.handler_name() == "attestation"
|
||||
|| self.handler_name() == "attester_slashing"
|
||||
|| self.handler_name() == "block_header"
|
||||
|| self.handler_name() == "bls_to_execution_change"
|
||||
|| self.handler_name() == "consolidation_request"
|
||||
|| self.handler_name() == "deposit_request"
|
||||
|| self.handler_name() == "deposit"
|
||||
|| self.handler_name() == "execution_payload"
|
||||
|| self.handler_name() == "execution_payload_bid"
|
||||
|| self.handler_name() == "proposer_slashing"
|
||||
|| self.handler_name() == "sync_aggregate"
|
||||
|| self.handler_name() == "withdrawal_request"
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
pub use case_result::CaseResult;
|
||||
pub use cases::WithdrawalsPayload;
|
||||
pub use cases::{
|
||||
Case, EffectiveBalanceUpdates, Eth1DataReset, FeatureName, HistoricalRootsUpdate,
|
||||
HistoricalSummariesUpdate, InactivityUpdates, JustificationAndFinalization,
|
||||
ParticipationFlagUpdates, ParticipationRecordUpdates, PendingBalanceDeposits,
|
||||
PendingConsolidations, ProposerLookahead, RandaoMixesReset, RegistryUpdates,
|
||||
RewardsAndPenalties, Slashings, SlashingsReset, SyncCommitteeUpdates,
|
||||
Case, EffectiveBalanceUpdates, Eth1DataReset, ExecutionPayloadBidBlock, FeatureName,
|
||||
HistoricalRootsUpdate, HistoricalSummariesUpdate, InactivityUpdates,
|
||||
JustificationAndFinalization, ParticipationFlagUpdates, ParticipationRecordUpdates,
|
||||
PendingBalanceDeposits, PendingConsolidations, ProposerLookahead, RandaoMixesReset,
|
||||
RegistryUpdates, RewardsAndPenalties, Slashings, SlashingsReset, SyncCommitteeUpdates,
|
||||
WithdrawalsPayload,
|
||||
};
|
||||
pub use decode::log_file_access;
|
||||
pub use error::Error;
|
||||
|
||||
@@ -93,6 +93,12 @@ fn operations_execution_payload_envelope() {
|
||||
OperationsHandler::<MainnetEthSpec, SignedExecutionPayloadEnvelope<_>>::default().run();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn operations_execution_payload_bid() {
|
||||
OperationsHandler::<MinimalEthSpec, ExecutionPayloadBidBlock<_>>::default().run();
|
||||
OperationsHandler::<MainnetEthSpec, ExecutionPayloadBidBlock<_>>::default().run();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn operations_withdrawals() {
|
||||
OperationsHandler::<MinimalEthSpec, WithdrawalsPayload<_>>::default().run();
|
||||
|
||||
Reference in New Issue
Block a user