Fixes to make EF Capella tests pass (#3719)
* Fixes to make EF Capella tests pass * Clippy for state_processing
This commit is contained in:
parent
276e1845fd
commit
0cdd049da9
9
Makefile
9
Makefile
@ -20,6 +20,9 @@ CROSS_FEATURES ?= gnosis,slasher-lmdb,slasher-mdbx
|
|||||||
# Cargo profile for Cross builds. Default is for local builds, CI uses an override.
|
# Cargo profile for Cross builds. Default is for local builds, CI uses an override.
|
||||||
CROSS_PROFILE ?= release
|
CROSS_PROFILE ?= release
|
||||||
|
|
||||||
|
# List of features to use when running EF tests.
|
||||||
|
EF_TEST_FEATURES ?= beacon_chain/withdrawals,beacon_chain/withdrawals-processing
|
||||||
|
|
||||||
# Cargo profile for regular builds.
|
# Cargo profile for regular builds.
|
||||||
PROFILE ?= release
|
PROFILE ?= release
|
||||||
|
|
||||||
@ -108,9 +111,9 @@ check-consensus:
|
|||||||
# Runs only the ef-test vectors.
|
# Runs only the ef-test vectors.
|
||||||
run-ef-tests:
|
run-ef-tests:
|
||||||
rm -rf $(EF_TESTS)/.accessed_file_log.txt
|
rm -rf $(EF_TESTS)/.accessed_file_log.txt
|
||||||
cargo test --release -p ef_tests --features "ef_tests"
|
cargo test --release -p ef_tests --features "ef_tests,$(EF_TEST_FEATURES)"
|
||||||
cargo test --release -p ef_tests --features "ef_tests,fake_crypto"
|
cargo test --release -p ef_tests --features "ef_tests,$(EF_TEST_FEATURES),fake_crypto"
|
||||||
cargo test --release -p ef_tests --features "ef_tests,milagro"
|
cargo test --release -p ef_tests --features "ef_tests,$(EF_TEST_FEATURES),milagro"
|
||||||
./$(EF_TESTS)/check_all_files_accessed.py $(EF_TESTS)/.accessed_file_log.txt $(EF_TESTS)/consensus-spec-tests
|
./$(EF_TESTS)/check_all_files_accessed.py $(EF_TESTS)/.accessed_file_log.txt $(EF_TESTS)/consensus-spec-tests
|
||||||
|
|
||||||
# Run the tests in the `beacon_chain` crate for all known forks.
|
# Run the tests in the `beacon_chain` crate for all known forks.
|
||||||
|
@ -683,8 +683,8 @@ mod tests {
|
|||||||
};
|
};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use types::{
|
use types::{
|
||||||
BeaconBlock, BeaconBlockAltair, BeaconBlockBase, BeaconBlockMerge, Epoch, ForkContext,
|
BeaconBlock, BeaconBlockAltair, BeaconBlockBase, BeaconBlockMerge, EmptyBlock, Epoch,
|
||||||
FullPayload, Hash256, Signature, SignedBeaconBlock, Slot,
|
ForkContext, FullPayload, Hash256, Signature, SignedBeaconBlock, Slot,
|
||||||
};
|
};
|
||||||
|
|
||||||
use snap::write::FrameEncoder;
|
use snap::write::FrameEncoder;
|
||||||
|
@ -22,8 +22,8 @@ use tokio_util::{
|
|||||||
};
|
};
|
||||||
use types::BlobsSidecar;
|
use types::BlobsSidecar;
|
||||||
use types::{
|
use types::{
|
||||||
BeaconBlock, BeaconBlockAltair, BeaconBlockBase, BeaconBlockMerge, Blob, EthSpec, ForkContext,
|
BeaconBlock, BeaconBlockAltair, BeaconBlockBase, BeaconBlockMerge, Blob, EmptyBlock, EthSpec,
|
||||||
ForkName, Hash256, MainnetEthSpec, Signature, SignedBeaconBlock,
|
ForkContext, ForkName, Hash256, MainnetEthSpec, Signature, SignedBeaconBlock,
|
||||||
};
|
};
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
|
@ -492,17 +492,15 @@ impl<E: EthSpec, Hot: ItemStore<E>, Cold: ItemStore<E>> HotColdDB<E, Hot, Cold>
|
|||||||
pub fn get_blobs(&self, block_root: &Hash256) -> Result<Option<BlobsSidecar<E>>, Error> {
|
pub fn get_blobs(&self, block_root: &Hash256) -> Result<Option<BlobsSidecar<E>>, Error> {
|
||||||
if let Some(blobs) = self.blob_cache.lock().get(block_root) {
|
if let Some(blobs) = self.blob_cache.lock().get(block_root) {
|
||||||
Ok(Some(blobs.clone()))
|
Ok(Some(blobs.clone()))
|
||||||
|
} else if let Some(bytes) = self
|
||||||
|
.hot_db
|
||||||
|
.get_bytes(DBColumn::BeaconBlob.into(), block_root.as_bytes())?
|
||||||
|
{
|
||||||
|
let ret = BlobsSidecar::from_ssz_bytes(&bytes)?;
|
||||||
|
self.blob_cache.lock().put(*block_root, ret.clone());
|
||||||
|
Ok(Some(ret))
|
||||||
} else {
|
} else {
|
||||||
if let Some(bytes) = self
|
Ok(None)
|
||||||
.hot_db
|
|
||||||
.get_bytes(DBColumn::BeaconBlob.into(), block_root.as_bytes())?
|
|
||||||
{
|
|
||||||
let ret = BlobsSidecar::from_ssz_bytes(&bytes)?;
|
|
||||||
self.blob_cache.lock().put(*block_root, ret.clone());
|
|
||||||
Ok(Some(ret))
|
|
||||||
} else {
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use tree_hash::TreeHash;
|
use tree_hash::TreeHash;
|
||||||
use types::{
|
use types::{
|
||||||
AbstractExecPayload, BeaconState, BeaconStateError, ChainSpec, EthSpec, ExecPayload, Hash256,
|
AbstractExecPayload, BeaconState, BeaconStateError, ChainSpec, EthSpec, Hash256,
|
||||||
SignedBeaconBlock, Slot,
|
SignedBeaconBlock, Slot,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -42,7 +42,9 @@ mod verify_deposit;
|
|||||||
mod verify_exit;
|
mod verify_exit;
|
||||||
mod verify_proposer_slashing;
|
mod verify_proposer_slashing;
|
||||||
|
|
||||||
|
#[cfg(feature = "withdrawals-processing")]
|
||||||
use crate::common::decrease_balance;
|
use crate::common::decrease_balance;
|
||||||
|
|
||||||
#[cfg(feature = "arbitrary-fuzz")]
|
#[cfg(feature = "arbitrary-fuzz")]
|
||||||
use arbitrary::Arbitrary;
|
use arbitrary::Arbitrary;
|
||||||
|
|
||||||
@ -466,21 +468,22 @@ pub fn get_expected_withdrawals<T: EthSpec>(
|
|||||||
spec: &ChainSpec,
|
spec: &ChainSpec,
|
||||||
) -> Result<Withdrawals<T>, BlockProcessingError> {
|
) -> Result<Withdrawals<T>, BlockProcessingError> {
|
||||||
let epoch = state.current_epoch();
|
let epoch = state.current_epoch();
|
||||||
let mut withdrawal_index = *state.next_withdrawal_index()?;
|
let mut withdrawal_index = state.next_withdrawal_index()?;
|
||||||
let mut validator_index = *state.next_withdrawal_validator_index()?;
|
let mut validator_index = state.next_withdrawal_validator_index()?;
|
||||||
let mut withdrawals = vec![];
|
let mut withdrawals = vec![];
|
||||||
|
|
||||||
for _ in 0..state.validators().len() {
|
for _ in 0..state.validators().len() {
|
||||||
let validator = state.get_validator(validator_index as usize)?;
|
let validator = state.get_validator(validator_index as usize)?;
|
||||||
let balance = *state
|
let balance = *state.balances().get(validator_index as usize).ok_or(
|
||||||
.balances()
|
BeaconStateError::BalancesOutOfBounds(validator_index as usize),
|
||||||
.get(validator_index as usize)
|
)?;
|
||||||
.ok_or_else(|| BeaconStateError::BalancesOutOfBounds(validator_index as usize))?;
|
|
||||||
if validator.is_fully_withdrawable_at(balance, epoch, spec) {
|
if validator.is_fully_withdrawable_at(balance, epoch, spec) {
|
||||||
withdrawals.push(Withdrawal {
|
withdrawals.push(Withdrawal {
|
||||||
index: withdrawal_index,
|
index: withdrawal_index,
|
||||||
validator_index,
|
validator_index,
|
||||||
address: Address::from_slice(&validator.withdrawal_credentials[12..]),
|
address: validator
|
||||||
|
.get_eth1_withdrawal_address(spec)
|
||||||
|
.ok_or(BlockProcessingError::WithdrawalCredentialsInvalid)?,
|
||||||
amount: balance,
|
amount: balance,
|
||||||
});
|
});
|
||||||
withdrawal_index.safe_add_assign(1)?;
|
withdrawal_index.safe_add_assign(1)?;
|
||||||
@ -488,7 +491,9 @@ pub fn get_expected_withdrawals<T: EthSpec>(
|
|||||||
withdrawals.push(Withdrawal {
|
withdrawals.push(Withdrawal {
|
||||||
index: withdrawal_index,
|
index: withdrawal_index,
|
||||||
validator_index,
|
validator_index,
|
||||||
address: Address::from_slice(&validator.withdrawal_credentials[12..]),
|
address: validator
|
||||||
|
.get_eth1_withdrawal_address(spec)
|
||||||
|
.ok_or(BlockProcessingError::WithdrawalCredentialsInvalid)?,
|
||||||
amount: balance.safe_sub(spec.max_effective_balance)?,
|
amount: balance.safe_sub(spec.max_effective_balance)?,
|
||||||
});
|
});
|
||||||
withdrawal_index.safe_add_assign(1)?;
|
withdrawal_index.safe_add_assign(1)?;
|
||||||
@ -496,7 +501,9 @@ pub fn get_expected_withdrawals<T: EthSpec>(
|
|||||||
if withdrawals.len() == T::max_withdrawals_per_payload() {
|
if withdrawals.len() == T::max_withdrawals_per_payload() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
validator_index = validator_index.safe_add(1)? % state.validators().len() as u64;
|
validator_index = validator_index
|
||||||
|
.safe_add(1)?
|
||||||
|
.safe_rem(state.validators().len() as u64)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(withdrawals.into())
|
Ok(withdrawals.into())
|
||||||
@ -513,12 +520,13 @@ pub fn process_withdrawals<'payload, T: EthSpec, Payload: AbstractExecPayload<T>
|
|||||||
BeaconState::Merge(_) => Ok(()),
|
BeaconState::Merge(_) => Ok(()),
|
||||||
BeaconState::Capella(_) | BeaconState::Eip4844(_) => {
|
BeaconState::Capella(_) | BeaconState::Eip4844(_) => {
|
||||||
let expected_withdrawals = get_expected_withdrawals(state, spec)?;
|
let expected_withdrawals = get_expected_withdrawals(state, spec)?;
|
||||||
|
let expected_root = expected_withdrawals.tree_hash_root();
|
||||||
let withdrawals_root = payload.withdrawals_root()?;
|
let withdrawals_root = payload.withdrawals_root()?;
|
||||||
|
|
||||||
if expected_withdrawals.tree_hash_root() != payload.withdrawals_root()? {
|
if expected_root != withdrawals_root {
|
||||||
return Err(BlockProcessingError::WithdrawalsRootMismatch {
|
return Err(BlockProcessingError::WithdrawalsRootMismatch {
|
||||||
expected: expected_withdrawals.tree_hash_root(),
|
expected: expected_root,
|
||||||
found: payload.withdrawals_root()?,
|
found: withdrawals_root,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -531,9 +539,11 @@ pub fn process_withdrawals<'payload, T: EthSpec, Payload: AbstractExecPayload<T>
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(latest_withdrawal) = expected_withdrawals.last() {
|
if let Some(latest_withdrawal) = expected_withdrawals.last() {
|
||||||
*state.next_withdrawal_index_mut()? = latest_withdrawal.index + 1;
|
*state.next_withdrawal_index_mut()? = latest_withdrawal.index.safe_add(1)?;
|
||||||
let next_validator_index =
|
let next_validator_index = latest_withdrawal
|
||||||
(latest_withdrawal.validator_index + 1) % state.validators().len() as u64;
|
.validator_index
|
||||||
|
.safe_add(1)?
|
||||||
|
.safe_rem(state.validators().len() as u64)?;
|
||||||
*state.next_withdrawal_validator_index_mut()? = next_validator_index;
|
*state.next_withdrawal_validator_index_mut()? = next_validator_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1 +1,2 @@
|
|||||||
|
#[allow(clippy::module_inception)]
|
||||||
pub mod eip4844;
|
pub mod eip4844;
|
||||||
|
@ -6,8 +6,8 @@ use ssz::Decode;
|
|||||||
use ssz_types::VariableList;
|
use ssz_types::VariableList;
|
||||||
use types::consts::eip4844::{BLOB_TX_TYPE, VERSIONED_HASH_VERSION_KZG};
|
use types::consts::eip4844::{BLOB_TX_TYPE, VERSIONED_HASH_VERSION_KZG};
|
||||||
use types::{
|
use types::{
|
||||||
AbstractExecPayload, BeaconBlockBodyRef, EthSpec, ExecPayload, FullPayload, FullPayloadRef,
|
AbstractExecPayload, BeaconBlockBodyRef, EthSpec, ExecPayload, KzgCommitment, Transaction,
|
||||||
KzgCommitment, Transaction, Transactions, VersionedHash,
|
Transactions, VersionedHash,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn process_blob_kzg_commitments<T: EthSpec, Payload: AbstractExecPayload<T>>(
|
pub fn process_blob_kzg_commitments<T: EthSpec, Payload: AbstractExecPayload<T>>(
|
||||||
@ -34,7 +34,7 @@ pub fn verify_kzg_commitments_against_transactions<T: EthSpec>(
|
|||||||
let nested_iter = transactions
|
let nested_iter = transactions
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|tx| {
|
.filter(|tx| {
|
||||||
tx.get(0)
|
tx.first()
|
||||||
.map(|tx_type| *tx_type == BLOB_TX_TYPE)
|
.map(|tx_type| *tx_type == BLOB_TX_TYPE)
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
})
|
})
|
||||||
|
@ -94,6 +94,7 @@ pub enum BlockProcessingError {
|
|||||||
index: usize,
|
index: usize,
|
||||||
length: usize,
|
length: usize,
|
||||||
},
|
},
|
||||||
|
WithdrawalCredentialsInvalid,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<BeaconStateError> for BlockProcessingError {
|
impl From<BeaconStateError> for BlockProcessingError {
|
||||||
|
@ -33,8 +33,11 @@ pub fn process_operations<'a, T: EthSpec, Payload: AbstractExecPayload<T>>(
|
|||||||
process_attestations(state, block_body, verify_signatures, ctxt, spec)?;
|
process_attestations(state, block_body, verify_signatures, ctxt, spec)?;
|
||||||
process_deposits(state, block_body.deposits(), spec)?;
|
process_deposits(state, block_body.deposits(), spec)?;
|
||||||
process_exits(state, block_body.voluntary_exits(), verify_signatures, spec)?;
|
process_exits(state, block_body.voluntary_exits(), verify_signatures, spec)?;
|
||||||
|
|
||||||
#[cfg(all(feature = "withdrawals", feature = "withdrawals-processing"))]
|
#[cfg(all(feature = "withdrawals", feature = "withdrawals-processing"))]
|
||||||
process_bls_to_execution_changes(state, block_body, verify_signatures, spec)?;
|
if let Ok(bls_to_execution_changes) = block_body.bls_to_execution_changes() {
|
||||||
|
process_bls_to_execution_changes(state, bls_to_execution_changes, verify_signatures, spec)?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -287,39 +290,25 @@ pub fn process_exits<T: EthSpec>(
|
|||||||
/// Returns `Ok(())` if the validation and state updates completed successfully. Otherwise returs
|
/// Returns `Ok(())` if the validation and state updates completed successfully. Otherwise returs
|
||||||
/// an `Err` describing the invalid object or cause of failure.
|
/// an `Err` describing the invalid object or cause of failure.
|
||||||
#[cfg(all(feature = "withdrawals", feature = "withdrawals-processing"))]
|
#[cfg(all(feature = "withdrawals", feature = "withdrawals-processing"))]
|
||||||
pub fn process_bls_to_execution_changes<'a, T: EthSpec, Payload: AbstractExecPayload<T>>(
|
pub fn process_bls_to_execution_changes<T: EthSpec>(
|
||||||
state: &mut BeaconState<T>,
|
state: &mut BeaconState<T>,
|
||||||
block_body: BeaconBlockBodyRef<'a, T, Payload>,
|
bls_to_execution_changes: &[SignedBlsToExecutionChange],
|
||||||
verify_signatures: VerifySignatures,
|
verify_signatures: VerifySignatures,
|
||||||
spec: &ChainSpec,
|
spec: &ChainSpec,
|
||||||
) -> Result<(), BlockProcessingError> {
|
) -> Result<(), BlockProcessingError> {
|
||||||
match block_body {
|
for (i, signed_address_change) in bls_to_execution_changes.iter().enumerate() {
|
||||||
BeaconBlockBodyRef::Base(_)
|
verify_bls_to_execution_change(state, signed_address_change, verify_signatures, spec)
|
||||||
| BeaconBlockBodyRef::Altair(_)
|
.map_err(|e| e.into_with_index(i))?;
|
||||||
| BeaconBlockBodyRef::Merge(_) => Ok(()),
|
|
||||||
BeaconBlockBodyRef::Capella(_) | BeaconBlockBodyRef::Eip4844(_) => {
|
|
||||||
for (i, signed_address_change) in
|
|
||||||
block_body.bls_to_execution_changes()?.iter().enumerate()
|
|
||||||
{
|
|
||||||
verify_bls_to_execution_change(
|
|
||||||
state,
|
|
||||||
&signed_address_change,
|
|
||||||
verify_signatures,
|
|
||||||
spec,
|
|
||||||
)
|
|
||||||
.map_err(|e| e.into_with_index(i))?;
|
|
||||||
|
|
||||||
state
|
state
|
||||||
.get_validator_mut(signed_address_change.message.validator_index as usize)?
|
.get_validator_mut(signed_address_change.message.validator_index as usize)?
|
||||||
.change_withdrawal_credentials(
|
.change_withdrawal_credentials(
|
||||||
&signed_address_change.message.to_execution_address,
|
&signed_address_change.message.to_execution_address,
|
||||||
spec,
|
spec,
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Validates each `Deposit` and updates the state, short-circuiting on an invalid object.
|
/// Validates each `Deposit` and updates the state, short-circuiting on an invalid object.
|
||||||
|
@ -42,13 +42,13 @@ pub fn verify_bls_to_execution_change<T: EthSpec>(
|
|||||||
// FIXME: Should this check be put inside the verify_signatures.is_true() condition?
|
// FIXME: Should this check be put inside the verify_signatures.is_true() condition?
|
||||||
// I believe that's used for fuzzing so this is a Mehdi question..
|
// I believe that's used for fuzzing so this is a Mehdi question..
|
||||||
verify!(
|
verify!(
|
||||||
validator.withdrawal_credentials.as_bytes()[1..] == pubkey_hash[1..],
|
validator.withdrawal_credentials.as_bytes().get(1..) == pubkey_hash.get(1..),
|
||||||
Invalid::WithdrawalCredentialsMismatch
|
Invalid::WithdrawalCredentialsMismatch
|
||||||
);
|
);
|
||||||
|
|
||||||
if verify_signatures.is_true() {
|
if verify_signatures.is_true() {
|
||||||
verify!(
|
verify!(
|
||||||
bls_execution_change_signature_set(state, signed_address_change, spec,)?.verify(),
|
bls_execution_change_signature_set(state, signed_address_change, spec)?.verify(),
|
||||||
Invalid::BadSignature
|
Invalid::BadSignature
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
use crate::upgrade::{upgrade_to_altair, upgrade_to_bellatrix};
|
use crate::upgrade::{
|
||||||
|
upgrade_to_altair, upgrade_to_bellatrix, upgrade_to_capella, upgrade_to_eip4844,
|
||||||
|
};
|
||||||
use crate::{per_epoch_processing::EpochProcessingSummary, *};
|
use crate::{per_epoch_processing::EpochProcessingSummary, *};
|
||||||
use safe_arith::{ArithError, SafeArith};
|
use safe_arith::{ArithError, SafeArith};
|
||||||
use types::*;
|
use types::*;
|
||||||
@ -55,6 +57,14 @@ pub fn per_slot_processing<T: EthSpec>(
|
|||||||
if spec.bellatrix_fork_epoch == Some(state.current_epoch()) {
|
if spec.bellatrix_fork_epoch == Some(state.current_epoch()) {
|
||||||
upgrade_to_bellatrix(state, spec)?;
|
upgrade_to_bellatrix(state, spec)?;
|
||||||
}
|
}
|
||||||
|
// Capella.
|
||||||
|
if spec.capella_fork_epoch == Some(state.current_epoch()) {
|
||||||
|
upgrade_to_capella(state, spec)?;
|
||||||
|
}
|
||||||
|
// Eip4844
|
||||||
|
if spec.eip4844_fork_epoch == Some(state.current_epoch()) {
|
||||||
|
upgrade_to_eip4844(state, spec)?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(summary)
|
Ok(summary)
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
use ssz_types::VariableList;
|
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use types::{BeaconState, BeaconStateCapella, BeaconStateError as Error, ChainSpec, EthSpec, Fork};
|
use types::{BeaconState, BeaconStateCapella, BeaconStateError as Error, ChainSpec, EthSpec, Fork};
|
||||||
|
|
||||||
|
@ -78,17 +78,20 @@ impl<'a, T: EthSpec, Payload: AbstractExecPayload<T>> SignedRoot
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Empty block trait for each block variant to implement.
|
||||||
|
pub trait EmptyBlock {
|
||||||
|
/// Returns an empty block to be used during genesis.
|
||||||
|
fn empty(spec: &ChainSpec) -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
impl<T: EthSpec, Payload: AbstractExecPayload<T>> BeaconBlock<T, Payload> {
|
impl<T: EthSpec, Payload: AbstractExecPayload<T>> BeaconBlock<T, Payload> {
|
||||||
// FIXME: deal with capella / eip4844 forks here as well
|
|
||||||
/// Returns an empty block to be used during genesis.
|
/// Returns an empty block to be used during genesis.
|
||||||
pub fn empty(spec: &ChainSpec) -> Self {
|
pub fn empty(spec: &ChainSpec) -> Self {
|
||||||
if spec.bellatrix_fork_epoch == Some(T::genesis_epoch()) {
|
map_fork_name!(
|
||||||
Self::Merge(BeaconBlockMerge::empty(spec))
|
spec.fork_name_at_epoch(T::genesis_epoch()),
|
||||||
} else if spec.altair_fork_epoch == Some(T::genesis_epoch()) {
|
Self,
|
||||||
Self::Altair(BeaconBlockAltair::empty(spec))
|
EmptyBlock::empty(spec)
|
||||||
} else {
|
)
|
||||||
Self::Base(BeaconBlockBase::empty(spec))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Custom SSZ decoder that takes a `ChainSpec` as context.
|
/// Custom SSZ decoder that takes a `ChainSpec` as context.
|
||||||
@ -117,13 +120,12 @@ impl<T: EthSpec, Payload: AbstractExecPayload<T>> BeaconBlock<T, Payload> {
|
|||||||
/// Usually it's better to prefer `from_ssz_bytes` which will decode the correct variant based
|
/// Usually it's better to prefer `from_ssz_bytes` which will decode the correct variant based
|
||||||
/// on the fork slot.
|
/// on the fork slot.
|
||||||
pub fn any_from_ssz_bytes(bytes: &[u8]) -> Result<Self, ssz::DecodeError> {
|
pub fn any_from_ssz_bytes(bytes: &[u8]) -> Result<Self, ssz::DecodeError> {
|
||||||
BeaconBlockMerge::from_ssz_bytes(bytes)
|
BeaconBlockEip4844::from_ssz_bytes(bytes)
|
||||||
.map(BeaconBlock::Merge)
|
.map(BeaconBlock::Eip4844)
|
||||||
.or_else(|_| {
|
.or_else(|_| BeaconBlockCapella::from_ssz_bytes(bytes).map(BeaconBlock::Capella))
|
||||||
BeaconBlockAltair::from_ssz_bytes(bytes)
|
.or_else(|_| BeaconBlockMerge::from_ssz_bytes(bytes).map(BeaconBlock::Merge))
|
||||||
.map(BeaconBlock::Altair)
|
.or_else(|_| BeaconBlockAltair::from_ssz_bytes(bytes).map(BeaconBlock::Altair))
|
||||||
.or_else(|_| BeaconBlockBase::from_ssz_bytes(bytes).map(BeaconBlock::Base))
|
.or_else(|_| BeaconBlockBase::from_ssz_bytes(bytes).map(BeaconBlock::Base))
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convenience accessor for the `body` as a `BeaconBlockBodyRef`.
|
/// Convenience accessor for the `body` as a `BeaconBlockBodyRef`.
|
||||||
@ -266,9 +268,8 @@ impl<'a, T: EthSpec, Payload: AbstractExecPayload<T>> BeaconBlockRefMut<'a, T, P
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: EthSpec, Payload: AbstractExecPayload<T>> BeaconBlockBase<T, Payload> {
|
impl<T: EthSpec, Payload: AbstractExecPayload<T>> EmptyBlock for BeaconBlockBase<T, Payload> {
|
||||||
/// Returns an empty block to be used during genesis.
|
fn empty(spec: &ChainSpec) -> Self {
|
||||||
pub fn empty(spec: &ChainSpec) -> Self {
|
|
||||||
BeaconBlockBase {
|
BeaconBlockBase {
|
||||||
slot: spec.genesis_slot,
|
slot: spec.genesis_slot,
|
||||||
proposer_index: 0,
|
proposer_index: 0,
|
||||||
@ -291,7 +292,9 @@ impl<T: EthSpec, Payload: AbstractExecPayload<T>> BeaconBlockBase<T, Payload> {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: EthSpec, Payload: AbstractExecPayload<T>> BeaconBlockBase<T, Payload> {
|
||||||
/// Return a block where the block has maximum size.
|
/// Return a block where the block has maximum size.
|
||||||
pub fn full(spec: &ChainSpec) -> Self {
|
pub fn full(spec: &ChainSpec) -> Self {
|
||||||
let header = BeaconBlockHeader {
|
let header = BeaconBlockHeader {
|
||||||
@ -387,9 +390,9 @@ impl<T: EthSpec, Payload: AbstractExecPayload<T>> BeaconBlockBase<T, Payload> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: EthSpec, Payload: AbstractExecPayload<T>> BeaconBlockAltair<T, Payload> {
|
impl<T: EthSpec, Payload: AbstractExecPayload<T>> EmptyBlock for BeaconBlockAltair<T, Payload> {
|
||||||
/// Returns an empty Altair block to be used during genesis.
|
/// Returns an empty Altair block to be used during genesis.
|
||||||
pub fn empty(spec: &ChainSpec) -> Self {
|
fn empty(spec: &ChainSpec) -> Self {
|
||||||
BeaconBlockAltair {
|
BeaconBlockAltair {
|
||||||
slot: spec.genesis_slot,
|
slot: spec.genesis_slot,
|
||||||
proposer_index: 0,
|
proposer_index: 0,
|
||||||
@ -413,7 +416,9 @@ impl<T: EthSpec, Payload: AbstractExecPayload<T>> BeaconBlockAltair<T, Payload>
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: EthSpec, Payload: AbstractExecPayload<T>> BeaconBlockAltair<T, Payload> {
|
||||||
/// Return an Altair block where the block has maximum size.
|
/// Return an Altair block where the block has maximum size.
|
||||||
pub fn full(spec: &ChainSpec) -> Self {
|
pub fn full(spec: &ChainSpec) -> Self {
|
||||||
let base_block: BeaconBlockBase<_, Payload> = BeaconBlockBase::full(spec);
|
let base_block: BeaconBlockBase<_, Payload> = BeaconBlockBase::full(spec);
|
||||||
@ -446,9 +451,9 @@ impl<T: EthSpec, Payload: AbstractExecPayload<T>> BeaconBlockAltair<T, Payload>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: EthSpec, Payload: AbstractExecPayload<T>> BeaconBlockMerge<T, Payload> {
|
impl<T: EthSpec, Payload: AbstractExecPayload<T>> EmptyBlock for BeaconBlockMerge<T, Payload> {
|
||||||
/// Returns an empty Merge block to be used during genesis.
|
/// Returns an empty Merge block to be used during genesis.
|
||||||
pub fn empty(spec: &ChainSpec) -> Self {
|
fn empty(spec: &ChainSpec) -> Self {
|
||||||
BeaconBlockMerge {
|
BeaconBlockMerge {
|
||||||
slot: spec.genesis_slot,
|
slot: spec.genesis_slot,
|
||||||
proposer_index: 0,
|
proposer_index: 0,
|
||||||
@ -474,6 +479,67 @@ impl<T: EthSpec, Payload: AbstractExecPayload<T>> BeaconBlockMerge<T, Payload> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: EthSpec, Payload: AbstractExecPayload<T>> EmptyBlock for BeaconBlockCapella<T, Payload> {
|
||||||
|
/// Returns an empty Capella block to be used during genesis.
|
||||||
|
fn empty(spec: &ChainSpec) -> Self {
|
||||||
|
BeaconBlockCapella {
|
||||||
|
slot: spec.genesis_slot,
|
||||||
|
proposer_index: 0,
|
||||||
|
parent_root: Hash256::zero(),
|
||||||
|
state_root: Hash256::zero(),
|
||||||
|
body: BeaconBlockBodyCapella {
|
||||||
|
randao_reveal: Signature::empty(),
|
||||||
|
eth1_data: Eth1Data {
|
||||||
|
deposit_root: Hash256::zero(),
|
||||||
|
block_hash: Hash256::zero(),
|
||||||
|
deposit_count: 0,
|
||||||
|
},
|
||||||
|
graffiti: Graffiti::default(),
|
||||||
|
proposer_slashings: VariableList::empty(),
|
||||||
|
attester_slashings: VariableList::empty(),
|
||||||
|
attestations: VariableList::empty(),
|
||||||
|
deposits: VariableList::empty(),
|
||||||
|
voluntary_exits: VariableList::empty(),
|
||||||
|
sync_aggregate: SyncAggregate::empty(),
|
||||||
|
execution_payload: Payload::Capella::default(),
|
||||||
|
#[cfg(feature = "withdrawals")]
|
||||||
|
bls_to_execution_changes: VariableList::empty(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: EthSpec, Payload: AbstractExecPayload<T>> EmptyBlock for BeaconBlockEip4844<T, Payload> {
|
||||||
|
/// Returns an empty Eip4844 block to be used during genesis.
|
||||||
|
fn empty(spec: &ChainSpec) -> Self {
|
||||||
|
BeaconBlockEip4844 {
|
||||||
|
slot: spec.genesis_slot,
|
||||||
|
proposer_index: 0,
|
||||||
|
parent_root: Hash256::zero(),
|
||||||
|
state_root: Hash256::zero(),
|
||||||
|
body: BeaconBlockBodyEip4844 {
|
||||||
|
randao_reveal: Signature::empty(),
|
||||||
|
eth1_data: Eth1Data {
|
||||||
|
deposit_root: Hash256::zero(),
|
||||||
|
block_hash: Hash256::zero(),
|
||||||
|
deposit_count: 0,
|
||||||
|
},
|
||||||
|
graffiti: Graffiti::default(),
|
||||||
|
proposer_slashings: VariableList::empty(),
|
||||||
|
attester_slashings: VariableList::empty(),
|
||||||
|
attestations: VariableList::empty(),
|
||||||
|
deposits: VariableList::empty(),
|
||||||
|
voluntary_exits: VariableList::empty(),
|
||||||
|
sync_aggregate: SyncAggregate::empty(),
|
||||||
|
execution_payload: Payload::Eip4844::default(),
|
||||||
|
#[cfg(feature = "withdrawals")]
|
||||||
|
bls_to_execution_changes: VariableList::empty(),
|
||||||
|
blob_kzg_commitments: VariableList::empty(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// We can convert pre-Bellatrix blocks without payloads into blocks "with" payloads.
|
// We can convert pre-Bellatrix blocks without payloads into blocks "with" payloads.
|
||||||
impl<E: EthSpec> From<BeaconBlockBase<E, BlindedPayload<E>>>
|
impl<E: EthSpec> From<BeaconBlockBase<E, BlindedPayload<E>>>
|
||||||
for BeaconBlockBase<E, FullPayload<E>>
|
for BeaconBlockBase<E, FullPayload<E>>
|
||||||
|
@ -76,7 +76,7 @@ pub struct BeaconBlockBody<T: EthSpec, Payload: AbstractExecPayload<T> = FullPay
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<T: EthSpec, Payload: AbstractExecPayload<T>> BeaconBlockBody<T, Payload> {
|
impl<T: EthSpec, Payload: AbstractExecPayload<T>> BeaconBlockBody<T, Payload> {
|
||||||
pub fn execution_payload<'a>(&'a self) -> Result<Payload::Ref<'a>, Error> {
|
pub fn execution_payload(&self) -> Result<Payload::Ref<'_>, Error> {
|
||||||
self.to_ref().execution_payload()
|
self.to_ref().execution_payload()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -296,10 +296,10 @@ where
|
|||||||
|
|
||||||
// Withdrawals
|
// Withdrawals
|
||||||
#[cfg(feature = "withdrawals")]
|
#[cfg(feature = "withdrawals")]
|
||||||
#[superstruct(only(Capella, Eip4844))]
|
#[superstruct(only(Capella, Eip4844), partial_getter(copy))]
|
||||||
pub next_withdrawal_index: u64,
|
pub next_withdrawal_index: u64,
|
||||||
#[cfg(feature = "withdrawals")]
|
#[cfg(feature = "withdrawals")]
|
||||||
#[superstruct(only(Capella, Eip4844))]
|
#[superstruct(only(Capella, Eip4844), partial_getter(copy))]
|
||||||
pub next_withdrawal_validator_index: u64,
|
pub next_withdrawal_validator_index: u64,
|
||||||
|
|
||||||
// Caching (not in the spec)
|
// Caching (not in the spec)
|
||||||
@ -1784,6 +1784,8 @@ impl<T: EthSpec> CompareFields for BeaconState<T> {
|
|||||||
(BeaconState::Base(x), BeaconState::Base(y)) => x.compare_fields(y),
|
(BeaconState::Base(x), BeaconState::Base(y)) => x.compare_fields(y),
|
||||||
(BeaconState::Altair(x), BeaconState::Altair(y)) => x.compare_fields(y),
|
(BeaconState::Altair(x), BeaconState::Altair(y)) => x.compare_fields(y),
|
||||||
(BeaconState::Merge(x), BeaconState::Merge(y)) => x.compare_fields(y),
|
(BeaconState::Merge(x), BeaconState::Merge(y)) => x.compare_fields(y),
|
||||||
|
(BeaconState::Capella(x), BeaconState::Capella(y)) => x.compare_fields(y),
|
||||||
|
(BeaconState::Eip4844(x), BeaconState::Eip4844(y)) => x.compare_fields(y),
|
||||||
_ => panic!("compare_fields: mismatched state variants",),
|
_ => panic!("compare_fields: mismatched state variants",),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -363,6 +363,16 @@ impl<T: EthSpec> BeaconTreeHashCacheInner<T> {
|
|||||||
hasher.write(payload_header.tree_hash_root().as_bytes())?;
|
hasher.write(payload_header.tree_hash_root().as_bytes())?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Withdrawal indices (Capella and later).
|
||||||
|
#[cfg(feature = "withdrawals")]
|
||||||
|
if let Ok(next_withdrawal_index) = state.next_withdrawal_index() {
|
||||||
|
hasher.write(next_withdrawal_index.tree_hash_root().as_bytes())?;
|
||||||
|
}
|
||||||
|
#[cfg(feature = "withdrawals")]
|
||||||
|
if let Ok(next_withdrawal_validator_index) = state.next_withdrawal_validator_index() {
|
||||||
|
hasher.write(next_withdrawal_validator_index.tree_hash_root().as_bytes())?;
|
||||||
|
}
|
||||||
|
|
||||||
let root = hasher.finish()?;
|
let root = hasher.finish()?;
|
||||||
|
|
||||||
self.previous_state = Some((root, state.slot()));
|
self.previous_state = Some((root, state.slot()));
|
||||||
|
@ -4,7 +4,6 @@ use serde_derive::{Deserialize, Serialize};
|
|||||||
use ssz::Encode;
|
use ssz::Encode;
|
||||||
use ssz_derive::{Decode, Encode};
|
use ssz_derive::{Decode, Encode};
|
||||||
use ssz_types::VariableList;
|
use ssz_types::VariableList;
|
||||||
use tree_hash::TreeHash;
|
|
||||||
use tree_hash_derive::TreeHash;
|
use tree_hash_derive::TreeHash;
|
||||||
|
|
||||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||||
@ -23,6 +22,7 @@ impl<T: EthSpec> BlobsSidecar<T> {
|
|||||||
pub fn empty() -> Self {
|
pub fn empty() -> Self {
|
||||||
Self::default()
|
Self::default()
|
||||||
}
|
}
|
||||||
|
#[allow(clippy::integer_arithmetic)]
|
||||||
pub fn max_size() -> usize {
|
pub fn max_size() -> usize {
|
||||||
// Fixed part
|
// Fixed part
|
||||||
Self::empty().as_ssz_bytes().len()
|
Self::empty().as_ssz_bytes().len()
|
||||||
|
@ -324,6 +324,7 @@ impl EthSpec for MinimalEthSpec {
|
|||||||
type SyncSubcommitteeSize = U8; // 32 committee size / 4 sync committee subnet count
|
type SyncSubcommitteeSize = U8; // 32 committee size / 4 sync committee subnet count
|
||||||
type MaxPendingAttestations = U1024; // 128 max attestations * 8 slots per epoch
|
type MaxPendingAttestations = U1024; // 128 max attestations * 8 slots per epoch
|
||||||
type SlotsPerEth1VotingPeriod = U32; // 4 epochs * 8 slots per epoch
|
type SlotsPerEth1VotingPeriod = U32; // 4 epochs * 8 slots per epoch
|
||||||
|
type MaxWithdrawalsPerPayload = U4;
|
||||||
|
|
||||||
params_from_eth_spec!(MainnetEthSpec {
|
params_from_eth_spec!(MainnetEthSpec {
|
||||||
JustificationBitsLength,
|
JustificationBitsLength,
|
||||||
@ -345,7 +346,6 @@ impl EthSpec for MinimalEthSpec {
|
|||||||
MinGasLimit,
|
MinGasLimit,
|
||||||
MaxExtraDataBytes,
|
MaxExtraDataBytes,
|
||||||
MaxBlsToExecutionChanges,
|
MaxBlsToExecutionChanges,
|
||||||
MaxWithdrawalsPerPayload,
|
|
||||||
MaxBlobsPerBlock,
|
MaxBlobsPerBlock,
|
||||||
FieldElementsPerBlob
|
FieldElementsPerBlob
|
||||||
});
|
});
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use crate::{test_utils::TestRandom, *};
|
use crate::{test_utils::TestRandom, *};
|
||||||
use derivative::Derivative;
|
use derivative::Derivative;
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
use ssz::Encode;
|
use ssz::{Decode, Encode};
|
||||||
use ssz_derive::{Decode, Encode};
|
use ssz_derive::{Decode, Encode};
|
||||||
use test_random_derive::TestRandom;
|
use test_random_derive::TestRandom;
|
||||||
use tree_hash_derive::TreeHash;
|
use tree_hash_derive::TreeHash;
|
||||||
@ -87,6 +87,17 @@ pub struct ExecutionPayload<T: EthSpec> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<T: EthSpec> ExecutionPayload<T> {
|
impl<T: EthSpec> ExecutionPayload<T> {
|
||||||
|
pub fn from_ssz_bytes(bytes: &[u8], fork_name: ForkName) -> Result<Self, ssz::DecodeError> {
|
||||||
|
match fork_name {
|
||||||
|
ForkName::Base | ForkName::Altair => Err(ssz::DecodeError::BytesInvalid(format!(
|
||||||
|
"unsupported fork for ExecutionPayload: {fork_name}",
|
||||||
|
))),
|
||||||
|
ForkName::Merge => ExecutionPayloadMerge::from_ssz_bytes(bytes).map(Self::Merge),
|
||||||
|
ForkName::Capella => ExecutionPayloadCapella::from_ssz_bytes(bytes).map(Self::Capella),
|
||||||
|
ForkName::Eip4844 => ExecutionPayloadEip4844::from_ssz_bytes(bytes).map(Self::Eip4844),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(clippy::integer_arithmetic)]
|
#[allow(clippy::integer_arithmetic)]
|
||||||
/// Returns the maximum size of an execution payload.
|
/// Returns the maximum size of an execution payload.
|
||||||
pub fn max_execution_payload_merge_size() -> usize {
|
pub fn max_execution_payload_merge_size() -> usize {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use crate::{test_utils::TestRandom, *};
|
use crate::{test_utils::TestRandom, *};
|
||||||
use derivative::Derivative;
|
use derivative::Derivative;
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
use ssz::Decode;
|
||||||
use ssz_derive::{Decode, Encode};
|
use ssz_derive::{Decode, Encode};
|
||||||
use test_random_derive::TestRandom;
|
use test_random_derive::TestRandom;
|
||||||
use tree_hash::TreeHash;
|
use tree_hash::TreeHash;
|
||||||
@ -84,31 +85,34 @@ impl<T: EthSpec> ExecutionPayloadHeader<T> {
|
|||||||
pub fn transactions(&self) -> Option<&Transactions<T>> {
|
pub fn transactions(&self) -> Option<&Transactions<T>> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, T: EthSpec> ExecutionPayloadHeaderRef<'a, T> {
|
pub fn from_ssz_bytes(bytes: &[u8], fork_name: ForkName) -> Result<Self, ssz::DecodeError> {
|
||||||
// FIXME: maybe this could be a derived trait..
|
match fork_name {
|
||||||
pub fn is_default(self) -> bool {
|
ForkName::Base | ForkName::Altair => Err(ssz::DecodeError::BytesInvalid(format!(
|
||||||
match self {
|
"unsupported fork for ExecutionPayloadHeader: {fork_name}",
|
||||||
ExecutionPayloadHeaderRef::Merge(header) => {
|
))),
|
||||||
*header == ExecutionPayloadHeaderMerge::default()
|
ForkName::Merge => ExecutionPayloadHeaderMerge::from_ssz_bytes(bytes).map(Self::Merge),
|
||||||
|
ForkName::Capella => {
|
||||||
|
ExecutionPayloadHeaderCapella::from_ssz_bytes(bytes).map(Self::Capella)
|
||||||
}
|
}
|
||||||
ExecutionPayloadHeaderRef::Capella(header) => {
|
ForkName::Eip4844 => {
|
||||||
*header == ExecutionPayloadHeaderCapella::default()
|
ExecutionPayloadHeaderEip4844::from_ssz_bytes(bytes).map(Self::Eip4844)
|
||||||
}
|
|
||||||
ExecutionPayloadHeaderRef::Eip4844(header) => {
|
|
||||||
*header == ExecutionPayloadHeaderEip4844::default()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a, T: EthSpec> ExecutionPayloadHeaderRef<'a, T> {
|
||||||
|
pub fn is_default(self) -> bool {
|
||||||
|
map_execution_payload_header_ref!(&'a _, self, |inner, cons| {
|
||||||
|
let _ = cons(inner);
|
||||||
|
*inner == Default::default()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T: EthSpec> ExecutionPayloadHeaderMerge<T> {
|
impl<T: EthSpec> ExecutionPayloadHeaderMerge<T> {
|
||||||
pub fn upgrade_to_capella(&self) -> ExecutionPayloadHeaderCapella<T> {
|
pub fn upgrade_to_capella(&self) -> ExecutionPayloadHeaderCapella<T> {
|
||||||
#[cfg(feature = "withdrawals")]
|
|
||||||
// TODO: if this is correct we should calculate and hardcode this..
|
|
||||||
let empty_withdrawals_root =
|
|
||||||
VariableList::<Withdrawal, T::MaxWithdrawalsPerPayload>::empty().tree_hash_root();
|
|
||||||
ExecutionPayloadHeaderCapella {
|
ExecutionPayloadHeaderCapella {
|
||||||
parent_hash: self.parent_hash,
|
parent_hash: self.parent_hash,
|
||||||
fee_recipient: self.fee_recipient,
|
fee_recipient: self.fee_recipient,
|
||||||
@ -125,8 +129,7 @@ impl<T: EthSpec> ExecutionPayloadHeaderMerge<T> {
|
|||||||
block_hash: self.block_hash,
|
block_hash: self.block_hash,
|
||||||
transactions_root: self.transactions_root,
|
transactions_root: self.transactions_root,
|
||||||
#[cfg(feature = "withdrawals")]
|
#[cfg(feature = "withdrawals")]
|
||||||
// FIXME: the spec doesn't seem to define what to do here..
|
withdrawals_root: Hash256::zero(),
|
||||||
withdrawals_root: empty_withdrawals_root,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ pub struct KzgCommitment(#[serde(with = "BigArray")] pub [u8; 48]);
|
|||||||
|
|
||||||
impl Display for KzgCommitment {
|
impl Display for KzgCommitment {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
write!(f, "{}", eth2_serde_utils::hex::encode(&self.0))
|
write!(f, "{}", eth2_serde_utils::hex::encode(self.0))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
use crate::test_utils::{RngCore, TestRandom};
|
use crate::test_utils::{RngCore, TestRandom};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_big_array::BigArray;
|
use serde_big_array::BigArray;
|
||||||
use ssz::{Decode, DecodeError, Encode};
|
|
||||||
use ssz_derive::{Decode, Encode};
|
use ssz_derive::{Decode, Encode};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use tree_hash::{PackedEncoding, TreeHash};
|
use tree_hash::{PackedEncoding, TreeHash};
|
||||||
@ -15,7 +14,7 @@ pub struct KzgProof(#[serde(with = "BigArray")] pub [u8; KZG_PROOF_BYTES_LEN]);
|
|||||||
|
|
||||||
impl fmt::Display for KzgProof {
|
impl fmt::Display for KzgProof {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(f, "{}", eth2_serde_utils::hex::encode(&self.0))
|
write!(f, "{}", eth2_serde_utils::hex::encode(self.0))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,7 +109,7 @@ pub use crate::attestation_duty::AttestationDuty;
|
|||||||
pub use crate::attester_slashing::AttesterSlashing;
|
pub use crate::attester_slashing::AttesterSlashing;
|
||||||
pub use crate::beacon_block::{
|
pub use crate::beacon_block::{
|
||||||
BeaconBlock, BeaconBlockAltair, BeaconBlockBase, BeaconBlockCapella, BeaconBlockEip4844,
|
BeaconBlock, BeaconBlockAltair, BeaconBlockBase, BeaconBlockCapella, BeaconBlockEip4844,
|
||||||
BeaconBlockMerge, BeaconBlockRef, BeaconBlockRefMut, BlindedBeaconBlock,
|
BeaconBlockMerge, BeaconBlockRef, BeaconBlockRefMut, BlindedBeaconBlock, EmptyBlock,
|
||||||
};
|
};
|
||||||
pub use crate::beacon_block_body::{
|
pub use crate::beacon_block_body::{
|
||||||
BeaconBlockBody, BeaconBlockBodyAltair, BeaconBlockBodyBase, BeaconBlockBodyCapella,
|
BeaconBlockBody, BeaconBlockBodyAltair, BeaconBlockBodyBase, BeaconBlockBodyCapella,
|
||||||
|
@ -221,7 +221,7 @@ impl<T: EthSpec> ExecPayload<T> for FullPayload<T> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn transactions<'a>(&'a self) -> Option<&Transactions<T>> {
|
fn transactions<'a>(&'a self) -> Option<&'a Transactions<T>> {
|
||||||
map_full_payload_ref!(&'a _, self.to_ref(), move |payload, cons| {
|
map_full_payload_ref!(&'a _, self.to_ref(), move |payload, cons| {
|
||||||
cons(payload);
|
cons(payload);
|
||||||
Some(&payload.execution_payload.transactions)
|
Some(&payload.execution_payload.transactions)
|
||||||
@ -265,7 +265,7 @@ impl<'b, T: EthSpec> ExecPayload<T> for FullPayloadRef<'b, T> {
|
|||||||
fn to_execution_payload_header<'a>(&'a self) -> ExecutionPayloadHeader<T> {
|
fn to_execution_payload_header<'a>(&'a self) -> ExecutionPayloadHeader<T> {
|
||||||
map_full_payload_ref!(&'a _, self, move |payload, cons| {
|
map_full_payload_ref!(&'a _, self, move |payload, cons| {
|
||||||
cons(payload);
|
cons(payload);
|
||||||
ExecutionPayloadHeader::from(payload.to_execution_payload_header())
|
payload.to_execution_payload_header()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -318,7 +318,7 @@ impl<'b, T: EthSpec> ExecPayload<T> for FullPayloadRef<'b, T> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn transactions<'a>(&'a self) -> Option<&Transactions<T>> {
|
fn transactions<'a>(&'a self) -> Option<&'a Transactions<T>> {
|
||||||
map_full_payload_ref!(&'a _, self, move |payload, cons| {
|
map_full_payload_ref!(&'a _, self, move |payload, cons| {
|
||||||
cons(payload);
|
cons(payload);
|
||||||
Some(&payload.execution_payload.transactions)
|
Some(&payload.execution_payload.transactions)
|
||||||
@ -488,7 +488,7 @@ impl<T: EthSpec> ExecPayload<T> for BlindedPayload<T> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn transactions<'a>(&'a self) -> Option<&Transactions<T>> {
|
fn transactions(&self) -> Option<&Transactions<T>> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -574,7 +574,7 @@ impl<'b, T: EthSpec> ExecPayload<T> for BlindedPayloadRef<'b, T> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn transactions<'a>(&'a self) -> Option<&Transactions<T>> {
|
fn transactions(&self) -> Option<&Transactions<T>> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ impl CachedTreeHash<TreeHashCache> for Validator {
|
|||||||
|
|
||||||
/// Efficiently tree hash a `Validator`, assuming it was updated by a valid state transition.
|
/// Efficiently tree hash a `Validator`, assuming it was updated by a valid state transition.
|
||||||
///
|
///
|
||||||
/// Specifically, we assume that the `pubkey` and `withdrawal_credentials` fields are constant.
|
/// Specifically, we assume that the `pubkey` field is constant.
|
||||||
fn recalculate_tree_hash_root(
|
fn recalculate_tree_hash_root(
|
||||||
&self,
|
&self,
|
||||||
arena: &mut CacheArena,
|
arena: &mut CacheArena,
|
||||||
@ -29,8 +29,8 @@ impl CachedTreeHash<TreeHashCache> for Validator {
|
|||||||
.iter_mut(arena)?
|
.iter_mut(arena)?
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.flat_map(|(i, leaf)| {
|
.flat_map(|(i, leaf)| {
|
||||||
// Fields pubkey and withdrawal_credentials are constant
|
// Pubkey field (index 0) is constant.
|
||||||
if (i == 0 || i == 1) && cache.initialized {
|
if i == 0 && cache.initialized {
|
||||||
None
|
None
|
||||||
} else if process_field_by_index(self, i, leaf, !cache.initialized) {
|
} else if process_field_by_index(self, i, leaf, !cache.initialized) {
|
||||||
Some(i)
|
Some(i)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
test_utils::TestRandom, Address, BeaconState, BlsToExecutionChange, ChainSpec, Epoch, EthSpec,
|
test_utils::TestRandom, Address, BeaconState, ChainSpec, Epoch, EthSpec, Hash256,
|
||||||
Hash256, PublicKeyBytes,
|
PublicKeyBytes,
|
||||||
};
|
};
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
use ssz_derive::{Decode, Encode};
|
use ssz_derive::{Decode, Encode};
|
||||||
@ -76,6 +76,18 @@ impl Validator {
|
|||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the eth1 withdrawal address if this validator has one initialized.
|
||||||
|
pub fn get_eth1_withdrawal_address(&self, spec: &ChainSpec) -> Option<Address> {
|
||||||
|
self.has_eth1_withdrawal_credential(spec)
|
||||||
|
.then(|| {
|
||||||
|
self.withdrawal_credentials
|
||||||
|
.as_bytes()
|
||||||
|
.get(12..)
|
||||||
|
.map(Address::from_slice)
|
||||||
|
})
|
||||||
|
.flatten()
|
||||||
|
}
|
||||||
|
|
||||||
/// Changes withdrawal credentials to the provided eth1 execution address
|
/// Changes withdrawal credentials to the provided eth1 execution address
|
||||||
///
|
///
|
||||||
/// WARNING: this function does NO VALIDATION - it just does it!
|
/// WARNING: this function does NO VALIDATION - it just does it!
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
TESTS_TAG := v1.2.0
|
TESTS_TAG := f5c7cf78
|
||||||
TESTS = general minimal mainnet
|
TESTS = general minimal mainnet
|
||||||
TARBALLS = $(patsubst %,%-$(TESTS_TAG).tar.gz,$(TESTS))
|
TARBALLS = $(patsubst %,%-$(TESTS_TAG).tar.gz,$(TESTS))
|
||||||
|
|
||||||
|
@ -289,8 +289,9 @@ impl<E: EthSpec, T: EpochTransition<E>> Case for EpochProcessing<E, T> {
|
|||||||
&& T::name() != "participation_flag_updates"
|
&& T::name() != "participation_flag_updates"
|
||||||
}
|
}
|
||||||
// No phase0 tests for Altair and later.
|
// No phase0 tests for Altair and later.
|
||||||
ForkName::Altair | ForkName::Merge => T::name() != "participation_record_updates",
|
ForkName::Altair | ForkName::Merge | ForkName::Capella => {
|
||||||
ForkName::Capella => false, // TODO: revisit when tests are out
|
T::name() != "participation_record_updates"
|
||||||
|
}
|
||||||
ForkName::Eip4844 => false, // TODO: revisit when tests are out
|
ForkName::Eip4844 => false, // TODO: revisit when tests are out
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ use crate::case_result::compare_beacon_state_results_without_caches;
|
|||||||
use crate::cases::common::previous_fork;
|
use crate::cases::common::previous_fork;
|
||||||
use crate::decode::{ssz_decode_state, yaml_decode_file};
|
use crate::decode::{ssz_decode_state, yaml_decode_file};
|
||||||
use serde_derive::Deserialize;
|
use serde_derive::Deserialize;
|
||||||
use state_processing::upgrade::{upgrade_to_altair, upgrade_to_bellatrix};
|
use state_processing::upgrade::{upgrade_to_altair, upgrade_to_bellatrix, upgrade_to_capella};
|
||||||
use types::{BeaconState, ForkName};
|
use types::{BeaconState, ForkName};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default, Deserialize)]
|
#[derive(Debug, Clone, Default, Deserialize)]
|
||||||
@ -61,8 +61,8 @@ impl<E: EthSpec> Case for ForkTest<E> {
|
|||||||
ForkName::Base => panic!("phase0 not supported"),
|
ForkName::Base => panic!("phase0 not supported"),
|
||||||
ForkName::Altair => upgrade_to_altair(&mut result_state, spec).map(|_| result_state),
|
ForkName::Altair => upgrade_to_altair(&mut result_state, spec).map(|_| result_state),
|
||||||
ForkName::Merge => upgrade_to_bellatrix(&mut result_state, spec).map(|_| result_state),
|
ForkName::Merge => upgrade_to_bellatrix(&mut result_state, spec).map(|_| result_state),
|
||||||
|
ForkName::Capella => upgrade_to_capella(&mut result_state, spec).map(|_| result_state),
|
||||||
ForkName::Eip4844 => panic!("eip4844 not supported"),
|
ForkName::Eip4844 => panic!("eip4844 not supported"),
|
||||||
ForkName::Capella => panic!("capella not supported"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
compare_beacon_state_results_without_caches(&mut result, &mut expected)
|
compare_beacon_state_results_without_caches(&mut result, &mut expected)
|
||||||
|
@ -1,13 +1,10 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
use crate::case_result::compare_beacon_state_results_without_caches;
|
use crate::case_result::compare_beacon_state_results_without_caches;
|
||||||
use crate::decode::{ssz_decode_file, ssz_decode_state, yaml_decode_file};
|
use crate::decode::{ssz_decode_file, ssz_decode_file_with, ssz_decode_state, yaml_decode_file};
|
||||||
use serde_derive::Deserialize;
|
use serde_derive::Deserialize;
|
||||||
use state_processing::initialize_beacon_state_from_eth1;
|
use state_processing::initialize_beacon_state_from_eth1;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use types::{
|
use types::{BeaconState, Deposit, EthSpec, ExecutionPayloadHeader, ForkName, Hash256};
|
||||||
BeaconState, Deposit, EthSpec, ExecutionPayloadHeader, ExecutionPayloadHeaderMerge, ForkName,
|
|
||||||
Hash256,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize)]
|
#[derive(Debug, Clone, Deserialize)]
|
||||||
struct Metadata {
|
struct Metadata {
|
||||||
@ -41,14 +38,10 @@ impl<E: EthSpec> LoadCase for GenesisInitialization<E> {
|
|||||||
let meta: Metadata = yaml_decode_file(&path.join("meta.yaml"))?;
|
let meta: Metadata = yaml_decode_file(&path.join("meta.yaml"))?;
|
||||||
let execution_payload_header: Option<ExecutionPayloadHeader<E>> =
|
let execution_payload_header: Option<ExecutionPayloadHeader<E>> =
|
||||||
if meta.execution_payload_header.unwrap_or(false) {
|
if meta.execution_payload_header.unwrap_or(false) {
|
||||||
//FIXME(sean) we could decode based on timestamp - we probably don't do decode a payload
|
Some(ssz_decode_file_with(
|
||||||
// without a block this elsewhere at presetn. But when we support SSZ in the builder api we may need to.
|
|
||||||
// Although that API should include fork info. Hardcoding this for now
|
|
||||||
Some(ExecutionPayloadHeader::Merge(ssz_decode_file::<
|
|
||||||
ExecutionPayloadHeaderMerge<E>,
|
|
||||||
>(
|
|
||||||
&path.join("execution_payload_header.ssz_snappy"),
|
&path.join("execution_payload_header.ssz_snappy"),
|
||||||
)?))
|
|bytes| ExecutionPayloadHeader::from_ssz_bytes(bytes, fork_name),
|
||||||
|
)?)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
@ -3,17 +3,16 @@ use crate::bls_setting::BlsSetting;
|
|||||||
use crate::case_result::compare_beacon_state_results_without_caches;
|
use crate::case_result::compare_beacon_state_results_without_caches;
|
||||||
use crate::decode::{ssz_decode_file, ssz_decode_file_with, ssz_decode_state, yaml_decode_file};
|
use crate::decode::{ssz_decode_file, ssz_decode_file_with, ssz_decode_state, yaml_decode_file};
|
||||||
use crate::testing_spec;
|
use crate::testing_spec;
|
||||||
use crate::type_name::TypeName;
|
|
||||||
use serde_derive::Deserialize;
|
use serde_derive::Deserialize;
|
||||||
use state_processing::{
|
use state_processing::{
|
||||||
per_block_processing::{
|
per_block_processing::{
|
||||||
errors::BlockProcessingError,
|
errors::BlockProcessingError,
|
||||||
process_block_header, process_execution_payload,
|
process_block_header, process_execution_payload,
|
||||||
process_operations::{
|
process_operations::{
|
||||||
altair, base, process_attester_slashings, process_deposits, process_exits,
|
altair, base, process_attester_slashings, process_bls_to_execution_changes,
|
||||||
process_proposer_slashings,
|
process_deposits, process_exits, process_proposer_slashings,
|
||||||
},
|
},
|
||||||
process_sync_aggregate, VerifyBlockRoot, VerifySignatures,
|
process_sync_aggregate, process_withdrawals, VerifyBlockRoot, VerifySignatures,
|
||||||
},
|
},
|
||||||
ConsensusContext,
|
ConsensusContext,
|
||||||
};
|
};
|
||||||
@ -21,7 +20,7 @@ use std::fmt::Debug;
|
|||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use types::{
|
use types::{
|
||||||
Attestation, AttesterSlashing, BeaconBlock, BeaconState, BlindedPayload, ChainSpec, Deposit,
|
Attestation, AttesterSlashing, BeaconBlock, BeaconState, BlindedPayload, ChainSpec, Deposit,
|
||||||
EthSpec, ExecutionPayload, ExecutionPayloadMerge, ForkName, FullPayload, ProposerSlashing,
|
EthSpec, ExecutionPayload, ForkName, FullPayload, ProposerSlashing, SignedBlsToExecutionChange,
|
||||||
SignedVoluntaryExit, SyncAggregate,
|
SignedVoluntaryExit, SyncAggregate,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -36,6 +35,12 @@ struct ExecutionMetadata {
|
|||||||
execution_valid: bool,
|
execution_valid: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Newtype for testing withdrawals.
|
||||||
|
#[derive(Debug, Clone, Deserialize)]
|
||||||
|
pub struct WithdrawalsPayload<T: EthSpec> {
|
||||||
|
payload: FullPayload<T>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Operations<E: EthSpec, O: Operation<E>> {
|
pub struct Operations<E: EthSpec, O: Operation<E>> {
|
||||||
metadata: Metadata,
|
metadata: Metadata,
|
||||||
@ -45,10 +50,8 @@ pub struct Operations<E: EthSpec, O: Operation<E>> {
|
|||||||
pub post: Option<BeaconState<E>>,
|
pub post: Option<BeaconState<E>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Operation<E: EthSpec>: TypeName + Debug + Sync + Sized {
|
pub trait Operation<E: EthSpec>: Debug + Sync + Sized {
|
||||||
fn handler_name() -> String {
|
fn handler_name() -> String;
|
||||||
Self::name().to_lowercase()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn filename() -> String {
|
fn filename() -> String {
|
||||||
format!("{}.ssz_snappy", Self::handler_name())
|
format!("{}.ssz_snappy", Self::handler_name())
|
||||||
@ -58,7 +61,7 @@ pub trait Operation<E: EthSpec>: TypeName + Debug + Sync + Sized {
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decode(path: &Path, spec: &ChainSpec) -> Result<Self, Error>;
|
fn decode(path: &Path, fork_name: ForkName, spec: &ChainSpec) -> Result<Self, Error>;
|
||||||
|
|
||||||
fn apply_to(
|
fn apply_to(
|
||||||
&self,
|
&self,
|
||||||
@ -69,7 +72,11 @@ pub trait Operation<E: EthSpec>: TypeName + Debug + Sync + Sized {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<E: EthSpec> Operation<E> for Attestation<E> {
|
impl<E: EthSpec> Operation<E> for Attestation<E> {
|
||||||
fn decode(path: &Path, _spec: &ChainSpec) -> Result<Self, Error> {
|
fn handler_name() -> String {
|
||||||
|
"attestation".into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decode(path: &Path, _fork_name: ForkName, _spec: &ChainSpec) -> Result<Self, Error> {
|
||||||
ssz_decode_file(path)
|
ssz_decode_file(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,7 +116,7 @@ impl<E: EthSpec> Operation<E> for AttesterSlashing<E> {
|
|||||||
"attester_slashing".into()
|
"attester_slashing".into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decode(path: &Path, _spec: &ChainSpec) -> Result<Self, Error> {
|
fn decode(path: &Path, _fork_name: ForkName, _spec: &ChainSpec) -> Result<Self, Error> {
|
||||||
ssz_decode_file(path)
|
ssz_decode_file(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,7 +138,11 @@ impl<E: EthSpec> Operation<E> for AttesterSlashing<E> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<E: EthSpec> Operation<E> for Deposit {
|
impl<E: EthSpec> Operation<E> for Deposit {
|
||||||
fn decode(path: &Path, _spec: &ChainSpec) -> Result<Self, Error> {
|
fn handler_name() -> String {
|
||||||
|
"deposit".into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decode(path: &Path, _fork_name: ForkName, _spec: &ChainSpec) -> Result<Self, Error> {
|
||||||
ssz_decode_file(path)
|
ssz_decode_file(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,7 +166,7 @@ impl<E: EthSpec> Operation<E> for ProposerSlashing {
|
|||||||
"proposer_slashing".into()
|
"proposer_slashing".into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decode(path: &Path, _spec: &ChainSpec) -> Result<Self, Error> {
|
fn decode(path: &Path, _fork_name: ForkName, _spec: &ChainSpec) -> Result<Self, Error> {
|
||||||
ssz_decode_file(path)
|
ssz_decode_file(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,7 +192,7 @@ impl<E: EthSpec> Operation<E> for SignedVoluntaryExit {
|
|||||||
"voluntary_exit".into()
|
"voluntary_exit".into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decode(path: &Path, _spec: &ChainSpec) -> Result<Self, Error> {
|
fn decode(path: &Path, _fork_name: ForkName, _spec: &ChainSpec) -> Result<Self, Error> {
|
||||||
ssz_decode_file(path)
|
ssz_decode_file(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,7 +215,7 @@ impl<E: EthSpec> Operation<E> for BeaconBlock<E> {
|
|||||||
"block.ssz_snappy".into()
|
"block.ssz_snappy".into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decode(path: &Path, spec: &ChainSpec) -> Result<Self, Error> {
|
fn decode(path: &Path, _fork_name: ForkName, spec: &ChainSpec) -> Result<Self, Error> {
|
||||||
ssz_decode_file_with(path, |bytes| BeaconBlock::from_ssz_bytes(bytes, spec))
|
ssz_decode_file_with(path, |bytes| BeaconBlock::from_ssz_bytes(bytes, spec))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -239,7 +250,7 @@ impl<E: EthSpec> Operation<E> for SyncAggregate<E> {
|
|||||||
fork_name != ForkName::Base
|
fork_name != ForkName::Base
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decode(path: &Path, _spec: &ChainSpec) -> Result<Self, Error> {
|
fn decode(path: &Path, _fork_name: ForkName, _spec: &ChainSpec) -> Result<Self, Error> {
|
||||||
ssz_decode_file(path)
|
ssz_decode_file(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -267,13 +278,11 @@ impl<E: EthSpec> Operation<E> for FullPayload<E> {
|
|||||||
fork_name != ForkName::Base && fork_name != ForkName::Altair
|
fork_name != ForkName::Base && fork_name != ForkName::Altair
|
||||||
}
|
}
|
||||||
|
|
||||||
//FIXME(sean) we could decode based on timestamp - we probably don't do decode a payload
|
fn decode(path: &Path, fork_name: ForkName, _spec: &ChainSpec) -> Result<Self, Error> {
|
||||||
// without a block this elsewhere at presetn. But when we support SSZ in the builder api we may need to.
|
ssz_decode_file_with(path, |bytes| {
|
||||||
// Although that API should include fork info. Hardcoding this for now
|
ExecutionPayload::from_ssz_bytes(bytes, fork_name)
|
||||||
fn decode(path: &Path, _spec: &ChainSpec) -> Result<Self, Error> {
|
})
|
||||||
ssz_decode_file::<ExecutionPayloadMerge<E>>(path)
|
.map(Into::into)
|
||||||
.map(ExecutionPayload::Merge)
|
|
||||||
.map(Into::into)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_to(
|
fn apply_to(
|
||||||
@ -306,13 +315,11 @@ impl<E: EthSpec> Operation<E> for BlindedPayload<E> {
|
|||||||
fork_name != ForkName::Base && fork_name != ForkName::Altair
|
fork_name != ForkName::Base && fork_name != ForkName::Altair
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decode(path: &Path, _spec: &ChainSpec) -> Result<Self, Error> {
|
fn decode(path: &Path, fork_name: ForkName, _spec: &ChainSpec) -> Result<Self, Error> {
|
||||||
//FIXME(sean) we could decode based on timestamp - we probably don't do decode a payload
|
ssz_decode_file_with(path, |bytes| {
|
||||||
// without a block this elsewhere at presetn. But when we support SSZ in the builder api we may need to.
|
ExecutionPayload::from_ssz_bytes(bytes, fork_name)
|
||||||
// Although that API should include fork info. Hardcoding this for now
|
})
|
||||||
let payload: Result<ExecutionPayload<E>, Error> =
|
.map(Into::into)
|
||||||
ssz_decode_file::<ExecutionPayloadMerge<E>>(path).map(Into::into);
|
|
||||||
payload.map(Into::into)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_to(
|
fn apply_to(
|
||||||
@ -333,6 +340,65 @@ impl<E: EthSpec> Operation<E> for BlindedPayload<E> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<E: EthSpec> Operation<E> for WithdrawalsPayload<E> {
|
||||||
|
fn handler_name() -> String {
|
||||||
|
"withdrawals".into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn filename() -> String {
|
||||||
|
"execution_payload.ssz_snappy".into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_enabled_for_fork(fork_name: ForkName) -> bool {
|
||||||
|
fork_name != ForkName::Base && fork_name != ForkName::Altair && fork_name != ForkName::Merge
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decode(path: &Path, fork_name: ForkName, _spec: &ChainSpec) -> Result<Self, Error> {
|
||||||
|
ssz_decode_file_with(path, |bytes| {
|
||||||
|
ExecutionPayload::from_ssz_bytes(bytes, fork_name)
|
||||||
|
})
|
||||||
|
.map(|payload| WithdrawalsPayload {
|
||||||
|
payload: payload.into(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply_to(
|
||||||
|
&self,
|
||||||
|
state: &mut BeaconState<E>,
|
||||||
|
spec: &ChainSpec,
|
||||||
|
_: &Operations<E, Self>,
|
||||||
|
) -> Result<(), BlockProcessingError> {
|
||||||
|
process_withdrawals::<_, FullPayload<_>>(state, self.payload.to_ref(), spec)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: EthSpec> Operation<E> for SignedBlsToExecutionChange {
|
||||||
|
fn handler_name() -> String {
|
||||||
|
"bls_to_execution_change".into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn filename() -> String {
|
||||||
|
"address_change.ssz_snappy".into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_enabled_for_fork(fork_name: ForkName) -> bool {
|
||||||
|
fork_name != ForkName::Base && fork_name != ForkName::Altair && fork_name != ForkName::Merge
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decode(path: &Path, _fork_name: ForkName, _spec: &ChainSpec) -> Result<Self, Error> {
|
||||||
|
ssz_decode_file(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply_to(
|
||||||
|
&self,
|
||||||
|
state: &mut BeaconState<E>,
|
||||||
|
spec: &ChainSpec,
|
||||||
|
_extra: &Operations<E, Self>,
|
||||||
|
) -> Result<(), BlockProcessingError> {
|
||||||
|
process_bls_to_execution_changes(state, &[self.clone()], VerifySignatures::True, spec)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<E: EthSpec, O: Operation<E>> LoadCase for Operations<E, O> {
|
impl<E: EthSpec, O: Operation<E>> LoadCase for Operations<E, O> {
|
||||||
fn load_from_dir(path: &Path, fork_name: ForkName) -> Result<Self, Error> {
|
fn load_from_dir(path: &Path, fork_name: ForkName) -> Result<Self, Error> {
|
||||||
let spec = &testing_spec::<E>(fork_name);
|
let spec = &testing_spec::<E>(fork_name);
|
||||||
@ -356,7 +422,7 @@ impl<E: EthSpec, O: Operation<E>> LoadCase for Operations<E, O> {
|
|||||||
// Check BLS setting here before SSZ deserialization, as most types require signatures
|
// Check BLS setting here before SSZ deserialization, as most types require signatures
|
||||||
// to be valid.
|
// to be valid.
|
||||||
let (operation, bls_error) = if metadata.bls_setting.unwrap_or_default().check().is_ok() {
|
let (operation, bls_error) = if metadata.bls_setting.unwrap_or_default().check().is_ok() {
|
||||||
match O::decode(&path.join(O::filename()), spec) {
|
match O::decode(&path.join(O::filename()), fork_name, spec) {
|
||||||
Ok(op) => (Some(op), None),
|
Ok(op) => (Some(op), None),
|
||||||
Err(Error::InvalidBLSInput(error)) => (None, Some(error)),
|
Err(Error::InvalidBLSInput(error)) => (None, Some(error)),
|
||||||
Err(e) => return Err(e),
|
Err(e) => return Err(e),
|
||||||
@ -399,9 +465,11 @@ impl<E: EthSpec, O: Operation<E>> Case for Operations<E, O> {
|
|||||||
let mut expected = self.post.clone();
|
let mut expected = self.post.clone();
|
||||||
|
|
||||||
// Processing requires the committee caches.
|
// Processing requires the committee caches.
|
||||||
state
|
// NOTE: some of the withdrawals tests have 0 active validators, do not try
|
||||||
.build_all_committee_caches(spec)
|
// to build the commitee cache in this case.
|
||||||
.expect("committee caches OK");
|
if O::handler_name() != "withdrawals" {
|
||||||
|
state.build_all_committee_caches(spec).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
let mut result = self
|
let mut result = self
|
||||||
.operation
|
.operation
|
||||||
|
@ -42,14 +42,17 @@ impl<E: EthSpec> LoadCase for TransitionTest<E> {
|
|||||||
spec.altair_fork_epoch = Some(Epoch::new(0));
|
spec.altair_fork_epoch = Some(Epoch::new(0));
|
||||||
spec.bellatrix_fork_epoch = Some(metadata.fork_epoch);
|
spec.bellatrix_fork_epoch = Some(metadata.fork_epoch);
|
||||||
}
|
}
|
||||||
ForkName::Eip4844 => {
|
|
||||||
spec.bellatrix_fork_epoch = Some(Epoch::new(0));
|
|
||||||
spec.eip4844_fork_epoch = Some(metadata.fork_epoch);
|
|
||||||
}
|
|
||||||
ForkName::Capella => {
|
ForkName::Capella => {
|
||||||
spec.capella_fork_epoch = Some(Epoch::new(0));
|
spec.altair_fork_epoch = Some(Epoch::new(0));
|
||||||
|
spec.bellatrix_fork_epoch = Some(Epoch::new(0));
|
||||||
spec.capella_fork_epoch = Some(metadata.fork_epoch);
|
spec.capella_fork_epoch = Some(metadata.fork_epoch);
|
||||||
}
|
}
|
||||||
|
ForkName::Eip4844 => {
|
||||||
|
spec.altair_fork_epoch = Some(Epoch::new(0));
|
||||||
|
spec.bellatrix_fork_epoch = Some(Epoch::new(0));
|
||||||
|
spec.capella_fork_epoch = Some(Epoch::new(0));
|
||||||
|
spec.eip4844_fork_epoch = Some(metadata.fork_epoch);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load blocks
|
// Load blocks
|
||||||
|
@ -24,6 +24,11 @@ pub trait Handler {
|
|||||||
|
|
||||||
fn run(&self) {
|
fn run(&self) {
|
||||||
for fork_name in ForkName::list_all() {
|
for fork_name in ForkName::list_all() {
|
||||||
|
// FIXME(eip4844): enable eip4844
|
||||||
|
if fork_name == ForkName::Eip4844 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if self.is_enabled_for_fork(fork_name) {
|
if self.is_enabled_for_fork(fork_name) {
|
||||||
self.run_for_fork(fork_name)
|
self.run_for_fork(fork_name)
|
||||||
}
|
}
|
||||||
@ -218,6 +223,10 @@ impl<T, E> SszStaticHandler<T, E> {
|
|||||||
Self::for_forks(vec![ForkName::Merge])
|
Self::for_forks(vec![ForkName::Merge])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn capella_only() -> Self {
|
||||||
|
Self::for_forks(vec![ForkName::Capella])
|
||||||
|
}
|
||||||
|
|
||||||
pub fn merge_and_later() -> Self {
|
pub fn merge_and_later() -> Self {
|
||||||
Self::for_forks(ForkName::list_all()[2..].to_vec())
|
Self::for_forks(ForkName::list_all()[2..].to_vec())
|
||||||
}
|
}
|
||||||
@ -533,10 +542,8 @@ impl<E: EthSpec + TypeName> Handler for ForkChoiceHandler<E> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn is_enabled_for_fork(&self, fork_name: ForkName) -> bool {
|
fn is_enabled_for_fork(&self, fork_name: ForkName) -> bool {
|
||||||
// Merge block tests are only enabled for Bellatrix or later.
|
// Merge block tests are only enabled for Bellatrix.
|
||||||
if self.handler_name == "on_merge_block"
|
if self.handler_name == "on_merge_block" && fork_name != ForkName::Merge {
|
||||||
&& (fork_name == ForkName::Base || fork_name == ForkName::Altair)
|
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
pub use case_result::CaseResult;
|
pub use case_result::CaseResult;
|
||||||
pub use cases::Case;
|
|
||||||
pub use cases::{
|
pub use cases::{
|
||||||
EffectiveBalanceUpdates, Eth1DataReset, HistoricalRootsUpdate, InactivityUpdates,
|
Case, EffectiveBalanceUpdates, Eth1DataReset, HistoricalRootsUpdate, InactivityUpdates,
|
||||||
JustificationAndFinalization, ParticipationFlagUpdates, ParticipationRecordUpdates,
|
JustificationAndFinalization, ParticipationFlagUpdates, ParticipationRecordUpdates,
|
||||||
RandaoMixesReset, RegistryUpdates, RewardsAndPenalties, Slashings, SlashingsReset,
|
RandaoMixesReset, RegistryUpdates, RewardsAndPenalties, Slashings, SlashingsReset,
|
||||||
SyncCommitteeUpdates,
|
SyncCommitteeUpdates, WithdrawalsPayload,
|
||||||
};
|
};
|
||||||
pub use decode::log_file_access;
|
pub use decode::log_file_access;
|
||||||
pub use error::Error;
|
pub use error::Error;
|
||||||
|
@ -45,6 +45,8 @@ type_name_generic!(BeaconBlockBody);
|
|||||||
type_name_generic!(BeaconBlockBodyBase, "BeaconBlockBody");
|
type_name_generic!(BeaconBlockBodyBase, "BeaconBlockBody");
|
||||||
type_name_generic!(BeaconBlockBodyAltair, "BeaconBlockBody");
|
type_name_generic!(BeaconBlockBodyAltair, "BeaconBlockBody");
|
||||||
type_name_generic!(BeaconBlockBodyMerge, "BeaconBlockBody");
|
type_name_generic!(BeaconBlockBodyMerge, "BeaconBlockBody");
|
||||||
|
type_name_generic!(BeaconBlockBodyCapella, "BeaconBlockBody");
|
||||||
|
type_name_generic!(BeaconBlockBodyEip4844, "BeaconBlockBody");
|
||||||
type_name!(BeaconBlockHeader);
|
type_name!(BeaconBlockHeader);
|
||||||
type_name_generic!(BeaconState);
|
type_name_generic!(BeaconState);
|
||||||
type_name!(Checkpoint);
|
type_name!(Checkpoint);
|
||||||
@ -54,8 +56,14 @@ type_name!(DepositData);
|
|||||||
type_name!(DepositMessage);
|
type_name!(DepositMessage);
|
||||||
type_name!(Eth1Data);
|
type_name!(Eth1Data);
|
||||||
type_name_generic!(ExecutionPayload);
|
type_name_generic!(ExecutionPayload);
|
||||||
|
type_name_generic!(ExecutionPayloadMerge, "ExecutionPayload");
|
||||||
|
type_name_generic!(ExecutionPayloadCapella, "ExecutionPayload");
|
||||||
|
type_name_generic!(ExecutionPayloadEip4844, "ExecutionPayload");
|
||||||
type_name_generic!(FullPayload, "ExecutionPayload");
|
type_name_generic!(FullPayload, "ExecutionPayload");
|
||||||
type_name_generic!(ExecutionPayloadHeader);
|
type_name_generic!(ExecutionPayloadHeader);
|
||||||
|
type_name_generic!(ExecutionPayloadHeaderMerge, "ExecutionPayloadHeader");
|
||||||
|
type_name_generic!(ExecutionPayloadHeaderCapella, "ExecutionPayloadHeader");
|
||||||
|
type_name_generic!(ExecutionPayloadHeaderEip4844, "ExecutionPayloadHeader");
|
||||||
type_name_generic!(BlindedPayload, "ExecutionPayloadHeader");
|
type_name_generic!(BlindedPayload, "ExecutionPayloadHeader");
|
||||||
type_name!(Fork);
|
type_name!(Fork);
|
||||||
type_name!(ForkData);
|
type_name!(ForkData);
|
||||||
@ -76,3 +84,6 @@ type_name_generic!(SyncAggregate);
|
|||||||
type_name_generic!(SyncCommittee);
|
type_name_generic!(SyncCommittee);
|
||||||
type_name!(Validator);
|
type_name!(Validator);
|
||||||
type_name!(VoluntaryExit);
|
type_name!(VoluntaryExit);
|
||||||
|
type_name!(Withdrawal);
|
||||||
|
type_name!(BlsToExecutionChange, "BLSToExecutionChange");
|
||||||
|
type_name!(SignedBlsToExecutionChange, "SignedBLSToExecutionChange");
|
||||||
|
@ -82,6 +82,18 @@ fn operations_execution_payload_blinded() {
|
|||||||
OperationsHandler::<MainnetEthSpec, BlindedPayload<_>>::default().run();
|
OperationsHandler::<MainnetEthSpec, BlindedPayload<_>>::default().run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn operations_withdrawals() {
|
||||||
|
OperationsHandler::<MinimalEthSpec, WithdrawalsPayload<_>>::default().run();
|
||||||
|
OperationsHandler::<MainnetEthSpec, WithdrawalsPayload<_>>::default().run();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn operations_bls_to_execution_change() {
|
||||||
|
OperationsHandler::<MinimalEthSpec, SignedBlsToExecutionChange>::default().run();
|
||||||
|
OperationsHandler::<MainnetEthSpec, SignedBlsToExecutionChange>::default().run();
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn sanity_blocks() {
|
fn sanity_blocks() {
|
||||||
SanityBlocksHandler::<MinimalEthSpec>::default().run();
|
SanityBlocksHandler::<MinimalEthSpec>::default().run();
|
||||||
@ -250,6 +262,10 @@ mod ssz_static {
|
|||||||
.run();
|
.run();
|
||||||
SszStaticHandler::<BeaconBlockBodyMerge<MainnetEthSpec>, MainnetEthSpec>::merge_only()
|
SszStaticHandler::<BeaconBlockBodyMerge<MainnetEthSpec>, MainnetEthSpec>::merge_only()
|
||||||
.run();
|
.run();
|
||||||
|
SszStaticHandler::<BeaconBlockBodyCapella<MinimalEthSpec>, MinimalEthSpec>::capella_only()
|
||||||
|
.run();
|
||||||
|
SszStaticHandler::<BeaconBlockBodyCapella<MainnetEthSpec>, MainnetEthSpec>::capella_only()
|
||||||
|
.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Altair and later
|
// Altair and later
|
||||||
@ -302,18 +318,44 @@ mod ssz_static {
|
|||||||
// Merge and later
|
// Merge and later
|
||||||
#[test]
|
#[test]
|
||||||
fn execution_payload() {
|
fn execution_payload() {
|
||||||
SszStaticHandler::<ExecutionPayload<MinimalEthSpec>, MinimalEthSpec>::merge_and_later()
|
SszStaticHandler::<ExecutionPayloadMerge<MinimalEthSpec>, MinimalEthSpec>::merge_only()
|
||||||
.run();
|
.run();
|
||||||
SszStaticHandler::<ExecutionPayload<MainnetEthSpec>, MainnetEthSpec>::merge_and_later()
|
SszStaticHandler::<ExecutionPayloadMerge<MainnetEthSpec>, MainnetEthSpec>::merge_only()
|
||||||
|
.run();
|
||||||
|
SszStaticHandler::<ExecutionPayloadCapella<MinimalEthSpec>, MinimalEthSpec>::capella_only()
|
||||||
|
.run();
|
||||||
|
SszStaticHandler::<ExecutionPayloadCapella<MainnetEthSpec>, MainnetEthSpec>::capella_only()
|
||||||
.run();
|
.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn execution_payload_header() {
|
fn execution_payload_header() {
|
||||||
SszStaticHandler::<ExecutionPayloadHeader<MinimalEthSpec>, MinimalEthSpec>::merge_and_later()
|
SszStaticHandler::<ExecutionPayloadHeaderMerge<MinimalEthSpec>, MinimalEthSpec>::merge_only()
|
||||||
.run();
|
.run();
|
||||||
SszStaticHandler::<ExecutionPayloadHeader<MainnetEthSpec>, MainnetEthSpec>::merge_and_later()
|
SszStaticHandler::<ExecutionPayloadHeaderMerge<MainnetEthSpec>, MainnetEthSpec>::merge_only()
|
||||||
.run();
|
.run();
|
||||||
|
SszStaticHandler::<ExecutionPayloadHeaderCapella<MinimalEthSpec>, MinimalEthSpec>
|
||||||
|
::capella_only().run();
|
||||||
|
SszStaticHandler::<ExecutionPayloadHeaderCapella<MainnetEthSpec>, MainnetEthSpec>
|
||||||
|
::capella_only().run();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn withdrawal() {
|
||||||
|
SszStaticHandler::<Withdrawal, MinimalEthSpec>::capella_only().run();
|
||||||
|
SszStaticHandler::<Withdrawal, MainnetEthSpec>::capella_only().run();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn bls_to_execution_change() {
|
||||||
|
SszStaticHandler::<BlsToExecutionChange, MinimalEthSpec>::capella_only().run();
|
||||||
|
SszStaticHandler::<BlsToExecutionChange, MainnetEthSpec>::capella_only().run();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn signed_bls_to_execution_change() {
|
||||||
|
SszStaticHandler::<SignedBlsToExecutionChange, MinimalEthSpec>::capella_only().run();
|
||||||
|
SszStaticHandler::<SignedBlsToExecutionChange, MainnetEthSpec>::capella_only().run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user