mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-21 13:54:44 +00:00
merge with upstream
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>>
|
||||
|
||||
@@ -62,6 +62,10 @@ pub struct BeaconBlockBody<T: EthSpec, Payload: AbstractExecPayload<T> = FullPay
|
||||
#[superstruct(only(Eip4844), partial_getter(rename = "execution_payload_eip4844"))]
|
||||
#[serde(flatten)]
|
||||
pub execution_payload: Payload::Eip4844,
|
||||
#[cfg(feature = "withdrawals")]
|
||||
#[superstruct(only(Capella, Eip4844))]
|
||||
pub bls_to_execution_changes:
|
||||
VariableList<SignedBlsToExecutionChange, T::MaxBlsToExecutionChanges>,
|
||||
#[superstruct(only(Eip4844))]
|
||||
pub blob_kzg_commitments: VariableList<KzgCommitment, T::MaxBlobsPerBlock>,
|
||||
#[superstruct(only(Base, Altair))]
|
||||
@@ -72,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()
|
||||
}
|
||||
}
|
||||
@@ -297,6 +301,8 @@ impl<E: EthSpec> From<BeaconBlockBodyCapella<E, FullPayload<E>>>
|
||||
voluntary_exits,
|
||||
sync_aggregate,
|
||||
execution_payload: FullPayloadCapella { execution_payload },
|
||||
#[cfg(feature = "withdrawals")]
|
||||
bls_to_execution_changes,
|
||||
} = body;
|
||||
|
||||
(
|
||||
@@ -313,6 +319,8 @@ impl<E: EthSpec> From<BeaconBlockBodyCapella<E, FullPayload<E>>>
|
||||
execution_payload: BlindedPayloadCapella {
|
||||
execution_payload_header: From::from(execution_payload.clone()),
|
||||
},
|
||||
#[cfg(feature = "withdrawals")]
|
||||
bls_to_execution_changes,
|
||||
},
|
||||
Some(execution_payload),
|
||||
)
|
||||
@@ -337,6 +345,8 @@ impl<E: EthSpec> From<BeaconBlockBodyEip4844<E, FullPayload<E>>>
|
||||
voluntary_exits,
|
||||
sync_aggregate,
|
||||
execution_payload: FullPayloadEip4844 { execution_payload },
|
||||
#[cfg(feature = "withdrawals")]
|
||||
bls_to_execution_changes,
|
||||
blob_kzg_commitments,
|
||||
} = body;
|
||||
|
||||
@@ -354,6 +364,8 @@ impl<E: EthSpec> From<BeaconBlockBodyEip4844<E, FullPayload<E>>>
|
||||
execution_payload: BlindedPayloadEip4844 {
|
||||
execution_payload_header: From::from(execution_payload.clone()),
|
||||
},
|
||||
#[cfg(feature = "withdrawals")]
|
||||
bls_to_execution_changes,
|
||||
blob_kzg_commitments,
|
||||
},
|
||||
Some(execution_payload),
|
||||
@@ -421,6 +433,8 @@ impl<E: EthSpec> BeaconBlockBodyCapella<E, FullPayload<E>> {
|
||||
voluntary_exits,
|
||||
sync_aggregate,
|
||||
execution_payload: FullPayloadCapella { execution_payload },
|
||||
#[cfg(feature = "withdrawals")]
|
||||
bls_to_execution_changes,
|
||||
} = self;
|
||||
|
||||
BeaconBlockBodyCapella {
|
||||
@@ -436,6 +450,8 @@ impl<E: EthSpec> BeaconBlockBodyCapella<E, FullPayload<E>> {
|
||||
execution_payload: BlindedPayloadCapella {
|
||||
execution_payload_header: From::from(execution_payload.clone()),
|
||||
},
|
||||
#[cfg(feature = "withdrawals")]
|
||||
bls_to_execution_changes: bls_to_execution_changes.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -453,6 +469,8 @@ impl<E: EthSpec> BeaconBlockBodyEip4844<E, FullPayload<E>> {
|
||||
voluntary_exits,
|
||||
sync_aggregate,
|
||||
execution_payload: FullPayloadEip4844 { execution_payload },
|
||||
#[cfg(feature = "withdrawals")]
|
||||
bls_to_execution_changes,
|
||||
blob_kzg_commitments,
|
||||
} = self;
|
||||
|
||||
@@ -469,6 +487,8 @@ impl<E: EthSpec> BeaconBlockBodyEip4844<E, FullPayload<E>> {
|
||||
execution_payload: BlindedPayloadEip4844 {
|
||||
execution_payload_header: From::from(execution_payload.clone()),
|
||||
},
|
||||
#[cfg(feature = "withdrawals")]
|
||||
bls_to_execution_changes: bls_to_execution_changes.clone(),
|
||||
blob_kzg_commitments: blob_kzg_commitments.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -296,14 +296,11 @@ where
|
||||
|
||||
// Withdrawals
|
||||
#[cfg(feature = "withdrawals")]
|
||||
#[superstruct(only(Capella, Eip4844))]
|
||||
pub withdrawal_queue: VariableList<Withdrawal, T::WithdrawalQueueLimit>,
|
||||
#[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))]
|
||||
pub next_partial_withdrawal_validator_index: u64,
|
||||
#[superstruct(only(Capella, Eip4844), partial_getter(copy))]
|
||||
pub next_withdrawal_validator_index: u64,
|
||||
|
||||
// Caching (not in the spec)
|
||||
#[serde(skip_serializing, skip_deserializing)]
|
||||
@@ -1787,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()
|
||||
|
||||
30
consensus/types/src/bls_to_execution_change.rs
Normal file
30
consensus/types/src/bls_to_execution_change.rs
Normal file
@@ -0,0 +1,30 @@
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::*;
|
||||
use bls::PublicKeyBytes;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
/// A deposit to potentially become a beacon chain validator.
|
||||
///
|
||||
/// Spec v0.12.1
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(
|
||||
Debug, PartialEq, Hash, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom,
|
||||
)]
|
||||
pub struct BlsToExecutionChange {
|
||||
#[serde(with = "eth2_serde_utils::quoted_u64")]
|
||||
pub validator_index: u64,
|
||||
pub from_bls_pubkey: PublicKeyBytes,
|
||||
pub to_execution_address: Address,
|
||||
}
|
||||
|
||||
impl SignedRoot for BlsToExecutionChange {}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
ssz_and_tree_hash_tests!(BlsToExecutionChange);
|
||||
}
|
||||
@@ -98,8 +98,6 @@ pub trait EthSpec: 'static + Default + Sync + Send + Clone + Debug + PartialEq +
|
||||
/*
|
||||
* New in Capella
|
||||
*/
|
||||
type MaxPartialWithdrawalsPerEpoch: Unsigned + Clone + Sync + Send + Debug + PartialEq;
|
||||
type WithdrawalQueueLimit: Unsigned + Clone + Sync + Send + Debug + PartialEq;
|
||||
type MaxBlsToExecutionChanges: Unsigned + Clone + Sync + Send + Debug + PartialEq;
|
||||
type MaxWithdrawalsPerPayload: Unsigned + Clone + Sync + Send + Debug + PartialEq;
|
||||
/*
|
||||
@@ -235,16 +233,6 @@ pub trait EthSpec: 'static + Default + Sync + Send + Clone + Debug + PartialEq +
|
||||
Self::BytesPerLogsBloom::to_usize()
|
||||
}
|
||||
|
||||
/// Returns the `MAX_PARTIAL_WITHDRAWALS_PER_EPOCH` constant for this specification.
|
||||
fn max_partial_withdrawals_per_epoch() -> usize {
|
||||
Self::MaxPartialWithdrawalsPerEpoch::to_usize()
|
||||
}
|
||||
|
||||
/// Returns the `WITHDRAWAL_QUEUE_LIMIT` constant for this specification.
|
||||
fn withdrawal_queue_limit() -> usize {
|
||||
Self::WithdrawalQueueLimit::to_usize()
|
||||
}
|
||||
|
||||
/// Returns the `MAX_BLS_TO_EXECUTION_CHANGES` constant for this specification.
|
||||
fn max_bls_to_execution_changes() -> usize {
|
||||
Self::MaxBlsToExecutionChanges::to_usize()
|
||||
@@ -309,8 +297,6 @@ impl EthSpec for MainnetEthSpec {
|
||||
type SyncSubcommitteeSize = U128; // 512 committee size / 4 sync committee subnet count
|
||||
type MaxPendingAttestations = U4096; // 128 max attestations * 32 slots per epoch
|
||||
type SlotsPerEth1VotingPeriod = U2048; // 64 epochs * 32 slots per epoch
|
||||
type MaxPartialWithdrawalsPerEpoch = U256;
|
||||
type WithdrawalQueueLimit = U1099511627776;
|
||||
type MaxBlsToExecutionChanges = U16;
|
||||
type MaxWithdrawalsPerPayload = U16;
|
||||
|
||||
@@ -338,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,
|
||||
@@ -358,10 +345,7 @@ impl EthSpec for MinimalEthSpec {
|
||||
GasLimitDenominator,
|
||||
MinGasLimit,
|
||||
MaxExtraDataBytes,
|
||||
MaxPartialWithdrawalsPerEpoch,
|
||||
WithdrawalQueueLimit,
|
||||
MaxBlsToExecutionChanges,
|
||||
MaxWithdrawalsPerPayload,
|
||||
MaxBlobsPerBlock,
|
||||
FieldElementsPerBlob
|
||||
});
|
||||
@@ -408,8 +392,6 @@ impl EthSpec for GnosisEthSpec {
|
||||
type SyncSubcommitteeSize = U128; // 512 committee size / 4 sync committee subnet count
|
||||
type MaxPendingAttestations = U2048; // 128 max attestations * 16 slots per epoch
|
||||
type SlotsPerEth1VotingPeriod = U1024; // 64 epochs * 16 slots per epoch
|
||||
type MaxPartialWithdrawalsPerEpoch = U256;
|
||||
type WithdrawalQueueLimit = U1099511627776;
|
||||
type MaxBlsToExecutionChanges = U16;
|
||||
type MaxWithdrawalsPerPayload = U16;
|
||||
type MaxBlobsPerBlock = U16; // 2**4 = 16
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
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 std::slice::Iter;
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
@@ -13,6 +12,8 @@ pub type Transactions<T> = VariableList<
|
||||
<T as EthSpec>::MaxTransactionsPerPayload,
|
||||
>;
|
||||
|
||||
pub type Withdrawals<T> = VariableList<Withdrawal, <T as EthSpec>::MaxWithdrawalsPerPayload>;
|
||||
|
||||
#[superstruct(
|
||||
variants(Merge, Capella, Eip4844),
|
||||
variant_attributes(
|
||||
@@ -82,10 +83,21 @@ pub struct ExecutionPayload<T: EthSpec> {
|
||||
pub transactions: Transactions<T>,
|
||||
#[cfg(feature = "withdrawals")]
|
||||
#[superstruct(only(Capella, Eip4844))]
|
||||
pub withdrawals: VariableList<Withdrawal, T::MaxWithdrawalsPerPayload>,
|
||||
pub withdrawals: Withdrawals<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)]
|
||||
/// 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))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ pub mod beacon_block_body;
|
||||
pub mod beacon_block_header;
|
||||
pub mod beacon_committee;
|
||||
pub mod beacon_state;
|
||||
pub mod bls_to_execution_change;
|
||||
pub mod builder_bid;
|
||||
pub mod chain_spec;
|
||||
pub mod checkpoint;
|
||||
@@ -61,6 +62,7 @@ pub mod shuffling_id;
|
||||
pub mod signed_aggregate_and_proof;
|
||||
pub mod signed_beacon_block;
|
||||
pub mod signed_beacon_block_header;
|
||||
pub mod signed_bls_to_execution_change;
|
||||
pub mod signed_contribution_and_proof;
|
||||
pub mod signed_voluntary_exit;
|
||||
pub mod signing_data;
|
||||
@@ -108,7 +110,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,
|
||||
@@ -118,6 +120,7 @@ pub use crate::beacon_block_header::BeaconBlockHeader;
|
||||
pub use crate::beacon_committee::{BeaconCommittee, OwnedBeaconCommittee};
|
||||
pub use crate::beacon_state::{BeaconTreeHashCache, Error as BeaconStateError, *};
|
||||
pub use crate::blobs_sidecar::BlobsSidecar;
|
||||
pub use crate::bls_to_execution_change::BlsToExecutionChange;
|
||||
pub use crate::chain_spec::{ChainSpec, Config, Domain};
|
||||
pub use crate::checkpoint::Checkpoint;
|
||||
pub use crate::config_and_preset::{
|
||||
@@ -134,7 +137,7 @@ pub use crate::eth_spec::EthSpecId;
|
||||
pub use crate::execution_block_hash::ExecutionBlockHash;
|
||||
pub use crate::execution_payload::{
|
||||
ExecutionPayload, ExecutionPayloadCapella, ExecutionPayloadEip4844, ExecutionPayloadMerge,
|
||||
ExecutionPayloadRef, Transaction, Transactions,
|
||||
ExecutionPayloadRef, Transaction, Transactions, Withdrawals,
|
||||
};
|
||||
pub use crate::execution_payload_header::{
|
||||
ExecutionPayloadHeader, ExecutionPayloadHeaderCapella, ExecutionPayloadHeaderEip4844,
|
||||
@@ -171,6 +174,7 @@ pub use crate::signed_beacon_block::{
|
||||
SignedBlindedBeaconBlock,
|
||||
};
|
||||
pub use crate::signed_beacon_block_header::SignedBeaconBlockHeader;
|
||||
pub use crate::signed_bls_to_execution_change::SignedBlsToExecutionChange;
|
||||
pub use crate::signed_block_and_blobs::SignedBeaconBlockAndBlobsSidecar;
|
||||
pub use crate::signed_contribution_and_proof::SignedContributionAndProof;
|
||||
pub use crate::signed_voluntary_exit::SignedVoluntaryExit;
|
||||
|
||||
@@ -36,6 +36,9 @@ pub trait ExecPayload<T: EthSpec>: Debug + Clone + PartialEq + Hash + TreeHash +
|
||||
fn fee_recipient(&self) -> Address;
|
||||
fn gas_limit(&self) -> u64;
|
||||
fn transactions(&self) -> Option<&Transactions<T>>;
|
||||
/// fork-specific fields
|
||||
#[cfg(feature = "withdrawals")]
|
||||
fn withdrawals_root(&self) -> Result<Hash256, Error>;
|
||||
|
||||
/// Is this a default payload? (pre-merge)
|
||||
fn is_default(&self) -> bool;
|
||||
@@ -218,13 +221,26 @@ 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)
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "withdrawals")]
|
||||
fn withdrawals_root(&self) -> Result<Hash256, Error> {
|
||||
match self {
|
||||
FullPayload::Merge(_) => Err(Error::IncorrectStateVariant),
|
||||
FullPayload::Capella(ref inner) => {
|
||||
Ok(inner.execution_payload.withdrawals.tree_hash_root())
|
||||
}
|
||||
FullPayload::Eip4844(ref inner) => {
|
||||
Ok(inner.execution_payload.withdrawals.tree_hash_root())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_default<'a>(&'a self) -> bool {
|
||||
map_full_payload_ref!(&'a _, self.to_ref(), move |payload, cons| {
|
||||
cons(payload);
|
||||
@@ -249,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()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -302,13 +318,26 @@ 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)
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "withdrawals")]
|
||||
fn withdrawals_root(&self) -> Result<Hash256, Error> {
|
||||
match self {
|
||||
FullPayloadRef::Merge(_) => Err(Error::IncorrectStateVariant),
|
||||
FullPayloadRef::Capella(inner) => {
|
||||
Ok(inner.execution_payload.withdrawals.tree_hash_root())
|
||||
}
|
||||
FullPayloadRef::Eip4844(inner) => {
|
||||
Ok(inner.execution_payload.withdrawals.tree_hash_root())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: can this function be optimized?
|
||||
fn is_default<'a>(&'a self) -> bool {
|
||||
map_full_payload_ref!(&'a _, self, move |payload, cons| {
|
||||
@@ -459,10 +488,23 @@ impl<T: EthSpec> ExecPayload<T> for BlindedPayload<T> {
|
||||
})
|
||||
}
|
||||
|
||||
fn transactions<'a>(&'a self) -> Option<&Transactions<T>> {
|
||||
fn transactions(&self) -> Option<&Transactions<T>> {
|
||||
None
|
||||
}
|
||||
|
||||
#[cfg(feature = "withdrawals")]
|
||||
fn withdrawals_root(&self) -> Result<Hash256, Error> {
|
||||
match self {
|
||||
BlindedPayload::Merge(_) => Err(Error::IncorrectStateVariant),
|
||||
BlindedPayload::Capella(ref inner) => {
|
||||
Ok(inner.execution_payload_header.withdrawals_root)
|
||||
}
|
||||
BlindedPayload::Eip4844(ref inner) => {
|
||||
Ok(inner.execution_payload_header.withdrawals_root)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_default<'a>(&'a self) -> bool {
|
||||
map_blinded_payload_ref!(&'a _, self.to_ref(), move |payload, cons| {
|
||||
cons(payload);
|
||||
@@ -532,10 +574,23 @@ 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
|
||||
}
|
||||
|
||||
#[cfg(feature = "withdrawals")]
|
||||
fn withdrawals_root(&self) -> Result<Hash256, Error> {
|
||||
match self {
|
||||
BlindedPayloadRef::Merge(_) => Err(Error::IncorrectStateVariant),
|
||||
BlindedPayloadRef::Capella(inner) => {
|
||||
Ok(inner.execution_payload_header.withdrawals_root)
|
||||
}
|
||||
BlindedPayloadRef::Eip4844(inner) => {
|
||||
Ok(inner.execution_payload_header.withdrawals_root)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: can this function be optimized?
|
||||
fn is_default<'a>(&'a self) -> bool {
|
||||
map_blinded_payload_ref!(&'a _, self, move |payload, cons| {
|
||||
@@ -546,7 +601,7 @@ impl<'b, T: EthSpec> ExecPayload<T> for BlindedPayloadRef<'b, T> {
|
||||
}
|
||||
|
||||
macro_rules! impl_exec_payload_common {
|
||||
($wrapper_type:ident, $wrapped_type_full:ident, $wrapped_header_type:ident, $wrapped_field:ident, $fork_variant:ident, $block_type_variant:ident, $f:block) => {
|
||||
($wrapper_type:ident, $wrapped_type_full:ident, $wrapped_header_type:ident, $wrapped_field:ident, $fork_variant:ident, $block_type_variant:ident, $f:block, $g:block) => {
|
||||
impl<T: EthSpec> ExecPayload<T> for $wrapper_type<T> {
|
||||
fn block_type() -> BlockType {
|
||||
BlockType::$block_type_variant
|
||||
@@ -594,6 +649,12 @@ macro_rules! impl_exec_payload_common {
|
||||
let f = $f;
|
||||
f(self)
|
||||
}
|
||||
|
||||
#[cfg(feature = "withdrawals")]
|
||||
fn withdrawals_root(&self) -> Result<Hash256, Error> {
|
||||
let g = $g;
|
||||
g(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: EthSpec> From<$wrapped_type_full<T>> for $wrapper_type<T> {
|
||||
@@ -615,7 +676,15 @@ macro_rules! impl_exec_payload_for_fork {
|
||||
execution_payload_header,
|
||||
$fork_variant,
|
||||
Blinded,
|
||||
{ |_| { None } }
|
||||
{ |_| { None } },
|
||||
{
|
||||
let c: for<'a> fn(&'a $wrapper_type_header<T>) -> Result<Hash256, Error> =
|
||||
|payload: &$wrapper_type_header<T>| {
|
||||
let wrapper_ref_type = BlindedPayloadRef::$fork_variant(&payload);
|
||||
wrapper_ref_type.withdrawals_root()
|
||||
};
|
||||
c
|
||||
}
|
||||
);
|
||||
|
||||
impl<T: EthSpec> TryInto<$wrapper_type_header<T>> for BlindedPayload<T> {
|
||||
@@ -680,6 +749,14 @@ macro_rules! impl_exec_payload_for_fork {
|
||||
let c: for<'a> fn(&'a $wrapper_type_full<T>) -> Option<&'a Transactions<T>> =
|
||||
|payload: &$wrapper_type_full<T>| Some(&payload.execution_payload.transactions);
|
||||
c
|
||||
},
|
||||
{
|
||||
let c: for<'a> fn(&'a $wrapper_type_full<T>) -> Result<Hash256, Error> =
|
||||
|payload: &$wrapper_type_full<T>| {
|
||||
let wrapper_ref_type = FullPayloadRef::$fork_variant(&payload);
|
||||
wrapper_ref_type.withdrawals_root()
|
||||
};
|
||||
c
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@@ -341,6 +341,8 @@ impl<E: EthSpec> SignedBeaconBlockCapella<E, BlindedPayload<E>> {
|
||||
voluntary_exits,
|
||||
sync_aggregate,
|
||||
execution_payload: BlindedPayloadCapella { .. },
|
||||
#[cfg(feature = "withdrawals")]
|
||||
bls_to_execution_changes,
|
||||
},
|
||||
},
|
||||
signature,
|
||||
@@ -362,6 +364,8 @@ impl<E: EthSpec> SignedBeaconBlockCapella<E, BlindedPayload<E>> {
|
||||
voluntary_exits,
|
||||
sync_aggregate,
|
||||
execution_payload: FullPayloadCapella { execution_payload },
|
||||
#[cfg(feature = "withdrawals")]
|
||||
bls_to_execution_changes,
|
||||
},
|
||||
},
|
||||
signature,
|
||||
@@ -393,6 +397,8 @@ impl<E: EthSpec> SignedBeaconBlockEip4844<E, BlindedPayload<E>> {
|
||||
voluntary_exits,
|
||||
sync_aggregate,
|
||||
execution_payload: BlindedPayloadEip4844 { .. },
|
||||
#[cfg(feature = "withdrawals")]
|
||||
bls_to_execution_changes,
|
||||
blob_kzg_commitments,
|
||||
},
|
||||
},
|
||||
@@ -415,6 +421,8 @@ impl<E: EthSpec> SignedBeaconBlockEip4844<E, BlindedPayload<E>> {
|
||||
voluntary_exits,
|
||||
sync_aggregate,
|
||||
execution_payload: FullPayloadEip4844 { execution_payload },
|
||||
#[cfg(feature = "withdrawals")]
|
||||
bls_to_execution_changes,
|
||||
blob_kzg_commitments,
|
||||
},
|
||||
},
|
||||
|
||||
26
consensus/types/src/signed_bls_to_execution_change.rs
Normal file
26
consensus/types/src/signed_bls_to_execution_change.rs
Normal file
@@ -0,0 +1,26 @@
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::*;
|
||||
use bls::Signature;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
/// A deposit to potentially become a beacon chain validator.
|
||||
///
|
||||
/// Spec v0.12.1
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(
|
||||
Debug, PartialEq, Hash, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom,
|
||||
)]
|
||||
pub struct SignedBlsToExecutionChange {
|
||||
pub message: BlsToExecutionChange,
|
||||
pub signature: Signature,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
ssz_and_tree_hash_tests!(SignedBlsToExecutionChange);
|
||||
}
|
||||
@@ -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,5 +1,6 @@
|
||||
use crate::{
|
||||
test_utils::TestRandom, BeaconState, 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};
|
||||
@@ -75,6 +76,28 @@ 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!
|
||||
pub fn change_withdrawal_credentials(&mut self, execution_address: &Address, spec: &ChainSpec) {
|
||||
let mut bytes = [0u8; 32];
|
||||
bytes[0] = spec.eth1_address_withdrawal_prefix_byte;
|
||||
bytes[12..].copy_from_slice(execution_address.as_bytes());
|
||||
self.withdrawal_credentials = Hash256::from(bytes);
|
||||
}
|
||||
|
||||
/// Returns `true` if the validator is fully withdrawable at some epoch
|
||||
pub fn is_fully_withdrawable_at(&self, balance: u64, epoch: Epoch, spec: &ChainSpec) -> bool {
|
||||
self.has_eth1_withdrawal_credential(spec) && self.withdrawable_epoch <= epoch && balance > 0
|
||||
|
||||
Reference in New Issue
Block a user