mirror of
https://github.com/sigp/lighthouse.git
synced 2026-04-21 14:58:31 +00:00
Merge branch 'unstable' into validator-manager
This commit is contained in:
@@ -11,9 +11,20 @@ use tree_hash_derive::TreeHash;
|
||||
/// A Validators aggregate attestation and selection proof.
|
||||
///
|
||||
/// Spec v0.12.1
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode, TestRandom, TreeHash)]
|
||||
#[derive(
|
||||
arbitrary::Arbitrary,
|
||||
Debug,
|
||||
Clone,
|
||||
PartialEq,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
TestRandom,
|
||||
TreeHash,
|
||||
)]
|
||||
#[serde(bound = "T: EthSpec")]
|
||||
#[arbitrary(bound = "T: EthSpec")]
|
||||
pub struct AggregateAndProof<T: EthSpec> {
|
||||
/// The index of the validator that created the attestation.
|
||||
#[serde(with = "eth2_serde_utils::quoted_u64")]
|
||||
|
||||
@@ -23,12 +23,21 @@ pub enum Error {
|
||||
/// Details an attestation that can be slashable.
|
||||
///
|
||||
/// Spec v0.12.1
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(
|
||||
Debug, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom, Derivative,
|
||||
arbitrary::Arbitrary,
|
||||
Debug,
|
||||
Clone,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
TreeHash,
|
||||
TestRandom,
|
||||
Derivative,
|
||||
)]
|
||||
#[derivative(PartialEq, Hash(bound = "T: EthSpec"))]
|
||||
#[serde(bound = "T: EthSpec")]
|
||||
#[arbitrary(bound = "T: EthSpec")]
|
||||
pub struct Attestation<T: EthSpec> {
|
||||
pub aggregation_bits: BitList<T::MaxValidatorsPerCommittee>,
|
||||
pub data: AttestationData,
|
||||
|
||||
@@ -10,8 +10,8 @@ use tree_hash_derive::TreeHash;
|
||||
/// The data upon which an attestation is based.
|
||||
///
|
||||
/// Spec v0.12.1
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(
|
||||
arbitrary::Arbitrary,
|
||||
Debug,
|
||||
Clone,
|
||||
PartialEq,
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
use crate::*;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(Debug, PartialEq, Clone, Copy, Default, Serialize, Deserialize)]
|
||||
#[derive(arbitrary::Arbitrary, Debug, PartialEq, Clone, Copy, Default, Serialize, Deserialize)]
|
||||
pub struct AttestationDuty {
|
||||
/// The slot during which the attester must attest.
|
||||
pub slot: Slot,
|
||||
|
||||
@@ -9,12 +9,21 @@ use tree_hash_derive::TreeHash;
|
||||
/// Two conflicting attestations.
|
||||
///
|
||||
/// Spec v0.12.1
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(
|
||||
Derivative, Debug, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom,
|
||||
Derivative,
|
||||
Debug,
|
||||
Clone,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
TreeHash,
|
||||
TestRandom,
|
||||
arbitrary::Arbitrary,
|
||||
)]
|
||||
#[derivative(PartialEq, Eq, Hash(bound = "T: EthSpec"))]
|
||||
#[serde(bound = "T: EthSpec")]
|
||||
#[arbitrary(bound = "T: EthSpec")]
|
||||
pub struct AttesterSlashing<T: EthSpec> {
|
||||
pub attestation_1: IndexedAttestation<T>,
|
||||
pub attestation_2: IndexedAttestation<T>,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::beacon_block_body::{
|
||||
BeaconBlockBodyAltair, BeaconBlockBodyBase, BeaconBlockBodyMerge, BeaconBlockBodyRef,
|
||||
BeaconBlockBodyRefMut,
|
||||
BeaconBlockBodyAltair, BeaconBlockBodyBase, BeaconBlockBodyEip4844, BeaconBlockBodyMerge,
|
||||
BeaconBlockBodyRef, BeaconBlockBodyRefMut,
|
||||
};
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::*;
|
||||
@@ -17,7 +17,7 @@ use tree_hash_derive::TreeHash;
|
||||
|
||||
/// A block of the `BeaconChain`.
|
||||
#[superstruct(
|
||||
variants(Base, Altair, Merge),
|
||||
variants(Base, Altair, Merge, Capella, Eip4844),
|
||||
variant_attributes(
|
||||
derive(
|
||||
Debug,
|
||||
@@ -29,10 +29,14 @@ use tree_hash_derive::TreeHash;
|
||||
TreeHash,
|
||||
TestRandom,
|
||||
Derivative,
|
||||
arbitrary::Arbitrary
|
||||
),
|
||||
derivative(PartialEq, Hash(bound = "T: EthSpec, Payload: ExecPayload<T>")),
|
||||
serde(bound = "T: EthSpec, Payload: ExecPayload<T>", deny_unknown_fields),
|
||||
cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary)),
|
||||
derivative(PartialEq, Hash(bound = "T: EthSpec, Payload: AbstractExecPayload<T>")),
|
||||
serde(
|
||||
bound = "T: EthSpec, Payload: AbstractExecPayload<T>",
|
||||
deny_unknown_fields
|
||||
),
|
||||
arbitrary(bound = "T: EthSpec, Payload: AbstractExecPayload<T>"),
|
||||
),
|
||||
ref_attributes(
|
||||
derive(Debug, PartialEq, TreeHash),
|
||||
@@ -41,14 +45,16 @@ use tree_hash_derive::TreeHash;
|
||||
map_ref_into(BeaconBlockBodyRef, BeaconBlock),
|
||||
map_ref_mut_into(BeaconBlockBodyRefMut)
|
||||
)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Encode, TreeHash, Derivative)]
|
||||
#[derive(
|
||||
Debug, Clone, Serialize, Deserialize, Encode, TreeHash, Derivative, arbitrary::Arbitrary,
|
||||
)]
|
||||
#[derivative(PartialEq, Hash(bound = "T: EthSpec"))]
|
||||
#[serde(untagged)]
|
||||
#[serde(bound = "T: EthSpec, Payload: ExecPayload<T>")]
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[serde(bound = "T: EthSpec, Payload: AbstractExecPayload<T>")]
|
||||
#[arbitrary(bound = "T: EthSpec, Payload: AbstractExecPayload<T>")]
|
||||
#[tree_hash(enum_behaviour = "transparent")]
|
||||
#[ssz(enum_behaviour = "transparent")]
|
||||
pub struct BeaconBlock<T: EthSpec, Payload: ExecPayload<T> = FullPayload<T>> {
|
||||
pub struct BeaconBlock<T: EthSpec, Payload: AbstractExecPayload<T> = FullPayload<T>> {
|
||||
#[superstruct(getter(copy))]
|
||||
pub slot: Slot,
|
||||
#[superstruct(getter(copy))]
|
||||
@@ -64,23 +70,34 @@ pub struct BeaconBlock<T: EthSpec, Payload: ExecPayload<T> = FullPayload<T>> {
|
||||
pub body: BeaconBlockBodyAltair<T, Payload>,
|
||||
#[superstruct(only(Merge), partial_getter(rename = "body_merge"))]
|
||||
pub body: BeaconBlockBodyMerge<T, Payload>,
|
||||
#[superstruct(only(Capella), partial_getter(rename = "body_capella"))]
|
||||
pub body: BeaconBlockBodyCapella<T, Payload>,
|
||||
#[superstruct(only(Eip4844), partial_getter(rename = "body_eip4844"))]
|
||||
pub body: BeaconBlockBodyEip4844<T, Payload>,
|
||||
}
|
||||
|
||||
pub type BlindedBeaconBlock<E> = BeaconBlock<E, BlindedPayload<E>>;
|
||||
|
||||
impl<T: EthSpec, Payload: ExecPayload<T>> SignedRoot for BeaconBlock<T, Payload> {}
|
||||
impl<'a, T: EthSpec, Payload: ExecPayload<T>> SignedRoot for BeaconBlockRef<'a, T, Payload> {}
|
||||
impl<T: EthSpec, Payload: AbstractExecPayload<T>> SignedRoot for BeaconBlock<T, Payload> {}
|
||||
impl<'a, T: EthSpec, Payload: AbstractExecPayload<T>> SignedRoot
|
||||
for BeaconBlockRef<'a, T, Payload>
|
||||
{
|
||||
}
|
||||
|
||||
impl<T: EthSpec, Payload: ExecPayload<T>> BeaconBlock<T, Payload> {
|
||||
/// 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> {
|
||||
/// 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.
|
||||
@@ -109,13 +126,12 @@ impl<T: EthSpec, Payload: ExecPayload<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`.
|
||||
@@ -178,7 +194,7 @@ impl<T: EthSpec, Payload: ExecPayload<T>> BeaconBlock<T, Payload> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: EthSpec, Payload: ExecPayload<T>> BeaconBlockRef<'a, T, Payload> {
|
||||
impl<'a, T: EthSpec, Payload: AbstractExecPayload<T>> BeaconBlockRef<'a, T, Payload> {
|
||||
/// Returns the name of the fork pertaining to `self`.
|
||||
///
|
||||
/// Will return an `Err` if `self` has been instantiated to a variant conflicting with the fork
|
||||
@@ -189,6 +205,8 @@ impl<'a, T: EthSpec, Payload: ExecPayload<T>> BeaconBlockRef<'a, T, Payload> {
|
||||
BeaconBlockRef::Base { .. } => ForkName::Base,
|
||||
BeaconBlockRef::Altair { .. } => ForkName::Altair,
|
||||
BeaconBlockRef::Merge { .. } => ForkName::Merge,
|
||||
BeaconBlockRef::Capella { .. } => ForkName::Capella,
|
||||
BeaconBlockRef::Eip4844 { .. } => ForkName::Eip4844,
|
||||
};
|
||||
|
||||
if fork_at_slot == object_fork {
|
||||
@@ -242,12 +260,12 @@ impl<'a, T: EthSpec, Payload: ExecPayload<T>> BeaconBlockRef<'a, T, Payload> {
|
||||
|
||||
/// Extracts a reference to an execution payload from a block, returning an error if the block
|
||||
/// is pre-merge.
|
||||
pub fn execution_payload(&self) -> Result<&Payload, Error> {
|
||||
pub fn execution_payload(&self) -> Result<Payload::Ref<'a>, Error> {
|
||||
self.body().execution_payload()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: EthSpec, Payload: ExecPayload<T>> BeaconBlockRefMut<'a, T, Payload> {
|
||||
impl<'a, T: EthSpec, Payload: AbstractExecPayload<T>> BeaconBlockRefMut<'a, T, Payload> {
|
||||
/// Convert a mutable reference to a beacon block to a mutable ref to its body.
|
||||
pub fn body_mut(self) -> BeaconBlockBodyRefMut<'a, T, Payload> {
|
||||
map_beacon_block_ref_mut_into_beacon_block_body_ref_mut!(&'a _, self, |block, cons| cons(
|
||||
@@ -256,9 +274,8 @@ impl<'a, T: EthSpec, Payload: ExecPayload<T>> BeaconBlockRefMut<'a, T, Payload>
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: EthSpec, Payload: ExecPayload<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,
|
||||
@@ -281,7 +298,9 @@ impl<T: EthSpec, Payload: ExecPayload<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 {
|
||||
@@ -377,9 +396,9 @@ impl<T: EthSpec, Payload: ExecPayload<T>> BeaconBlockBase<T, Payload> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: EthSpec, Payload: ExecPayload<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,
|
||||
@@ -403,7 +422,9 @@ impl<T: EthSpec, Payload: ExecPayload<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);
|
||||
@@ -436,9 +457,9 @@ impl<T: EthSpec, Payload: ExecPayload<T>> BeaconBlockAltair<T, Payload> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: EthSpec, Payload: ExecPayload<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,
|
||||
@@ -458,7 +479,112 @@ impl<T: EthSpec, Payload: ExecPayload<T>> BeaconBlockMerge<T, Payload> {
|
||||
deposits: VariableList::empty(),
|
||||
voluntary_exits: VariableList::empty(),
|
||||
sync_aggregate: SyncAggregate::empty(),
|
||||
execution_payload: Payload::default(),
|
||||
execution_payload: Payload::Merge::default(),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: EthSpec, Payload: AbstractExecPayload<T>> BeaconBlockCapella<T, Payload> {
|
||||
/// Return a Capella block where the block has maximum size.
|
||||
pub fn full(spec: &ChainSpec) -> Self {
|
||||
let base_block: BeaconBlockBase<_, Payload> = BeaconBlockBase::full(spec);
|
||||
let bls_to_execution_changes = vec![
|
||||
SignedBlsToExecutionChange {
|
||||
message: BlsToExecutionChange {
|
||||
validator_index: 0,
|
||||
from_bls_pubkey: PublicKeyBytes::empty(),
|
||||
to_execution_address: Address::zero(),
|
||||
},
|
||||
signature: Signature::empty()
|
||||
};
|
||||
T::max_bls_to_execution_changes()
|
||||
]
|
||||
.into();
|
||||
let sync_aggregate = SyncAggregate {
|
||||
sync_committee_signature: AggregateSignature::empty(),
|
||||
sync_committee_bits: BitVector::default(),
|
||||
};
|
||||
BeaconBlockCapella {
|
||||
slot: spec.genesis_slot,
|
||||
proposer_index: 0,
|
||||
parent_root: Hash256::zero(),
|
||||
state_root: Hash256::zero(),
|
||||
body: BeaconBlockBodyCapella {
|
||||
proposer_slashings: base_block.body.proposer_slashings,
|
||||
attester_slashings: base_block.body.attester_slashings,
|
||||
attestations: base_block.body.attestations,
|
||||
deposits: base_block.body.deposits,
|
||||
voluntary_exits: base_block.body.voluntary_exits,
|
||||
bls_to_execution_changes,
|
||||
sync_aggregate,
|
||||
randao_reveal: Signature::empty(),
|
||||
eth1_data: Eth1Data {
|
||||
deposit_root: Hash256::zero(),
|
||||
block_hash: Hash256::zero(),
|
||||
deposit_count: 0,
|
||||
},
|
||||
graffiti: Graffiti::default(),
|
||||
execution_payload: Payload::Capella::default(),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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(),
|
||||
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(),
|
||||
bls_to_execution_changes: VariableList::empty(),
|
||||
blob_kzg_commitments: VariableList::empty(),
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -533,7 +659,7 @@ macro_rules! impl_from {
|
||||
parent_root,
|
||||
state_root,
|
||||
body,
|
||||
}, payload)
|
||||
}, payload.map(Into::into))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -542,6 +668,8 @@ macro_rules! impl_from {
|
||||
impl_from!(BeaconBlockBase, <E, FullPayload<E>>, <E, BlindedPayload<E>>, |body: BeaconBlockBodyBase<_, _>| body.into());
|
||||
impl_from!(BeaconBlockAltair, <E, FullPayload<E>>, <E, BlindedPayload<E>>, |body: BeaconBlockBodyAltair<_, _>| body.into());
|
||||
impl_from!(BeaconBlockMerge, <E, FullPayload<E>>, <E, BlindedPayload<E>>, |body: BeaconBlockBodyMerge<_, _>| body.into());
|
||||
impl_from!(BeaconBlockCapella, <E, FullPayload<E>>, <E, BlindedPayload<E>>, |body: BeaconBlockBodyCapella<_, _>| body.into());
|
||||
impl_from!(BeaconBlockEip4844, <E, FullPayload<E>>, <E, BlindedPayload<E>>, |body: BeaconBlockBodyEip4844<_, _>| body.into());
|
||||
|
||||
// We can clone blocks with payloads to blocks without payloads, without cloning the payload.
|
||||
macro_rules! impl_clone_as_blinded {
|
||||
@@ -572,6 +700,8 @@ macro_rules! impl_clone_as_blinded {
|
||||
impl_clone_as_blinded!(BeaconBlockBase, <E, FullPayload<E>>, <E, BlindedPayload<E>>);
|
||||
impl_clone_as_blinded!(BeaconBlockAltair, <E, FullPayload<E>>, <E, BlindedPayload<E>>);
|
||||
impl_clone_as_blinded!(BeaconBlockMerge, <E, FullPayload<E>>, <E, BlindedPayload<E>>);
|
||||
impl_clone_as_blinded!(BeaconBlockCapella, <E, FullPayload<E>>, <E, BlindedPayload<E>>);
|
||||
impl_clone_as_blinded!(BeaconBlockEip4844, <E, FullPayload<E>>, <E, BlindedPayload<E>>);
|
||||
|
||||
// A reference to a full beacon block can be cloned into a blinded beacon block, without cloning the
|
||||
// execution payload.
|
||||
@@ -601,6 +731,24 @@ impl<E: EthSpec> From<BeaconBlock<E, FullPayload<E>>>
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: EthSpec, Payload: AbstractExecPayload<T>> ForkVersionDeserialize
|
||||
for BeaconBlock<T, Payload>
|
||||
{
|
||||
fn deserialize_by_fork<'de, D: serde::Deserializer<'de>>(
|
||||
value: serde_json::value::Value,
|
||||
fork_name: ForkName,
|
||||
) -> Result<Self, D::Error> {
|
||||
Ok(map_fork_name!(
|
||||
fork_name,
|
||||
Self,
|
||||
serde_json::from_value(value).map_err(|e| serde::de::Error::custom(format!(
|
||||
"BeaconBlock failed to deserialize: {:?}",
|
||||
e
|
||||
)))?
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -650,19 +798,65 @@ mod tests {
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn roundtrip_capella_block() {
|
||||
let rng = &mut XorShiftRng::from_seed([42; 16]);
|
||||
let spec = &ForkName::Capella.make_genesis_spec(MainnetEthSpec::default_spec());
|
||||
|
||||
let inner_block = BeaconBlockCapella {
|
||||
slot: Slot::random_for_test(rng),
|
||||
proposer_index: u64::random_for_test(rng),
|
||||
parent_root: Hash256::random_for_test(rng),
|
||||
state_root: Hash256::random_for_test(rng),
|
||||
body: BeaconBlockBodyCapella::random_for_test(rng),
|
||||
};
|
||||
let block = BeaconBlock::Capella(inner_block.clone());
|
||||
|
||||
test_ssz_tree_hash_pair_with(&block, &inner_block, |bytes| {
|
||||
BeaconBlock::from_ssz_bytes(bytes, spec)
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn roundtrip_4844_block() {
|
||||
let rng = &mut XorShiftRng::from_seed([42; 16]);
|
||||
let spec = &ForkName::Eip4844.make_genesis_spec(MainnetEthSpec::default_spec());
|
||||
|
||||
let inner_block = BeaconBlockEip4844 {
|
||||
slot: Slot::random_for_test(rng),
|
||||
proposer_index: u64::random_for_test(rng),
|
||||
parent_root: Hash256::random_for_test(rng),
|
||||
state_root: Hash256::random_for_test(rng),
|
||||
body: BeaconBlockBodyEip4844::random_for_test(rng),
|
||||
};
|
||||
let block = BeaconBlock::Eip4844(inner_block.clone());
|
||||
|
||||
test_ssz_tree_hash_pair_with(&block, &inner_block, |bytes| {
|
||||
BeaconBlock::from_ssz_bytes(bytes, spec)
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_base_and_altair() {
|
||||
type E = MainnetEthSpec;
|
||||
let spec = E::default_spec();
|
||||
let mut spec = E::default_spec();
|
||||
|
||||
let rng = &mut XorShiftRng::from_seed([42; 16]);
|
||||
|
||||
let fork_epoch = spec.altair_fork_epoch.unwrap();
|
||||
let altair_fork_epoch = spec.altair_fork_epoch.unwrap();
|
||||
|
||||
let base_epoch = fork_epoch.saturating_sub(1_u64);
|
||||
let base_epoch = altair_fork_epoch.saturating_sub(1_u64);
|
||||
let base_slot = base_epoch.end_slot(E::slots_per_epoch());
|
||||
let altair_epoch = fork_epoch;
|
||||
let altair_epoch = altair_fork_epoch;
|
||||
let altair_slot = altair_epoch.start_slot(E::slots_per_epoch());
|
||||
let capella_epoch = altair_fork_epoch + 1;
|
||||
let capella_slot = capella_epoch.start_slot(E::slots_per_epoch());
|
||||
let eip4844_epoch = capella_epoch + 1;
|
||||
let eip4844_slot = eip4844_epoch.start_slot(E::slots_per_epoch());
|
||||
|
||||
spec.altair_fork_epoch = Some(altair_epoch);
|
||||
spec.capella_fork_epoch = Some(capella_epoch);
|
||||
spec.eip4844_fork_epoch = Some(eip4844_epoch);
|
||||
|
||||
// BeaconBlockBase
|
||||
{
|
||||
@@ -707,5 +901,49 @@ mod tests {
|
||||
BeaconBlock::from_ssz_bytes(&bad_altair_block.as_ssz_bytes(), &spec)
|
||||
.expect_err("bad altair block cannot be decoded");
|
||||
}
|
||||
|
||||
// BeaconBlockCapella
|
||||
{
|
||||
let good_block = BeaconBlock::Capella(BeaconBlockCapella {
|
||||
slot: capella_slot,
|
||||
..<_>::random_for_test(rng)
|
||||
});
|
||||
// It's invalid to have an Capella block with a epoch lower than the fork epoch.
|
||||
let bad_block = {
|
||||
let mut bad = good_block.clone();
|
||||
*bad.slot_mut() = altair_slot;
|
||||
bad
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
BeaconBlock::from_ssz_bytes(&good_block.as_ssz_bytes(), &spec)
|
||||
.expect("good capella block can be decoded"),
|
||||
good_block
|
||||
);
|
||||
BeaconBlock::from_ssz_bytes(&bad_block.as_ssz_bytes(), &spec)
|
||||
.expect_err("bad capella block cannot be decoded");
|
||||
}
|
||||
|
||||
// BeaconBlockEip4844
|
||||
{
|
||||
let good_block = BeaconBlock::Eip4844(BeaconBlockEip4844 {
|
||||
slot: eip4844_slot,
|
||||
..<_>::random_for_test(rng)
|
||||
});
|
||||
// It's invalid to have an Capella block with a epoch lower than the fork epoch.
|
||||
let bad_block = {
|
||||
let mut bad = good_block.clone();
|
||||
*bad.slot_mut() = capella_slot;
|
||||
bad
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
BeaconBlock::from_ssz_bytes(&good_block.as_ssz_bytes(), &spec)
|
||||
.expect("good eip4844 block can be decoded"),
|
||||
good_block
|
||||
);
|
||||
BeaconBlock::from_ssz_bytes(&bad_block.as_ssz_bytes(), &spec)
|
||||
.expect_err("bad eip4844 block cannot be decoded");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use crate::kzg_commitment::KzgCommitment;
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::*;
|
||||
use derivative::Derivative;
|
||||
@@ -13,7 +14,7 @@ use tree_hash_derive::TreeHash;
|
||||
///
|
||||
/// This *superstruct* abstracts over the hard-fork.
|
||||
#[superstruct(
|
||||
variants(Base, Altair, Merge),
|
||||
variants(Base, Altair, Merge, Capella, Eip4844),
|
||||
variant_attributes(
|
||||
derive(
|
||||
Debug,
|
||||
@@ -25,20 +26,24 @@ use tree_hash_derive::TreeHash;
|
||||
TreeHash,
|
||||
TestRandom,
|
||||
Derivative,
|
||||
arbitrary::Arbitrary
|
||||
),
|
||||
derivative(PartialEq, Hash(bound = "T: EthSpec, Payload: ExecPayload<T>")),
|
||||
serde(bound = "T: EthSpec, Payload: ExecPayload<T>", deny_unknown_fields),
|
||||
cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))
|
||||
derivative(PartialEq, Hash(bound = "T: EthSpec, Payload: AbstractExecPayload<T>")),
|
||||
serde(
|
||||
bound = "T: EthSpec, Payload: AbstractExecPayload<T>",
|
||||
deny_unknown_fields
|
||||
),
|
||||
arbitrary(bound = "T: EthSpec, Payload: AbstractExecPayload<T>"),
|
||||
),
|
||||
cast_error(ty = "Error", expr = "Error::IncorrectStateVariant"),
|
||||
partial_getter_error(ty = "Error", expr = "Error::IncorrectStateVariant")
|
||||
)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Derivative)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Derivative, arbitrary::Arbitrary)]
|
||||
#[derivative(PartialEq, Hash(bound = "T: EthSpec"))]
|
||||
#[serde(untagged)]
|
||||
#[serde(bound = "T: EthSpec, Payload: ExecPayload<T>")]
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
pub struct BeaconBlockBody<T: EthSpec, Payload: ExecPayload<T> = FullPayload<T>> {
|
||||
#[serde(bound = "T: EthSpec, Payload: AbstractExecPayload<T>")]
|
||||
#[arbitrary(bound = "T: EthSpec, Payload: AbstractExecPayload<T>")]
|
||||
pub struct BeaconBlockBody<T: EthSpec, Payload: AbstractExecPayload<T> = FullPayload<T>> {
|
||||
pub randao_reveal: Signature,
|
||||
pub eth1_data: Eth1Data,
|
||||
pub graffiti: Graffiti,
|
||||
@@ -47,21 +52,50 @@ pub struct BeaconBlockBody<T: EthSpec, Payload: ExecPayload<T> = FullPayload<T>>
|
||||
pub attestations: VariableList<Attestation<T>, T::MaxAttestations>,
|
||||
pub deposits: VariableList<Deposit, T::MaxDeposits>,
|
||||
pub voluntary_exits: VariableList<SignedVoluntaryExit, T::MaxVoluntaryExits>,
|
||||
#[superstruct(only(Altair, Merge))]
|
||||
#[superstruct(only(Altair, Merge, Capella, Eip4844))]
|
||||
pub sync_aggregate: SyncAggregate<T>,
|
||||
// We flatten the execution payload so that serde can use the name of the inner type,
|
||||
// either `execution_payload` for full payloads, or `execution_payload_header` for blinded
|
||||
// payloads.
|
||||
#[superstruct(only(Merge))]
|
||||
#[superstruct(only(Merge), partial_getter(rename = "execution_payload_merge"))]
|
||||
#[serde(flatten)]
|
||||
pub execution_payload: Payload,
|
||||
pub execution_payload: Payload::Merge,
|
||||
#[superstruct(only(Capella), partial_getter(rename = "execution_payload_capella"))]
|
||||
#[serde(flatten)]
|
||||
pub execution_payload: Payload::Capella,
|
||||
#[superstruct(only(Eip4844), partial_getter(rename = "execution_payload_eip4844"))]
|
||||
#[serde(flatten)]
|
||||
pub execution_payload: Payload::Eip4844,
|
||||
#[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))]
|
||||
#[ssz(skip_serializing, skip_deserializing)]
|
||||
#[tree_hash(skip_hashing)]
|
||||
#[serde(skip)]
|
||||
#[arbitrary(default)]
|
||||
pub _phantom: PhantomData<Payload>,
|
||||
}
|
||||
|
||||
impl<T: EthSpec, Payload: AbstractExecPayload<T>> BeaconBlockBody<T, Payload> {
|
||||
pub fn execution_payload(&self) -> Result<Payload::Ref<'_>, Error> {
|
||||
self.to_ref().execution_payload()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: EthSpec, Payload: AbstractExecPayload<T>> BeaconBlockBodyRef<'a, T, Payload> {
|
||||
pub fn execution_payload(&self) -> Result<Payload::Ref<'a>, Error> {
|
||||
match self {
|
||||
Self::Base(_) | Self::Altair(_) => Err(Error::IncorrectStateVariant),
|
||||
Self::Merge(body) => Ok(Payload::Ref::from(&body.execution_payload)),
|
||||
Self::Capella(body) => Ok(Payload::Ref::from(&body.execution_payload)),
|
||||
Self::Eip4844(body) => Ok(Payload::Ref::from(&body.execution_payload)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: EthSpec> BeaconBlockBodyRef<'a, T> {
|
||||
/// Get the fork_name of this object
|
||||
pub fn fork_name(self) -> ForkName {
|
||||
@@ -69,6 +103,8 @@ impl<'a, T: EthSpec> BeaconBlockBodyRef<'a, T> {
|
||||
BeaconBlockBodyRef::Base { .. } => ForkName::Base,
|
||||
BeaconBlockBodyRef::Altair { .. } => ForkName::Altair,
|
||||
BeaconBlockBodyRef::Merge { .. } => ForkName::Merge,
|
||||
BeaconBlockBodyRef::Capella { .. } => ForkName::Capella,
|
||||
BeaconBlockBodyRef::Eip4844 { .. } => ForkName::Eip4844,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -214,7 +250,7 @@ impl<E: EthSpec> From<BeaconBlockBodyAltair<E, FullPayload<E>>>
|
||||
impl<E: EthSpec> From<BeaconBlockBodyMerge<E, FullPayload<E>>>
|
||||
for (
|
||||
BeaconBlockBodyMerge<E, BlindedPayload<E>>,
|
||||
Option<ExecutionPayload<E>>,
|
||||
Option<ExecutionPayloadMerge<E>>,
|
||||
)
|
||||
{
|
||||
fn from(body: BeaconBlockBodyMerge<E, FullPayload<E>>) -> Self {
|
||||
@@ -228,7 +264,7 @@ impl<E: EthSpec> From<BeaconBlockBodyMerge<E, FullPayload<E>>>
|
||||
deposits,
|
||||
voluntary_exits,
|
||||
sync_aggregate,
|
||||
execution_payload: FullPayload { execution_payload },
|
||||
execution_payload: FullPayloadMerge { execution_payload },
|
||||
} = body;
|
||||
|
||||
(
|
||||
@@ -242,7 +278,7 @@ impl<E: EthSpec> From<BeaconBlockBodyMerge<E, FullPayload<E>>>
|
||||
deposits,
|
||||
voluntary_exits,
|
||||
sync_aggregate,
|
||||
execution_payload: BlindedPayload {
|
||||
execution_payload: BlindedPayloadMerge {
|
||||
execution_payload_header: From::from(&execution_payload),
|
||||
},
|
||||
},
|
||||
@@ -251,6 +287,92 @@ impl<E: EthSpec> From<BeaconBlockBodyMerge<E, FullPayload<E>>>
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EthSpec> From<BeaconBlockBodyCapella<E, FullPayload<E>>>
|
||||
for (
|
||||
BeaconBlockBodyCapella<E, BlindedPayload<E>>,
|
||||
Option<ExecutionPayloadCapella<E>>,
|
||||
)
|
||||
{
|
||||
fn from(body: BeaconBlockBodyCapella<E, FullPayload<E>>) -> Self {
|
||||
let BeaconBlockBodyCapella {
|
||||
randao_reveal,
|
||||
eth1_data,
|
||||
graffiti,
|
||||
proposer_slashings,
|
||||
attester_slashings,
|
||||
attestations,
|
||||
deposits,
|
||||
voluntary_exits,
|
||||
sync_aggregate,
|
||||
execution_payload: FullPayloadCapella { execution_payload },
|
||||
bls_to_execution_changes,
|
||||
} = body;
|
||||
|
||||
(
|
||||
BeaconBlockBodyCapella {
|
||||
randao_reveal,
|
||||
eth1_data,
|
||||
graffiti,
|
||||
proposer_slashings,
|
||||
attester_slashings,
|
||||
attestations,
|
||||
deposits,
|
||||
voluntary_exits,
|
||||
sync_aggregate,
|
||||
execution_payload: BlindedPayloadCapella {
|
||||
execution_payload_header: From::from(&execution_payload),
|
||||
},
|
||||
bls_to_execution_changes,
|
||||
},
|
||||
Some(execution_payload),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EthSpec> From<BeaconBlockBodyEip4844<E, FullPayload<E>>>
|
||||
for (
|
||||
BeaconBlockBodyEip4844<E, BlindedPayload<E>>,
|
||||
Option<ExecutionPayloadEip4844<E>>,
|
||||
)
|
||||
{
|
||||
fn from(body: BeaconBlockBodyEip4844<E, FullPayload<E>>) -> Self {
|
||||
let BeaconBlockBodyEip4844 {
|
||||
randao_reveal,
|
||||
eth1_data,
|
||||
graffiti,
|
||||
proposer_slashings,
|
||||
attester_slashings,
|
||||
attestations,
|
||||
deposits,
|
||||
voluntary_exits,
|
||||
sync_aggregate,
|
||||
execution_payload: FullPayloadEip4844 { execution_payload },
|
||||
bls_to_execution_changes,
|
||||
blob_kzg_commitments,
|
||||
} = body;
|
||||
|
||||
(
|
||||
BeaconBlockBodyEip4844 {
|
||||
randao_reveal,
|
||||
eth1_data,
|
||||
graffiti,
|
||||
proposer_slashings,
|
||||
attester_slashings,
|
||||
attestations,
|
||||
deposits,
|
||||
voluntary_exits,
|
||||
sync_aggregate,
|
||||
execution_payload: BlindedPayloadEip4844 {
|
||||
execution_payload_header: From::from(&execution_payload),
|
||||
},
|
||||
bls_to_execution_changes,
|
||||
blob_kzg_commitments,
|
||||
},
|
||||
Some(execution_payload),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// We can clone a full block into a blinded block, without cloning the payload.
|
||||
impl<E: EthSpec> BeaconBlockBodyBase<E, FullPayload<E>> {
|
||||
pub fn clone_as_blinded(&self) -> BeaconBlockBodyBase<E, BlindedPayload<E>> {
|
||||
@@ -278,7 +400,7 @@ impl<E: EthSpec> BeaconBlockBodyMerge<E, FullPayload<E>> {
|
||||
deposits,
|
||||
voluntary_exits,
|
||||
sync_aggregate,
|
||||
execution_payload: FullPayload { execution_payload },
|
||||
execution_payload: FullPayloadMerge { execution_payload },
|
||||
} = self;
|
||||
|
||||
BeaconBlockBodyMerge {
|
||||
@@ -291,13 +413,83 @@ impl<E: EthSpec> BeaconBlockBodyMerge<E, FullPayload<E>> {
|
||||
deposits: deposits.clone(),
|
||||
voluntary_exits: voluntary_exits.clone(),
|
||||
sync_aggregate: sync_aggregate.clone(),
|
||||
execution_payload: BlindedPayload {
|
||||
execution_payload_header: From::from(execution_payload),
|
||||
execution_payload: BlindedPayloadMerge {
|
||||
execution_payload_header: execution_payload.into(),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EthSpec> BeaconBlockBodyCapella<E, FullPayload<E>> {
|
||||
pub fn clone_as_blinded(&self) -> BeaconBlockBodyCapella<E, BlindedPayload<E>> {
|
||||
let BeaconBlockBodyCapella {
|
||||
randao_reveal,
|
||||
eth1_data,
|
||||
graffiti,
|
||||
proposer_slashings,
|
||||
attester_slashings,
|
||||
attestations,
|
||||
deposits,
|
||||
voluntary_exits,
|
||||
sync_aggregate,
|
||||
execution_payload: FullPayloadCapella { execution_payload },
|
||||
bls_to_execution_changes,
|
||||
} = self;
|
||||
|
||||
BeaconBlockBodyCapella {
|
||||
randao_reveal: randao_reveal.clone(),
|
||||
eth1_data: eth1_data.clone(),
|
||||
graffiti: *graffiti,
|
||||
proposer_slashings: proposer_slashings.clone(),
|
||||
attester_slashings: attester_slashings.clone(),
|
||||
attestations: attestations.clone(),
|
||||
deposits: deposits.clone(),
|
||||
voluntary_exits: voluntary_exits.clone(),
|
||||
sync_aggregate: sync_aggregate.clone(),
|
||||
execution_payload: BlindedPayloadCapella {
|
||||
execution_payload_header: execution_payload.into(),
|
||||
},
|
||||
bls_to_execution_changes: bls_to_execution_changes.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EthSpec> BeaconBlockBodyEip4844<E, FullPayload<E>> {
|
||||
pub fn clone_as_blinded(&self) -> BeaconBlockBodyEip4844<E, BlindedPayload<E>> {
|
||||
let BeaconBlockBodyEip4844 {
|
||||
randao_reveal,
|
||||
eth1_data,
|
||||
graffiti,
|
||||
proposer_slashings,
|
||||
attester_slashings,
|
||||
attestations,
|
||||
deposits,
|
||||
voluntary_exits,
|
||||
sync_aggregate,
|
||||
execution_payload: FullPayloadEip4844 { execution_payload },
|
||||
bls_to_execution_changes,
|
||||
blob_kzg_commitments,
|
||||
} = self;
|
||||
|
||||
BeaconBlockBodyEip4844 {
|
||||
randao_reveal: randao_reveal.clone(),
|
||||
eth1_data: eth1_data.clone(),
|
||||
graffiti: *graffiti,
|
||||
proposer_slashings: proposer_slashings.clone(),
|
||||
attester_slashings: attester_slashings.clone(),
|
||||
attestations: attestations.clone(),
|
||||
deposits: deposits.clone(),
|
||||
voluntary_exits: voluntary_exits.clone(),
|
||||
sync_aggregate: sync_aggregate.clone(),
|
||||
execution_payload: BlindedPayloadEip4844 {
|
||||
execution_payload_header: execution_payload.into(),
|
||||
},
|
||||
bls_to_execution_changes: bls_to_execution_changes.clone(),
|
||||
blob_kzg_commitments: blob_kzg_commitments.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EthSpec> From<BeaconBlockBody<E, FullPayload<E>>>
|
||||
for (
|
||||
BeaconBlockBody<E, BlindedPayload<E>>,
|
||||
@@ -307,7 +499,7 @@ impl<E: EthSpec> From<BeaconBlockBody<E, FullPayload<E>>>
|
||||
fn from(body: BeaconBlockBody<E, FullPayload<E>>) -> Self {
|
||||
map_beacon_block_body!(body, |inner, cons| {
|
||||
let (block, payload) = inner.into();
|
||||
(cons(block), payload)
|
||||
(cons(block), payload.map(Into::into))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,9 +10,19 @@ use tree_hash_derive::TreeHash;
|
||||
/// A header of a `BeaconBlock`.
|
||||
///
|
||||
/// Spec v0.12.1
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(
|
||||
Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom,
|
||||
arbitrary::Arbitrary,
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
Hash,
|
||||
Clone,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
TreeHash,
|
||||
TestRandom,
|
||||
)]
|
||||
pub struct BeaconBlockHeader {
|
||||
pub slot: Slot,
|
||||
|
||||
@@ -17,8 +17,7 @@ impl<'a> BeaconCommittee<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(Default, Clone, Debug, PartialEq)]
|
||||
#[derive(arbitrary::Arbitrary, Default, Clone, Debug, PartialEq)]
|
||||
pub struct OwnedBeaconCommittee {
|
||||
pub slot: Slot,
|
||||
pub index: CommitteeIndex,
|
||||
|
||||
@@ -14,6 +14,7 @@ use ssz::{ssz_encode, Decode, DecodeError, Encode};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use ssz_types::{typenum::Unsigned, BitVector, FixedVector};
|
||||
use std::convert::TryInto;
|
||||
use std::hash::Hash;
|
||||
use std::{fmt, mem, sync::Arc};
|
||||
use superstruct::superstruct;
|
||||
use swap_or_not_shuffle::compute_shuffled_index;
|
||||
@@ -25,6 +26,7 @@ pub use self::committee_cache::{
|
||||
compute_committee_index_in_epoch, compute_committee_range_in_epoch, epoch_committee_count,
|
||||
CommitteeCache,
|
||||
};
|
||||
use crate::historical_summary::HistoricalSummary;
|
||||
pub use clone_config::CloneConfig;
|
||||
pub use eth_spec::*;
|
||||
pub use iter::BlockRootsIter;
|
||||
@@ -120,6 +122,7 @@ pub enum Error {
|
||||
ArithError(ArithError),
|
||||
MissingBeaconBlock(SignedBeaconBlockHash),
|
||||
MissingBeaconState(BeaconStateHash),
|
||||
PayloadConversionLogicFlaw,
|
||||
SyncCommitteeNotKnown {
|
||||
current_epoch: Epoch,
|
||||
epoch: Epoch,
|
||||
@@ -144,8 +147,7 @@ impl AllowNextEpoch {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(PartialEq, Eq, Hash, Clone, Copy)]
|
||||
#[derive(PartialEq, Eq, Hash, Clone, Copy, arbitrary::Arbitrary)]
|
||||
pub struct BeaconStateHash(Hash256);
|
||||
|
||||
impl fmt::Debug for BeaconStateHash {
|
||||
@@ -174,7 +176,7 @@ impl From<BeaconStateHash> for Hash256 {
|
||||
|
||||
/// The state of the `BeaconChain` at some slot.
|
||||
#[superstruct(
|
||||
variants(Base, Altair, Merge),
|
||||
variants(Base, Altair, Merge, Capella, Eip4844),
|
||||
variant_attributes(
|
||||
derive(
|
||||
Derivative,
|
||||
@@ -187,18 +189,19 @@ impl From<BeaconStateHash> for Hash256 {
|
||||
TreeHash,
|
||||
TestRandom,
|
||||
CompareFields,
|
||||
arbitrary::Arbitrary
|
||||
),
|
||||
serde(bound = "T: EthSpec", deny_unknown_fields),
|
||||
arbitrary(bound = "T: EthSpec"),
|
||||
derivative(Clone),
|
||||
cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))
|
||||
),
|
||||
cast_error(ty = "Error", expr = "Error::IncorrectStateVariant"),
|
||||
partial_getter_error(ty = "Error", expr = "Error::IncorrectStateVariant")
|
||||
)]
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize, Encode, TreeHash)]
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize, Encode, TreeHash, arbitrary::Arbitrary)]
|
||||
#[serde(untagged)]
|
||||
#[serde(bound = "T: EthSpec")]
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[arbitrary(bound = "T: EthSpec")]
|
||||
#[tree_hash(enum_behaviour = "transparent")]
|
||||
#[ssz(enum_behaviour = "transparent")]
|
||||
pub struct BeaconState<T>
|
||||
@@ -222,6 +225,7 @@ where
|
||||
pub block_roots: FixedVector<Hash256, T::SlotsPerHistoricalRoot>,
|
||||
#[compare_fields(as_slice)]
|
||||
pub state_roots: FixedVector<Hash256, T::SlotsPerHistoricalRoot>,
|
||||
// Frozen in Capella, replaced by historical_summaries
|
||||
pub historical_roots: VariableList<Hash256, T::HistoricalRootsLimit>,
|
||||
|
||||
// Ethereum 1.0 chain data
|
||||
@@ -252,9 +256,9 @@ where
|
||||
pub current_epoch_attestations: VariableList<PendingAttestation<T>, T::MaxPendingAttestations>,
|
||||
|
||||
// Participation (Altair and later)
|
||||
#[superstruct(only(Altair, Merge))]
|
||||
#[superstruct(only(Altair, Merge, Capella, Eip4844))]
|
||||
pub previous_epoch_participation: VariableList<ParticipationFlags, T::ValidatorRegistryLimit>,
|
||||
#[superstruct(only(Altair, Merge))]
|
||||
#[superstruct(only(Altair, Merge, Capella, Eip4844))]
|
||||
pub current_epoch_participation: VariableList<ParticipationFlags, T::ValidatorRegistryLimit>,
|
||||
|
||||
// Finality
|
||||
@@ -269,18 +273,42 @@ where
|
||||
|
||||
// Inactivity
|
||||
#[serde(with = "ssz_types::serde_utils::quoted_u64_var_list")]
|
||||
#[superstruct(only(Altair, Merge))]
|
||||
#[superstruct(only(Altair, Merge, Capella, Eip4844))]
|
||||
pub inactivity_scores: VariableList<u64, T::ValidatorRegistryLimit>,
|
||||
|
||||
// Light-client sync committees
|
||||
#[superstruct(only(Altair, Merge))]
|
||||
#[superstruct(only(Altair, Merge, Capella, Eip4844))]
|
||||
pub current_sync_committee: Arc<SyncCommittee<T>>,
|
||||
#[superstruct(only(Altair, Merge))]
|
||||
#[superstruct(only(Altair, Merge, Capella, Eip4844))]
|
||||
pub next_sync_committee: Arc<SyncCommittee<T>>,
|
||||
|
||||
// Execution
|
||||
#[superstruct(only(Merge))]
|
||||
pub latest_execution_payload_header: ExecutionPayloadHeader<T>,
|
||||
#[superstruct(
|
||||
only(Merge),
|
||||
partial_getter(rename = "latest_execution_payload_header_merge")
|
||||
)]
|
||||
pub latest_execution_payload_header: ExecutionPayloadHeaderMerge<T>,
|
||||
#[superstruct(
|
||||
only(Capella),
|
||||
partial_getter(rename = "latest_execution_payload_header_capella")
|
||||
)]
|
||||
pub latest_execution_payload_header: ExecutionPayloadHeaderCapella<T>,
|
||||
#[superstruct(
|
||||
only(Eip4844),
|
||||
partial_getter(rename = "latest_execution_payload_header_eip4844")
|
||||
)]
|
||||
pub latest_execution_payload_header: ExecutionPayloadHeaderEip4844<T>,
|
||||
|
||||
// Capella
|
||||
#[superstruct(only(Capella, Eip4844), partial_getter(copy))]
|
||||
#[serde(with = "eth2_serde_utils::quoted_u64")]
|
||||
pub next_withdrawal_index: u64,
|
||||
#[superstruct(only(Capella, Eip4844), partial_getter(copy))]
|
||||
#[serde(with = "eth2_serde_utils::quoted_u64")]
|
||||
pub next_withdrawal_validator_index: u64,
|
||||
// Deep history valid from Capella onwards.
|
||||
#[superstruct(only(Capella, Eip4844))]
|
||||
pub historical_summaries: VariableList<HistoricalSummary, T::HistoricalRootsLimit>,
|
||||
|
||||
// Caching (not in the spec)
|
||||
#[serde(skip_serializing, skip_deserializing)]
|
||||
@@ -391,6 +419,8 @@ impl<T: EthSpec> BeaconState<T> {
|
||||
BeaconState::Base { .. } => ForkName::Base,
|
||||
BeaconState::Altair { .. } => ForkName::Altair,
|
||||
BeaconState::Merge { .. } => ForkName::Merge,
|
||||
BeaconState::Capella { .. } => ForkName::Capella,
|
||||
BeaconState::Eip4844 { .. } => ForkName::Eip4844,
|
||||
};
|
||||
|
||||
if fork_at_slot == object_fork {
|
||||
@@ -680,6 +710,39 @@ impl<T: EthSpec> BeaconState<T> {
|
||||
.ok_or(Error::ShuffleIndexOutOfBounds(index))
|
||||
}
|
||||
|
||||
/// Convenience accessor for the `execution_payload_header` as an `ExecutionPayloadHeaderRef`.
|
||||
pub fn latest_execution_payload_header(&self) -> Result<ExecutionPayloadHeaderRef<T>, Error> {
|
||||
match self {
|
||||
BeaconState::Base(_) | BeaconState::Altair(_) => Err(Error::IncorrectStateVariant),
|
||||
BeaconState::Merge(state) => Ok(ExecutionPayloadHeaderRef::Merge(
|
||||
&state.latest_execution_payload_header,
|
||||
)),
|
||||
BeaconState::Capella(state) => Ok(ExecutionPayloadHeaderRef::Capella(
|
||||
&state.latest_execution_payload_header,
|
||||
)),
|
||||
BeaconState::Eip4844(state) => Ok(ExecutionPayloadHeaderRef::Eip4844(
|
||||
&state.latest_execution_payload_header,
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn latest_execution_payload_header_mut(
|
||||
&mut self,
|
||||
) -> Result<ExecutionPayloadHeaderRefMut<T>, Error> {
|
||||
match self {
|
||||
BeaconState::Base(_) | BeaconState::Altair(_) => Err(Error::IncorrectStateVariant),
|
||||
BeaconState::Merge(state) => Ok(ExecutionPayloadHeaderRefMut::Merge(
|
||||
&mut state.latest_execution_payload_header,
|
||||
)),
|
||||
BeaconState::Capella(state) => Ok(ExecutionPayloadHeaderRefMut::Capella(
|
||||
&mut state.latest_execution_payload_header,
|
||||
)),
|
||||
BeaconState::Eip4844(state) => Ok(ExecutionPayloadHeaderRefMut::Eip4844(
|
||||
&mut state.latest_execution_payload_header,
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Return `true` if the validator who produced `slot_signature` is eligible to aggregate.
|
||||
///
|
||||
/// Spec v0.12.1
|
||||
@@ -1104,6 +1167,8 @@ impl<T: EthSpec> BeaconState<T> {
|
||||
BeaconState::Base(state) => (&mut state.validators, &mut state.balances),
|
||||
BeaconState::Altair(state) => (&mut state.validators, &mut state.balances),
|
||||
BeaconState::Merge(state) => (&mut state.validators, &mut state.balances),
|
||||
BeaconState::Capella(state) => (&mut state.validators, &mut state.balances),
|
||||
BeaconState::Eip4844(state) => (&mut state.validators, &mut state.balances),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1300,12 +1365,16 @@ impl<T: EthSpec> BeaconState<T> {
|
||||
BeaconState::Base(_) => Err(BeaconStateError::IncorrectStateVariant),
|
||||
BeaconState::Altair(state) => Ok(&mut state.current_epoch_participation),
|
||||
BeaconState::Merge(state) => Ok(&mut state.current_epoch_participation),
|
||||
BeaconState::Capella(state) => Ok(&mut state.current_epoch_participation),
|
||||
BeaconState::Eip4844(state) => Ok(&mut state.current_epoch_participation),
|
||||
}
|
||||
} else if epoch == self.previous_epoch() {
|
||||
match self {
|
||||
BeaconState::Base(_) => Err(BeaconStateError::IncorrectStateVariant),
|
||||
BeaconState::Altair(state) => Ok(&mut state.previous_epoch_participation),
|
||||
BeaconState::Merge(state) => Ok(&mut state.previous_epoch_participation),
|
||||
BeaconState::Capella(state) => Ok(&mut state.previous_epoch_participation),
|
||||
BeaconState::Eip4844(state) => Ok(&mut state.previous_epoch_participation),
|
||||
}
|
||||
} else {
|
||||
Err(BeaconStateError::EpochOutOfBounds)
|
||||
@@ -1610,6 +1679,8 @@ impl<T: EthSpec> BeaconState<T> {
|
||||
BeaconState::Base(inner) => BeaconState::Base(inner.clone()),
|
||||
BeaconState::Altair(inner) => BeaconState::Altair(inner.clone()),
|
||||
BeaconState::Merge(inner) => BeaconState::Merge(inner.clone()),
|
||||
BeaconState::Capella(inner) => BeaconState::Capella(inner.clone()),
|
||||
BeaconState::Eip4844(inner) => BeaconState::Eip4844(inner.clone()),
|
||||
};
|
||||
if config.committee_caches {
|
||||
*res.committee_caches_mut() = self.committee_caches().clone();
|
||||
@@ -1777,7 +1848,25 @@ 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",),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: EthSpec> ForkVersionDeserialize for BeaconState<T> {
|
||||
fn deserialize_by_fork<'de, D: serde::Deserializer<'de>>(
|
||||
value: serde_json::value::Value,
|
||||
fork_name: ForkName,
|
||||
) -> Result<Self, D::Error> {
|
||||
Ok(map_fork_name!(
|
||||
fork_name,
|
||||
Self,
|
||||
serde_json::from_value(value).map_err(|e| serde::de::Error::custom(format!(
|
||||
"BeaconState failed to deserialize: {:?}",
|
||||
e
|
||||
)))?
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -336,7 +336,6 @@ pub fn get_active_validator_indices(validators: &[Validator], epoch: Epoch) -> V
|
||||
active
|
||||
}
|
||||
|
||||
#[cfg(feature = "arbitrary-fuzz")]
|
||||
impl arbitrary::Arbitrary<'_> for CommitteeCache {
|
||||
fn arbitrary(_u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
|
||||
Ok(Self::default())
|
||||
|
||||
@@ -61,7 +61,6 @@ impl ExitCache {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "arbitrary-fuzz")]
|
||||
impl arbitrary::Arbitrary<'_> for ExitCache {
|
||||
fn arbitrary(_u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
|
||||
Ok(Self::default())
|
||||
|
||||
@@ -42,7 +42,6 @@ impl PubkeyCache {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "arbitrary-fuzz")]
|
||||
impl arbitrary::Arbitrary<'_> for PubkeyCache {
|
||||
fn arbitrary(_u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
|
||||
Ok(Self::default())
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
use crate::test_utils::*;
|
||||
use crate::test_utils::{SeedableRng, XorShiftRng};
|
||||
use beacon_chain::test_utils::{
|
||||
interop_genesis_state, test_spec, BeaconChainHarness, EphemeralHarnessType,
|
||||
interop_genesis_state_with_eth1, test_spec, BeaconChainHarness, EphemeralHarnessType,
|
||||
DEFAULT_ETH1_BLOCK_HASH,
|
||||
};
|
||||
use beacon_chain::types::{
|
||||
@@ -551,7 +551,7 @@ fn tree_hash_cache_linear_history_long_skip() {
|
||||
let spec = &test_spec::<MinimalEthSpec>();
|
||||
|
||||
// This state has a cache that advances normally each slot.
|
||||
let mut state: BeaconState<MinimalEthSpec> = interop_genesis_state(
|
||||
let mut state: BeaconState<MinimalEthSpec> = interop_genesis_state_with_eth1(
|
||||
&keypairs,
|
||||
0,
|
||||
Hash256::from_slice(DEFAULT_ETH1_BLOCK_HASH),
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#![allow(clippy::indexing_slicing)]
|
||||
|
||||
use super::Error;
|
||||
use crate::historical_summary::HistoricalSummaryCache;
|
||||
use crate::{BeaconState, EthSpec, Hash256, ParticipationList, Slot, Unsigned, Validator};
|
||||
use cached_tree_hash::{int_log, CacheArena, CachedTreeHash, TreeHashCache};
|
||||
use rayon::prelude::*;
|
||||
@@ -142,6 +143,7 @@ pub struct BeaconTreeHashCacheInner<T: EthSpec> {
|
||||
block_roots: TreeHashCache,
|
||||
state_roots: TreeHashCache,
|
||||
historical_roots: TreeHashCache,
|
||||
historical_summaries: OptionalTreeHashCache,
|
||||
balances: TreeHashCache,
|
||||
randao_mixes: TreeHashCache,
|
||||
slashings: TreeHashCache,
|
||||
@@ -164,6 +166,14 @@ impl<T: EthSpec> BeaconTreeHashCacheInner<T> {
|
||||
let historical_roots = state
|
||||
.historical_roots()
|
||||
.new_tree_hash_cache(&mut fixed_arena);
|
||||
let historical_summaries = OptionalTreeHashCache::new(
|
||||
state
|
||||
.historical_summaries()
|
||||
.ok()
|
||||
.map(HistoricalSummaryCache::new)
|
||||
.as_ref(),
|
||||
);
|
||||
|
||||
let randao_mixes = state.randao_mixes().new_tree_hash_cache(&mut fixed_arena);
|
||||
|
||||
let validators = ValidatorsListTreeHashCache::new::<T>(state.validators());
|
||||
@@ -200,6 +210,7 @@ impl<T: EthSpec> BeaconTreeHashCacheInner<T> {
|
||||
block_roots,
|
||||
state_roots,
|
||||
historical_roots,
|
||||
historical_summaries,
|
||||
balances,
|
||||
randao_mixes,
|
||||
slashings,
|
||||
@@ -249,6 +260,7 @@ impl<T: EthSpec> BeaconTreeHashCacheInner<T> {
|
||||
.slashings()
|
||||
.recalculate_tree_hash_root(&mut self.slashings_arena, &mut self.slashings)?,
|
||||
];
|
||||
|
||||
// Participation
|
||||
if let BeaconState::Base(state) = state {
|
||||
leaves.push(state.previous_epoch_attestations.tree_hash_root());
|
||||
@@ -291,6 +303,24 @@ impl<T: EthSpec> BeaconTreeHashCacheInner<T> {
|
||||
if let Ok(payload_header) = state.latest_execution_payload_header() {
|
||||
leaves.push(payload_header.tree_hash_root());
|
||||
}
|
||||
|
||||
// Withdrawal indices (Capella and later).
|
||||
if let Ok(next_withdrawal_index) = state.next_withdrawal_index() {
|
||||
leaves.push(next_withdrawal_index.tree_hash_root());
|
||||
}
|
||||
if let Ok(next_withdrawal_validator_index) = state.next_withdrawal_validator_index() {
|
||||
leaves.push(next_withdrawal_validator_index.tree_hash_root());
|
||||
}
|
||||
|
||||
// Historical roots/summaries (Capella and later).
|
||||
if let Ok(historical_summaries) = state.historical_summaries() {
|
||||
leaves.push(
|
||||
self.historical_summaries.recalculate_tree_hash_root(
|
||||
&HistoricalSummaryCache::new(historical_summaries),
|
||||
)?,
|
||||
);
|
||||
}
|
||||
|
||||
Ok(leaves)
|
||||
}
|
||||
|
||||
@@ -570,7 +600,6 @@ impl OptionalTreeHashCacheInner {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "arbitrary-fuzz")]
|
||||
impl<T: EthSpec> arbitrary::Arbitrary<'_> for BeaconTreeHashCache<T> {
|
||||
fn arbitrary(_u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
|
||||
Ok(Self::default())
|
||||
|
||||
43
consensus/types/src/blobs_sidecar.rs
Normal file
43
consensus/types/src/blobs_sidecar.rs
Normal file
@@ -0,0 +1,43 @@
|
||||
use crate::kzg_proof::KzgProof;
|
||||
use crate::{Blob, EthSpec, Hash256, SignedRoot, Slot};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use ssz::Encode;
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use ssz_types::VariableList;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Clone,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
TreeHash,
|
||||
PartialEq,
|
||||
Default,
|
||||
arbitrary::Arbitrary,
|
||||
)]
|
||||
#[serde(bound = "T: EthSpec")]
|
||||
#[arbitrary(bound = "T: EthSpec")]
|
||||
pub struct BlobsSidecar<T: EthSpec> {
|
||||
pub beacon_block_root: Hash256,
|
||||
pub beacon_block_slot: Slot,
|
||||
pub blobs: VariableList<Blob<T>, T::MaxBlobsPerBlock>,
|
||||
pub kzg_aggregate_proof: KzgProof,
|
||||
}
|
||||
|
||||
impl<T: EthSpec> SignedRoot for BlobsSidecar<T> {}
|
||||
|
||||
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()
|
||||
// Max size of variable length `blobs` field
|
||||
+ (T::max_blobs_per_block() * <Blob<T> as Encode>::ssz_fixed_len())
|
||||
}
|
||||
}
|
||||
57
consensus/types/src/bls_to_execution_change.rs
Normal file
57
consensus/types/src/bls_to_execution_change.rs
Normal file
@@ -0,0 +1,57 @@
|
||||
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;
|
||||
|
||||
#[derive(
|
||||
arbitrary::Arbitrary,
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
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 {}
|
||||
|
||||
impl BlsToExecutionChange {
|
||||
pub fn sign(
|
||||
self,
|
||||
secret_key: &SecretKey,
|
||||
genesis_validators_root: Hash256,
|
||||
spec: &ChainSpec,
|
||||
) -> SignedBlsToExecutionChange {
|
||||
let domain = spec.compute_domain(
|
||||
Domain::BlsToExecutionChange,
|
||||
spec.genesis_fork_version,
|
||||
genesis_validators_root,
|
||||
);
|
||||
let message = self.signing_root(domain);
|
||||
SignedBlsToExecutionChange {
|
||||
message: self,
|
||||
signature: secret_key.sign(message),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
ssz_and_tree_hash_tests!(BlsToExecutionChange);
|
||||
}
|
||||
@@ -1,4 +1,7 @@
|
||||
use crate::{ChainSpec, EthSpec, ExecPayload, ExecutionPayloadHeader, SignedRoot, Uint256};
|
||||
use crate::{
|
||||
AbstractExecPayload, ChainSpec, EthSpec, ExecPayload, ExecutionPayloadHeader, ForkName,
|
||||
ForkVersionDeserialize, SignedRoot, Uint256,
|
||||
};
|
||||
use bls::PublicKeyBytes;
|
||||
use bls::Signature;
|
||||
use serde::{Deserialize as De, Deserializer, Serialize as Ser, Serializer};
|
||||
@@ -10,7 +13,7 @@ use tree_hash_derive::TreeHash;
|
||||
#[serde_as]
|
||||
#[derive(PartialEq, Debug, Serialize, Deserialize, TreeHash, Clone)]
|
||||
#[serde(bound = "E: EthSpec, Payload: ExecPayload<E>")]
|
||||
pub struct BuilderBid<E: EthSpec, Payload: ExecPayload<E>> {
|
||||
pub struct BuilderBid<E: EthSpec, Payload: AbstractExecPayload<E>> {
|
||||
#[serde_as(as = "BlindedPayloadAsHeader<E>")]
|
||||
pub header: Payload,
|
||||
#[serde(with = "eth2_serde_utils::quoted_u256")]
|
||||
@@ -21,16 +24,70 @@ pub struct BuilderBid<E: EthSpec, Payload: ExecPayload<E>> {
|
||||
_phantom_data: PhantomData<E>,
|
||||
}
|
||||
|
||||
impl<E: EthSpec, Payload: ExecPayload<E>> SignedRoot for BuilderBid<E, Payload> {}
|
||||
impl<E: EthSpec, Payload: AbstractExecPayload<E>> SignedRoot for BuilderBid<E, Payload> {}
|
||||
|
||||
/// Validator registration, for use in interacting with servers implementing the builder API.
|
||||
#[derive(PartialEq, Debug, Serialize, Deserialize, Clone)]
|
||||
#[serde(bound = "E: EthSpec, Payload: ExecPayload<E>")]
|
||||
pub struct SignedBuilderBid<E: EthSpec, Payload: ExecPayload<E>> {
|
||||
pub struct SignedBuilderBid<E: EthSpec, Payload: AbstractExecPayload<E>> {
|
||||
pub message: BuilderBid<E, Payload>,
|
||||
pub signature: Signature,
|
||||
}
|
||||
|
||||
impl<T: EthSpec, Payload: AbstractExecPayload<T>> ForkVersionDeserialize
|
||||
for BuilderBid<T, Payload>
|
||||
{
|
||||
fn deserialize_by_fork<'de, D: serde::Deserializer<'de>>(
|
||||
value: serde_json::value::Value,
|
||||
fork_name: ForkName,
|
||||
) -> Result<Self, D::Error> {
|
||||
let convert_err = |_| {
|
||||
serde::de::Error::custom(
|
||||
"BuilderBid failed to deserialize: unable to convert payload header to payload",
|
||||
)
|
||||
};
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct Helper {
|
||||
header: serde_json::Value,
|
||||
#[serde(with = "eth2_serde_utils::quoted_u256")]
|
||||
value: Uint256,
|
||||
pubkey: PublicKeyBytes,
|
||||
}
|
||||
let helper: Helper = serde_json::from_value(value).map_err(serde::de::Error::custom)?;
|
||||
let payload_header =
|
||||
ExecutionPayloadHeader::deserialize_by_fork::<'de, D>(helper.header, fork_name)?;
|
||||
|
||||
Ok(Self {
|
||||
header: Payload::try_from(payload_header).map_err(convert_err)?,
|
||||
value: helper.value,
|
||||
pubkey: helper.pubkey,
|
||||
_phantom_data: Default::default(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: EthSpec, Payload: AbstractExecPayload<T>> ForkVersionDeserialize
|
||||
for SignedBuilderBid<T, Payload>
|
||||
{
|
||||
fn deserialize_by_fork<'de, D: serde::Deserializer<'de>>(
|
||||
value: serde_json::value::Value,
|
||||
fork_name: ForkName,
|
||||
) -> Result<Self, D::Error> {
|
||||
#[derive(Deserialize)]
|
||||
struct Helper {
|
||||
pub message: serde_json::Value,
|
||||
pub signature: Signature,
|
||||
}
|
||||
let helper: Helper = serde_json::from_value(value).map_err(serde::de::Error::custom)?;
|
||||
|
||||
Ok(Self {
|
||||
message: BuilderBid::deserialize_by_fork::<'de, D>(helper.message, fork_name)?,
|
||||
signature: helper.signature,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
struct BlindedPayloadAsHeader<E>(PhantomData<E>);
|
||||
|
||||
impl<E: EthSpec, Payload: ExecPayload<E>> SerializeAs<Payload> for BlindedPayloadAsHeader<E> {
|
||||
@@ -42,7 +99,7 @@ impl<E: EthSpec, Payload: ExecPayload<E>> SerializeAs<Payload> for BlindedPayloa
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, E: EthSpec, Payload: ExecPayload<E>> DeserializeAs<'de, Payload>
|
||||
impl<'de, E: EthSpec, Payload: AbstractExecPayload<E>> DeserializeAs<'de, Payload>
|
||||
for BlindedPayloadAsHeader<E>
|
||||
{
|
||||
fn deserialize_as<D>(deserializer: D) -> Result<Payload, D::Error>
|
||||
@@ -55,7 +112,7 @@ impl<'de, E: EthSpec, Payload: ExecPayload<E>> DeserializeAs<'de, Payload>
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EthSpec, Payload: ExecPayload<E>> SignedBuilderBid<E, Payload> {
|
||||
impl<E: EthSpec, Payload: AbstractExecPayload<E>> SignedBuilderBid<E, Payload> {
|
||||
pub fn verify_signature(&self, spec: &ChainSpec) -> bool {
|
||||
self.message
|
||||
.pubkey
|
||||
|
||||
@@ -11,8 +11,10 @@ use tree_hash::TreeHash;
|
||||
/// Each of the BLS signature domains.
|
||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||
pub enum Domain {
|
||||
BlsToExecutionChange,
|
||||
BeaconProposer,
|
||||
BeaconAttester,
|
||||
BlobsSideCar,
|
||||
Randao,
|
||||
Deposit,
|
||||
VoluntaryExit,
|
||||
@@ -27,8 +29,7 @@ pub enum Domain {
|
||||
/// Lighthouse's internal configuration struct.
|
||||
///
|
||||
/// Contains a mixture of "preset" and "config" values w.r.t to the EF definitions.
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(PartialEq, Debug, Clone)]
|
||||
#[derive(arbitrary::Arbitrary, PartialEq, Debug, Clone)]
|
||||
pub struct ChainSpec {
|
||||
/*
|
||||
* Config name
|
||||
@@ -99,6 +100,7 @@ pub struct ChainSpec {
|
||||
*/
|
||||
pub(crate) domain_beacon_proposer: u32,
|
||||
pub(crate) domain_beacon_attester: u32,
|
||||
pub(crate) domain_blobs_sidecar: u32,
|
||||
pub(crate) domain_randao: u32,
|
||||
pub(crate) domain_deposit: u32,
|
||||
pub(crate) domain_voluntary_exit: u32,
|
||||
@@ -151,6 +153,20 @@ pub struct ChainSpec {
|
||||
pub terminal_block_hash_activation_epoch: Epoch,
|
||||
pub safe_slots_to_import_optimistically: u64,
|
||||
|
||||
/*
|
||||
* Capella hard fork params
|
||||
*/
|
||||
pub capella_fork_version: [u8; 4],
|
||||
/// The Capella fork epoch is optional, with `None` representing "Capella never happens".
|
||||
pub capella_fork_epoch: Option<Epoch>,
|
||||
pub max_validators_per_withdrawals_sweep: u64,
|
||||
|
||||
/*
|
||||
* Eip4844 hard fork params
|
||||
*/
|
||||
pub eip4844_fork_version: [u8; 4],
|
||||
pub eip4844_fork_epoch: Option<Epoch>,
|
||||
|
||||
/*
|
||||
* Networking
|
||||
*/
|
||||
@@ -170,6 +186,11 @@ pub struct ChainSpec {
|
||||
* Application params
|
||||
*/
|
||||
pub(crate) domain_application_mask: u32,
|
||||
|
||||
/*
|
||||
* Capella params
|
||||
*/
|
||||
pub(crate) domain_bls_to_execution_change: u32,
|
||||
}
|
||||
|
||||
impl ChainSpec {
|
||||
@@ -234,11 +255,17 @@ impl ChainSpec {
|
||||
|
||||
/// Returns the name of the fork which is active at `epoch`.
|
||||
pub fn fork_name_at_epoch(&self, epoch: Epoch) -> ForkName {
|
||||
match self.bellatrix_fork_epoch {
|
||||
Some(fork_epoch) if epoch >= fork_epoch => ForkName::Merge,
|
||||
_ => match self.altair_fork_epoch {
|
||||
Some(fork_epoch) if epoch >= fork_epoch => ForkName::Altair,
|
||||
_ => ForkName::Base,
|
||||
match self.eip4844_fork_epoch {
|
||||
Some(fork_epoch) if epoch >= fork_epoch => ForkName::Eip4844,
|
||||
_ => match self.capella_fork_epoch {
|
||||
Some(fork_epoch) if epoch >= fork_epoch => ForkName::Capella,
|
||||
_ => match self.bellatrix_fork_epoch {
|
||||
Some(fork_epoch) if epoch >= fork_epoch => ForkName::Merge,
|
||||
_ => match self.altair_fork_epoch {
|
||||
Some(fork_epoch) if epoch >= fork_epoch => ForkName::Altair,
|
||||
_ => ForkName::Base,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -249,6 +276,8 @@ impl ChainSpec {
|
||||
ForkName::Base => self.genesis_fork_version,
|
||||
ForkName::Altair => self.altair_fork_version,
|
||||
ForkName::Merge => self.bellatrix_fork_version,
|
||||
ForkName::Capella => self.capella_fork_version,
|
||||
ForkName::Eip4844 => self.eip4844_fork_version,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -258,6 +287,8 @@ impl ChainSpec {
|
||||
ForkName::Base => Some(Epoch::new(0)),
|
||||
ForkName::Altair => self.altair_fork_epoch,
|
||||
ForkName::Merge => self.bellatrix_fork_epoch,
|
||||
ForkName::Capella => self.capella_fork_epoch,
|
||||
ForkName::Eip4844 => self.eip4844_fork_epoch,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -267,6 +298,8 @@ impl ChainSpec {
|
||||
BeaconState::Base(_) => self.inactivity_penalty_quotient,
|
||||
BeaconState::Altair(_) => self.inactivity_penalty_quotient_altair,
|
||||
BeaconState::Merge(_) => self.inactivity_penalty_quotient_bellatrix,
|
||||
BeaconState::Capella(_) => self.inactivity_penalty_quotient_bellatrix,
|
||||
BeaconState::Eip4844(_) => self.inactivity_penalty_quotient_bellatrix,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -279,6 +312,8 @@ impl ChainSpec {
|
||||
BeaconState::Base(_) => self.proportional_slashing_multiplier,
|
||||
BeaconState::Altair(_) => self.proportional_slashing_multiplier_altair,
|
||||
BeaconState::Merge(_) => self.proportional_slashing_multiplier_bellatrix,
|
||||
BeaconState::Capella(_) => self.proportional_slashing_multiplier_bellatrix,
|
||||
BeaconState::Eip4844(_) => self.proportional_slashing_multiplier_bellatrix,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -291,6 +326,8 @@ impl ChainSpec {
|
||||
BeaconState::Base(_) => self.min_slashing_penalty_quotient,
|
||||
BeaconState::Altair(_) => self.min_slashing_penalty_quotient_altair,
|
||||
BeaconState::Merge(_) => self.min_slashing_penalty_quotient_bellatrix,
|
||||
BeaconState::Capella(_) => self.min_slashing_penalty_quotient_bellatrix,
|
||||
BeaconState::Eip4844(_) => self.min_slashing_penalty_quotient_bellatrix,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -329,6 +366,7 @@ impl ChainSpec {
|
||||
match domain {
|
||||
Domain::BeaconProposer => self.domain_beacon_proposer,
|
||||
Domain::BeaconAttester => self.domain_beacon_attester,
|
||||
Domain::BlobsSideCar => self.domain_blobs_sidecar,
|
||||
Domain::Randao => self.domain_randao,
|
||||
Domain::Deposit => self.domain_deposit,
|
||||
Domain::VoluntaryExit => self.domain_voluntary_exit,
|
||||
@@ -338,6 +376,7 @@ impl ChainSpec {
|
||||
Domain::ContributionAndProof => self.domain_contribution_and_proof,
|
||||
Domain::SyncCommitteeSelectionProof => self.domain_sync_committee_selection_proof,
|
||||
Domain::ApplicationMask(application_domain) => application_domain.get_domain_constant(),
|
||||
Domain::BlsToExecutionChange => self.domain_bls_to_execution_change,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -500,8 +539,8 @@ impl ChainSpec {
|
||||
* Initial Values
|
||||
*/
|
||||
genesis_fork_version: [0; 4],
|
||||
bls_withdrawal_prefix_byte: 0,
|
||||
eth1_address_withdrawal_prefix_byte: 1,
|
||||
bls_withdrawal_prefix_byte: 0x00,
|
||||
eth1_address_withdrawal_prefix_byte: 0x01,
|
||||
|
||||
/*
|
||||
* Time parameters
|
||||
@@ -535,6 +574,7 @@ impl ChainSpec {
|
||||
domain_voluntary_exit: 4,
|
||||
domain_selection_proof: 5,
|
||||
domain_aggregate_and_proof: 6,
|
||||
domain_blobs_sidecar: 10, // 0x0a000000
|
||||
|
||||
/*
|
||||
* Fork choice
|
||||
@@ -589,6 +629,19 @@ impl ChainSpec {
|
||||
terminal_block_hash_activation_epoch: Epoch::new(u64::MAX),
|
||||
safe_slots_to_import_optimistically: 128u64,
|
||||
|
||||
/*
|
||||
* Capella hard fork params
|
||||
*/
|
||||
capella_fork_version: [0x03, 00, 00, 00],
|
||||
capella_fork_epoch: None,
|
||||
max_validators_per_withdrawals_sweep: 16384,
|
||||
|
||||
/*
|
||||
* Eip4844 hard fork params
|
||||
*/
|
||||
eip4844_fork_version: [0x04, 0x00, 0x00, 0x00],
|
||||
eip4844_fork_epoch: None,
|
||||
|
||||
/*
|
||||
* Network specific
|
||||
*/
|
||||
@@ -608,6 +661,11 @@ impl ChainSpec {
|
||||
* Application specific
|
||||
*/
|
||||
domain_application_mask: APPLICATION_DOMAIN_BUILDER,
|
||||
|
||||
/*
|
||||
* Capella params
|
||||
*/
|
||||
domain_bls_to_execution_change: 10,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -647,6 +705,13 @@ impl ChainSpec {
|
||||
// `Uint256::MAX` which is `2*256- 1`.
|
||||
.checked_add(Uint256::one())
|
||||
.expect("addition does not overflow"),
|
||||
// Capella
|
||||
capella_fork_version: [0x03, 0x00, 0x00, 0x01],
|
||||
capella_fork_epoch: None,
|
||||
max_validators_per_withdrawals_sweep: 16,
|
||||
// Eip4844
|
||||
eip4844_fork_version: [0x04, 0x00, 0x00, 0x01],
|
||||
eip4844_fork_epoch: None,
|
||||
// Other
|
||||
network_id: 2, // lighthouse testnet network id
|
||||
deposit_chain_id: 5,
|
||||
@@ -709,8 +774,8 @@ impl ChainSpec {
|
||||
* Initial Values
|
||||
*/
|
||||
genesis_fork_version: [0x00, 0x00, 0x00, 0x64],
|
||||
bls_withdrawal_prefix_byte: 0,
|
||||
eth1_address_withdrawal_prefix_byte: 1,
|
||||
bls_withdrawal_prefix_byte: 0x00,
|
||||
eth1_address_withdrawal_prefix_byte: 0x01,
|
||||
|
||||
/*
|
||||
* Time parameters
|
||||
@@ -744,6 +809,7 @@ impl ChainSpec {
|
||||
domain_voluntary_exit: 4,
|
||||
domain_selection_proof: 5,
|
||||
domain_aggregate_and_proof: 6,
|
||||
domain_blobs_sidecar: 10,
|
||||
|
||||
/*
|
||||
* Fork choice
|
||||
@@ -800,6 +866,19 @@ impl ChainSpec {
|
||||
terminal_block_hash_activation_epoch: Epoch::new(u64::MAX),
|
||||
safe_slots_to_import_optimistically: 128u64,
|
||||
|
||||
/*
|
||||
* Capella hard fork params
|
||||
*/
|
||||
capella_fork_version: [0x03, 0x00, 0x00, 0x64],
|
||||
capella_fork_epoch: None,
|
||||
max_validators_per_withdrawals_sweep: 16384,
|
||||
|
||||
/*
|
||||
* Eip4844 hard fork params
|
||||
*/
|
||||
eip4844_fork_version: [0x04, 0x00, 0x00, 0x64],
|
||||
eip4844_fork_epoch: None,
|
||||
|
||||
/*
|
||||
* Network specific
|
||||
*/
|
||||
@@ -819,6 +898,11 @@ impl ChainSpec {
|
||||
* Application specific
|
||||
*/
|
||||
domain_application_mask: APPLICATION_DOMAIN_BUILDER,
|
||||
|
||||
/*
|
||||
* Capella params
|
||||
*/
|
||||
domain_bls_to_execution_change: 10,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -878,6 +962,22 @@ pub struct Config {
|
||||
#[serde(deserialize_with = "deserialize_fork_epoch")]
|
||||
pub bellatrix_fork_epoch: Option<MaybeQuoted<Epoch>>,
|
||||
|
||||
#[serde(default = "default_capella_fork_version")]
|
||||
#[serde(with = "eth2_serde_utils::bytes_4_hex")]
|
||||
capella_fork_version: [u8; 4],
|
||||
#[serde(default)]
|
||||
#[serde(serialize_with = "serialize_fork_epoch")]
|
||||
#[serde(deserialize_with = "deserialize_fork_epoch")]
|
||||
pub capella_fork_epoch: Option<MaybeQuoted<Epoch>>,
|
||||
|
||||
#[serde(default = "default_eip4844_fork_version")]
|
||||
#[serde(with = "eth2_serde_utils::bytes_4_hex")]
|
||||
eip4844_fork_version: [u8; 4],
|
||||
#[serde(default)]
|
||||
#[serde(serialize_with = "serialize_fork_epoch")]
|
||||
#[serde(deserialize_with = "deserialize_fork_epoch")]
|
||||
pub eip4844_fork_epoch: Option<MaybeQuoted<Epoch>>,
|
||||
|
||||
#[serde(with = "eth2_serde_utils::quoted_u64")]
|
||||
seconds_per_slot: u64,
|
||||
#[serde(with = "eth2_serde_utils::quoted_u64")]
|
||||
@@ -915,6 +1015,16 @@ fn default_bellatrix_fork_version() -> [u8; 4] {
|
||||
[0xff, 0xff, 0xff, 0xff]
|
||||
}
|
||||
|
||||
fn default_capella_fork_version() -> [u8; 4] {
|
||||
// TODO: determine if the bellatrix example should be copied like this
|
||||
[0xff, 0xff, 0xff, 0xff]
|
||||
}
|
||||
|
||||
fn default_eip4844_fork_version() -> [u8; 4] {
|
||||
// This value shouldn't be used.
|
||||
[0xff, 0xff, 0xff, 0xff]
|
||||
}
|
||||
|
||||
/// Placeholder value: 2^256-2^10 (115792089237316195423570985008687907853269984665640564039457584007913129638912).
|
||||
///
|
||||
/// Taken from https://github.com/ethereum/consensus-specs/blob/d5e4828aecafaf1c57ef67a5f23c4ae7b08c5137/configs/mainnet.yaml#L15-L16
|
||||
@@ -1011,6 +1121,14 @@ impl Config {
|
||||
bellatrix_fork_epoch: spec
|
||||
.bellatrix_fork_epoch
|
||||
.map(|epoch| MaybeQuoted { value: epoch }),
|
||||
capella_fork_version: spec.capella_fork_version,
|
||||
capella_fork_epoch: spec
|
||||
.capella_fork_epoch
|
||||
.map(|epoch| MaybeQuoted { value: epoch }),
|
||||
eip4844_fork_version: spec.eip4844_fork_version,
|
||||
eip4844_fork_epoch: spec
|
||||
.eip4844_fork_epoch
|
||||
.map(|epoch| MaybeQuoted { value: epoch }),
|
||||
|
||||
seconds_per_slot: spec.seconds_per_slot,
|
||||
seconds_per_eth1_block: spec.seconds_per_eth1_block,
|
||||
@@ -1056,6 +1174,10 @@ impl Config {
|
||||
altair_fork_epoch,
|
||||
bellatrix_fork_epoch,
|
||||
bellatrix_fork_version,
|
||||
capella_fork_epoch,
|
||||
capella_fork_version,
|
||||
eip4844_fork_epoch,
|
||||
eip4844_fork_version,
|
||||
seconds_per_slot,
|
||||
seconds_per_eth1_block,
|
||||
min_validator_withdrawability_delay,
|
||||
@@ -1086,6 +1208,10 @@ impl Config {
|
||||
altair_fork_epoch: altair_fork_epoch.map(|q| q.value),
|
||||
bellatrix_fork_epoch: bellatrix_fork_epoch.map(|q| q.value),
|
||||
bellatrix_fork_version,
|
||||
capella_fork_epoch: capella_fork_epoch.map(|q| q.value),
|
||||
capella_fork_version,
|
||||
eip4844_fork_epoch: eip4844_fork_epoch.map(|q| q.value),
|
||||
eip4844_fork_version,
|
||||
seconds_per_slot,
|
||||
seconds_per_eth1_block,
|
||||
min_validator_withdrawability_delay,
|
||||
@@ -1159,6 +1285,7 @@ mod tests {
|
||||
|
||||
test_domain(Domain::BeaconProposer, spec.domain_beacon_proposer, &spec);
|
||||
test_domain(Domain::BeaconAttester, spec.domain_beacon_attester, &spec);
|
||||
test_domain(Domain::BlobsSideCar, spec.domain_blobs_sidecar, &spec);
|
||||
test_domain(Domain::Randao, spec.domain_randao, &spec);
|
||||
test_domain(Domain::Deposit, spec.domain_deposit, &spec);
|
||||
test_domain(Domain::VoluntaryExit, spec.domain_voluntary_exit, &spec);
|
||||
@@ -1177,6 +1304,14 @@ mod tests {
|
||||
apply_bit_mask(builder_domain_pre_mask, &spec),
|
||||
&spec,
|
||||
);
|
||||
|
||||
test_domain(
|
||||
Domain::BlsToExecutionChange,
|
||||
spec.domain_bls_to_execution_change,
|
||||
&spec,
|
||||
);
|
||||
|
||||
test_domain(Domain::BlobsSideCar, spec.domain_blobs_sidecar, &spec);
|
||||
}
|
||||
|
||||
fn apply_bit_mask(domain_bytes: [u8; 4], spec: &ChainSpec) -> u32 {
|
||||
|
||||
@@ -8,8 +8,8 @@ use tree_hash_derive::TreeHash;
|
||||
/// Casper FFG checkpoint, used in attestations.
|
||||
///
|
||||
/// Spec v0.12.1
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(
|
||||
arbitrary::Arbitrary,
|
||||
Debug,
|
||||
Clone,
|
||||
Copy,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use crate::{
|
||||
consts::altair, AltairPreset, BasePreset, BellatrixPreset, ChainSpec, Config, EthSpec, ForkName,
|
||||
consts::altair, AltairPreset, BasePreset, BellatrixPreset, CapellaPreset, ChainSpec, Config,
|
||||
EthSpec, ForkName,
|
||||
};
|
||||
use maplit::hashmap;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
@@ -11,7 +12,7 @@ use superstruct::superstruct;
|
||||
///
|
||||
/// Mostly useful for the API.
|
||||
#[superstruct(
|
||||
variants(Altair, Bellatrix),
|
||||
variants(Bellatrix, Capella),
|
||||
variant_attributes(derive(Serialize, Deserialize, Debug, PartialEq, Clone))
|
||||
)]
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
|
||||
@@ -24,9 +25,11 @@ pub struct ConfigAndPreset {
|
||||
pub base_preset: BasePreset,
|
||||
#[serde(flatten)]
|
||||
pub altair_preset: AltairPreset,
|
||||
#[superstruct(only(Bellatrix))]
|
||||
#[serde(flatten)]
|
||||
pub bellatrix_preset: BellatrixPreset,
|
||||
#[superstruct(only(Capella))]
|
||||
#[serde(flatten)]
|
||||
pub capella_preset: CapellaPreset,
|
||||
/// The `extra_fields` map allows us to gracefully decode fields intended for future hard forks.
|
||||
#[serde(flatten)]
|
||||
pub extra_fields: HashMap<String, Value>,
|
||||
@@ -37,14 +40,24 @@ impl ConfigAndPreset {
|
||||
let config = Config::from_chain_spec::<T>(spec);
|
||||
let base_preset = BasePreset::from_chain_spec::<T>(spec);
|
||||
let altair_preset = AltairPreset::from_chain_spec::<T>(spec);
|
||||
let bellatrix_preset = BellatrixPreset::from_chain_spec::<T>(spec);
|
||||
let extra_fields = get_extra_fields(spec);
|
||||
|
||||
if spec.bellatrix_fork_epoch.is_some()
|
||||
if spec.capella_fork_epoch.is_some()
|
||||
|| fork_name.is_none()
|
||||
|| fork_name == Some(ForkName::Merge)
|
||||
|| fork_name == Some(ForkName::Capella)
|
||||
{
|
||||
let bellatrix_preset = BellatrixPreset::from_chain_spec::<T>(spec);
|
||||
let capella_preset = CapellaPreset::from_chain_spec::<T>(spec);
|
||||
|
||||
ConfigAndPreset::Capella(ConfigAndPresetCapella {
|
||||
config,
|
||||
base_preset,
|
||||
altair_preset,
|
||||
bellatrix_preset,
|
||||
capella_preset,
|
||||
extra_fields,
|
||||
})
|
||||
} else {
|
||||
ConfigAndPreset::Bellatrix(ConfigAndPresetBellatrix {
|
||||
config,
|
||||
base_preset,
|
||||
@@ -52,13 +65,6 @@ impl ConfigAndPreset {
|
||||
bellatrix_preset,
|
||||
extra_fields,
|
||||
})
|
||||
} else {
|
||||
ConfigAndPreset::Altair(ConfigAndPresetAltair {
|
||||
config,
|
||||
base_preset,
|
||||
altair_preset,
|
||||
extra_fields,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -72,6 +78,7 @@ pub fn get_extra_fields(spec: &ChainSpec) -> HashMap<String, Value> {
|
||||
"bls_withdrawal_prefix".to_uppercase() => u8_hex(spec.bls_withdrawal_prefix_byte),
|
||||
"domain_beacon_proposer".to_uppercase() => u32_hex(spec.domain_beacon_proposer),
|
||||
"domain_beacon_attester".to_uppercase() => u32_hex(spec.domain_beacon_attester),
|
||||
"domain_blobs_sidecar".to_uppercase() => u32_hex(spec.domain_blobs_sidecar),
|
||||
"domain_randao".to_uppercase()=> u32_hex(spec.domain_randao),
|
||||
"domain_deposit".to_uppercase()=> u32_hex(spec.domain_deposit),
|
||||
"domain_voluntary_exit".to_uppercase() => u32_hex(spec.domain_voluntary_exit),
|
||||
@@ -130,8 +137,8 @@ mod test {
|
||||
.write(false)
|
||||
.open(tmp_file.as_ref())
|
||||
.expect("error while opening the file");
|
||||
let from: ConfigAndPresetBellatrix =
|
||||
let from: ConfigAndPresetCapella =
|
||||
serde_yaml::from_reader(reader).expect("error while deserializing");
|
||||
assert_eq!(ConfigAndPreset::Bellatrix(from), yamlconfig);
|
||||
assert_eq!(ConfigAndPreset::Capella(from), yamlconfig);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,3 +22,17 @@ pub mod altair {
|
||||
pub mod merge {
|
||||
pub const INTERVALS_PER_SLOT: u64 = 3;
|
||||
}
|
||||
pub mod eip4844 {
|
||||
use crate::Uint256;
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
lazy_static! {
|
||||
pub static ref BLS_MODULUS: Uint256 = Uint256::from_dec_str(
|
||||
"52435875175126190479447740508185965837690552500527637822603658699938581184513"
|
||||
)
|
||||
.expect("should initialize BLS_MODULUS");
|
||||
}
|
||||
pub const BLOB_TX_TYPE: u8 = 5;
|
||||
pub const VERSIONED_HASH_VERSION_KZG: u8 = 1;
|
||||
}
|
||||
|
||||
@@ -9,9 +9,20 @@ use test_random_derive::TestRandom;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
/// A Validators aggregate sync committee contribution and selection proof.
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode, TestRandom, TreeHash)]
|
||||
#[derive(
|
||||
Debug,
|
||||
Clone,
|
||||
PartialEq,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
TestRandom,
|
||||
TreeHash,
|
||||
arbitrary::Arbitrary,
|
||||
)]
|
||||
#[serde(bound = "T: EthSpec")]
|
||||
#[arbitrary(bound = "T: EthSpec")]
|
||||
pub struct ContributionAndProof<T: EthSpec> {
|
||||
/// The index of the validator that created the sync contribution.
|
||||
#[serde(with = "eth2_serde_utils::quoted_u64")]
|
||||
|
||||
@@ -11,9 +11,18 @@ pub const DEPOSIT_TREE_DEPTH: usize = 32;
|
||||
/// 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,
|
||||
arbitrary::Arbitrary,
|
||||
Debug,
|
||||
PartialEq,
|
||||
Hash,
|
||||
Clone,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
TreeHash,
|
||||
TestRandom,
|
||||
)]
|
||||
pub struct Deposit {
|
||||
pub proof: FixedVector<Hash256, U33>,
|
||||
|
||||
@@ -10,9 +10,18 @@ use tree_hash_derive::TreeHash;
|
||||
/// The data supplied by the user to the deposit contract.
|
||||
///
|
||||
/// Spec v0.12.1
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(
|
||||
Debug, PartialEq, Hash, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom,
|
||||
arbitrary::Arbitrary,
|
||||
Debug,
|
||||
PartialEq,
|
||||
Hash,
|
||||
Clone,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
TreeHash,
|
||||
TestRandom,
|
||||
)]
|
||||
pub struct DepositData {
|
||||
pub pubkey: PublicKeyBytes,
|
||||
|
||||
@@ -10,8 +10,18 @@ use tree_hash_derive::TreeHash;
|
||||
/// The data supplied by the user to the deposit contract.
|
||||
///
|
||||
/// Spec v0.12.1
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)]
|
||||
#[derive(
|
||||
arbitrary::Arbitrary,
|
||||
Debug,
|
||||
PartialEq,
|
||||
Clone,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
TreeHash,
|
||||
TestRandom,
|
||||
)]
|
||||
pub struct DepositMessage {
|
||||
pub pubkey: PublicKeyBytes,
|
||||
pub withdrawal_credentials: Hash256,
|
||||
|
||||
@@ -10,9 +10,18 @@ use tree_hash_derive::TreeHash;
|
||||
/// a nodes local ENR.
|
||||
///
|
||||
/// Spec v0.11
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(
|
||||
Debug, Clone, PartialEq, Default, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom,
|
||||
arbitrary::Arbitrary,
|
||||
Debug,
|
||||
Clone,
|
||||
PartialEq,
|
||||
Default,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
TreeHash,
|
||||
TestRandom,
|
||||
)]
|
||||
pub struct EnrForkId {
|
||||
#[serde(with = "eth2_serde_utils::bytes_4_hex")]
|
||||
|
||||
@@ -9,8 +9,8 @@ use tree_hash_derive::TreeHash;
|
||||
/// Contains data obtained from the Eth1 chain.
|
||||
///
|
||||
/// Spec v0.12.1
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(
|
||||
arbitrary::Arbitrary,
|
||||
Debug,
|
||||
PartialEq,
|
||||
Clone,
|
||||
|
||||
@@ -48,7 +48,9 @@ impl fmt::Display for EthSpecId {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait EthSpec: 'static + Default + Sync + Send + Clone + Debug + PartialEq + Eq {
|
||||
pub trait EthSpec:
|
||||
'static + Default + Sync + Send + Clone + Debug + PartialEq + Eq + for<'a> arbitrary::Arbitrary<'a>
|
||||
{
|
||||
/*
|
||||
* Constants
|
||||
*/
|
||||
@@ -95,6 +97,16 @@ pub trait EthSpec: 'static + Default + Sync + Send + Clone + Debug + PartialEq +
|
||||
type GasLimitDenominator: Unsigned + Clone + Sync + Send + Debug + PartialEq;
|
||||
type MinGasLimit: Unsigned + Clone + Sync + Send + Debug + PartialEq;
|
||||
type MaxExtraDataBytes: Unsigned + Clone + Sync + Send + Debug + PartialEq;
|
||||
/*
|
||||
* New in Capella
|
||||
*/
|
||||
type MaxBlsToExecutionChanges: Unsigned + Clone + Sync + Send + Debug + PartialEq;
|
||||
type MaxWithdrawalsPerPayload: Unsigned + Clone + Sync + Send + Debug + PartialEq;
|
||||
/*
|
||||
* New in Eip4844
|
||||
*/
|
||||
type MaxBlobsPerBlock: Unsigned + Clone + Sync + Send + Debug + PartialEq;
|
||||
type FieldElementsPerBlob: Unsigned + Clone + Sync + Send + Debug + PartialEq;
|
||||
/*
|
||||
* Derived values (set these CAREFULLY)
|
||||
*/
|
||||
@@ -222,6 +234,21 @@ pub trait EthSpec: 'static + Default + Sync + Send + Clone + Debug + PartialEq +
|
||||
fn bytes_per_logs_bloom() -> usize {
|
||||
Self::BytesPerLogsBloom::to_usize()
|
||||
}
|
||||
|
||||
/// Returns the `MAX_BLS_TO_EXECUTION_CHANGES` constant for this specification.
|
||||
fn max_bls_to_execution_changes() -> usize {
|
||||
Self::MaxBlsToExecutionChanges::to_usize()
|
||||
}
|
||||
|
||||
/// Returns the `MAX_WITHDRAWALS_PER_PAYLOAD` constant for this specification.
|
||||
fn max_withdrawals_per_payload() -> usize {
|
||||
Self::MaxWithdrawalsPerPayload::to_usize()
|
||||
}
|
||||
|
||||
/// Returns the `MAX_BLOBS_PER_BLOCK` constant for this specification.
|
||||
fn max_blobs_per_block() -> usize {
|
||||
Self::MaxBlobsPerBlock::to_usize()
|
||||
}
|
||||
}
|
||||
|
||||
/// Macro to inherit some type values from another EthSpec.
|
||||
@@ -233,8 +260,7 @@ macro_rules! params_from_eth_spec {
|
||||
}
|
||||
|
||||
/// Ethereum Foundation specifications.
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Default, Serialize, Deserialize)]
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Default, Serialize, Deserialize, arbitrary::Arbitrary)]
|
||||
pub struct MainnetEthSpec;
|
||||
|
||||
impl EthSpec for MainnetEthSpec {
|
||||
@@ -262,9 +288,13 @@ impl EthSpec for MainnetEthSpec {
|
||||
type GasLimitDenominator = U1024;
|
||||
type MinGasLimit = U5000;
|
||||
type MaxExtraDataBytes = U32;
|
||||
type MaxBlobsPerBlock = U16; // 2**4 = 16
|
||||
type FieldElementsPerBlob = U4096;
|
||||
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 MaxBlsToExecutionChanges = U16;
|
||||
type MaxWithdrawalsPerPayload = U16;
|
||||
|
||||
fn default_spec() -> ChainSpec {
|
||||
ChainSpec::mainnet()
|
||||
@@ -276,8 +306,7 @@ impl EthSpec for MainnetEthSpec {
|
||||
}
|
||||
|
||||
/// Ethereum Foundation minimal spec, as defined in the eth2.0-specs repo.
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Default, Serialize, Deserialize)]
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Default, Serialize, Deserialize, arbitrary::Arbitrary)]
|
||||
pub struct MinimalEthSpec;
|
||||
|
||||
impl EthSpec for MinimalEthSpec {
|
||||
@@ -290,6 +319,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,
|
||||
@@ -309,7 +339,10 @@ impl EthSpec for MinimalEthSpec {
|
||||
BytesPerLogsBloom,
|
||||
GasLimitDenominator,
|
||||
MinGasLimit,
|
||||
MaxExtraDataBytes
|
||||
MaxExtraDataBytes,
|
||||
MaxBlsToExecutionChanges,
|
||||
MaxBlobsPerBlock,
|
||||
FieldElementsPerBlob
|
||||
});
|
||||
|
||||
fn default_spec() -> ChainSpec {
|
||||
@@ -322,8 +355,7 @@ impl EthSpec for MinimalEthSpec {
|
||||
}
|
||||
|
||||
/// Gnosis Beacon Chain specifications.
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Default, Serialize, Deserialize)]
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Default, Serialize, Deserialize, arbitrary::Arbitrary)]
|
||||
pub struct GnosisEthSpec;
|
||||
|
||||
impl EthSpec for GnosisEthSpec {
|
||||
@@ -354,6 +386,10 @@ 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 MaxBlsToExecutionChanges = U16;
|
||||
type MaxWithdrawalsPerPayload = U16;
|
||||
type MaxBlobsPerBlock = U16; // 2**4 = 16
|
||||
type FieldElementsPerBlob = U4096;
|
||||
|
||||
fn default_spec() -> ChainSpec {
|
||||
ChainSpec::gnosis()
|
||||
|
||||
@@ -6,8 +6,18 @@ use serde_derive::{Deserialize, Serialize};
|
||||
use ssz::{Decode, DecodeError, Encode};
|
||||
use std::fmt;
|
||||
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(Default, Clone, Copy, Serialize, Deserialize, Eq, PartialEq, Hash, Derivative)]
|
||||
#[derive(
|
||||
arbitrary::Arbitrary,
|
||||
Default,
|
||||
Clone,
|
||||
Copy,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Eq,
|
||||
PartialEq,
|
||||
Hash,
|
||||
Derivative,
|
||||
)]
|
||||
#[derivative(Debug = "transparent")]
|
||||
#[serde(transparent)]
|
||||
pub struct ExecutionBlockHash(Hash256);
|
||||
|
||||
@@ -17,14 +17,16 @@
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
use crate::{Address, EthSpec, ExecutionPayload, Hash256, Hash64, Uint256};
|
||||
use crate::{Address, EthSpec, ExecutionPayloadRef, Hash256, Hash64, Uint256};
|
||||
use metastruct::metastruct;
|
||||
|
||||
/// Execution block header as used for RLP encoding and Keccak hashing.
|
||||
///
|
||||
/// Credit to Reth for the type definition.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
#[metastruct(mappings(map_execution_block_header_fields()))]
|
||||
#[metastruct(mappings(map_execution_block_header_fields_except_withdrawals(exclude(
|
||||
withdrawals_root
|
||||
))))]
|
||||
pub struct ExecutionBlockHeader {
|
||||
pub parent_hash: Hash256,
|
||||
pub ommers_hash: Hash256,
|
||||
@@ -42,33 +44,36 @@ pub struct ExecutionBlockHeader {
|
||||
pub mix_hash: Hash256,
|
||||
pub nonce: Hash64,
|
||||
pub base_fee_per_gas: Uint256,
|
||||
pub withdrawals_root: Option<Hash256>,
|
||||
}
|
||||
|
||||
impl ExecutionBlockHeader {
|
||||
pub fn from_payload<E: EthSpec>(
|
||||
payload: &ExecutionPayload<E>,
|
||||
payload: ExecutionPayloadRef<E>,
|
||||
rlp_empty_list_root: Hash256,
|
||||
rlp_transactions_root: Hash256,
|
||||
rlp_withdrawals_root: Option<Hash256>,
|
||||
) -> Self {
|
||||
// Most of these field mappings are defined in EIP-3675 except for `mixHash`, which is
|
||||
// defined in EIP-4399.
|
||||
ExecutionBlockHeader {
|
||||
parent_hash: payload.parent_hash.into_root(),
|
||||
parent_hash: payload.parent_hash().into_root(),
|
||||
ommers_hash: rlp_empty_list_root,
|
||||
beneficiary: payload.fee_recipient,
|
||||
state_root: payload.state_root,
|
||||
beneficiary: payload.fee_recipient(),
|
||||
state_root: payload.state_root(),
|
||||
transactions_root: rlp_transactions_root,
|
||||
receipts_root: payload.receipts_root,
|
||||
logs_bloom: payload.logs_bloom.clone().into(),
|
||||
receipts_root: payload.receipts_root(),
|
||||
logs_bloom: payload.logs_bloom().clone().into(),
|
||||
difficulty: Uint256::zero(),
|
||||
number: payload.block_number.into(),
|
||||
gas_limit: payload.gas_limit.into(),
|
||||
gas_used: payload.gas_used.into(),
|
||||
timestamp: payload.timestamp,
|
||||
extra_data: payload.extra_data.clone().into(),
|
||||
mix_hash: payload.prev_randao,
|
||||
number: payload.block_number().into(),
|
||||
gas_limit: payload.gas_limit().into(),
|
||||
gas_used: payload.gas_used().into(),
|
||||
timestamp: payload.timestamp(),
|
||||
extra_data: payload.extra_data().clone().into(),
|
||||
mix_hash: payload.prev_randao(),
|
||||
nonce: Hash64::zero(),
|
||||
base_fee_per_gas: payload.base_fee_per_gas,
|
||||
base_fee_per_gas: payload.base_fee_per_gas(),
|
||||
withdrawals_root: rlp_withdrawals_root,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -12,50 +12,162 @@ pub type Transactions<T> = VariableList<
|
||||
<T as EthSpec>::MaxTransactionsPerPayload,
|
||||
>;
|
||||
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
pub type Withdrawals<T> = VariableList<Withdrawal, <T as EthSpec>::MaxWithdrawalsPerPayload>;
|
||||
|
||||
#[superstruct(
|
||||
variants(Merge, Capella, Eip4844),
|
||||
variant_attributes(
|
||||
derive(
|
||||
Default,
|
||||
Debug,
|
||||
Clone,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
TreeHash,
|
||||
TestRandom,
|
||||
Derivative,
|
||||
arbitrary::Arbitrary
|
||||
),
|
||||
derivative(PartialEq, Hash(bound = "T: EthSpec")),
|
||||
serde(bound = "T: EthSpec", deny_unknown_fields),
|
||||
arbitrary(bound = "T: EthSpec")
|
||||
),
|
||||
cast_error(ty = "Error", expr = "BeaconStateError::IncorrectStateVariant"),
|
||||
partial_getter_error(ty = "Error", expr = "BeaconStateError::IncorrectStateVariant"),
|
||||
map_into(FullPayload, BlindedPayload),
|
||||
map_ref_into(ExecutionPayloadHeader)
|
||||
)]
|
||||
#[derive(
|
||||
Default, Debug, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom, Derivative,
|
||||
Debug, Clone, Serialize, Encode, Deserialize, TreeHash, Derivative, arbitrary::Arbitrary,
|
||||
)]
|
||||
#[derivative(PartialEq, Hash(bound = "T: EthSpec"))]
|
||||
#[serde(bound = "T: EthSpec")]
|
||||
#[serde(bound = "T: EthSpec", untagged)]
|
||||
#[arbitrary(bound = "T: EthSpec")]
|
||||
#[ssz(enum_behaviour = "transparent")]
|
||||
#[tree_hash(enum_behaviour = "transparent")]
|
||||
pub struct ExecutionPayload<T: EthSpec> {
|
||||
#[superstruct(getter(copy))]
|
||||
pub parent_hash: ExecutionBlockHash,
|
||||
#[superstruct(getter(copy))]
|
||||
pub fee_recipient: Address,
|
||||
#[superstruct(getter(copy))]
|
||||
pub state_root: Hash256,
|
||||
#[superstruct(getter(copy))]
|
||||
pub receipts_root: Hash256,
|
||||
#[serde(with = "ssz_types::serde_utils::hex_fixed_vec")]
|
||||
pub logs_bloom: FixedVector<u8, T::BytesPerLogsBloom>,
|
||||
#[superstruct(getter(copy))]
|
||||
pub prev_randao: Hash256,
|
||||
#[serde(with = "eth2_serde_utils::quoted_u64")]
|
||||
#[superstruct(getter(copy))]
|
||||
pub block_number: u64,
|
||||
#[serde(with = "eth2_serde_utils::quoted_u64")]
|
||||
#[superstruct(getter(copy))]
|
||||
pub gas_limit: u64,
|
||||
#[serde(with = "eth2_serde_utils::quoted_u64")]
|
||||
#[superstruct(getter(copy))]
|
||||
pub gas_used: u64,
|
||||
#[serde(with = "eth2_serde_utils::quoted_u64")]
|
||||
#[superstruct(getter(copy))]
|
||||
pub timestamp: u64,
|
||||
#[serde(with = "ssz_types::serde_utils::hex_var_list")]
|
||||
pub extra_data: VariableList<u8, T::MaxExtraDataBytes>,
|
||||
#[serde(with = "eth2_serde_utils::quoted_u256")]
|
||||
#[superstruct(getter(copy))]
|
||||
pub base_fee_per_gas: Uint256,
|
||||
#[superstruct(only(Eip4844))]
|
||||
#[serde(with = "eth2_serde_utils::quoted_u256")]
|
||||
#[superstruct(getter(copy))]
|
||||
pub excess_data_gas: Uint256,
|
||||
#[superstruct(getter(copy))]
|
||||
pub block_hash: ExecutionBlockHash,
|
||||
#[serde(with = "ssz_types::serde_utils::list_of_hex_var_list")]
|
||||
pub transactions: Transactions<T>,
|
||||
#[superstruct(only(Capella, Eip4844))]
|
||||
pub withdrawals: Withdrawals<T>,
|
||||
}
|
||||
|
||||
impl<'a, T: EthSpec> ExecutionPayloadRef<'a, T> {
|
||||
// this emulates clone on a normal reference type
|
||||
pub fn clone_from_ref(&self) -> ExecutionPayload<T> {
|
||||
map_execution_payload_ref!(&'a _, self, move |payload, cons| {
|
||||
cons(payload);
|
||||
payload.clone().into()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: EthSpec> ExecutionPayload<T> {
|
||||
pub fn empty() -> Self {
|
||||
Self::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 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_size() -> usize {
|
||||
pub fn max_execution_payload_merge_size() -> usize {
|
||||
// Fixed part
|
||||
Self::empty().as_ssz_bytes().len()
|
||||
ExecutionPayloadMerge::<T>::default().as_ssz_bytes().len()
|
||||
// Max size of variable length `extra_data` field
|
||||
+ (T::max_extra_data_bytes() * <u8 as Encode>::ssz_fixed_len())
|
||||
// Max size of variable length `transactions` field
|
||||
+ (T::max_transactions_per_payload() * (ssz::BYTES_PER_LENGTH_OFFSET + T::max_bytes_per_transaction()))
|
||||
}
|
||||
|
||||
#[allow(clippy::integer_arithmetic)]
|
||||
/// Returns the maximum size of an execution payload.
|
||||
pub fn max_execution_payload_capella_size() -> usize {
|
||||
// Fixed part
|
||||
ExecutionPayloadCapella::<T>::default().as_ssz_bytes().len()
|
||||
// Max size of variable length `extra_data` field
|
||||
+ (T::max_extra_data_bytes() * <u8 as Encode>::ssz_fixed_len())
|
||||
// Max size of variable length `transactions` field
|
||||
+ (T::max_transactions_per_payload() * (ssz::BYTES_PER_LENGTH_OFFSET + T::max_bytes_per_transaction()))
|
||||
// Max size of variable length `withdrawals` field
|
||||
+ (T::max_withdrawals_per_payload() * <Withdrawal as Encode>::ssz_fixed_len())
|
||||
}
|
||||
|
||||
#[allow(clippy::integer_arithmetic)]
|
||||
/// Returns the maximum size of an execution payload.
|
||||
pub fn max_execution_payload_eip4844_size() -> usize {
|
||||
// Fixed part
|
||||
ExecutionPayloadEip4844::<T>::default().as_ssz_bytes().len()
|
||||
// Max size of variable length `extra_data` field
|
||||
+ (T::max_extra_data_bytes() * <u8 as Encode>::ssz_fixed_len())
|
||||
// Max size of variable length `transactions` field
|
||||
+ (T::max_transactions_per_payload() * (ssz::BYTES_PER_LENGTH_OFFSET + T::max_bytes_per_transaction()))
|
||||
// Max size of variable length `withdrawals` field
|
||||
+ (T::max_withdrawals_per_payload() * <Withdrawal as Encode>::ssz_fixed_len())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: EthSpec> ForkVersionDeserialize for ExecutionPayload<T> {
|
||||
fn deserialize_by_fork<'de, D: serde::Deserializer<'de>>(
|
||||
value: serde_json::value::Value,
|
||||
fork_name: ForkName,
|
||||
) -> Result<Self, D::Error> {
|
||||
let convert_err = |e| {
|
||||
serde::de::Error::custom(format!("ExecutionPayload failed to deserialize: {:?}", e))
|
||||
};
|
||||
|
||||
Ok(match fork_name {
|
||||
ForkName::Merge => Self::Merge(serde_json::from_value(value).map_err(convert_err)?),
|
||||
ForkName::Capella => Self::Capella(serde_json::from_value(value).map_err(convert_err)?),
|
||||
ForkName::Eip4844 => Self::Eip4844(serde_json::from_value(value).map_err(convert_err)?),
|
||||
ForkName::Base | ForkName::Altair => {
|
||||
return Err(serde::de::Error::custom(format!(
|
||||
"ExecutionPayload failed to deserialize: unsupported fork '{}'",
|
||||
fork_name
|
||||
)));
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,49 +1,167 @@
|
||||
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;
|
||||
use tree_hash_derive::TreeHash;
|
||||
use BeaconStateError;
|
||||
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[superstruct(
|
||||
variants(Merge, Capella, Eip4844),
|
||||
variant_attributes(
|
||||
derive(
|
||||
Default,
|
||||
Debug,
|
||||
Clone,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
TreeHash,
|
||||
TestRandom,
|
||||
Derivative,
|
||||
arbitrary::Arbitrary
|
||||
),
|
||||
derivative(PartialEq, Hash(bound = "T: EthSpec")),
|
||||
serde(bound = "T: EthSpec", deny_unknown_fields),
|
||||
arbitrary(bound = "T: EthSpec")
|
||||
),
|
||||
ref_attributes(derive(PartialEq, TreeHash), tree_hash(enum_behaviour = "transparent")),
|
||||
cast_error(ty = "Error", expr = "BeaconStateError::IncorrectStateVariant"),
|
||||
partial_getter_error(ty = "Error", expr = "BeaconStateError::IncorrectStateVariant")
|
||||
)]
|
||||
#[derive(
|
||||
Default, Debug, Clone, Serialize, Deserialize, Derivative, Encode, Decode, TreeHash, TestRandom,
|
||||
Debug, Clone, Serialize, Deserialize, Encode, TreeHash, Derivative, arbitrary::Arbitrary,
|
||||
)]
|
||||
#[derivative(PartialEq, Hash(bound = "T: EthSpec"))]
|
||||
#[serde(bound = "T: EthSpec", untagged)]
|
||||
#[arbitrary(bound = "T: EthSpec")]
|
||||
#[tree_hash(enum_behaviour = "transparent")]
|
||||
#[ssz(enum_behaviour = "transparent")]
|
||||
pub struct ExecutionPayloadHeader<T: EthSpec> {
|
||||
#[superstruct(getter(copy))]
|
||||
pub parent_hash: ExecutionBlockHash,
|
||||
#[superstruct(getter(copy))]
|
||||
pub fee_recipient: Address,
|
||||
#[superstruct(getter(copy))]
|
||||
pub state_root: Hash256,
|
||||
#[superstruct(getter(copy))]
|
||||
pub receipts_root: Hash256,
|
||||
#[serde(with = "ssz_types::serde_utils::hex_fixed_vec")]
|
||||
pub logs_bloom: FixedVector<u8, T::BytesPerLogsBloom>,
|
||||
#[superstruct(getter(copy))]
|
||||
pub prev_randao: Hash256,
|
||||
#[serde(with = "eth2_serde_utils::quoted_u64")]
|
||||
#[superstruct(getter(copy))]
|
||||
pub block_number: u64,
|
||||
#[serde(with = "eth2_serde_utils::quoted_u64")]
|
||||
#[superstruct(getter(copy))]
|
||||
pub gas_limit: u64,
|
||||
#[serde(with = "eth2_serde_utils::quoted_u64")]
|
||||
#[superstruct(getter(copy))]
|
||||
pub gas_used: u64,
|
||||
#[serde(with = "eth2_serde_utils::quoted_u64")]
|
||||
#[superstruct(getter(copy))]
|
||||
pub timestamp: u64,
|
||||
#[serde(with = "ssz_types::serde_utils::hex_var_list")]
|
||||
pub extra_data: VariableList<u8, T::MaxExtraDataBytes>,
|
||||
#[serde(with = "eth2_serde_utils::quoted_u256")]
|
||||
#[superstruct(getter(copy))]
|
||||
pub base_fee_per_gas: Uint256,
|
||||
#[superstruct(only(Eip4844))]
|
||||
#[serde(with = "eth2_serde_utils::quoted_u256")]
|
||||
#[superstruct(getter(copy))]
|
||||
pub excess_data_gas: Uint256,
|
||||
#[superstruct(getter(copy))]
|
||||
pub block_hash: ExecutionBlockHash,
|
||||
#[superstruct(getter(copy))]
|
||||
pub transactions_root: Hash256,
|
||||
#[superstruct(only(Capella, Eip4844))]
|
||||
#[superstruct(getter(copy))]
|
||||
pub withdrawals_root: Hash256,
|
||||
}
|
||||
|
||||
impl<T: EthSpec> ExecutionPayloadHeader<T> {
|
||||
pub fn empty() -> Self {
|
||||
Self::default()
|
||||
pub fn transactions(&self) -> Option<&Transactions<T>> {
|
||||
None
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
ForkName::Eip4844 => {
|
||||
ExecutionPayloadHeaderEip4844::from_ssz_bytes(bytes).map(Self::Eip4844)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: EthSpec> From<&'a ExecutionPayload<T>> for ExecutionPayloadHeader<T> {
|
||||
fn from(payload: &'a ExecutionPayload<T>) -> Self {
|
||||
ExecutionPayloadHeader {
|
||||
impl<'a, T: EthSpec> ExecutionPayloadHeaderRef<'a, T> {
|
||||
pub fn is_default_with_zero_roots(self) -> bool {
|
||||
map_execution_payload_header_ref!(&'a _, self, |inner, cons| {
|
||||
cons(inner);
|
||||
*inner == Default::default()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: EthSpec> ExecutionPayloadHeaderMerge<T> {
|
||||
pub fn upgrade_to_capella(&self) -> ExecutionPayloadHeaderCapella<T> {
|
||||
ExecutionPayloadHeaderCapella {
|
||||
parent_hash: self.parent_hash,
|
||||
fee_recipient: self.fee_recipient,
|
||||
state_root: self.state_root,
|
||||
receipts_root: self.receipts_root,
|
||||
logs_bloom: self.logs_bloom.clone(),
|
||||
prev_randao: self.prev_randao,
|
||||
block_number: self.block_number,
|
||||
gas_limit: self.gas_limit,
|
||||
gas_used: self.gas_used,
|
||||
timestamp: self.timestamp,
|
||||
extra_data: self.extra_data.clone(),
|
||||
base_fee_per_gas: self.base_fee_per_gas,
|
||||
block_hash: self.block_hash,
|
||||
transactions_root: self.transactions_root,
|
||||
withdrawals_root: Hash256::zero(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: EthSpec> ExecutionPayloadHeaderCapella<T> {
|
||||
pub fn upgrade_to_eip4844(&self) -> ExecutionPayloadHeaderEip4844<T> {
|
||||
ExecutionPayloadHeaderEip4844 {
|
||||
parent_hash: self.parent_hash,
|
||||
fee_recipient: self.fee_recipient,
|
||||
state_root: self.state_root,
|
||||
receipts_root: self.receipts_root,
|
||||
logs_bloom: self.logs_bloom.clone(),
|
||||
prev_randao: self.prev_randao,
|
||||
block_number: self.block_number,
|
||||
gas_limit: self.gas_limit,
|
||||
gas_used: self.gas_used,
|
||||
timestamp: self.timestamp,
|
||||
extra_data: self.extra_data.clone(),
|
||||
base_fee_per_gas: self.base_fee_per_gas,
|
||||
// TODO: verify if this is correct
|
||||
excess_data_gas: Uint256::zero(),
|
||||
block_hash: self.block_hash,
|
||||
transactions_root: self.transactions_root,
|
||||
withdrawals_root: self.withdrawals_root,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: EthSpec> From<&'a ExecutionPayloadMerge<T>> for ExecutionPayloadHeaderMerge<T> {
|
||||
fn from(payload: &'a ExecutionPayloadMerge<T>) -> Self {
|
||||
Self {
|
||||
parent_hash: payload.parent_hash,
|
||||
fee_recipient: payload.fee_recipient,
|
||||
state_root: payload.state_root,
|
||||
@@ -61,3 +179,135 @@ impl<'a, T: EthSpec> From<&'a ExecutionPayload<T>> for ExecutionPayloadHeader<T>
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<'a, T: EthSpec> From<&'a ExecutionPayloadCapella<T>> for ExecutionPayloadHeaderCapella<T> {
|
||||
fn from(payload: &'a ExecutionPayloadCapella<T>) -> Self {
|
||||
Self {
|
||||
parent_hash: payload.parent_hash,
|
||||
fee_recipient: payload.fee_recipient,
|
||||
state_root: payload.state_root,
|
||||
receipts_root: payload.receipts_root,
|
||||
logs_bloom: payload.logs_bloom.clone(),
|
||||
prev_randao: payload.prev_randao,
|
||||
block_number: payload.block_number,
|
||||
gas_limit: payload.gas_limit,
|
||||
gas_used: payload.gas_used,
|
||||
timestamp: payload.timestamp,
|
||||
extra_data: payload.extra_data.clone(),
|
||||
base_fee_per_gas: payload.base_fee_per_gas,
|
||||
block_hash: payload.block_hash,
|
||||
transactions_root: payload.transactions.tree_hash_root(),
|
||||
withdrawals_root: payload.withdrawals.tree_hash_root(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: EthSpec> From<&'a ExecutionPayloadEip4844<T>> for ExecutionPayloadHeaderEip4844<T> {
|
||||
fn from(payload: &'a ExecutionPayloadEip4844<T>) -> Self {
|
||||
Self {
|
||||
parent_hash: payload.parent_hash,
|
||||
fee_recipient: payload.fee_recipient,
|
||||
state_root: payload.state_root,
|
||||
receipts_root: payload.receipts_root,
|
||||
logs_bloom: payload.logs_bloom.clone(),
|
||||
prev_randao: payload.prev_randao,
|
||||
block_number: payload.block_number,
|
||||
gas_limit: payload.gas_limit,
|
||||
gas_used: payload.gas_used,
|
||||
timestamp: payload.timestamp,
|
||||
extra_data: payload.extra_data.clone(),
|
||||
base_fee_per_gas: payload.base_fee_per_gas,
|
||||
excess_data_gas: payload.excess_data_gas,
|
||||
block_hash: payload.block_hash,
|
||||
transactions_root: payload.transactions.tree_hash_root(),
|
||||
withdrawals_root: payload.withdrawals.tree_hash_root(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// These impls are required to work around an inelegance in `to_execution_payload_header`.
|
||||
// They only clone headers so they should be relatively cheap.
|
||||
impl<'a, T: EthSpec> From<&'a Self> for ExecutionPayloadHeaderMerge<T> {
|
||||
fn from(payload: &'a Self) -> Self {
|
||||
payload.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: EthSpec> From<&'a Self> for ExecutionPayloadHeaderCapella<T> {
|
||||
fn from(payload: &'a Self) -> Self {
|
||||
payload.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: EthSpec> From<&'a Self> for ExecutionPayloadHeaderEip4844<T> {
|
||||
fn from(payload: &'a Self) -> Self {
|
||||
payload.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: EthSpec> From<ExecutionPayloadRef<'a, T>> for ExecutionPayloadHeader<T> {
|
||||
fn from(payload: ExecutionPayloadRef<'a, T>) -> Self {
|
||||
map_execution_payload_ref_into_execution_payload_header!(
|
||||
&'a _,
|
||||
payload,
|
||||
|inner, cons| cons(inner.into())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: EthSpec> TryFrom<ExecutionPayloadHeader<T>> for ExecutionPayloadHeaderMerge<T> {
|
||||
type Error = BeaconStateError;
|
||||
fn try_from(header: ExecutionPayloadHeader<T>) -> Result<Self, Self::Error> {
|
||||
match header {
|
||||
ExecutionPayloadHeader::Merge(execution_payload_header) => Ok(execution_payload_header),
|
||||
_ => Err(BeaconStateError::IncorrectStateVariant),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<T: EthSpec> TryFrom<ExecutionPayloadHeader<T>> for ExecutionPayloadHeaderCapella<T> {
|
||||
type Error = BeaconStateError;
|
||||
fn try_from(header: ExecutionPayloadHeader<T>) -> Result<Self, Self::Error> {
|
||||
match header {
|
||||
ExecutionPayloadHeader::Capella(execution_payload_header) => {
|
||||
Ok(execution_payload_header)
|
||||
}
|
||||
_ => Err(BeaconStateError::IncorrectStateVariant),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<T: EthSpec> TryFrom<ExecutionPayloadHeader<T>> for ExecutionPayloadHeaderEip4844<T> {
|
||||
type Error = BeaconStateError;
|
||||
fn try_from(header: ExecutionPayloadHeader<T>) -> Result<Self, Self::Error> {
|
||||
match header {
|
||||
ExecutionPayloadHeader::Eip4844(execution_payload_header) => {
|
||||
Ok(execution_payload_header)
|
||||
}
|
||||
_ => Err(BeaconStateError::IncorrectStateVariant),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: EthSpec> ForkVersionDeserialize for ExecutionPayloadHeader<T> {
|
||||
fn deserialize_by_fork<'de, D: serde::Deserializer<'de>>(
|
||||
value: serde_json::value::Value,
|
||||
fork_name: ForkName,
|
||||
) -> Result<Self, D::Error> {
|
||||
let convert_err = |e| {
|
||||
serde::de::Error::custom(format!(
|
||||
"ExecutionPayloadHeader failed to deserialize: {:?}",
|
||||
e
|
||||
))
|
||||
};
|
||||
|
||||
Ok(match fork_name {
|
||||
ForkName::Merge => Self::Merge(serde_json::from_value(value).map_err(convert_err)?),
|
||||
ForkName::Capella => Self::Capella(serde_json::from_value(value).map_err(convert_err)?),
|
||||
ForkName::Eip4844 => Self::Eip4844(serde_json::from_value(value).map_err(convert_err)?),
|
||||
ForkName::Base | ForkName::Altair => {
|
||||
return Err(serde::de::Error::custom(format!(
|
||||
"ExecutionPayloadHeader failed to deserialize: unsupported fork '{}'",
|
||||
fork_name
|
||||
)));
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@ use tree_hash_derive::TreeHash;
|
||||
/// Specifies a fork of the `BeaconChain`, to prevent replay attacks.
|
||||
///
|
||||
/// Spec v0.12.1
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(
|
||||
arbitrary::Arbitrary,
|
||||
Debug,
|
||||
Clone,
|
||||
Copy,
|
||||
|
||||
@@ -47,6 +47,20 @@ impl ForkContext {
|
||||
));
|
||||
}
|
||||
|
||||
if spec.capella_fork_epoch.is_some() {
|
||||
fork_to_digest.push((
|
||||
ForkName::Capella,
|
||||
ChainSpec::compute_fork_digest(spec.capella_fork_version, genesis_validators_root),
|
||||
));
|
||||
}
|
||||
|
||||
if spec.eip4844_fork_epoch.is_some() {
|
||||
fork_to_digest.push((
|
||||
ForkName::Eip4844,
|
||||
ChainSpec::compute_fork_digest(spec.eip4844_fork_version, genesis_validators_root),
|
||||
));
|
||||
}
|
||||
|
||||
let fork_to_digest: HashMap<ForkName, [u8; 4]> = fork_to_digest.into_iter().collect();
|
||||
|
||||
let digest_to_fork = fork_to_digest
|
||||
|
||||
@@ -9,9 +9,18 @@ use tree_hash_derive::TreeHash;
|
||||
/// Specifies a fork of the `BeaconChain`, to prevent replay attacks.
|
||||
///
|
||||
/// Spec v0.12.1
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(
|
||||
Debug, Clone, PartialEq, Default, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom,
|
||||
arbitrary::Arbitrary,
|
||||
Debug,
|
||||
Clone,
|
||||
PartialEq,
|
||||
Default,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
TreeHash,
|
||||
TestRandom,
|
||||
)]
|
||||
pub struct ForkData {
|
||||
#[serde(with = "eth2_serde_utils::bytes_4_hex")]
|
||||
|
||||
@@ -11,11 +11,19 @@ pub enum ForkName {
|
||||
Base,
|
||||
Altair,
|
||||
Merge,
|
||||
Capella,
|
||||
Eip4844,
|
||||
}
|
||||
|
||||
impl ForkName {
|
||||
pub fn list_all() -> Vec<ForkName> {
|
||||
vec![ForkName::Base, ForkName::Altair, ForkName::Merge]
|
||||
vec![
|
||||
ForkName::Base,
|
||||
ForkName::Altair,
|
||||
ForkName::Merge,
|
||||
ForkName::Capella,
|
||||
ForkName::Eip4844,
|
||||
]
|
||||
}
|
||||
|
||||
/// Set the activation slots in the given `ChainSpec` so that the fork named by `self`
|
||||
@@ -26,16 +34,36 @@ impl ForkName {
|
||||
ForkName::Base => {
|
||||
spec.altair_fork_epoch = None;
|
||||
spec.bellatrix_fork_epoch = None;
|
||||
spec.capella_fork_epoch = None;
|
||||
spec.eip4844_fork_epoch = None;
|
||||
spec
|
||||
}
|
||||
ForkName::Altair => {
|
||||
spec.altair_fork_epoch = Some(Epoch::new(0));
|
||||
spec.bellatrix_fork_epoch = None;
|
||||
spec.capella_fork_epoch = None;
|
||||
spec.eip4844_fork_epoch = None;
|
||||
spec
|
||||
}
|
||||
ForkName::Merge => {
|
||||
spec.altair_fork_epoch = Some(Epoch::new(0));
|
||||
spec.bellatrix_fork_epoch = Some(Epoch::new(0));
|
||||
spec.capella_fork_epoch = None;
|
||||
spec.eip4844_fork_epoch = None;
|
||||
spec
|
||||
}
|
||||
ForkName::Capella => {
|
||||
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 = None;
|
||||
spec
|
||||
}
|
||||
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(Epoch::new(0));
|
||||
spec
|
||||
}
|
||||
}
|
||||
@@ -49,6 +77,8 @@ impl ForkName {
|
||||
ForkName::Base => None,
|
||||
ForkName::Altair => Some(ForkName::Base),
|
||||
ForkName::Merge => Some(ForkName::Altair),
|
||||
ForkName::Capella => Some(ForkName::Merge),
|
||||
ForkName::Eip4844 => Some(ForkName::Capella),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +89,9 @@ impl ForkName {
|
||||
match self {
|
||||
ForkName::Base => Some(ForkName::Altair),
|
||||
ForkName::Altair => Some(ForkName::Merge),
|
||||
ForkName::Merge => None,
|
||||
ForkName::Merge => Some(ForkName::Capella),
|
||||
ForkName::Capella => Some(ForkName::Eip4844),
|
||||
ForkName::Eip4844 => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -101,6 +133,14 @@ macro_rules! map_fork_name_with {
|
||||
let (value, extra_data) = $body;
|
||||
($t::Merge(value), extra_data)
|
||||
}
|
||||
ForkName::Capella => {
|
||||
let (value, extra_data) = $body;
|
||||
($t::Capella(value), extra_data)
|
||||
}
|
||||
ForkName::Eip4844 => {
|
||||
let (value, extra_data) = $body;
|
||||
($t::Eip4844(value), extra_data)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -113,6 +153,8 @@ impl FromStr for ForkName {
|
||||
"phase0" | "base" => ForkName::Base,
|
||||
"altair" => ForkName::Altair,
|
||||
"bellatrix" | "merge" => ForkName::Merge,
|
||||
"capella" => ForkName::Capella,
|
||||
"eip4844" => ForkName::Eip4844,
|
||||
_ => return Err(format!("unknown fork name: {}", fork_name)),
|
||||
})
|
||||
}
|
||||
@@ -124,6 +166,8 @@ impl Display for ForkName {
|
||||
ForkName::Base => "phase0".fmt(f),
|
||||
ForkName::Altair => "altair".fmt(f),
|
||||
ForkName::Merge => "bellatrix".fmt(f),
|
||||
ForkName::Capella => "capella".fmt(f),
|
||||
ForkName::Eip4844 => "eip4844".fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -155,7 +199,7 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn previous_and_next_fork_consistent() {
|
||||
assert_eq!(ForkName::Merge.next_fork(), None);
|
||||
assert_eq!(ForkName::Eip4844.next_fork(), None);
|
||||
assert_eq!(ForkName::Base.previous_fork(), None);
|
||||
|
||||
for (prev_fork, fork) in ForkName::list_all().into_iter().tuple_windows() {
|
||||
|
||||
138
consensus/types/src/fork_versioned_response.rs
Normal file
138
consensus/types/src/fork_versioned_response.rs
Normal file
@@ -0,0 +1,138 @@
|
||||
use crate::ForkName;
|
||||
use serde::de::DeserializeOwned;
|
||||
use serde::{Deserialize, Deserializer, Serialize};
|
||||
use serde_json::value::Value;
|
||||
use std::sync::Arc;
|
||||
|
||||
// Deserialize is only implemented for types that implement ForkVersionDeserialize
|
||||
#[derive(Debug, PartialEq, Clone, Serialize)]
|
||||
pub struct ExecutionOptimisticForkVersionedResponse<T> {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub version: Option<ForkName>,
|
||||
pub execution_optimistic: Option<bool>,
|
||||
pub data: T,
|
||||
}
|
||||
|
||||
impl<'de, F> serde::Deserialize<'de> for ExecutionOptimisticForkVersionedResponse<F>
|
||||
where
|
||||
F: ForkVersionDeserialize,
|
||||
{
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
#[derive(Deserialize)]
|
||||
struct Helper {
|
||||
version: Option<ForkName>,
|
||||
execution_optimistic: Option<bool>,
|
||||
data: serde_json::Value,
|
||||
}
|
||||
|
||||
let helper = Helper::deserialize(deserializer)?;
|
||||
let data = match helper.version {
|
||||
Some(fork_name) => F::deserialize_by_fork::<'de, D>(helper.data, fork_name)?,
|
||||
None => serde_json::from_value(helper.data).map_err(serde::de::Error::custom)?,
|
||||
};
|
||||
|
||||
Ok(ExecutionOptimisticForkVersionedResponse {
|
||||
version: helper.version,
|
||||
execution_optimistic: helper.execution_optimistic,
|
||||
data,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ForkVersionDeserialize: Sized + DeserializeOwned {
|
||||
fn deserialize_by_fork<'de, D: Deserializer<'de>>(
|
||||
value: Value,
|
||||
fork_name: ForkName,
|
||||
) -> Result<Self, D::Error>;
|
||||
}
|
||||
|
||||
// Deserialize is only implemented for types that implement ForkVersionDeserialize
|
||||
#[derive(Debug, PartialEq, Clone, Serialize)]
|
||||
pub struct ForkVersionedResponse<T> {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub version: Option<ForkName>,
|
||||
pub data: T,
|
||||
}
|
||||
|
||||
impl<'de, F> serde::Deserialize<'de> for ForkVersionedResponse<F>
|
||||
where
|
||||
F: ForkVersionDeserialize,
|
||||
{
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
#[derive(Deserialize)]
|
||||
struct Helper {
|
||||
version: Option<ForkName>,
|
||||
data: serde_json::Value,
|
||||
}
|
||||
|
||||
let helper = Helper::deserialize(deserializer)?;
|
||||
let data = match helper.version {
|
||||
Some(fork_name) => F::deserialize_by_fork::<'de, D>(helper.data, fork_name)?,
|
||||
None => serde_json::from_value(helper.data).map_err(serde::de::Error::custom)?,
|
||||
};
|
||||
|
||||
Ok(ForkVersionedResponse {
|
||||
version: helper.version,
|
||||
data,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: ForkVersionDeserialize> ForkVersionDeserialize for Arc<F> {
|
||||
fn deserialize_by_fork<'de, D: Deserializer<'de>>(
|
||||
value: Value,
|
||||
fork_name: ForkName,
|
||||
) -> Result<Self, D::Error> {
|
||||
Ok(Arc::new(F::deserialize_by_fork::<'de, D>(
|
||||
value, fork_name,
|
||||
)?))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod fork_version_response_tests {
|
||||
use crate::{
|
||||
ExecutionPayload, ExecutionPayloadMerge, ForkName, ForkVersionedResponse, MainnetEthSpec,
|
||||
};
|
||||
use serde_json::json;
|
||||
|
||||
#[test]
|
||||
fn fork_versioned_response_deserialize_correct_fork() {
|
||||
type E = MainnetEthSpec;
|
||||
|
||||
let response_json =
|
||||
serde_json::to_string(&json!(ForkVersionedResponse::<ExecutionPayload<E>> {
|
||||
version: Some(ForkName::Merge),
|
||||
data: ExecutionPayload::Merge(ExecutionPayloadMerge::default()),
|
||||
}))
|
||||
.unwrap();
|
||||
|
||||
let result: Result<ForkVersionedResponse<ExecutionPayload<E>>, _> =
|
||||
serde_json::from_str(&response_json);
|
||||
|
||||
assert!(result.is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fork_versioned_response_deserialize_incorrect_fork() {
|
||||
type E = MainnetEthSpec;
|
||||
|
||||
let response_json =
|
||||
serde_json::to_string(&json!(ForkVersionedResponse::<ExecutionPayload<E>> {
|
||||
version: Some(ForkName::Capella),
|
||||
data: ExecutionPayload::Merge(ExecutionPayloadMerge::default()),
|
||||
}))
|
||||
.unwrap();
|
||||
|
||||
let result: Result<ForkVersionedResponse<ExecutionPayload<E>>, _> =
|
||||
serde_json::from_str(&response_json);
|
||||
|
||||
assert!(result.is_err());
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
/// Note: this object does not actually exist in the spec.
|
||||
///
|
||||
/// We use it for managing attestations that have not been aggregated.
|
||||
use super::{AttestationData, Signature};
|
||||
use serde_derive::Serialize;
|
||||
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(Debug, Clone, PartialEq, Serialize)]
|
||||
pub struct FreeAttestation {
|
||||
pub data: AttestationData,
|
||||
pub signature: Signature,
|
||||
#[serde(with = "eth2_serde_utils::quoted_u64")]
|
||||
pub validator_index: u64,
|
||||
}
|
||||
@@ -14,7 +14,7 @@ pub const GRAFFITI_BYTES_LEN: usize = 32;
|
||||
/// The 32-byte `graffiti` field on a beacon block.
|
||||
#[derive(Default, Debug, PartialEq, Hash, Clone, Copy, Serialize, Deserialize)]
|
||||
#[serde(transparent)]
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(arbitrary::Arbitrary)]
|
||||
pub struct Graffiti(#[serde(with = "serde_graffiti")] pub [u8; GRAFFITI_BYTES_LEN]);
|
||||
|
||||
impl Graffiti {
|
||||
|
||||
@@ -10,8 +10,19 @@ use tree_hash_derive::TreeHash;
|
||||
/// Historical block and state roots.
|
||||
///
|
||||
/// Spec v0.12.1
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)]
|
||||
#[derive(
|
||||
Debug,
|
||||
Clone,
|
||||
PartialEq,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
TreeHash,
|
||||
TestRandom,
|
||||
arbitrary::Arbitrary,
|
||||
)]
|
||||
#[arbitrary(bound = "T: EthSpec")]
|
||||
pub struct HistoricalBatch<T: EthSpec> {
|
||||
pub block_roots: FixedVector<Hash256, T::SlotsPerHistoricalRoot>,
|
||||
pub state_roots: FixedVector<Hash256, T::SlotsPerHistoricalRoot>,
|
||||
|
||||
89
consensus/types/src/historical_summary.rs
Normal file
89
consensus/types/src/historical_summary.rs
Normal file
@@ -0,0 +1,89 @@
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::Unsigned;
|
||||
use crate::{BeaconState, EthSpec, Hash256};
|
||||
use cached_tree_hash::Error;
|
||||
use cached_tree_hash::{int_log, CacheArena, CachedTreeHash, TreeHashCache};
|
||||
use compare_fields_derive::CompareFields;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use ssz_types::VariableList;
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash::{mix_in_length, TreeHash, BYTES_PER_CHUNK};
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
/// `HistoricalSummary` matches the components of the phase0 `HistoricalBatch`
|
||||
/// making the two hash_tree_root-compatible. This struct is introduced into the beacon state
|
||||
/// in the Capella hard fork.
|
||||
///
|
||||
/// https://github.com/ethereum/consensus-specs/blob/dev/specs/capella/beacon-chain.md#historicalsummary
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
TreeHash,
|
||||
TestRandom,
|
||||
CompareFields,
|
||||
Clone,
|
||||
Copy,
|
||||
Default,
|
||||
arbitrary::Arbitrary,
|
||||
)]
|
||||
pub struct HistoricalSummary {
|
||||
block_summary_root: Hash256,
|
||||
state_summary_root: Hash256,
|
||||
}
|
||||
|
||||
impl HistoricalSummary {
|
||||
pub fn new<T: EthSpec>(state: &BeaconState<T>) -> Self {
|
||||
Self {
|
||||
block_summary_root: state.block_roots().tree_hash_root(),
|
||||
state_summary_root: state.state_roots().tree_hash_root(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper type allowing the implementation of `CachedTreeHash`.
|
||||
#[derive(Debug)]
|
||||
pub struct HistoricalSummaryCache<'a, N: Unsigned> {
|
||||
pub inner: &'a VariableList<HistoricalSummary, N>,
|
||||
}
|
||||
|
||||
impl<'a, N: Unsigned> HistoricalSummaryCache<'a, N> {
|
||||
pub fn new(inner: &'a VariableList<HistoricalSummary, N>) -> Self {
|
||||
Self { inner }
|
||||
}
|
||||
|
||||
#[allow(clippy::len_without_is_empty)]
|
||||
pub fn len(&self) -> usize {
|
||||
self.inner.len()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, N: Unsigned> CachedTreeHash<TreeHashCache> for HistoricalSummaryCache<'a, N> {
|
||||
fn new_tree_hash_cache(&self, arena: &mut CacheArena) -> TreeHashCache {
|
||||
TreeHashCache::new(arena, int_log(N::to_usize()), self.len())
|
||||
}
|
||||
|
||||
fn recalculate_tree_hash_root(
|
||||
&self,
|
||||
arena: &mut CacheArena,
|
||||
cache: &mut TreeHashCache,
|
||||
) -> Result<Hash256, Error> {
|
||||
Ok(mix_in_length(
|
||||
&cache.recalculate_merkle_root(arena, leaf_iter(self.inner))?,
|
||||
self.len(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn leaf_iter(
|
||||
values: &[HistoricalSummary],
|
||||
) -> impl Iterator<Item = [u8; BYTES_PER_CHUNK]> + ExactSizeIterator + '_ {
|
||||
values
|
||||
.iter()
|
||||
.map(|value| value.tree_hash_root())
|
||||
.map(Hash256::to_fixed_bytes)
|
||||
}
|
||||
@@ -12,12 +12,21 @@ use tree_hash_derive::TreeHash;
|
||||
/// To be included in an `AttesterSlashing`.
|
||||
///
|
||||
/// Spec v0.12.1
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(
|
||||
Derivative, Debug, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom,
|
||||
Derivative,
|
||||
Debug,
|
||||
Clone,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
TreeHash,
|
||||
TestRandom,
|
||||
arbitrary::Arbitrary,
|
||||
)]
|
||||
#[derivative(PartialEq, Eq)] // to satisfy Clippy's lint about `Hash`
|
||||
#[serde(bound = "T: EthSpec")]
|
||||
#[arbitrary(bound = "T: EthSpec")]
|
||||
pub struct IndexedAttestation<T: EthSpec> {
|
||||
/// Lists validator registry indices, not committee indices.
|
||||
#[serde(with = "quoted_variable_list_u64")]
|
||||
|
||||
45
consensus/types/src/kzg_commitment.rs
Normal file
45
consensus/types/src/kzg_commitment.rs
Normal file
@@ -0,0 +1,45 @@
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::*;
|
||||
use derivative::Derivative;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use std::fmt;
|
||||
use std::fmt::{Display, Formatter};
|
||||
use tree_hash::{PackedEncoding, TreeHash};
|
||||
|
||||
#[derive(
|
||||
Derivative, Debug, Clone, Encode, Decode, Serialize, Deserialize, arbitrary::Arbitrary,
|
||||
)]
|
||||
#[derivative(PartialEq, Eq, Hash)]
|
||||
#[ssz(struct_behaviour = "transparent")]
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
impl TreeHash for KzgCommitment {
|
||||
fn tree_hash_type() -> tree_hash::TreeHashType {
|
||||
<[u8; 48] as TreeHash>::tree_hash_type()
|
||||
}
|
||||
|
||||
fn tree_hash_packed_encoding(&self) -> PackedEncoding {
|
||||
self.0.tree_hash_packed_encoding()
|
||||
}
|
||||
|
||||
fn tree_hash_packing_factor() -> usize {
|
||||
<[u8; 48] as TreeHash>::tree_hash_packing_factor()
|
||||
}
|
||||
|
||||
fn tree_hash_root(&self) -> tree_hash::Hash256 {
|
||||
self.0.tree_hash_root()
|
||||
}
|
||||
}
|
||||
|
||||
impl TestRandom for KzgCommitment {
|
||||
fn random_for_test(rng: &mut impl rand::RngCore) -> Self {
|
||||
KzgCommitment(<[u8; 48] as TestRandom>::random_for_test(rng))
|
||||
}
|
||||
}
|
||||
74
consensus/types/src/kzg_proof.rs
Normal file
74
consensus/types/src/kzg_proof.rs
Normal file
@@ -0,0 +1,74 @@
|
||||
use crate::test_utils::{RngCore, TestRandom};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_big_array::BigArray;
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use std::fmt;
|
||||
use tree_hash::{PackedEncoding, TreeHash};
|
||||
|
||||
const KZG_PROOF_BYTES_LEN: usize = 48;
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Hash,
|
||||
Clone,
|
||||
Copy,
|
||||
Encode,
|
||||
Decode,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
arbitrary::Arbitrary,
|
||||
)]
|
||||
#[serde(transparent)]
|
||||
#[ssz(struct_behaviour = "transparent")]
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for KzgProof {
|
||||
fn default() -> Self {
|
||||
KzgProof([0; 48])
|
||||
}
|
||||
}
|
||||
|
||||
impl From<[u8; KZG_PROOF_BYTES_LEN]> for KzgProof {
|
||||
fn from(bytes: [u8; KZG_PROOF_BYTES_LEN]) -> Self {
|
||||
Self(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<[u8; KZG_PROOF_BYTES_LEN]> for KzgProof {
|
||||
fn into(self) -> [u8; KZG_PROOF_BYTES_LEN] {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl TreeHash for KzgProof {
|
||||
fn tree_hash_type() -> tree_hash::TreeHashType {
|
||||
<[u8; KZG_PROOF_BYTES_LEN]>::tree_hash_type()
|
||||
}
|
||||
|
||||
fn tree_hash_packed_encoding(&self) -> PackedEncoding {
|
||||
self.0.tree_hash_packed_encoding()
|
||||
}
|
||||
|
||||
fn tree_hash_packing_factor() -> usize {
|
||||
<[u8; KZG_PROOF_BYTES_LEN]>::tree_hash_packing_factor()
|
||||
}
|
||||
|
||||
fn tree_hash_root(&self) -> tree_hash::Hash256 {
|
||||
self.0.tree_hash_root()
|
||||
}
|
||||
}
|
||||
|
||||
impl TestRandom for KzgProof {
|
||||
fn random_for_test(rng: &mut impl RngCore) -> Self {
|
||||
let mut bytes = [0; KZG_PROOF_BYTES_LEN];
|
||||
rng.fill_bytes(&mut bytes);
|
||||
Self(bytes)
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
//! Ethereum 2.0 types
|
||||
|
||||
// Required for big type-level numbers
|
||||
#![recursion_limit = "128"]
|
||||
// Clippy lint set up
|
||||
@@ -28,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;
|
||||
@@ -46,9 +46,10 @@ pub mod execution_payload_header;
|
||||
pub mod fork;
|
||||
pub mod fork_data;
|
||||
pub mod fork_name;
|
||||
pub mod free_attestation;
|
||||
pub mod fork_versioned_response;
|
||||
pub mod graffiti;
|
||||
pub mod historical_batch;
|
||||
pub mod historical_summary;
|
||||
pub mod indexed_attestation;
|
||||
pub mod light_client_bootstrap;
|
||||
pub mod light_client_finality_update;
|
||||
@@ -63,6 +64,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;
|
||||
@@ -92,11 +94,16 @@ pub mod sync_selection_proof;
|
||||
pub mod sync_subnet_id;
|
||||
mod tree_hash_impls;
|
||||
pub mod validator_registration_data;
|
||||
pub mod withdrawal;
|
||||
|
||||
pub mod slot_data;
|
||||
#[cfg(feature = "sqlite")]
|
||||
pub mod sqlite;
|
||||
|
||||
pub mod blobs_sidecar;
|
||||
pub mod kzg_commitment;
|
||||
pub mod kzg_proof;
|
||||
|
||||
use ethereum_types::{H160, H256};
|
||||
|
||||
pub use crate::aggregate_and_proof::AggregateAndProof;
|
||||
@@ -105,20 +112,22 @@ pub use crate::attestation_data::AttestationData;
|
||||
pub use crate::attestation_duty::AttestationDuty;
|
||||
pub use crate::attester_slashing::AttesterSlashing;
|
||||
pub use crate::beacon_block::{
|
||||
BeaconBlock, BeaconBlockAltair, BeaconBlockBase, BeaconBlockMerge, BeaconBlockRef,
|
||||
BeaconBlockRefMut, BlindedBeaconBlock,
|
||||
BeaconBlock, BeaconBlockAltair, BeaconBlockBase, BeaconBlockCapella, BeaconBlockEip4844,
|
||||
BeaconBlockMerge, BeaconBlockRef, BeaconBlockRefMut, BlindedBeaconBlock, EmptyBlock,
|
||||
};
|
||||
pub use crate::beacon_block_body::{
|
||||
BeaconBlockBody, BeaconBlockBodyAltair, BeaconBlockBodyBase, BeaconBlockBodyMerge,
|
||||
BeaconBlockBodyRef, BeaconBlockBodyRefMut,
|
||||
BeaconBlockBody, BeaconBlockBodyAltair, BeaconBlockBodyBase, BeaconBlockBodyCapella,
|
||||
BeaconBlockBodyEip4844, BeaconBlockBodyMerge, BeaconBlockBodyRef, BeaconBlockBodyRefMut,
|
||||
};
|
||||
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::{
|
||||
ConfigAndPreset, ConfigAndPresetAltair, ConfigAndPresetBellatrix,
|
||||
ConfigAndPreset, ConfigAndPresetBellatrix, ConfigAndPresetCapella,
|
||||
};
|
||||
pub use crate::contribution_and_proof::ContributionAndProof;
|
||||
pub use crate::deposit::{Deposit, DEPOSIT_TREE_DEPTH};
|
||||
@@ -130,23 +139,37 @@ pub use crate::eth1_data::Eth1Data;
|
||||
pub use crate::eth_spec::EthSpecId;
|
||||
pub use crate::execution_block_hash::ExecutionBlockHash;
|
||||
pub use crate::execution_block_header::ExecutionBlockHeader;
|
||||
pub use crate::execution_payload::{ExecutionPayload, Transaction, Transactions};
|
||||
pub use crate::execution_payload_header::ExecutionPayloadHeader;
|
||||
pub use crate::execution_payload::{
|
||||
ExecutionPayload, ExecutionPayloadCapella, ExecutionPayloadEip4844, ExecutionPayloadMerge,
|
||||
ExecutionPayloadRef, Transaction, Transactions, Withdrawals,
|
||||
};
|
||||
pub use crate::execution_payload_header::{
|
||||
ExecutionPayloadHeader, ExecutionPayloadHeaderCapella, ExecutionPayloadHeaderEip4844,
|
||||
ExecutionPayloadHeaderMerge, ExecutionPayloadHeaderRef, ExecutionPayloadHeaderRefMut,
|
||||
};
|
||||
pub use crate::fork::Fork;
|
||||
pub use crate::fork_context::ForkContext;
|
||||
pub use crate::fork_data::ForkData;
|
||||
pub use crate::fork_name::{ForkName, InconsistentFork};
|
||||
pub use crate::free_attestation::FreeAttestation;
|
||||
pub use crate::fork_versioned_response::{
|
||||
ExecutionOptimisticForkVersionedResponse, ForkVersionDeserialize, ForkVersionedResponse,
|
||||
};
|
||||
pub use crate::graffiti::{Graffiti, GRAFFITI_BYTES_LEN};
|
||||
pub use crate::historical_batch::HistoricalBatch;
|
||||
pub use crate::indexed_attestation::IndexedAttestation;
|
||||
pub use crate::kzg_commitment::KzgCommitment;
|
||||
pub use crate::kzg_proof::KzgProof;
|
||||
pub use crate::light_client_finality_update::LightClientFinalityUpdate;
|
||||
pub use crate::light_client_optimistic_update::LightClientOptimisticUpdate;
|
||||
pub use crate::participation_flags::ParticipationFlags;
|
||||
pub use crate::participation_list::ParticipationList;
|
||||
pub use crate::payload::{BlindedPayload, BlockType, ExecPayload, FullPayload};
|
||||
pub use crate::payload::{
|
||||
AbstractExecPayload, BlindedPayload, BlindedPayloadCapella, BlindedPayloadEip4844,
|
||||
BlindedPayloadMerge, BlindedPayloadRef, BlockType, ExecPayload, FullPayload,
|
||||
FullPayloadCapella, FullPayloadEip4844, FullPayloadMerge, FullPayloadRef, OwnedExecPayload,
|
||||
};
|
||||
pub use crate::pending_attestation::PendingAttestation;
|
||||
pub use crate::preset::{AltairPreset, BasePreset, BellatrixPreset};
|
||||
pub use crate::preset::{AltairPreset, BasePreset, BellatrixPreset, CapellaPreset};
|
||||
pub use crate::proposer_preparation_data::ProposerPreparationData;
|
||||
pub use crate::proposer_slashing::ProposerSlashing;
|
||||
pub use crate::relative_epoch::{Error as RelativeEpochError, RelativeEpoch};
|
||||
@@ -154,10 +177,12 @@ pub use crate::selection_proof::SelectionProof;
|
||||
pub use crate::shuffling_id::AttestationShufflingId;
|
||||
pub use crate::signed_aggregate_and_proof::SignedAggregateAndProof;
|
||||
pub use crate::signed_beacon_block::{
|
||||
SignedBeaconBlock, SignedBeaconBlockAltair, SignedBeaconBlockBase, SignedBeaconBlockHash,
|
||||
SignedBeaconBlockMerge, SignedBlindedBeaconBlock,
|
||||
SignedBeaconBlock, SignedBeaconBlockAltair, SignedBeaconBlockBase, SignedBeaconBlockCapella,
|
||||
SignedBeaconBlockEip4844, SignedBeaconBlockHash, SignedBeaconBlockMerge,
|
||||
SignedBlindedBeaconBlock,
|
||||
};
|
||||
pub use crate::signed_beacon_block_header::SignedBeaconBlockHeader;
|
||||
pub use crate::signed_bls_to_execution_change::SignedBlsToExecutionChange;
|
||||
pub use crate::signed_contribution_and_proof::SignedContributionAndProof;
|
||||
pub use crate::signed_voluntary_exit::SignedVoluntaryExit;
|
||||
pub use crate::signing_data::{SignedRoot, SigningData};
|
||||
@@ -176,13 +201,18 @@ pub use crate::validator::Validator;
|
||||
pub use crate::validator_registration_data::*;
|
||||
pub use crate::validator_subscription::ValidatorSubscription;
|
||||
pub use crate::voluntary_exit::VoluntaryExit;
|
||||
pub use crate::withdrawal::Withdrawal;
|
||||
pub use crate::withdrawal_credentials::WithdrawalCredentials;
|
||||
use serde_big_array::BigArray;
|
||||
|
||||
pub type CommitteeIndex = u64;
|
||||
pub type Hash256 = H256;
|
||||
pub type Uint256 = ethereum_types::U256;
|
||||
pub type Address = H160;
|
||||
pub type ForkVersion = [u8; 4];
|
||||
pub type BLSFieldElement = Uint256;
|
||||
pub type Blob<T> = FixedVector<BLSFieldElement, <T as EthSpec>::FieldElementsPerBlob>;
|
||||
pub type VersionedHash = Hash256;
|
||||
pub type Hash64 = ethereum_types::H64;
|
||||
|
||||
pub use bls::{
|
||||
|
||||
@@ -8,9 +8,19 @@ use tree_hash::TreeHash;
|
||||
|
||||
/// A LightClientBootstrap is the initializer we send over to lightclient nodes
|
||||
/// that are trying to generate their basic storage when booting up.
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode, TestRandom)]
|
||||
#[derive(
|
||||
Debug,
|
||||
Clone,
|
||||
PartialEq,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
TestRandom,
|
||||
arbitrary::Arbitrary,
|
||||
)]
|
||||
#[serde(bound = "T: EthSpec")]
|
||||
#[arbitrary(bound = "T: EthSpec")]
|
||||
pub struct LightClientBootstrap<T: EthSpec> {
|
||||
/// Requested beacon block header.
|
||||
pub header: BeaconBlockHeader,
|
||||
|
||||
@@ -10,9 +10,19 @@ use tree_hash::TreeHash;
|
||||
|
||||
/// A LightClientFinalityUpdate is the update lightclient request or received by a gossip that
|
||||
/// signal a new finalized beacon block header for the light client sync protocol.
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode, TestRandom)]
|
||||
#[derive(
|
||||
Debug,
|
||||
Clone,
|
||||
PartialEq,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
TestRandom,
|
||||
arbitrary::Arbitrary,
|
||||
)]
|
||||
#[serde(bound = "T: EthSpec")]
|
||||
#[arbitrary(bound = "T: EthSpec")]
|
||||
pub struct LightClientFinalityUpdate<T: EthSpec> {
|
||||
/// The last `BeaconBlockHeader` from the last attested block by the sync committee.
|
||||
pub attested_header: BeaconBlockHeader,
|
||||
|
||||
@@ -9,9 +9,19 @@ use tree_hash::TreeHash;
|
||||
|
||||
/// A LightClientOptimisticUpdate is the update we send on each slot,
|
||||
/// it is based off the current unfinalized epoch is verified only against BLS signature.
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode, TestRandom)]
|
||||
#[derive(
|
||||
Debug,
|
||||
Clone,
|
||||
PartialEq,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
TestRandom,
|
||||
arbitrary::Arbitrary,
|
||||
)]
|
||||
#[serde(bound = "T: EthSpec")]
|
||||
#[arbitrary(bound = "T: EthSpec")]
|
||||
pub struct LightClientOptimisticUpdate<T: EthSpec> {
|
||||
/// The last `BeaconBlockHeader` from the last attested block by the sync committee.
|
||||
pub attested_header: BeaconBlockHeader,
|
||||
|
||||
@@ -52,9 +52,19 @@ impl From<ArithError> for Error {
|
||||
/// A LightClientUpdate is the update we request solely to either complete the bootstraping process,
|
||||
/// or to sync up to the last committee period, we need to have one ready for each ALTAIR period
|
||||
/// we go over, note: there is no need to keep all of the updates from [ALTAIR_PERIOD, CURRENT_PERIOD].
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode, TestRandom)]
|
||||
#[derive(
|
||||
Debug,
|
||||
Clone,
|
||||
PartialEq,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
TestRandom,
|
||||
arbitrary::Arbitrary,
|
||||
)]
|
||||
#[serde(bound = "T: EthSpec")]
|
||||
#[arbitrary(bound = "T: EthSpec")]
|
||||
pub struct LightClientUpdate<T: EthSpec> {
|
||||
/// The last `BeaconBlockHeader` from the last attested block by the sync committee.
|
||||
pub attested_header: BeaconBlockHeader,
|
||||
|
||||
@@ -7,7 +7,7 @@ use tree_hash::{PackedEncoding, TreeHash, TreeHashType};
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy, PartialEq, Deserialize, Serialize, TestRandom)]
|
||||
#[serde(transparent)]
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(arbitrary::Arbitrary)]
|
||||
pub struct ParticipationFlags {
|
||||
#[serde(with = "eth2_serde_utils::quoted_u8")]
|
||||
bits: u8,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,7 +9,19 @@ use tree_hash_derive::TreeHash;
|
||||
/// An attestation that has been included in the state but not yet fully processed.
|
||||
///
|
||||
/// Spec v0.12.1
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)]
|
||||
#[derive(
|
||||
Debug,
|
||||
Clone,
|
||||
PartialEq,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
TreeHash,
|
||||
TestRandom,
|
||||
arbitrary::Arbitrary,
|
||||
)]
|
||||
#[arbitrary(bound = "T: EthSpec")]
|
||||
pub struct PendingAttestation<T: EthSpec> {
|
||||
pub aggregation_bits: BitList<T::MaxValidatorsPerCommittee>,
|
||||
pub data: AttestationData,
|
||||
@@ -19,18 +31,6 @@ pub struct PendingAttestation<T: EthSpec> {
|
||||
pub proposer_index: u64,
|
||||
}
|
||||
|
||||
#[cfg(feature = "arbitrary-fuzz")]
|
||||
impl<T: EthSpec> arbitrary::Arbitrary<'_> for PendingAttestation<T> {
|
||||
fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
|
||||
Ok(Self {
|
||||
aggregation_bits: <BitList<T::MaxValidatorsPerCommittee>>::arbitrary(u)?,
|
||||
data: AttestationData::arbitrary(u)?,
|
||||
inclusion_delay: u64::arbitrary(u)?,
|
||||
proposer_index: u64::arbitrary(u)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
@@ -184,6 +184,27 @@ impl BellatrixPreset {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "UPPERCASE")]
|
||||
pub struct CapellaPreset {
|
||||
#[serde(with = "eth2_serde_utils::quoted_u64")]
|
||||
pub max_bls_to_execution_changes: u64,
|
||||
#[serde(with = "eth2_serde_utils::quoted_u64")]
|
||||
pub max_withdrawals_per_payload: u64,
|
||||
#[serde(with = "eth2_serde_utils::quoted_u64")]
|
||||
pub max_validators_per_withdrawals_sweep: u64,
|
||||
}
|
||||
|
||||
impl CapellaPreset {
|
||||
pub fn from_chain_spec<T: EthSpec>(spec: &ChainSpec) -> Self {
|
||||
Self {
|
||||
max_bls_to_execution_changes: T::max_bls_to_execution_changes() as u64,
|
||||
max_withdrawals_per_payload: T::max_withdrawals_per_payload() as u64,
|
||||
max_validators_per_withdrawals_sweep: spec.max_validators_per_withdrawals_sweep,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
@@ -219,6 +240,9 @@ mod test {
|
||||
|
||||
let bellatrix: BellatrixPreset = preset_from_file(&preset_name, "bellatrix.yaml");
|
||||
assert_eq!(bellatrix, BellatrixPreset::from_chain_spec::<E>(&spec));
|
||||
|
||||
let capella: CapellaPreset = preset_from_file(&preset_name, "capella.yaml");
|
||||
assert_eq!(capella, CapellaPreset::from_chain_spec::<E>(&spec));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -9,9 +9,19 @@ use tree_hash_derive::TreeHash;
|
||||
/// Two conflicting proposals from the same proposer (validator).
|
||||
///
|
||||
/// Spec v0.12.1
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(
|
||||
Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom,
|
||||
arbitrary::Arbitrary,
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
Hash,
|
||||
Clone,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
TreeHash,
|
||||
TestRandom,
|
||||
)]
|
||||
pub struct ProposerSlashing {
|
||||
pub signed_header_1: SignedBeaconBlockHeader,
|
||||
|
||||
@@ -14,15 +14,11 @@ impl From<ArithError> for Error {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "arbitrary-fuzz")]
|
||||
use arbitrary::Arbitrary;
|
||||
|
||||
/// Defines the epochs relative to some epoch. Most useful when referring to the committees prior
|
||||
/// to and following some epoch.
|
||||
///
|
||||
/// Spec v0.12.1
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(Arbitrary))]
|
||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||
#[derive(Debug, PartialEq, Clone, Copy, arbitrary::Arbitrary)]
|
||||
pub enum RelativeEpoch {
|
||||
/// The prior epoch.
|
||||
Previous,
|
||||
|
||||
@@ -7,8 +7,7 @@ use ssz::Encode;
|
||||
use std::cmp;
|
||||
use std::convert::TryInto;
|
||||
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(PartialEq, Debug, Clone)]
|
||||
#[derive(arbitrary::Arbitrary, PartialEq, Debug, Clone)]
|
||||
pub struct SelectionProof(Signature);
|
||||
|
||||
impl SelectionProof {
|
||||
|
||||
@@ -12,9 +12,20 @@ use tree_hash_derive::TreeHash;
|
||||
/// gossipsub topic.
|
||||
///
|
||||
/// Spec v0.12.1
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode, TestRandom, TreeHash)]
|
||||
#[derive(
|
||||
Debug,
|
||||
Clone,
|
||||
PartialEq,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
TestRandom,
|
||||
TreeHash,
|
||||
arbitrary::Arbitrary,
|
||||
)]
|
||||
#[serde(bound = "T: EthSpec")]
|
||||
#[arbitrary(bound = "T: EthSpec")]
|
||||
pub struct SignedAggregateAndProof<T: EthSpec> {
|
||||
/// The `AggregateAndProof` that was signed.
|
||||
pub message: AggregateAndProof<T>,
|
||||
|
||||
@@ -8,8 +8,7 @@ use superstruct::superstruct;
|
||||
use tree_hash::TreeHash;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(PartialEq, Eq, Hash, Clone, Copy)]
|
||||
#[derive(arbitrary::Arbitrary, PartialEq, Eq, Hash, Clone, Copy)]
|
||||
pub struct SignedBeaconBlockHash(Hash256);
|
||||
|
||||
impl fmt::Debug for SignedBeaconBlockHash {
|
||||
@@ -38,7 +37,7 @@ impl From<SignedBeaconBlockHash> for Hash256 {
|
||||
|
||||
/// A `BeaconBlock` and a signature from its proposer.
|
||||
#[superstruct(
|
||||
variants(Base, Altair, Merge),
|
||||
variants(Base, Altair, Merge, Capella, Eip4844),
|
||||
variant_attributes(
|
||||
derive(
|
||||
Debug,
|
||||
@@ -49,35 +48,42 @@ impl From<SignedBeaconBlockHash> for Hash256 {
|
||||
Decode,
|
||||
TreeHash,
|
||||
Derivative,
|
||||
arbitrary::Arbitrary
|
||||
),
|
||||
derivative(PartialEq, Hash(bound = "E: EthSpec")),
|
||||
cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary)),
|
||||
serde(bound = "E: EthSpec, Payload: ExecPayload<E>"),
|
||||
serde(bound = "E: EthSpec, Payload: AbstractExecPayload<E>"),
|
||||
arbitrary(bound = "E: EthSpec, Payload: AbstractExecPayload<E>"),
|
||||
),
|
||||
map_into(BeaconBlock),
|
||||
map_ref_into(BeaconBlockRef),
|
||||
map_ref_mut_into(BeaconBlockRefMut)
|
||||
)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Encode, TreeHash, Derivative)]
|
||||
#[derive(
|
||||
Debug, Clone, Serialize, Deserialize, Encode, TreeHash, Derivative, arbitrary::Arbitrary,
|
||||
)]
|
||||
#[derivative(PartialEq, Hash(bound = "E: EthSpec"))]
|
||||
#[serde(untagged)]
|
||||
#[serde(bound = "E: EthSpec, Payload: ExecPayload<E>")]
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[serde(bound = "E: EthSpec, Payload: AbstractExecPayload<E>")]
|
||||
#[arbitrary(bound = "E: EthSpec, Payload: AbstractExecPayload<E>")]
|
||||
#[tree_hash(enum_behaviour = "transparent")]
|
||||
#[ssz(enum_behaviour = "transparent")]
|
||||
pub struct SignedBeaconBlock<E: EthSpec, Payload: ExecPayload<E> = FullPayload<E>> {
|
||||
pub struct SignedBeaconBlock<E: EthSpec, Payload: AbstractExecPayload<E> = FullPayload<E>> {
|
||||
#[superstruct(only(Base), partial_getter(rename = "message_base"))]
|
||||
pub message: BeaconBlockBase<E, Payload>,
|
||||
#[superstruct(only(Altair), partial_getter(rename = "message_altair"))]
|
||||
pub message: BeaconBlockAltair<E, Payload>,
|
||||
#[superstruct(only(Merge), partial_getter(rename = "message_merge"))]
|
||||
pub message: BeaconBlockMerge<E, Payload>,
|
||||
#[superstruct(only(Capella), partial_getter(rename = "message_capella"))]
|
||||
pub message: BeaconBlockCapella<E, Payload>,
|
||||
#[superstruct(only(Eip4844), partial_getter(rename = "message_eip4844"))]
|
||||
pub message: BeaconBlockEip4844<E, Payload>,
|
||||
pub signature: Signature,
|
||||
}
|
||||
|
||||
pub type SignedBlindedBeaconBlock<E> = SignedBeaconBlock<E, BlindedPayload<E>>;
|
||||
|
||||
impl<E: EthSpec, Payload: ExecPayload<E>> SignedBeaconBlock<E, Payload> {
|
||||
impl<E: EthSpec, Payload: AbstractExecPayload<E>> SignedBeaconBlock<E, Payload> {
|
||||
/// Returns the name of the fork pertaining to `self`.
|
||||
///
|
||||
/// Will return an `Err` if `self` has been instantiated to a variant conflicting with the fork
|
||||
@@ -129,6 +135,12 @@ impl<E: EthSpec, Payload: ExecPayload<E>> SignedBeaconBlock<E, Payload> {
|
||||
BeaconBlock::Merge(message) => {
|
||||
SignedBeaconBlock::Merge(SignedBeaconBlockMerge { message, signature })
|
||||
}
|
||||
BeaconBlock::Capella(message) => {
|
||||
SignedBeaconBlock::Capella(SignedBeaconBlockCapella { message, signature })
|
||||
}
|
||||
BeaconBlock::Eip4844(message) => {
|
||||
SignedBeaconBlock::Eip4844(SignedBeaconBlockEip4844 { message, signature })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -258,7 +270,7 @@ impl<E: EthSpec> From<SignedBeaconBlockAltair<E, BlindedPayload<E>>>
|
||||
impl<E: EthSpec> SignedBeaconBlockMerge<E, BlindedPayload<E>> {
|
||||
pub fn into_full_block(
|
||||
self,
|
||||
execution_payload: ExecutionPayload<E>,
|
||||
execution_payload: ExecutionPayloadMerge<E>,
|
||||
) -> SignedBeaconBlockMerge<E, FullPayload<E>> {
|
||||
let SignedBeaconBlockMerge {
|
||||
message:
|
||||
@@ -278,7 +290,7 @@ impl<E: EthSpec> SignedBeaconBlockMerge<E, BlindedPayload<E>> {
|
||||
deposits,
|
||||
voluntary_exits,
|
||||
sync_aggregate,
|
||||
execution_payload: BlindedPayload { .. },
|
||||
execution_payload: BlindedPayloadMerge { .. },
|
||||
},
|
||||
},
|
||||
signature,
|
||||
@@ -299,7 +311,117 @@ impl<E: EthSpec> SignedBeaconBlockMerge<E, BlindedPayload<E>> {
|
||||
deposits,
|
||||
voluntary_exits,
|
||||
sync_aggregate,
|
||||
execution_payload: FullPayload { execution_payload },
|
||||
execution_payload: FullPayloadMerge { execution_payload },
|
||||
},
|
||||
},
|
||||
signature,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EthSpec> SignedBeaconBlockCapella<E, BlindedPayload<E>> {
|
||||
pub fn into_full_block(
|
||||
self,
|
||||
execution_payload: ExecutionPayloadCapella<E>,
|
||||
) -> SignedBeaconBlockCapella<E, FullPayload<E>> {
|
||||
let SignedBeaconBlockCapella {
|
||||
message:
|
||||
BeaconBlockCapella {
|
||||
slot,
|
||||
proposer_index,
|
||||
parent_root,
|
||||
state_root,
|
||||
body:
|
||||
BeaconBlockBodyCapella {
|
||||
randao_reveal,
|
||||
eth1_data,
|
||||
graffiti,
|
||||
proposer_slashings,
|
||||
attester_slashings,
|
||||
attestations,
|
||||
deposits,
|
||||
voluntary_exits,
|
||||
sync_aggregate,
|
||||
execution_payload: BlindedPayloadCapella { .. },
|
||||
bls_to_execution_changes,
|
||||
},
|
||||
},
|
||||
signature,
|
||||
} = self;
|
||||
SignedBeaconBlockCapella {
|
||||
message: BeaconBlockCapella {
|
||||
slot,
|
||||
proposer_index,
|
||||
parent_root,
|
||||
state_root,
|
||||
body: BeaconBlockBodyCapella {
|
||||
randao_reveal,
|
||||
eth1_data,
|
||||
graffiti,
|
||||
proposer_slashings,
|
||||
attester_slashings,
|
||||
attestations,
|
||||
deposits,
|
||||
voluntary_exits,
|
||||
sync_aggregate,
|
||||
execution_payload: FullPayloadCapella { execution_payload },
|
||||
bls_to_execution_changes,
|
||||
},
|
||||
},
|
||||
signature,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EthSpec> SignedBeaconBlockEip4844<E, BlindedPayload<E>> {
|
||||
pub fn into_full_block(
|
||||
self,
|
||||
execution_payload: ExecutionPayloadEip4844<E>,
|
||||
) -> SignedBeaconBlockEip4844<E, FullPayload<E>> {
|
||||
let SignedBeaconBlockEip4844 {
|
||||
message:
|
||||
BeaconBlockEip4844 {
|
||||
slot,
|
||||
proposer_index,
|
||||
parent_root,
|
||||
state_root,
|
||||
body:
|
||||
BeaconBlockBodyEip4844 {
|
||||
randao_reveal,
|
||||
eth1_data,
|
||||
graffiti,
|
||||
proposer_slashings,
|
||||
attester_slashings,
|
||||
attestations,
|
||||
deposits,
|
||||
voluntary_exits,
|
||||
sync_aggregate,
|
||||
execution_payload: BlindedPayloadEip4844 { .. },
|
||||
bls_to_execution_changes,
|
||||
blob_kzg_commitments,
|
||||
},
|
||||
},
|
||||
signature,
|
||||
} = self;
|
||||
SignedBeaconBlockEip4844 {
|
||||
message: BeaconBlockEip4844 {
|
||||
slot,
|
||||
proposer_index,
|
||||
parent_root,
|
||||
state_root,
|
||||
body: BeaconBlockBodyEip4844 {
|
||||
randao_reveal,
|
||||
eth1_data,
|
||||
graffiti,
|
||||
proposer_slashings,
|
||||
attester_slashings,
|
||||
attestations,
|
||||
deposits,
|
||||
voluntary_exits,
|
||||
sync_aggregate,
|
||||
execution_payload: FullPayloadEip4844 { execution_payload },
|
||||
bls_to_execution_changes,
|
||||
blob_kzg_commitments,
|
||||
},
|
||||
},
|
||||
signature,
|
||||
@@ -312,12 +434,23 @@ impl<E: EthSpec> SignedBeaconBlock<E, BlindedPayload<E>> {
|
||||
self,
|
||||
execution_payload: Option<ExecutionPayload<E>>,
|
||||
) -> Option<SignedBeaconBlock<E, FullPayload<E>>> {
|
||||
let full_block = match self {
|
||||
SignedBeaconBlock::Base(block) => SignedBeaconBlock::Base(block.into()),
|
||||
SignedBeaconBlock::Altair(block) => SignedBeaconBlock::Altair(block.into()),
|
||||
SignedBeaconBlock::Merge(block) => {
|
||||
SignedBeaconBlock::Merge(block.into_full_block(execution_payload?))
|
||||
let full_block = match (self, execution_payload) {
|
||||
(SignedBeaconBlock::Base(block), _) => SignedBeaconBlock::Base(block.into()),
|
||||
(SignedBeaconBlock::Altair(block), _) => SignedBeaconBlock::Altair(block.into()),
|
||||
(SignedBeaconBlock::Merge(block), Some(ExecutionPayload::Merge(payload))) => {
|
||||
SignedBeaconBlock::Merge(block.into_full_block(payload))
|
||||
}
|
||||
(SignedBeaconBlock::Capella(block), Some(ExecutionPayload::Capella(payload))) => {
|
||||
SignedBeaconBlock::Capella(block.into_full_block(payload))
|
||||
}
|
||||
(SignedBeaconBlock::Eip4844(block), Some(ExecutionPayload::Eip4844(payload))) => {
|
||||
SignedBeaconBlock::Eip4844(block.into_full_block(payload))
|
||||
}
|
||||
// avoid wildcard matching forks so that compiler will
|
||||
// direct us here when a new fork has been added
|
||||
(SignedBeaconBlock::Merge(_), _) => return None,
|
||||
(SignedBeaconBlock::Capella(_), _) => return None,
|
||||
(SignedBeaconBlock::Eip4844(_), _) => return None,
|
||||
};
|
||||
Some(full_block)
|
||||
}
|
||||
@@ -354,6 +487,24 @@ impl<E: EthSpec> SignedBeaconBlock<E> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EthSpec, Payload: AbstractExecPayload<E>> ForkVersionDeserialize
|
||||
for SignedBeaconBlock<E, Payload>
|
||||
{
|
||||
fn deserialize_by_fork<'de, D: serde::Deserializer<'de>>(
|
||||
value: serde_json::value::Value,
|
||||
fork_name: ForkName,
|
||||
) -> Result<Self, D::Error> {
|
||||
Ok(map_fork_name!(
|
||||
fork_name,
|
||||
Self,
|
||||
serde_json::from_value(value).map_err(|e| serde::de::Error::custom(format!(
|
||||
"SignedBeaconBlock failed to deserialize: {:?}",
|
||||
e
|
||||
)))?
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
@@ -10,9 +10,19 @@ use tree_hash_derive::TreeHash;
|
||||
/// A signed header of a `BeaconBlock`.
|
||||
///
|
||||
/// Spec v0.12.1
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(
|
||||
Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom,
|
||||
arbitrary::Arbitrary,
|
||||
Debug,
|
||||
Clone,
|
||||
PartialEq,
|
||||
Eq,
|
||||
Hash,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
TreeHash,
|
||||
TestRandom,
|
||||
)]
|
||||
pub struct SignedBeaconBlockHeader {
|
||||
pub message: BeaconBlockHeader,
|
||||
|
||||
33
consensus/types/src/signed_bls_to_execution_change.rs
Normal file
33
consensus/types/src/signed_bls_to_execution_change.rs
Normal file
@@ -0,0 +1,33 @@
|
||||
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;
|
||||
|
||||
#[derive(
|
||||
arbitrary::Arbitrary,
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
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);
|
||||
}
|
||||
@@ -10,9 +10,20 @@ use tree_hash_derive::TreeHash;
|
||||
|
||||
/// A Validators signed contribution proof to publish on the `sync_committee_contribution_and_proof`
|
||||
/// gossipsub topic.
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode, TestRandom, TreeHash)]
|
||||
#[derive(
|
||||
Debug,
|
||||
Clone,
|
||||
PartialEq,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
TestRandom,
|
||||
TreeHash,
|
||||
arbitrary::Arbitrary,
|
||||
)]
|
||||
#[serde(bound = "T: EthSpec")]
|
||||
#[arbitrary(bound = "T: EthSpec")]
|
||||
pub struct SignedContributionAndProof<T: EthSpec> {
|
||||
/// The `ContributionAndProof` that was signed.
|
||||
pub message: ContributionAndProof<T>,
|
||||
|
||||
@@ -9,9 +9,18 @@ use tree_hash_derive::TreeHash;
|
||||
/// An exit voluntarily submitted a validator who wishes to withdraw.
|
||||
///
|
||||
/// Spec v0.12.1
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(
|
||||
Debug, PartialEq, Hash, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom,
|
||||
arbitrary::Arbitrary,
|
||||
Debug,
|
||||
PartialEq,
|
||||
Hash,
|
||||
Clone,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
TreeHash,
|
||||
TestRandom,
|
||||
)]
|
||||
pub struct SignedVoluntaryExit {
|
||||
pub message: VoluntaryExit,
|
||||
|
||||
@@ -7,8 +7,18 @@ use test_random_derive::TestRandom;
|
||||
use tree_hash::TreeHash;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)]
|
||||
#[derive(
|
||||
arbitrary::Arbitrary,
|
||||
Debug,
|
||||
PartialEq,
|
||||
Clone,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
TreeHash,
|
||||
TestRandom,
|
||||
)]
|
||||
pub struct SigningData {
|
||||
pub object_root: Hash256,
|
||||
pub domain: Hash256,
|
||||
|
||||
@@ -24,13 +24,35 @@ use std::iter::Iterator;
|
||||
#[cfg(feature = "legacy-arith")]
|
||||
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Rem, Sub, SubAssign};
|
||||
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
||||
#[derive(
|
||||
arbitrary::Arbitrary,
|
||||
Clone,
|
||||
Copy,
|
||||
Default,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Hash,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
)]
|
||||
#[serde(transparent)]
|
||||
pub struct Slot(#[serde(with = "eth2_serde_utils::quoted_u64")] u64);
|
||||
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
||||
#[derive(
|
||||
arbitrary::Arbitrary,
|
||||
Clone,
|
||||
Copy,
|
||||
Default,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Hash,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
)]
|
||||
#[serde(transparent)]
|
||||
pub struct Epoch(#[serde(with = "eth2_serde_utils::quoted_u64")] u64);
|
||||
|
||||
|
||||
@@ -18,8 +18,7 @@ lazy_static! {
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
#[derive(arbitrary::Arbitrary, Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct SubnetId(#[serde(with = "eth2_serde_utils::quoted_u64")] u64);
|
||||
|
||||
|
||||
@@ -20,12 +20,21 @@ impl From<ArithError> for Error {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(
|
||||
Debug, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom, Derivative,
|
||||
Debug,
|
||||
Clone,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
TreeHash,
|
||||
TestRandom,
|
||||
Derivative,
|
||||
arbitrary::Arbitrary,
|
||||
)]
|
||||
#[derivative(PartialEq, Hash(bound = "T: EthSpec"))]
|
||||
#[serde(bound = "T: EthSpec")]
|
||||
#[arbitrary(bound = "T: EthSpec")]
|
||||
pub struct SyncAggregate<T: EthSpec> {
|
||||
pub sync_committee_bits: BitVector<T::SyncCommitteeSize>,
|
||||
pub sync_committee_signature: AggregateSignature,
|
||||
|
||||
@@ -6,9 +6,18 @@ use ssz_derive::{Decode, Encode};
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(
|
||||
Debug, PartialEq, Clone, Serialize, Deserialize, Hash, Encode, Decode, TreeHash, TestRandom,
|
||||
arbitrary::Arbitrary,
|
||||
Debug,
|
||||
PartialEq,
|
||||
Clone,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Hash,
|
||||
Encode,
|
||||
Decode,
|
||||
TreeHash,
|
||||
TestRandom,
|
||||
)]
|
||||
pub struct SyncAggregatorSelectionData {
|
||||
pub slot: Slot,
|
||||
|
||||
@@ -25,9 +25,20 @@ impl From<ArithError> for Error {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)]
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Clone,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
TreeHash,
|
||||
TestRandom,
|
||||
arbitrary::Arbitrary,
|
||||
)]
|
||||
#[serde(bound = "T: EthSpec")]
|
||||
#[arbitrary(bound = "T: EthSpec")]
|
||||
pub struct SyncCommittee<T: EthSpec> {
|
||||
pub pubkeys: FixedVector<PublicKeyBytes, T::SyncCommitteeSize>,
|
||||
pub aggregate_pubkey: PublicKeyBytes,
|
||||
|
||||
@@ -15,9 +15,20 @@ pub enum Error {
|
||||
}
|
||||
|
||||
/// An aggregation of `SyncCommitteeMessage`s, used in creating a `SignedContributionAndProof`.
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)]
|
||||
#[derive(
|
||||
Debug,
|
||||
Clone,
|
||||
PartialEq,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
TreeHash,
|
||||
TestRandom,
|
||||
arbitrary::Arbitrary,
|
||||
)]
|
||||
#[serde(bound = "T: EthSpec")]
|
||||
#[arbitrary(bound = "T: EthSpec")]
|
||||
pub struct SyncCommitteeContribution<T: EthSpec> {
|
||||
pub slot: Slot,
|
||||
pub beacon_block_root: Hash256,
|
||||
|
||||
@@ -8,8 +8,18 @@ use test_random_derive::TestRandom;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
/// The data upon which a `SyncCommitteeContribution` is based.
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)]
|
||||
#[derive(
|
||||
arbitrary::Arbitrary,
|
||||
Debug,
|
||||
Clone,
|
||||
PartialEq,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
TreeHash,
|
||||
TestRandom,
|
||||
)]
|
||||
pub struct SyncCommitteeMessage {
|
||||
pub slot: Slot,
|
||||
pub beacon_block_root: Hash256,
|
||||
|
||||
@@ -12,8 +12,7 @@ use ssz_types::typenum::Unsigned;
|
||||
use std::cmp;
|
||||
use std::convert::TryInto;
|
||||
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(PartialEq, Debug, Clone)]
|
||||
#[derive(arbitrary::Arbitrary, PartialEq, Debug, Clone)]
|
||||
pub struct SyncSelectionProof(Signature);
|
||||
|
||||
impl SyncSelectionProof {
|
||||
|
||||
@@ -19,8 +19,7 @@ lazy_static! {
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
#[derive(arbitrary::Arbitrary, Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct SyncSubnetId(#[serde(with = "eth2_serde_utils::quoted_u64")] u64);
|
||||
|
||||
|
||||
@@ -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};
|
||||
@@ -9,8 +10,18 @@ use tree_hash_derive::TreeHash;
|
||||
/// Information about a `BeaconChain` validator.
|
||||
///
|
||||
/// Spec v0.12.1
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode, TestRandom, TreeHash)]
|
||||
#[derive(
|
||||
arbitrary::Arbitrary,
|
||||
Debug,
|
||||
Clone,
|
||||
PartialEq,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
TestRandom,
|
||||
TreeHash,
|
||||
)]
|
||||
pub struct Validator {
|
||||
pub pubkey: PublicKeyBytes,
|
||||
pub withdrawal_credentials: Hash256,
|
||||
@@ -65,6 +76,49 @@ impl Validator {
|
||||
// Has not yet been activated
|
||||
&& self.activation_epoch == spec.far_future_epoch
|
||||
}
|
||||
|
||||
/// Returns `true` if the validator has eth1 withdrawal credential.
|
||||
pub fn has_eth1_withdrawal_credential(&self, spec: &ChainSpec) -> bool {
|
||||
self.withdrawal_credentials
|
||||
.as_bytes()
|
||||
.first()
|
||||
.map(|byte| *byte == spec.eth1_address_withdrawal_prefix_byte)
|
||||
.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
|
||||
}
|
||||
|
||||
/// Returns `true` if the validator is partially withdrawable.
|
||||
pub fn is_partially_withdrawable_validator(&self, balance: u64, spec: &ChainSpec) -> bool {
|
||||
self.has_eth1_withdrawal_credential(spec)
|
||||
&& self.effective_balance == spec.max_effective_balance
|
||||
&& balance > spec.max_effective_balance
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Validator {
|
||||
|
||||
@@ -11,9 +11,18 @@ use tree_hash_derive::TreeHash;
|
||||
/// An exit voluntarily submitted a validator who wishes to withdraw.
|
||||
///
|
||||
/// Spec v0.12.1
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(
|
||||
Debug, PartialEq, Hash, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom,
|
||||
arbitrary::Arbitrary,
|
||||
Debug,
|
||||
PartialEq,
|
||||
Hash,
|
||||
Clone,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
TreeHash,
|
||||
TestRandom,
|
||||
)]
|
||||
pub struct VoluntaryExit {
|
||||
/// Earliest epoch when voluntary exit can be processed.
|
||||
|
||||
37
consensus/types/src/withdrawal.rs
Normal file
37
consensus/types/src/withdrawal.rs
Normal file
@@ -0,0 +1,37 @@
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::*;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
#[derive(
|
||||
arbitrary::Arbitrary,
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
Hash,
|
||||
Clone,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
TreeHash,
|
||||
TestRandom,
|
||||
)]
|
||||
pub struct Withdrawal {
|
||||
#[serde(with = "eth2_serde_utils::quoted_u64")]
|
||||
pub index: u64,
|
||||
#[serde(with = "eth2_serde_utils::quoted_u64")]
|
||||
pub validator_index: u64,
|
||||
pub address: Address,
|
||||
#[serde(with = "eth2_serde_utils::quoted_u64")]
|
||||
pub amount: u64,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
ssz_and_tree_hash_tests!(Withdrawal);
|
||||
}
|
||||
Reference in New Issue
Block a user