mirror of
https://github.com/sigp/lighthouse.git
synced 2026-04-17 04:48:21 +00:00
Fixes to make EF Capella tests pass (#3719)
* Fixes to make EF Capella tests pass * Clippy for state_processing
This commit is contained in:
@@ -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> {
|
||||
// FIXME: deal with capella / eip4844 forks here as well
|
||||
/// Returns an empty block to be used during genesis.
|
||||
pub fn empty(spec: &ChainSpec) -> Self {
|
||||
if spec.bellatrix_fork_epoch == Some(T::genesis_epoch()) {
|
||||
Self::Merge(BeaconBlockMerge::empty(spec))
|
||||
} else if spec.altair_fork_epoch == Some(T::genesis_epoch()) {
|
||||
Self::Altair(BeaconBlockAltair::empty(spec))
|
||||
} else {
|
||||
Self::Base(BeaconBlockBase::empty(spec))
|
||||
}
|
||||
map_fork_name!(
|
||||
spec.fork_name_at_epoch(T::genesis_epoch()),
|
||||
Self,
|
||||
EmptyBlock::empty(spec)
|
||||
)
|
||||
}
|
||||
|
||||
/// 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
|
||||
/// on the fork slot.
|
||||
pub fn any_from_ssz_bytes(bytes: &[u8]) -> Result<Self, ssz::DecodeError> {
|
||||
BeaconBlockMerge::from_ssz_bytes(bytes)
|
||||
.map(BeaconBlock::Merge)
|
||||
.or_else(|_| {
|
||||
BeaconBlockAltair::from_ssz_bytes(bytes)
|
||||
.map(BeaconBlock::Altair)
|
||||
.or_else(|_| BeaconBlockBase::from_ssz_bytes(bytes).map(BeaconBlock::Base))
|
||||
})
|
||||
BeaconBlockEip4844::from_ssz_bytes(bytes)
|
||||
.map(BeaconBlock::Eip4844)
|
||||
.or_else(|_| BeaconBlockCapella::from_ssz_bytes(bytes).map(BeaconBlock::Capella))
|
||||
.or_else(|_| BeaconBlockMerge::from_ssz_bytes(bytes).map(BeaconBlock::Merge))
|
||||
.or_else(|_| BeaconBlockAltair::from_ssz_bytes(bytes).map(BeaconBlock::Altair))
|
||||
.or_else(|_| BeaconBlockBase::from_ssz_bytes(bytes).map(BeaconBlock::Base))
|
||||
}
|
||||
|
||||
/// 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> {
|
||||
/// Returns an empty block to be used during genesis.
|
||||
pub fn empty(spec: &ChainSpec) -> Self {
|
||||
impl<T: EthSpec, Payload: AbstractExecPayload<T>> EmptyBlock for BeaconBlockBase<T, Payload> {
|
||||
fn empty(spec: &ChainSpec) -> Self {
|
||||
BeaconBlockBase {
|
||||
slot: spec.genesis_slot,
|
||||
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.
|
||||
pub fn full(spec: &ChainSpec) -> Self {
|
||||
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.
|
||||
pub fn empty(spec: &ChainSpec) -> Self {
|
||||
fn empty(spec: &ChainSpec) -> Self {
|
||||
BeaconBlockAltair {
|
||||
slot: spec.genesis_slot,
|
||||
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.
|
||||
pub fn full(spec: &ChainSpec) -> Self {
|
||||
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.
|
||||
pub fn empty(spec: &ChainSpec) -> Self {
|
||||
fn empty(spec: &ChainSpec) -> Self {
|
||||
BeaconBlockMerge {
|
||||
slot: spec.genesis_slot,
|
||||
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.
|
||||
impl<E: EthSpec> From<BeaconBlockBase<E, BlindedPayload<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> {
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -296,10 +296,10 @@ where
|
||||
|
||||
// Withdrawals
|
||||
#[cfg(feature = "withdrawals")]
|
||||
#[superstruct(only(Capella, Eip4844))]
|
||||
#[superstruct(only(Capella, Eip4844), partial_getter(copy))]
|
||||
pub next_withdrawal_index: u64,
|
||||
#[cfg(feature = "withdrawals")]
|
||||
#[superstruct(only(Capella, Eip4844))]
|
||||
#[superstruct(only(Capella, Eip4844), partial_getter(copy))]
|
||||
pub next_withdrawal_validator_index: u64,
|
||||
|
||||
// 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::Altair(x), BeaconState::Altair(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",),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -363,6 +363,16 @@ impl<T: EthSpec> BeaconTreeHashCacheInner<T> {
|
||||
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()?;
|
||||
|
||||
self.previous_state = Some((root, state.slot()));
|
||||
|
||||
@@ -4,7 +4,6 @@ use serde_derive::{Deserialize, Serialize};
|
||||
use ssz::Encode;
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use ssz_types::VariableList;
|
||||
use tree_hash::TreeHash;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
@@ -23,6 +22,7 @@ impl<T: EthSpec> BlobsSidecar<T> {
|
||||
pub fn empty() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
#[allow(clippy::integer_arithmetic)]
|
||||
pub fn max_size() -> usize {
|
||||
// Fixed part
|
||||
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 MaxPendingAttestations = U1024; // 128 max attestations * 8 slots per epoch
|
||||
type SlotsPerEth1VotingPeriod = U32; // 4 epochs * 8 slots per epoch
|
||||
type MaxWithdrawalsPerPayload = U4;
|
||||
|
||||
params_from_eth_spec!(MainnetEthSpec {
|
||||
JustificationBitsLength,
|
||||
@@ -345,7 +346,6 @@ impl EthSpec for MinimalEthSpec {
|
||||
MinGasLimit,
|
||||
MaxExtraDataBytes,
|
||||
MaxBlsToExecutionChanges,
|
||||
MaxWithdrawalsPerPayload,
|
||||
MaxBlobsPerBlock,
|
||||
FieldElementsPerBlob
|
||||
});
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::{test_utils::TestRandom, *};
|
||||
use derivative::Derivative;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use ssz::Encode;
|
||||
use ssz::{Decode, Encode};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash_derive::TreeHash;
|
||||
@@ -87,6 +87,17 @@ pub struct ExecutionPayload<T: EthSpec> {
|
||||
}
|
||||
|
||||
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)]
|
||||
/// Returns the maximum size of an execution payload.
|
||||
pub fn max_execution_payload_merge_size() -> usize {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use crate::{test_utils::TestRandom, *};
|
||||
use derivative::Derivative;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use ssz::Decode;
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash::TreeHash;
|
||||
@@ -84,31 +85,34 @@ impl<T: EthSpec> ExecutionPayloadHeader<T> {
|
||||
pub fn transactions(&self) -> Option<&Transactions<T>> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: EthSpec> ExecutionPayloadHeaderRef<'a, T> {
|
||||
// FIXME: maybe this could be a derived trait..
|
||||
pub fn is_default(self) -> bool {
|
||||
match self {
|
||||
ExecutionPayloadHeaderRef::Merge(header) => {
|
||||
*header == ExecutionPayloadHeaderMerge::default()
|
||||
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 ExecutionPayloadHeader: {fork_name}",
|
||||
))),
|
||||
ForkName::Merge => ExecutionPayloadHeaderMerge::from_ssz_bytes(bytes).map(Self::Merge),
|
||||
ForkName::Capella => {
|
||||
ExecutionPayloadHeaderCapella::from_ssz_bytes(bytes).map(Self::Capella)
|
||||
}
|
||||
ExecutionPayloadHeaderRef::Capella(header) => {
|
||||
*header == ExecutionPayloadHeaderCapella::default()
|
||||
}
|
||||
ExecutionPayloadHeaderRef::Eip4844(header) => {
|
||||
*header == ExecutionPayloadHeaderEip4844::default()
|
||||
ForkName::Eip4844 => {
|
||||
ExecutionPayloadHeaderEip4844::from_ssz_bytes(bytes).map(Self::Eip4844)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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> {
|
||||
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 {
|
||||
parent_hash: self.parent_hash,
|
||||
fee_recipient: self.fee_recipient,
|
||||
@@ -125,8 +129,7 @@ impl<T: EthSpec> ExecutionPayloadHeaderMerge<T> {
|
||||
block_hash: self.block_hash,
|
||||
transactions_root: self.transactions_root,
|
||||
#[cfg(feature = "withdrawals")]
|
||||
// FIXME: the spec doesn't seem to define what to do here..
|
||||
withdrawals_root: empty_withdrawals_root,
|
||||
withdrawals_root: Hash256::zero(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ pub struct KzgCommitment(#[serde(with = "BigArray")] pub [u8; 48]);
|
||||
|
||||
impl Display for KzgCommitment {
|
||||
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 serde::{Deserialize, Serialize};
|
||||
use serde_big_array::BigArray;
|
||||
use ssz::{Decode, DecodeError, Encode};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use std::fmt;
|
||||
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 {
|
||||
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::beacon_block::{
|
||||
BeaconBlock, BeaconBlockAltair, BeaconBlockBase, BeaconBlockCapella, BeaconBlockEip4844,
|
||||
BeaconBlockMerge, BeaconBlockRef, BeaconBlockRefMut, BlindedBeaconBlock,
|
||||
BeaconBlockMerge, BeaconBlockRef, BeaconBlockRefMut, BlindedBeaconBlock, EmptyBlock,
|
||||
};
|
||||
pub use crate::beacon_block_body::{
|
||||
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| {
|
||||
cons(payload);
|
||||
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> {
|
||||
map_full_payload_ref!(&'a _, self, move |payload, cons| {
|
||||
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| {
|
||||
cons(payload);
|
||||
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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ impl CachedTreeHash<TreeHashCache> for Validator {
|
||||
|
||||
/// 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(
|
||||
&self,
|
||||
arena: &mut CacheArena,
|
||||
@@ -29,8 +29,8 @@ impl CachedTreeHash<TreeHashCache> for Validator {
|
||||
.iter_mut(arena)?
|
||||
.enumerate()
|
||||
.flat_map(|(i, leaf)| {
|
||||
// Fields pubkey and withdrawal_credentials are constant
|
||||
if (i == 0 || i == 1) && cache.initialized {
|
||||
// Pubkey field (index 0) is constant.
|
||||
if i == 0 && cache.initialized {
|
||||
None
|
||||
} else if process_field_by_index(self, i, leaf, !cache.initialized) {
|
||||
Some(i)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
test_utils::TestRandom, Address, BeaconState, BlsToExecutionChange, ChainSpec, Epoch, EthSpec,
|
||||
Hash256, PublicKeyBytes,
|
||||
test_utils::TestRandom, Address, BeaconState, ChainSpec, Epoch, EthSpec, Hash256,
|
||||
PublicKeyBytes,
|
||||
};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
@@ -76,6 +76,18 @@ impl Validator {
|
||||
.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
|
||||
///
|
||||
/// WARNING: this function does NO VALIDATION - it just does it!
|
||||
|
||||
Reference in New Issue
Block a user