mirror of
https://github.com/sigp/lighthouse.git
synced 2026-05-30 20:57:10 +00:00
@@ -9,6 +9,7 @@ name = "benches"
|
||||
harness = false
|
||||
|
||||
[dependencies]
|
||||
serde-big-array = {version = "0.3.2", features = ["const-generics"]}
|
||||
merkle_proof = { path = "../../consensus/merkle_proof" }
|
||||
bls = { path = "../../crypto/bls", features = ["arbitrary"] }
|
||||
compare_fields = { path = "../../common/compare_fields" }
|
||||
|
||||
@@ -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, Capella),
|
||||
variants(Base, Altair, Merge, Capella, Eip4844),
|
||||
variant_attributes(
|
||||
derive(
|
||||
Debug,
|
||||
@@ -72,6 +72,8 @@ pub struct BeaconBlock<T: EthSpec, Payload: AbstractExecPayload<T> = FullPayload
|
||||
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>>;
|
||||
@@ -124,8 +126,9 @@ impl<T: EthSpec, Payload: AbstractExecPayload<T>> BeaconBlock<T, Payload> {
|
||||
/// Usually it's better to prefer `from_ssz_bytes` which will decode the correct variant based
|
||||
/// on the fork slot.
|
||||
pub fn any_from_ssz_bytes(bytes: &[u8]) -> Result<Self, ssz::DecodeError> {
|
||||
BeaconBlockCapella::from_ssz_bytes(bytes)
|
||||
.map(BeaconBlock::Capella)
|
||||
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))
|
||||
@@ -203,6 +206,7 @@ impl<'a, T: EthSpec, Payload: AbstractExecPayload<T>> BeaconBlockRef<'a, T, Payl
|
||||
BeaconBlockRef::Altair { .. } => ForkName::Altair,
|
||||
BeaconBlockRef::Merge { .. } => ForkName::Merge,
|
||||
BeaconBlockRef::Capella { .. } => ForkName::Capella,
|
||||
BeaconBlockRef::Eip4844 { .. } => ForkName::Eip4844,
|
||||
};
|
||||
|
||||
if fork_at_slot == object_fork {
|
||||
@@ -556,6 +560,36 @@ impl<T: EthSpec, Payload: AbstractExecPayload<T>> EmptyBlock for BeaconBlockCape
|
||||
}
|
||||
}
|
||||
|
||||
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(),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We can convert pre-Bellatrix blocks without payloads into blocks "with" payloads.
|
||||
impl<E: EthSpec> From<BeaconBlockBase<E, BlindedPayload<E>>>
|
||||
for BeaconBlockBase<E, FullPayload<E>>
|
||||
@@ -635,6 +669,7 @@ impl_from!(BeaconBlockBase, <E, FullPayload<E>>, <E, BlindedPayload<E>>, |body:
|
||||
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 {
|
||||
@@ -666,6 +701,7 @@ impl_clone_as_blinded!(BeaconBlockBase, <E, FullPayload<E>>, <E, BlindedPayload<
|
||||
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.
|
||||
@@ -781,6 +817,25 @@ mod tests {
|
||||
});
|
||||
}
|
||||
|
||||
#[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;
|
||||
@@ -796,9 +851,12 @@ mod tests {
|
||||
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
|
||||
{
|
||||
@@ -865,5 +923,27 @@ mod tests {
|
||||
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, Capella),
|
||||
variants(Base, Altair, Merge, Capella, Eip4844),
|
||||
variant_attributes(
|
||||
derive(
|
||||
Debug,
|
||||
@@ -51,7 +52,7 @@ pub struct BeaconBlockBody<T: EthSpec, Payload: AbstractExecPayload<T> = FullPay
|
||||
pub attestations: VariableList<Attestation<T>, T::MaxAttestations>,
|
||||
pub deposits: VariableList<Deposit, T::MaxDeposits>,
|
||||
pub voluntary_exits: VariableList<SignedVoluntaryExit, T::MaxVoluntaryExits>,
|
||||
#[superstruct(only(Altair, Merge, Capella))]
|
||||
#[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
|
||||
@@ -62,9 +63,14 @@ pub struct BeaconBlockBody<T: EthSpec, Payload: AbstractExecPayload<T> = FullPay
|
||||
#[superstruct(only(Capella), partial_getter(rename = "execution_payload_capella"))]
|
||||
#[serde(flatten)]
|
||||
pub execution_payload: Payload::Capella,
|
||||
#[superstruct(only(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)]
|
||||
@@ -85,6 +91,7 @@ impl<'a, T: EthSpec, Payload: AbstractExecPayload<T>> BeaconBlockBodyRef<'a, T,
|
||||
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)),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -97,6 +104,7 @@ impl<'a, T: EthSpec> BeaconBlockBodyRef<'a, T> {
|
||||
BeaconBlockBodyRef::Altair { .. } => ForkName::Altair,
|
||||
BeaconBlockBodyRef::Merge { .. } => ForkName::Merge,
|
||||
BeaconBlockBodyRef::Capella { .. } => ForkName::Capella,
|
||||
BeaconBlockBodyRef::Eip4844 { .. } => ForkName::Eip4844,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -321,6 +329,50 @@ impl<E: EthSpec> From<BeaconBlockBodyCapella<E, FullPayload<E>>>
|
||||
}
|
||||
}
|
||||
|
||||
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>> {
|
||||
@@ -402,6 +454,42 @@ impl<E: EthSpec> BeaconBlockBodyCapella<E, FullPayload<E>> {
|
||||
}
|
||||
}
|
||||
|
||||
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>>,
|
||||
|
||||
@@ -176,7 +176,7 @@ impl From<BeaconStateHash> for Hash256 {
|
||||
|
||||
/// The state of the `BeaconChain` at some slot.
|
||||
#[superstruct(
|
||||
variants(Base, Altair, Merge, Capella),
|
||||
variants(Base, Altair, Merge, Capella, Eip4844),
|
||||
variant_attributes(
|
||||
derive(
|
||||
Derivative,
|
||||
@@ -256,9 +256,9 @@ where
|
||||
pub current_epoch_attestations: VariableList<PendingAttestation<T>, T::MaxPendingAttestations>,
|
||||
|
||||
// Participation (Altair and later)
|
||||
#[superstruct(only(Altair, Merge, Capella))]
|
||||
#[superstruct(only(Altair, Merge, Capella, Eip4844))]
|
||||
pub previous_epoch_participation: VariableList<ParticipationFlags, T::ValidatorRegistryLimit>,
|
||||
#[superstruct(only(Altair, Merge, Capella))]
|
||||
#[superstruct(only(Altair, Merge, Capella, Eip4844))]
|
||||
pub current_epoch_participation: VariableList<ParticipationFlags, T::ValidatorRegistryLimit>,
|
||||
|
||||
// Finality
|
||||
@@ -273,13 +273,13 @@ where
|
||||
|
||||
// Inactivity
|
||||
#[serde(with = "ssz_types::serde_utils::quoted_u64_var_list")]
|
||||
#[superstruct(only(Altair, Merge, Capella))]
|
||||
#[superstruct(only(Altair, Merge, Capella, Eip4844))]
|
||||
pub inactivity_scores: VariableList<u64, T::ValidatorRegistryLimit>,
|
||||
|
||||
// Light-client sync committees
|
||||
#[superstruct(only(Altair, Merge, Capella))]
|
||||
#[superstruct(only(Altair, Merge, Capella, Eip4844))]
|
||||
pub current_sync_committee: Arc<SyncCommittee<T>>,
|
||||
#[superstruct(only(Altair, Merge, Capella))]
|
||||
#[superstruct(only(Altair, Merge, Capella, Eip4844))]
|
||||
pub next_sync_committee: Arc<SyncCommittee<T>>,
|
||||
|
||||
// Execution
|
||||
@@ -293,16 +293,21 @@ where
|
||||
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), partial_getter(copy))]
|
||||
#[superstruct(only(Capella, Eip4844), partial_getter(copy))]
|
||||
#[serde(with = "eth2_serde_utils::quoted_u64")]
|
||||
pub next_withdrawal_index: u64,
|
||||
#[superstruct(only(Capella), partial_getter(copy))]
|
||||
#[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))]
|
||||
#[superstruct(only(Capella, Eip4844))]
|
||||
pub historical_summaries: VariableList<HistoricalSummary, T::HistoricalRootsLimit>,
|
||||
|
||||
// Caching (not in the spec)
|
||||
@@ -415,6 +420,7 @@ impl<T: EthSpec> BeaconState<T> {
|
||||
BeaconState::Altair { .. } => ForkName::Altair,
|
||||
BeaconState::Merge { .. } => ForkName::Merge,
|
||||
BeaconState::Capella { .. } => ForkName::Capella,
|
||||
BeaconState::Eip4844 { .. } => ForkName::Eip4844,
|
||||
};
|
||||
|
||||
if fork_at_slot == object_fork {
|
||||
@@ -714,6 +720,9 @@ impl<T: EthSpec> BeaconState<T> {
|
||||
BeaconState::Capella(state) => Ok(ExecutionPayloadHeaderRef::Capella(
|
||||
&state.latest_execution_payload_header,
|
||||
)),
|
||||
BeaconState::Eip4844(state) => Ok(ExecutionPayloadHeaderRef::Eip4844(
|
||||
&state.latest_execution_payload_header,
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -728,6 +737,9 @@ impl<T: EthSpec> BeaconState<T> {
|
||||
BeaconState::Capella(state) => Ok(ExecutionPayloadHeaderRefMut::Capella(
|
||||
&mut state.latest_execution_payload_header,
|
||||
)),
|
||||
BeaconState::Eip4844(state) => Ok(ExecutionPayloadHeaderRefMut::Eip4844(
|
||||
&mut state.latest_execution_payload_header,
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1156,6 +1168,7 @@ impl<T: EthSpec> BeaconState<T> {
|
||||
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),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1353,6 +1366,7 @@ impl<T: EthSpec> BeaconState<T> {
|
||||
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 {
|
||||
@@ -1360,6 +1374,7 @@ impl<T: EthSpec> BeaconState<T> {
|
||||
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)
|
||||
@@ -1665,6 +1680,7 @@ impl<T: EthSpec> BeaconState<T> {
|
||||
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();
|
||||
@@ -1833,6 +1849,7 @@ impl<T: EthSpec> CompareFields for BeaconState<T> {
|
||||
(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",),
|
||||
}
|
||||
}
|
||||
|
||||
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())
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@ pub enum Domain {
|
||||
BlsToExecutionChange,
|
||||
BeaconProposer,
|
||||
BeaconAttester,
|
||||
BlobsSideCar,
|
||||
Randao,
|
||||
Deposit,
|
||||
VoluntaryExit,
|
||||
@@ -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,
|
||||
@@ -159,6 +161,12 @@ pub struct ChainSpec {
|
||||
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
|
||||
*/
|
||||
@@ -247,13 +255,16 @@ 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.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,
|
||||
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,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -266,6 +277,7 @@ impl ChainSpec {
|
||||
ForkName::Altair => self.altair_fork_version,
|
||||
ForkName::Merge => self.bellatrix_fork_version,
|
||||
ForkName::Capella => self.capella_fork_version,
|
||||
ForkName::Eip4844 => self.eip4844_fork_version,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -276,6 +288,7 @@ impl ChainSpec {
|
||||
ForkName::Altair => self.altair_fork_epoch,
|
||||
ForkName::Merge => self.bellatrix_fork_epoch,
|
||||
ForkName::Capella => self.capella_fork_epoch,
|
||||
ForkName::Eip4844 => self.eip4844_fork_epoch,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -286,6 +299,7 @@ impl ChainSpec {
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -299,6 +313,7 @@ impl ChainSpec {
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -312,6 +327,7 @@ impl ChainSpec {
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -350,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,
|
||||
@@ -557,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
|
||||
@@ -618,6 +636,12 @@ impl ChainSpec {
|
||||
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
|
||||
*/
|
||||
@@ -685,6 +709,9 @@ impl ChainSpec {
|
||||
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,
|
||||
@@ -782,6 +809,7 @@ impl ChainSpec {
|
||||
domain_voluntary_exit: 4,
|
||||
domain_selection_proof: 5,
|
||||
domain_aggregate_and_proof: 6,
|
||||
domain_blobs_sidecar: 10,
|
||||
|
||||
/*
|
||||
* Fork choice
|
||||
@@ -845,6 +873,12 @@ impl ChainSpec {
|
||||
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
|
||||
*/
|
||||
@@ -936,6 +970,14 @@ pub struct Config {
|
||||
#[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")]
|
||||
@@ -978,6 +1020,11 @@ fn default_capella_fork_version() -> [u8; 4] {
|
||||
[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
|
||||
@@ -1078,6 +1125,10 @@ impl Config {
|
||||
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,
|
||||
@@ -1125,6 +1176,8 @@ impl Config {
|
||||
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,
|
||||
@@ -1157,6 +1210,8 @@ impl Config {
|
||||
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,
|
||||
@@ -1230,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);
|
||||
@@ -1254,6 +1310,8 @@ mod tests {
|
||||
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 {
|
||||
|
||||
@@ -78,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),
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -102,6 +102,11 @@ pub trait EthSpec:
|
||||
*/
|
||||
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)
|
||||
*/
|
||||
@@ -239,6 +244,11 @@ pub trait EthSpec:
|
||||
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.
|
||||
@@ -278,6 +288,8 @@ 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
|
||||
@@ -328,7 +340,9 @@ impl EthSpec for MinimalEthSpec {
|
||||
GasLimitDenominator,
|
||||
MinGasLimit,
|
||||
MaxExtraDataBytes,
|
||||
MaxBlsToExecutionChanges
|
||||
MaxBlsToExecutionChanges,
|
||||
MaxBlobsPerBlock,
|
||||
FieldElementsPerBlob
|
||||
});
|
||||
|
||||
fn default_spec() -> ChainSpec {
|
||||
@@ -374,6 +388,8 @@ impl EthSpec for GnosisEthSpec {
|
||||
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()
|
||||
|
||||
@@ -15,7 +15,7 @@ pub type Transactions<T> = VariableList<
|
||||
pub type Withdrawals<T> = VariableList<Withdrawal, <T as EthSpec>::MaxWithdrawalsPerPayload>;
|
||||
|
||||
#[superstruct(
|
||||
variants(Merge, Capella),
|
||||
variants(Merge, Capella, Eip4844),
|
||||
variant_attributes(
|
||||
derive(
|
||||
Default,
|
||||
@@ -77,11 +77,15 @@ pub struct ExecutionPayload<T: EthSpec> {
|
||||
#[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))]
|
||||
#[superstruct(only(Capella, Eip4844))]
|
||||
pub withdrawals: Withdrawals<T>,
|
||||
}
|
||||
|
||||
@@ -103,6 +107,7 @@ impl<T: EthSpec> ExecutionPayload<T> {
|
||||
))),
|
||||
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),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,6 +134,19 @@ impl<T: EthSpec> ExecutionPayload<T> {
|
||||
// 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> {
|
||||
@@ -143,6 +161,7 @@ impl<T: EthSpec> ForkVersionDeserialize for ExecutionPayload<T> {
|
||||
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 '{}'",
|
||||
|
||||
@@ -9,7 +9,7 @@ use tree_hash_derive::TreeHash;
|
||||
use BeaconStateError;
|
||||
|
||||
#[superstruct(
|
||||
variants(Merge, Capella),
|
||||
variants(Merge, Capella, Eip4844),
|
||||
variant_attributes(
|
||||
derive(
|
||||
Default,
|
||||
@@ -70,11 +70,15 @@ pub struct ExecutionPayloadHeader<T: EthSpec> {
|
||||
#[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))]
|
||||
#[superstruct(only(Capella, Eip4844))]
|
||||
#[superstruct(getter(copy))]
|
||||
pub withdrawals_root: Hash256,
|
||||
}
|
||||
@@ -93,6 +97,9 @@ impl<T: EthSpec> ExecutionPayloadHeader<T> {
|
||||
ForkName::Capella => {
|
||||
ExecutionPayloadHeaderCapella::from_ssz_bytes(bytes).map(Self::Capella)
|
||||
}
|
||||
ForkName::Eip4844 => {
|
||||
ExecutionPayloadHeaderEip4844::from_ssz_bytes(bytes).map(Self::Eip4844)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -128,6 +135,30 @@ impl<T: EthSpec> ExecutionPayloadHeaderMerge<T> {
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
@@ -170,6 +201,29 @@ impl<'a, T: EthSpec> From<&'a ExecutionPayloadCapella<T>> for ExecutionPayloadHe
|
||||
}
|
||||
}
|
||||
|
||||
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> {
|
||||
@@ -184,6 +238,12 @@ impl<'a, T: EthSpec> From<&'a Self> for ExecutionPayloadHeaderCapella<T> {
|
||||
}
|
||||
}
|
||||
|
||||
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!(
|
||||
@@ -214,6 +274,17 @@ impl<T: EthSpec> TryFrom<ExecutionPayloadHeader<T>> for ExecutionPayloadHeaderCa
|
||||
}
|
||||
}
|
||||
}
|
||||
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>>(
|
||||
@@ -230,6 +301,7 @@ impl<T: EthSpec> ForkVersionDeserialize for ExecutionPayloadHeader<T> {
|
||||
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 '{}'",
|
||||
|
||||
@@ -54,6 +54,13 @@ impl ForkContext {
|
||||
));
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
@@ -12,6 +12,7 @@ pub enum ForkName {
|
||||
Altair,
|
||||
Merge,
|
||||
Capella,
|
||||
Eip4844,
|
||||
}
|
||||
|
||||
impl ForkName {
|
||||
@@ -21,6 +22,7 @@ impl ForkName {
|
||||
ForkName::Altair,
|
||||
ForkName::Merge,
|
||||
ForkName::Capella,
|
||||
ForkName::Eip4844,
|
||||
]
|
||||
}
|
||||
|
||||
@@ -33,24 +35,35 @@ impl ForkName {
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -65,6 +78,7 @@ impl ForkName {
|
||||
ForkName::Altair => Some(ForkName::Base),
|
||||
ForkName::Merge => Some(ForkName::Altair),
|
||||
ForkName::Capella => Some(ForkName::Merge),
|
||||
ForkName::Eip4844 => Some(ForkName::Capella),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,7 +90,8 @@ impl ForkName {
|
||||
ForkName::Base => Some(ForkName::Altair),
|
||||
ForkName::Altair => Some(ForkName::Merge),
|
||||
ForkName::Merge => Some(ForkName::Capella),
|
||||
ForkName::Capella => None,
|
||||
ForkName::Capella => Some(ForkName::Eip4844),
|
||||
ForkName::Eip4844 => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -122,6 +137,10 @@ macro_rules! map_fork_name_with {
|
||||
let (value, extra_data) = $body;
|
||||
($t::Capella(value), extra_data)
|
||||
}
|
||||
ForkName::Eip4844 => {
|
||||
let (value, extra_data) = $body;
|
||||
($t::Eip4844(value), extra_data)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -135,6 +154,7 @@ impl FromStr for ForkName {
|
||||
"altair" => ForkName::Altair,
|
||||
"bellatrix" | "merge" => ForkName::Merge,
|
||||
"capella" => ForkName::Capella,
|
||||
"eip4844" => ForkName::Eip4844,
|
||||
_ => return Err(format!("unknown fork name: {}", fork_name)),
|
||||
})
|
||||
}
|
||||
@@ -147,6 +167,7 @@ impl Display for ForkName {
|
||||
ForkName::Altair => "altair".fmt(f),
|
||||
ForkName::Merge => "bellatrix".fmt(f),
|
||||
ForkName::Capella => "capella".fmt(f),
|
||||
ForkName::Eip4844 => "eip4844".fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -178,7 +199,7 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn previous_and_next_fork_consistent() {
|
||||
assert_eq!(ForkName::Capella.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() {
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
@@ -99,6 +99,10 @@ 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;
|
||||
@@ -107,16 +111,17 @@ 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, BeaconBlockCapella, BeaconBlockMerge,
|
||||
BeaconBlockRef, BeaconBlockRefMut, BlindedBeaconBlock, EmptyBlock,
|
||||
BeaconBlock, BeaconBlockAltair, BeaconBlockBase, BeaconBlockCapella, BeaconBlockEip4844,
|
||||
BeaconBlockMerge, BeaconBlockRef, BeaconBlockRefMut, BlindedBeaconBlock, EmptyBlock,
|
||||
};
|
||||
pub use crate::beacon_block_body::{
|
||||
BeaconBlockBody, BeaconBlockBodyAltair, BeaconBlockBodyBase, BeaconBlockBodyCapella,
|
||||
BeaconBlockBodyMerge, BeaconBlockBodyRef, BeaconBlockBodyRefMut,
|
||||
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;
|
||||
@@ -134,12 +139,12 @@ 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, ExecutionPayloadCapella, ExecutionPayloadMerge, ExecutionPayloadRef,
|
||||
Transaction, Transactions, Withdrawals,
|
||||
ExecutionPayload, ExecutionPayloadCapella, ExecutionPayloadEip4844, ExecutionPayloadMerge,
|
||||
ExecutionPayloadRef, Transaction, Transactions, Withdrawals,
|
||||
};
|
||||
pub use crate::execution_payload_header::{
|
||||
ExecutionPayloadHeader, ExecutionPayloadHeaderCapella, ExecutionPayloadHeaderMerge,
|
||||
ExecutionPayloadHeaderRef, ExecutionPayloadHeaderRefMut,
|
||||
ExecutionPayloadHeader, ExecutionPayloadHeaderCapella, ExecutionPayloadHeaderEip4844,
|
||||
ExecutionPayloadHeaderMerge, ExecutionPayloadHeaderRef, ExecutionPayloadHeaderRefMut,
|
||||
};
|
||||
pub use crate::fork::Fork;
|
||||
pub use crate::fork_context::ForkContext;
|
||||
@@ -151,14 +156,16 @@ pub use crate::fork_versioned_response::{
|
||||
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::{
|
||||
AbstractExecPayload, BlindedPayload, BlindedPayloadCapella, BlindedPayloadMerge,
|
||||
BlindedPayloadRef, BlockType, ExecPayload, FullPayload, FullPayloadCapella, FullPayloadMerge,
|
||||
FullPayloadRef, OwnedExecPayload,
|
||||
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, CapellaPreset};
|
||||
@@ -170,7 +177,8 @@ pub use crate::shuffling_id::AttestationShufflingId;
|
||||
pub use crate::signed_aggregate_and_proof::SignedAggregateAndProof;
|
||||
pub use crate::signed_beacon_block::{
|
||||
SignedBeaconBlock, SignedBeaconBlockAltair, SignedBeaconBlockBase, SignedBeaconBlockCapella,
|
||||
SignedBeaconBlockHash, SignedBeaconBlockMerge, SignedBlindedBeaconBlock,
|
||||
SignedBeaconBlockEip4844, SignedBeaconBlockHash, SignedBeaconBlockMerge,
|
||||
SignedBlindedBeaconBlock,
|
||||
};
|
||||
pub use crate::signed_beacon_block_header::SignedBeaconBlockHeader;
|
||||
pub use crate::signed_bls_to_execution_change::SignedBlsToExecutionChange;
|
||||
@@ -193,6 +201,7 @@ pub use crate::validator_registration_data::*;
|
||||
pub use crate::validator_subscription::ValidatorSubscription;
|
||||
pub use crate::voluntary_exit::VoluntaryExit;
|
||||
pub use crate::withdrawal::Withdrawal;
|
||||
use serde_big_array::BigArray;
|
||||
|
||||
pub type CommitteeIndex = u64;
|
||||
pub type Hash256 = H256;
|
||||
@@ -200,6 +209,7 @@ 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;
|
||||
|
||||
|
||||
@@ -81,8 +81,13 @@ pub trait AbstractExecPayload<T: EthSpec>:
|
||||
+ TryFrom<ExecutionPayloadHeader<T>>
|
||||
+ TryInto<Self::Merge>
|
||||
+ TryInto<Self::Capella>
|
||||
+ TryInto<Self::Eip4844>
|
||||
{
|
||||
type Ref<'a>: ExecPayload<T> + Copy + From<&'a Self::Merge> + From<&'a Self::Capella>;
|
||||
type Ref<'a>: ExecPayload<T>
|
||||
+ Copy
|
||||
+ From<&'a Self::Merge>
|
||||
+ From<&'a Self::Capella>
|
||||
+ From<&'a Self::Eip4844>;
|
||||
|
||||
type Merge: OwnedExecPayload<T>
|
||||
+ Into<Self>
|
||||
@@ -92,12 +97,16 @@ pub trait AbstractExecPayload<T: EthSpec>:
|
||||
+ Into<Self>
|
||||
+ for<'a> From<Cow<'a, ExecutionPayloadCapella<T>>>
|
||||
+ TryFrom<ExecutionPayloadHeaderCapella<T>>;
|
||||
type Eip4844: OwnedExecPayload<T>
|
||||
+ Into<Self>
|
||||
+ for<'a> From<Cow<'a, ExecutionPayloadEip4844<T>>>
|
||||
+ TryFrom<ExecutionPayloadHeaderEip4844<T>>;
|
||||
|
||||
fn default_at_fork(fork_name: ForkName) -> Result<Self, Error>;
|
||||
}
|
||||
|
||||
#[superstruct(
|
||||
variants(Merge, Capella),
|
||||
variants(Merge, Capella, Eip4844),
|
||||
variant_attributes(
|
||||
derive(
|
||||
Debug,
|
||||
@@ -136,6 +145,8 @@ pub struct FullPayload<T: EthSpec> {
|
||||
pub execution_payload: ExecutionPayloadMerge<T>,
|
||||
#[superstruct(only(Capella), partial_getter(rename = "execution_payload_capella"))]
|
||||
pub execution_payload: ExecutionPayloadCapella<T>,
|
||||
#[superstruct(only(Eip4844), partial_getter(rename = "execution_payload_eip4844"))]
|
||||
pub execution_payload: ExecutionPayloadEip4844<T>,
|
||||
}
|
||||
|
||||
impl<T: EthSpec> From<FullPayload<T>> for ExecutionPayload<T> {
|
||||
@@ -239,6 +250,9 @@ impl<T: EthSpec> ExecPayload<T> for FullPayload<T> {
|
||||
FullPayload::Capella(ref inner) => {
|
||||
Ok(inner.execution_payload.withdrawals.tree_hash_root())
|
||||
}
|
||||
FullPayload::Eip4844(ref inner) => {
|
||||
Ok(inner.execution_payload.withdrawals.tree_hash_root())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -345,6 +359,9 @@ impl<'b, T: EthSpec> ExecPayload<T> for FullPayloadRef<'b, T> {
|
||||
FullPayloadRef::Capella(inner) => {
|
||||
Ok(inner.execution_payload.withdrawals.tree_hash_root())
|
||||
}
|
||||
FullPayloadRef::Eip4844(inner) => {
|
||||
Ok(inner.execution_payload.withdrawals.tree_hash_root())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -365,12 +382,14 @@ impl<T: EthSpec> AbstractExecPayload<T> for FullPayload<T> {
|
||||
type Ref<'a> = FullPayloadRef<'a, T>;
|
||||
type Merge = FullPayloadMerge<T>;
|
||||
type Capella = FullPayloadCapella<T>;
|
||||
type Eip4844 = FullPayloadEip4844<T>;
|
||||
|
||||
fn default_at_fork(fork_name: ForkName) -> Result<Self, Error> {
|
||||
match fork_name {
|
||||
ForkName::Base | ForkName::Altair => Err(Error::IncorrectStateVariant),
|
||||
ForkName::Merge => Ok(FullPayloadMerge::default().into()),
|
||||
ForkName::Capella => Ok(FullPayloadCapella::default().into()),
|
||||
ForkName::Eip4844 => Ok(FullPayloadEip4844::default().into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -391,7 +410,7 @@ impl<T: EthSpec> TryFrom<ExecutionPayloadHeader<T>> for FullPayload<T> {
|
||||
}
|
||||
|
||||
#[superstruct(
|
||||
variants(Merge, Capella),
|
||||
variants(Merge, Capella, Eip4844),
|
||||
variant_attributes(
|
||||
derive(
|
||||
Debug,
|
||||
@@ -429,6 +448,8 @@ pub struct BlindedPayload<T: EthSpec> {
|
||||
pub execution_payload_header: ExecutionPayloadHeaderMerge<T>,
|
||||
#[superstruct(only(Capella), partial_getter(rename = "execution_payload_capella"))]
|
||||
pub execution_payload_header: ExecutionPayloadHeaderCapella<T>,
|
||||
#[superstruct(only(Eip4844), partial_getter(rename = "execution_payload_eip4844"))]
|
||||
pub execution_payload_header: ExecutionPayloadHeaderEip4844<T>,
|
||||
}
|
||||
|
||||
impl<'a, T: EthSpec> From<BlindedPayloadRef<'a, T>> for BlindedPayload<T> {
|
||||
@@ -510,6 +531,9 @@ impl<T: EthSpec> ExecPayload<T> for BlindedPayload<T> {
|
||||
BlindedPayload::Capella(ref inner) => {
|
||||
Ok(inner.execution_payload_header.withdrawals_root)
|
||||
}
|
||||
BlindedPayload::Eip4844(ref inner) => {
|
||||
Ok(inner.execution_payload_header.withdrawals_root)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -597,6 +621,9 @@ impl<'b, T: EthSpec> ExecPayload<T> for BlindedPayloadRef<'b, T> {
|
||||
BlindedPayloadRef::Capella(inner) => {
|
||||
Ok(inner.execution_payload_header.withdrawals_root)
|
||||
}
|
||||
BlindedPayloadRef::Eip4844(inner) => {
|
||||
Ok(inner.execution_payload_header.withdrawals_root)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -860,17 +887,26 @@ impl_exec_payload_for_fork!(
|
||||
ExecutionPayloadCapella,
|
||||
Capella
|
||||
);
|
||||
impl_exec_payload_for_fork!(
|
||||
BlindedPayloadEip4844,
|
||||
FullPayloadEip4844,
|
||||
ExecutionPayloadHeaderEip4844,
|
||||
ExecutionPayloadEip4844,
|
||||
Eip4844
|
||||
);
|
||||
|
||||
impl<T: EthSpec> AbstractExecPayload<T> for BlindedPayload<T> {
|
||||
type Ref<'a> = BlindedPayloadRef<'a, T>;
|
||||
type Merge = BlindedPayloadMerge<T>;
|
||||
type Capella = BlindedPayloadCapella<T>;
|
||||
type Eip4844 = BlindedPayloadEip4844<T>;
|
||||
|
||||
fn default_at_fork(fork_name: ForkName) -> Result<Self, Error> {
|
||||
match fork_name {
|
||||
ForkName::Base | ForkName::Altair => Err(Error::IncorrectStateVariant),
|
||||
ForkName::Merge => Ok(BlindedPayloadMerge::default().into()),
|
||||
ForkName::Capella => Ok(BlindedPayloadCapella::default().into()),
|
||||
ForkName::Eip4844 => Ok(BlindedPayloadEip4844::default().into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -899,6 +935,11 @@ impl<T: EthSpec> From<ExecutionPayloadHeader<T>> for BlindedPayload<T> {
|
||||
execution_payload_header,
|
||||
})
|
||||
}
|
||||
ExecutionPayloadHeader::Eip4844(execution_payload_header) => {
|
||||
Self::Eip4844(BlindedPayloadEip4844 {
|
||||
execution_payload_header,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -912,6 +953,9 @@ impl<T: EthSpec> From<BlindedPayload<T>> for ExecutionPayloadHeader<T> {
|
||||
BlindedPayload::Capella(blinded_payload) => {
|
||||
ExecutionPayloadHeader::Capella(blinded_payload.execution_payload_header)
|
||||
}
|
||||
BlindedPayload::Eip4844(blinded_payload) => {
|
||||
ExecutionPayloadHeader::Eip4844(blinded_payload.execution_payload_header)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ impl From<SignedBeaconBlockHash> for Hash256 {
|
||||
|
||||
/// A `BeaconBlock` and a signature from its proposer.
|
||||
#[superstruct(
|
||||
variants(Base, Altair, Merge, Capella),
|
||||
variants(Base, Altair, Merge, Capella, Eip4844),
|
||||
variant_attributes(
|
||||
derive(
|
||||
Debug,
|
||||
@@ -76,6 +76,8 @@ pub struct SignedBeaconBlock<E: EthSpec, Payload: AbstractExecPayload<E> = FullP
|
||||
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,
|
||||
}
|
||||
|
||||
@@ -136,6 +138,9 @@ impl<E: EthSpec, Payload: AbstractExecPayload<E>> SignedBeaconBlock<E, Payload>
|
||||
BeaconBlock::Capella(message) => {
|
||||
SignedBeaconBlock::Capella(SignedBeaconBlockCapella { message, signature })
|
||||
}
|
||||
BeaconBlock::Eip4844(message) => {
|
||||
SignedBeaconBlock::Eip4844(SignedBeaconBlockEip4844 { message, signature })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -368,6 +373,62 @@ impl<E: EthSpec> SignedBeaconBlockCapella<E, BlindedPayload<E>> {
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EthSpec> SignedBeaconBlock<E, BlindedPayload<E>> {
|
||||
pub fn try_into_full_block(
|
||||
self,
|
||||
@@ -382,10 +443,14 @@ impl<E: EthSpec> SignedBeaconBlock<E, BlindedPayload<E>> {
|
||||
(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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user