mirror of
https://github.com/sigp/lighthouse.git
synced 2026-05-07 00:42:42 +00:00
Add Electra fork boilerplate (#5122)
* Add Electra fork boilerplate * Remove electra from spec tests * Fix tests * Remove sneaky log file * Fix more tests * Fix even more tests and add suggestions * Remove unrelated lcli addition * Update more tests * Merge branch 'unstable' into electra * Add comment for test-suite lcli override * Merge branch 'unstable' into electra * Cleanup * Merge branch 'unstable' into electra * Apply suggestions * Merge branch 'unstable' into electra * Merge sigp/unstable into electra * Merge branch 'unstable' into electra
This commit is contained in:
3
consensus/types/presets/gnosis/electra.yaml
Normal file
3
consensus/types/presets/gnosis/electra.yaml
Normal file
@@ -0,0 +1,3 @@
|
||||
# Gnosis preset - Electra
|
||||
|
||||
ELECTRA_PLACEHOLDER: 0
|
||||
3
consensus/types/presets/mainnet/electra.yaml
Normal file
3
consensus/types/presets/mainnet/electra.yaml
Normal file
@@ -0,0 +1,3 @@
|
||||
# Mainnet preset - Electra
|
||||
|
||||
ELECTRA_PLACEHOLDER: 0
|
||||
3
consensus/types/presets/minimal/electra.yaml
Normal file
3
consensus/types/presets/minimal/electra.yaml
Normal file
@@ -0,0 +1,3 @@
|
||||
# Minimal preset - Electra
|
||||
|
||||
ELECTRA_PLACEHOLDER: 0
|
||||
@@ -12,7 +12,7 @@ use tree_hash_derive::TreeHash;
|
||||
|
||||
/// A block of the `BeaconChain`.
|
||||
#[superstruct(
|
||||
variants(Base, Altair, Merge, Capella, Deneb),
|
||||
variants(Base, Altair, Merge, Capella, Deneb, Electra),
|
||||
variant_attributes(
|
||||
derive(
|
||||
Debug,
|
||||
@@ -69,6 +69,8 @@ pub struct BeaconBlock<T: EthSpec, Payload: AbstractExecPayload<T> = FullPayload
|
||||
pub body: BeaconBlockBodyCapella<T, Payload>,
|
||||
#[superstruct(only(Deneb), partial_getter(rename = "body_deneb"))]
|
||||
pub body: BeaconBlockBodyDeneb<T, Payload>,
|
||||
#[superstruct(only(Electra), partial_getter(rename = "body_electra"))]
|
||||
pub body: BeaconBlockBodyElectra<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> {
|
||||
BeaconBlockDeneb::from_ssz_bytes(bytes)
|
||||
.map(BeaconBlock::Deneb)
|
||||
BeaconBlockElectra::from_ssz_bytes(bytes)
|
||||
.map(BeaconBlock::Electra)
|
||||
.or_else(|_| BeaconBlockDeneb::from_ssz_bytes(bytes).map(BeaconBlock::Deneb))
|
||||
.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))
|
||||
@@ -221,6 +224,7 @@ impl<'a, T: EthSpec, Payload: AbstractExecPayload<T>> BeaconBlockRef<'a, T, Payl
|
||||
BeaconBlockRef::Merge { .. } => ForkName::Merge,
|
||||
BeaconBlockRef::Capella { .. } => ForkName::Capella,
|
||||
BeaconBlockRef::Deneb { .. } => ForkName::Deneb,
|
||||
BeaconBlockRef::Electra { .. } => ForkName::Electra,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -595,6 +599,83 @@ impl<T: EthSpec, Payload: AbstractExecPayload<T>> EmptyBlock for BeaconBlockDene
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: EthSpec, Payload: AbstractExecPayload<T>> BeaconBlockElectra<T, Payload> {
|
||||
/// Return a Electra 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(),
|
||||
};
|
||||
BeaconBlockElectra {
|
||||
slot: spec.genesis_slot,
|
||||
proposer_index: 0,
|
||||
parent_root: Hash256::zero(),
|
||||
state_root: Hash256::zero(),
|
||||
body: BeaconBlockBodyElectra {
|
||||
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::Electra::default(),
|
||||
blob_kzg_commitments: VariableList::empty(),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: EthSpec, Payload: AbstractExecPayload<T>> EmptyBlock for BeaconBlockElectra<T, Payload> {
|
||||
/// Returns an empty Electra block to be used during genesis.
|
||||
fn empty(spec: &ChainSpec) -> Self {
|
||||
BeaconBlockElectra {
|
||||
slot: spec.genesis_slot,
|
||||
proposer_index: 0,
|
||||
parent_root: Hash256::zero(),
|
||||
state_root: Hash256::zero(),
|
||||
body: BeaconBlockBodyElectra {
|
||||
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::Electra::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>>
|
||||
@@ -675,6 +756,7 @@ impl_from!(BeaconBlockAltair, <E, FullPayload<E>>, <E, BlindedPayload<E>>, |body
|
||||
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!(BeaconBlockDeneb, <E, FullPayload<E>>, <E, BlindedPayload<E>>, |body: BeaconBlockBodyDeneb<_, _>| body.into());
|
||||
impl_from!(BeaconBlockElectra, <E, FullPayload<E>>, <E, BlindedPayload<E>>, |body: BeaconBlockBodyElectra<_, _>| body.into());
|
||||
|
||||
// We can clone blocks with payloads to blocks without payloads, without cloning the payload.
|
||||
macro_rules! impl_clone_as_blinded {
|
||||
@@ -707,6 +789,7 @@ impl_clone_as_blinded!(BeaconBlockAltair, <E, FullPayload<E>>, <E, BlindedPayloa
|
||||
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!(BeaconBlockDeneb, <E, FullPayload<E>>, <E, BlindedPayload<E>>);
|
||||
impl_clone_as_blinded!(BeaconBlockElectra, <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.
|
||||
@@ -822,7 +905,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn roundtrip_4844_block() {
|
||||
fn roundtrip_deneb_block() {
|
||||
let rng = &mut XorShiftRng::from_seed([42; 16]);
|
||||
let spec = &ForkName::Deneb.make_genesis_spec(MainnetEthSpec::default_spec());
|
||||
|
||||
@@ -840,6 +923,26 @@ mod tests {
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn roundtrip_electra_block() {
|
||||
let rng = &mut XorShiftRng::from_seed([42; 16]);
|
||||
let spec = &ForkName::Electra.make_genesis_spec(MainnetEthSpec::default_spec());
|
||||
|
||||
let inner_block = BeaconBlockElectra {
|
||||
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: BeaconBlockBodyElectra::random_for_test(rng),
|
||||
};
|
||||
|
||||
let block = BeaconBlock::Electra(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;
|
||||
@@ -857,10 +960,13 @@ mod tests {
|
||||
let capella_slot = capella_epoch.start_slot(E::slots_per_epoch());
|
||||
let deneb_epoch = capella_epoch + 1;
|
||||
let deneb_slot = deneb_epoch.start_slot(E::slots_per_epoch());
|
||||
let electra_epoch = deneb_epoch + 1;
|
||||
let electra_slot = electra_epoch.start_slot(E::slots_per_epoch());
|
||||
|
||||
spec.altair_fork_epoch = Some(altair_epoch);
|
||||
spec.capella_fork_epoch = Some(capella_epoch);
|
||||
spec.deneb_fork_epoch = Some(deneb_epoch);
|
||||
spec.electra_fork_epoch = Some(electra_epoch);
|
||||
|
||||
// BeaconBlockBase
|
||||
{
|
||||
@@ -934,7 +1040,7 @@ mod tests {
|
||||
slot: deneb_slot,
|
||||
..<_>::random_for_test(rng)
|
||||
});
|
||||
// It's invalid to have an Capella block with a epoch lower than the fork epoch.
|
||||
// It's invalid to have a Deneb block with a epoch lower than the fork epoch.
|
||||
let bad_block = {
|
||||
let mut bad = good_block.clone();
|
||||
*bad.slot_mut() = capella_slot;
|
||||
@@ -949,5 +1055,28 @@ mod tests {
|
||||
BeaconBlock::from_ssz_bytes(&bad_block.as_ssz_bytes(), &spec)
|
||||
.expect_err("bad deneb block cannot be decoded");
|
||||
}
|
||||
|
||||
// BeaconBlockElectra
|
||||
{
|
||||
let good_block = BeaconBlock::Electra(BeaconBlockElectra {
|
||||
slot: electra_slot,
|
||||
..<_>::random_for_test(rng)
|
||||
});
|
||||
// It's invalid to have an Electra block with a epoch lower than the fork epoch.
|
||||
let bad_block = {
|
||||
let mut bad = good_block.clone();
|
||||
*bad.slot_mut() = deneb_slot;
|
||||
bad
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
BeaconBlock::from_ssz_bytes(&good_block.as_ssz_bytes(), &spec)
|
||||
.expect("good electra block can be decoded"),
|
||||
good_block
|
||||
);
|
||||
// TODO(electra): once the Electra block is changed from Deneb, update this to match
|
||||
// the other forks.
|
||||
assert!(BeaconBlock::from_ssz_bytes(&bad_block.as_ssz_bytes(), &spec).is_ok());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ pub const BLOB_KZG_COMMITMENTS_INDEX: usize = 11;
|
||||
///
|
||||
/// This *superstruct* abstracts over the hard-fork.
|
||||
#[superstruct(
|
||||
variants(Base, Altair, Merge, Capella, Deneb),
|
||||
variants(Base, Altair, Merge, Capella, Deneb, Electra),
|
||||
variant_attributes(
|
||||
derive(
|
||||
Debug,
|
||||
@@ -67,7 +67,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, Deneb))]
|
||||
#[superstruct(only(Altair, Merge, Capella, Deneb, Electra))]
|
||||
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
|
||||
@@ -81,10 +81,13 @@ pub struct BeaconBlockBody<T: EthSpec, Payload: AbstractExecPayload<T> = FullPay
|
||||
#[superstruct(only(Deneb), partial_getter(rename = "execution_payload_deneb"))]
|
||||
#[serde(flatten)]
|
||||
pub execution_payload: Payload::Deneb,
|
||||
#[superstruct(only(Capella, Deneb))]
|
||||
#[superstruct(only(Electra), partial_getter(rename = "execution_payload_electra"))]
|
||||
#[serde(flatten)]
|
||||
pub execution_payload: Payload::Electra,
|
||||
#[superstruct(only(Capella, Deneb, Electra))]
|
||||
pub bls_to_execution_changes:
|
||||
VariableList<SignedBlsToExecutionChange, T::MaxBlsToExecutionChanges>,
|
||||
#[superstruct(only(Deneb))]
|
||||
#[superstruct(only(Deneb, Electra))]
|
||||
pub blob_kzg_commitments: KzgCommitments<T>,
|
||||
#[superstruct(only(Base, Altair))]
|
||||
#[ssz(skip_serializing, skip_deserializing)]
|
||||
@@ -107,6 +110,7 @@ impl<'a, T: EthSpec, Payload: AbstractExecPayload<T>> BeaconBlockBodyRef<'a, T,
|
||||
Self::Merge(body) => Ok(Payload::Ref::from(&body.execution_payload)),
|
||||
Self::Capella(body) => Ok(Payload::Ref::from(&body.execution_payload)),
|
||||
Self::Deneb(body) => Ok(Payload::Ref::from(&body.execution_payload)),
|
||||
Self::Electra(body) => Ok(Payload::Ref::from(&body.execution_payload)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,6 +181,67 @@ impl<'a, T: EthSpec, Payload: AbstractExecPayload<T>> BeaconBlockBodyRef<'a, T,
|
||||
// Join the proofs for the subtree and the main tree
|
||||
proof.append(&mut proof_body);
|
||||
|
||||
debug_assert_eq!(proof.len(), T::kzg_proof_inclusion_proof_depth());
|
||||
Ok(proof.into())
|
||||
}
|
||||
// TODO(electra): De-duplicate proof computation.
|
||||
Self::Electra(body) => {
|
||||
// We compute the branches by generating 2 merkle trees:
|
||||
// 1. Merkle tree for the `blob_kzg_commitments` List object
|
||||
// 2. Merkle tree for the `BeaconBlockBody` container
|
||||
// We then merge the branches for both the trees all the way up to the root.
|
||||
|
||||
// Part1 (Branches for the subtree rooted at `blob_kzg_commitments`)
|
||||
//
|
||||
// Branches for `blob_kzg_commitments` without length mix-in
|
||||
let depth = T::max_blob_commitments_per_block()
|
||||
.next_power_of_two()
|
||||
.ilog2();
|
||||
let leaves: Vec<_> = body
|
||||
.blob_kzg_commitments
|
||||
.iter()
|
||||
.map(|commitment| commitment.tree_hash_root())
|
||||
.collect();
|
||||
let tree = MerkleTree::create(&leaves, depth as usize);
|
||||
let (_, mut proof) = tree
|
||||
.generate_proof(index, depth as usize)
|
||||
.map_err(Error::MerkleTreeError)?;
|
||||
|
||||
// Add the branch corresponding to the length mix-in.
|
||||
let length = body.blob_kzg_commitments.len();
|
||||
let usize_len = std::mem::size_of::<usize>();
|
||||
let mut length_bytes = [0; BYTES_PER_CHUNK];
|
||||
length_bytes
|
||||
.get_mut(0..usize_len)
|
||||
.ok_or(Error::MerkleTreeError(MerkleTreeError::PleaseNotifyTheDevs))?
|
||||
.copy_from_slice(&length.to_le_bytes());
|
||||
let length_root = Hash256::from_slice(length_bytes.as_slice());
|
||||
proof.push(length_root);
|
||||
|
||||
// Part 2
|
||||
// Branches for `BeaconBlockBody` container
|
||||
let leaves = [
|
||||
body.randao_reveal.tree_hash_root(),
|
||||
body.eth1_data.tree_hash_root(),
|
||||
body.graffiti.tree_hash_root(),
|
||||
body.proposer_slashings.tree_hash_root(),
|
||||
body.attester_slashings.tree_hash_root(),
|
||||
body.attestations.tree_hash_root(),
|
||||
body.deposits.tree_hash_root(),
|
||||
body.voluntary_exits.tree_hash_root(),
|
||||
body.sync_aggregate.tree_hash_root(),
|
||||
body.execution_payload.tree_hash_root(),
|
||||
body.bls_to_execution_changes.tree_hash_root(),
|
||||
body.blob_kzg_commitments.tree_hash_root(),
|
||||
];
|
||||
let beacon_block_body_depth = leaves.len().next_power_of_two().ilog2() as usize;
|
||||
let tree = MerkleTree::create(&leaves, beacon_block_body_depth);
|
||||
let (_, mut proof_body) = tree
|
||||
.generate_proof(BLOB_KZG_COMMITMENTS_INDEX, beacon_block_body_depth)
|
||||
.map_err(Error::MerkleTreeError)?;
|
||||
// Join the proofs for the subtree and the main tree
|
||||
proof.append(&mut proof_body);
|
||||
|
||||
debug_assert_eq!(proof.len(), T::kzg_proof_inclusion_proof_depth());
|
||||
Ok(proof.into())
|
||||
}
|
||||
@@ -199,6 +264,7 @@ impl<'a, T: EthSpec, Payload: AbstractExecPayload<T>> BeaconBlockBodyRef<'a, T,
|
||||
BeaconBlockBodyRef::Merge { .. } => ForkName::Merge,
|
||||
BeaconBlockBodyRef::Capella { .. } => ForkName::Capella,
|
||||
BeaconBlockBodyRef::Deneb { .. } => ForkName::Deneb,
|
||||
BeaconBlockBodyRef::Electra { .. } => ForkName::Electra,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -467,6 +533,50 @@ impl<E: EthSpec> From<BeaconBlockBodyDeneb<E, FullPayload<E>>>
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EthSpec> From<BeaconBlockBodyElectra<E, FullPayload<E>>>
|
||||
for (
|
||||
BeaconBlockBodyElectra<E, BlindedPayload<E>>,
|
||||
Option<ExecutionPayloadElectra<E>>,
|
||||
)
|
||||
{
|
||||
fn from(body: BeaconBlockBodyElectra<E, FullPayload<E>>) -> Self {
|
||||
let BeaconBlockBodyElectra {
|
||||
randao_reveal,
|
||||
eth1_data,
|
||||
graffiti,
|
||||
proposer_slashings,
|
||||
attester_slashings,
|
||||
attestations,
|
||||
deposits,
|
||||
voluntary_exits,
|
||||
sync_aggregate,
|
||||
execution_payload: FullPayloadElectra { execution_payload },
|
||||
bls_to_execution_changes,
|
||||
blob_kzg_commitments,
|
||||
} = body;
|
||||
|
||||
(
|
||||
BeaconBlockBodyElectra {
|
||||
randao_reveal,
|
||||
eth1_data,
|
||||
graffiti,
|
||||
proposer_slashings,
|
||||
attester_slashings,
|
||||
attestations,
|
||||
deposits,
|
||||
voluntary_exits,
|
||||
sync_aggregate,
|
||||
execution_payload: BlindedPayloadElectra {
|
||||
execution_payload_header: From::from(&execution_payload),
|
||||
},
|
||||
bls_to_execution_changes,
|
||||
blob_kzg_commitments: blob_kzg_commitments.clone(),
|
||||
},
|
||||
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>> {
|
||||
@@ -584,6 +694,42 @@ impl<E: EthSpec> BeaconBlockBodyDeneb<E, FullPayload<E>> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EthSpec> BeaconBlockBodyElectra<E, FullPayload<E>> {
|
||||
pub fn clone_as_blinded(&self) -> BeaconBlockBodyElectra<E, BlindedPayload<E>> {
|
||||
let BeaconBlockBodyElectra {
|
||||
randao_reveal,
|
||||
eth1_data,
|
||||
graffiti,
|
||||
proposer_slashings,
|
||||
attester_slashings,
|
||||
attestations,
|
||||
deposits,
|
||||
voluntary_exits,
|
||||
sync_aggregate,
|
||||
execution_payload: FullPayloadElectra { execution_payload },
|
||||
bls_to_execution_changes,
|
||||
blob_kzg_commitments,
|
||||
} = self;
|
||||
|
||||
BeaconBlockBodyElectra {
|
||||
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: BlindedPayloadElectra {
|
||||
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>>,
|
||||
|
||||
@@ -181,7 +181,7 @@ impl From<BeaconStateHash> for Hash256 {
|
||||
|
||||
/// The state of the `BeaconChain` at some slot.
|
||||
#[superstruct(
|
||||
variants(Base, Altair, Merge, Capella, Deneb),
|
||||
variants(Base, Altair, Merge, Capella, Deneb, Electra),
|
||||
variant_attributes(
|
||||
derive(
|
||||
Derivative,
|
||||
@@ -261,9 +261,9 @@ where
|
||||
pub current_epoch_attestations: VariableList<PendingAttestation<T>, T::MaxPendingAttestations>,
|
||||
|
||||
// Participation (Altair and later)
|
||||
#[superstruct(only(Altair, Merge, Capella, Deneb))]
|
||||
#[superstruct(only(Altair, Merge, Capella, Deneb, Electra))]
|
||||
pub previous_epoch_participation: VariableList<ParticipationFlags, T::ValidatorRegistryLimit>,
|
||||
#[superstruct(only(Altair, Merge, Capella, Deneb))]
|
||||
#[superstruct(only(Altair, Merge, Capella, Deneb, Electra))]
|
||||
pub current_epoch_participation: VariableList<ParticipationFlags, T::ValidatorRegistryLimit>,
|
||||
|
||||
// Finality
|
||||
@@ -278,13 +278,13 @@ where
|
||||
|
||||
// Inactivity
|
||||
#[serde(with = "ssz_types::serde_utils::quoted_u64_var_list")]
|
||||
#[superstruct(only(Altair, Merge, Capella, Deneb))]
|
||||
#[superstruct(only(Altair, Merge, Capella, Deneb, Electra))]
|
||||
pub inactivity_scores: VariableList<u64, T::ValidatorRegistryLimit>,
|
||||
|
||||
// Light-client sync committees
|
||||
#[superstruct(only(Altair, Merge, Capella, Deneb))]
|
||||
#[superstruct(only(Altair, Merge, Capella, Deneb, Electra))]
|
||||
pub current_sync_committee: Arc<SyncCommittee<T>>,
|
||||
#[superstruct(only(Altair, Merge, Capella, Deneb))]
|
||||
#[superstruct(only(Altair, Merge, Capella, Deneb, Electra))]
|
||||
pub next_sync_committee: Arc<SyncCommittee<T>>,
|
||||
|
||||
// Execution
|
||||
@@ -303,16 +303,21 @@ where
|
||||
partial_getter(rename = "latest_execution_payload_header_deneb")
|
||||
)]
|
||||
pub latest_execution_payload_header: ExecutionPayloadHeaderDeneb<T>,
|
||||
#[superstruct(
|
||||
only(Electra),
|
||||
partial_getter(rename = "latest_execution_payload_header_electra")
|
||||
)]
|
||||
pub latest_execution_payload_header: ExecutionPayloadHeaderElectra<T>,
|
||||
|
||||
// Capella
|
||||
#[superstruct(only(Capella, Deneb), partial_getter(copy))]
|
||||
#[superstruct(only(Capella, Deneb, Electra), partial_getter(copy))]
|
||||
#[serde(with = "serde_utils::quoted_u64")]
|
||||
pub next_withdrawal_index: u64,
|
||||
#[superstruct(only(Capella, Deneb), partial_getter(copy))]
|
||||
#[superstruct(only(Capella, Deneb, Electra), partial_getter(copy))]
|
||||
#[serde(with = "serde_utils::quoted_u64")]
|
||||
pub next_withdrawal_validator_index: u64,
|
||||
// Deep history valid from Capella onwards.
|
||||
#[superstruct(only(Capella, Deneb))]
|
||||
#[superstruct(only(Capella, Deneb, Electra))]
|
||||
pub historical_summaries: VariableList<HistoricalSummary, T::HistoricalRootsLimit>,
|
||||
|
||||
// Caching (not in the spec)
|
||||
@@ -449,6 +454,7 @@ impl<T: EthSpec> BeaconState<T> {
|
||||
BeaconState::Merge { .. } => ForkName::Merge,
|
||||
BeaconState::Capella { .. } => ForkName::Capella,
|
||||
BeaconState::Deneb { .. } => ForkName::Deneb,
|
||||
BeaconState::Electra { .. } => ForkName::Electra,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -759,6 +765,9 @@ impl<T: EthSpec> BeaconState<T> {
|
||||
BeaconState::Deneb(state) => Ok(ExecutionPayloadHeaderRef::Deneb(
|
||||
&state.latest_execution_payload_header,
|
||||
)),
|
||||
BeaconState::Electra(state) => Ok(ExecutionPayloadHeaderRef::Electra(
|
||||
&state.latest_execution_payload_header,
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -776,6 +785,9 @@ impl<T: EthSpec> BeaconState<T> {
|
||||
BeaconState::Deneb(state) => Ok(ExecutionPayloadHeaderRefMut::Deneb(
|
||||
&mut state.latest_execution_payload_header,
|
||||
)),
|
||||
BeaconState::Electra(state) => Ok(ExecutionPayloadHeaderRefMut::Electra(
|
||||
&mut state.latest_execution_payload_header,
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1227,6 +1239,11 @@ impl<T: EthSpec> BeaconState<T> {
|
||||
&mut state.balances,
|
||||
&mut state.progressive_balances_cache,
|
||||
),
|
||||
BeaconState::Electra(state) => (
|
||||
&mut state.validators,
|
||||
&mut state.balances,
|
||||
&mut state.progressive_balances_cache,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1348,7 +1365,7 @@ impl<T: EthSpec> BeaconState<T> {
|
||||
| BeaconState::Altair(_)
|
||||
| BeaconState::Merge(_)
|
||||
| BeaconState::Capella(_) => self.get_churn_limit(spec)?,
|
||||
BeaconState::Deneb(_) => std::cmp::min(
|
||||
BeaconState::Deneb(_) | BeaconState::Electra(_) => std::cmp::min(
|
||||
spec.max_per_epoch_activation_churn_limit,
|
||||
self.get_churn_limit(spec)?,
|
||||
),
|
||||
@@ -1443,6 +1460,7 @@ impl<T: EthSpec> BeaconState<T> {
|
||||
BeaconState::Merge(state) => Ok(&mut state.current_epoch_participation),
|
||||
BeaconState::Capella(state) => Ok(&mut state.current_epoch_participation),
|
||||
BeaconState::Deneb(state) => Ok(&mut state.current_epoch_participation),
|
||||
BeaconState::Electra(state) => Ok(&mut state.current_epoch_participation),
|
||||
}
|
||||
} else if epoch == self.previous_epoch() {
|
||||
match self {
|
||||
@@ -1451,6 +1469,7 @@ impl<T: EthSpec> BeaconState<T> {
|
||||
BeaconState::Merge(state) => Ok(&mut state.previous_epoch_participation),
|
||||
BeaconState::Capella(state) => Ok(&mut state.previous_epoch_participation),
|
||||
BeaconState::Deneb(state) => Ok(&mut state.previous_epoch_participation),
|
||||
BeaconState::Electra(state) => Ok(&mut state.previous_epoch_participation),
|
||||
}
|
||||
} else {
|
||||
Err(BeaconStateError::EpochOutOfBounds)
|
||||
@@ -1763,6 +1782,7 @@ impl<T: EthSpec> BeaconState<T> {
|
||||
BeaconState::Merge(inner) => BeaconState::Merge(inner.clone()),
|
||||
BeaconState::Capella(inner) => BeaconState::Capella(inner.clone()),
|
||||
BeaconState::Deneb(inner) => BeaconState::Deneb(inner.clone()),
|
||||
BeaconState::Electra(inner) => BeaconState::Electra(inner.clone()),
|
||||
};
|
||||
if config.committee_caches {
|
||||
res.committee_caches_mut()
|
||||
@@ -1943,6 +1963,7 @@ impl<T: EthSpec> CompareFields for BeaconState<T> {
|
||||
(BeaconState::Merge(x), BeaconState::Merge(y)) => x.compare_fields(y),
|
||||
(BeaconState::Capella(x), BeaconState::Capella(y)) => x.compare_fields(y),
|
||||
(BeaconState::Deneb(x), BeaconState::Deneb(y)) => x.compare_fields(y),
|
||||
(BeaconState::Electra(x), BeaconState::Electra(y)) => x.compare_fields(y),
|
||||
_ => panic!("compare_fields: mismatched state variants",),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,6 +182,7 @@ pub fn is_progressive_balances_enabled<E: EthSpec>(state: &BeaconState<E>) -> bo
|
||||
BeaconState::Altair(_)
|
||||
| BeaconState::Merge(_)
|
||||
| BeaconState::Capella(_)
|
||||
| BeaconState::Deneb(_) => true,
|
||||
| BeaconState::Deneb(_)
|
||||
| BeaconState::Electra(_) => true,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use crate::beacon_block_body::KzgCommitments;
|
||||
use crate::{
|
||||
ChainSpec, EthSpec, ExecutionPayloadHeaderCapella, ExecutionPayloadHeaderDeneb,
|
||||
ExecutionPayloadHeaderMerge, ExecutionPayloadHeaderRef, ExecutionPayloadHeaderRefMut, ForkName,
|
||||
ForkVersionDeserialize, SignedRoot, Uint256,
|
||||
ExecutionPayloadHeaderElectra, ExecutionPayloadHeaderMerge, ExecutionPayloadHeaderRef,
|
||||
ExecutionPayloadHeaderRefMut, ForkName, ForkVersionDeserialize, SignedRoot, Uint256,
|
||||
};
|
||||
use bls::PublicKeyBytes;
|
||||
use bls::Signature;
|
||||
@@ -11,7 +11,7 @@ use superstruct::superstruct;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
#[superstruct(
|
||||
variants(Merge, Capella, Deneb),
|
||||
variants(Merge, Capella, Deneb, Electra),
|
||||
variant_attributes(
|
||||
derive(PartialEq, Debug, Serialize, Deserialize, TreeHash, Clone),
|
||||
serde(bound = "E: EthSpec", deny_unknown_fields)
|
||||
@@ -29,7 +29,9 @@ pub struct BuilderBid<E: EthSpec> {
|
||||
pub header: ExecutionPayloadHeaderCapella<E>,
|
||||
#[superstruct(only(Deneb), partial_getter(rename = "header_deneb"))]
|
||||
pub header: ExecutionPayloadHeaderDeneb<E>,
|
||||
#[superstruct(only(Deneb))]
|
||||
#[superstruct(only(Electra), partial_getter(rename = "header_electra"))]
|
||||
pub header: ExecutionPayloadHeaderElectra<E>,
|
||||
#[superstruct(only(Deneb, Electra))]
|
||||
pub blob_kzg_commitments: KzgCommitments<E>,
|
||||
#[serde(with = "serde_utils::quoted_u256")]
|
||||
pub value: Uint256,
|
||||
@@ -80,6 +82,7 @@ impl<T: EthSpec> ForkVersionDeserialize for BuilderBid<T> {
|
||||
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::Deneb => Self::Deneb(serde_json::from_value(value).map_err(convert_err)?),
|
||||
ForkName::Electra => Self::Electra(serde_json::from_value(value).map_err(convert_err)?),
|
||||
ForkName::Base | ForkName::Altair => {
|
||||
return Err(serde::de::Error::custom(format!(
|
||||
"BuilderBid failed to deserialize: unsupported fork '{}'",
|
||||
|
||||
@@ -169,6 +169,13 @@ pub struct ChainSpec {
|
||||
pub deneb_fork_version: [u8; 4],
|
||||
pub deneb_fork_epoch: Option<Epoch>,
|
||||
|
||||
/*
|
||||
* Electra hard fork params
|
||||
*/
|
||||
pub electra_fork_version: [u8; 4],
|
||||
/// The Electra fork epoch is optional, with `None` representing "Electra never happens".
|
||||
pub electra_fork_epoch: Option<Epoch>,
|
||||
|
||||
/*
|
||||
* Networking
|
||||
*/
|
||||
@@ -282,15 +289,18 @@ 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.deneb_fork_epoch {
|
||||
Some(fork_epoch) if epoch >= fork_epoch => ForkName::Deneb,
|
||||
_ => 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.electra_fork_epoch {
|
||||
Some(fork_epoch) if epoch >= fork_epoch => ForkName::Electra,
|
||||
_ => match self.deneb_fork_epoch {
|
||||
Some(fork_epoch) if epoch >= fork_epoch => ForkName::Deneb,
|
||||
_ => 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,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -305,6 +315,7 @@ impl ChainSpec {
|
||||
ForkName::Merge => self.bellatrix_fork_version,
|
||||
ForkName::Capella => self.capella_fork_version,
|
||||
ForkName::Deneb => self.deneb_fork_version,
|
||||
ForkName::Electra => self.electra_fork_version,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -316,6 +327,7 @@ impl ChainSpec {
|
||||
ForkName::Merge => self.bellatrix_fork_epoch,
|
||||
ForkName::Capella => self.capella_fork_epoch,
|
||||
ForkName::Deneb => self.deneb_fork_epoch,
|
||||
ForkName::Electra => self.electra_fork_epoch,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -327,6 +339,7 @@ impl ChainSpec {
|
||||
BeaconState::Merge(_) => self.inactivity_penalty_quotient_bellatrix,
|
||||
BeaconState::Capella(_) => self.inactivity_penalty_quotient_bellatrix,
|
||||
BeaconState::Deneb(_) => self.inactivity_penalty_quotient_bellatrix,
|
||||
BeaconState::Electra(_) => self.inactivity_penalty_quotient_bellatrix,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -341,6 +354,7 @@ impl ChainSpec {
|
||||
BeaconState::Merge(_) => self.proportional_slashing_multiplier_bellatrix,
|
||||
BeaconState::Capella(_) => self.proportional_slashing_multiplier_bellatrix,
|
||||
BeaconState::Deneb(_) => self.proportional_slashing_multiplier_bellatrix,
|
||||
BeaconState::Electra(_) => self.proportional_slashing_multiplier_bellatrix,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -355,6 +369,7 @@ impl ChainSpec {
|
||||
BeaconState::Merge(_) => self.min_slashing_penalty_quotient_bellatrix,
|
||||
BeaconState::Capella(_) => self.min_slashing_penalty_quotient_bellatrix,
|
||||
BeaconState::Deneb(_) => self.min_slashing_penalty_quotient_bellatrix,
|
||||
BeaconState::Electra(_) => self.min_slashing_penalty_quotient_bellatrix,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -513,7 +528,7 @@ impl ChainSpec {
|
||||
ForkName::Base | ForkName::Altair | ForkName::Merge | ForkName::Capella => {
|
||||
self.max_blocks_by_root_request
|
||||
}
|
||||
ForkName::Deneb => self.max_blocks_by_root_request_deneb,
|
||||
ForkName::Deneb | ForkName::Electra => self.max_blocks_by_root_request_deneb,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -522,7 +537,7 @@ impl ChainSpec {
|
||||
ForkName::Base | ForkName::Altair | ForkName::Merge | ForkName::Capella => {
|
||||
self.max_request_blocks
|
||||
}
|
||||
ForkName::Deneb => self.max_request_blocks_deneb,
|
||||
ForkName::Deneb | ForkName::Electra => self.max_request_blocks_deneb,
|
||||
};
|
||||
max_request_blocks as usize
|
||||
}
|
||||
@@ -683,6 +698,12 @@ impl ChainSpec {
|
||||
deneb_fork_version: [0x04, 0x00, 0x00, 0x00],
|
||||
deneb_fork_epoch: Some(Epoch::new(269568)),
|
||||
|
||||
/*
|
||||
* Electra hard fork params
|
||||
*/
|
||||
electra_fork_version: [0x05, 00, 00, 00],
|
||||
electra_fork_epoch: None,
|
||||
|
||||
/*
|
||||
* Network specific
|
||||
*/
|
||||
@@ -779,6 +800,9 @@ impl ChainSpec {
|
||||
// Deneb
|
||||
deneb_fork_version: [0x04, 0x00, 0x00, 0x01],
|
||||
deneb_fork_epoch: None,
|
||||
// Electra
|
||||
electra_fork_version: [0x05, 0x00, 0x00, 0x01],
|
||||
electra_fork_epoch: None,
|
||||
// Other
|
||||
network_id: 2, // lighthouse testnet network id
|
||||
deposit_chain_id: 5,
|
||||
@@ -946,6 +970,12 @@ impl ChainSpec {
|
||||
deneb_fork_version: [0x04, 0x00, 0x00, 0x64],
|
||||
deneb_fork_epoch: Some(Epoch::new(889856)),
|
||||
|
||||
/*
|
||||
* Electra hard fork params
|
||||
*/
|
||||
electra_fork_version: [0x05, 0x00, 0x00, 0x64],
|
||||
electra_fork_epoch: None,
|
||||
|
||||
/*
|
||||
* Network specific
|
||||
*/
|
||||
@@ -1069,6 +1099,14 @@ pub struct Config {
|
||||
#[serde(deserialize_with = "deserialize_fork_epoch")]
|
||||
pub deneb_fork_epoch: Option<MaybeQuoted<Epoch>>,
|
||||
|
||||
#[serde(default = "default_electra_fork_version")]
|
||||
#[serde(with = "serde_utils::bytes_4_hex")]
|
||||
electra_fork_version: [u8; 4],
|
||||
#[serde(default)]
|
||||
#[serde(serialize_with = "serialize_fork_epoch")]
|
||||
#[serde(deserialize_with = "deserialize_fork_epoch")]
|
||||
pub electra_fork_epoch: Option<MaybeQuoted<Epoch>>,
|
||||
|
||||
#[serde(with = "serde_utils::quoted_u64")]
|
||||
seconds_per_slot: u64,
|
||||
#[serde(with = "serde_utils::quoted_u64")]
|
||||
@@ -1177,6 +1215,11 @@ fn default_deneb_fork_version() -> [u8; 4] {
|
||||
[0xff, 0xff, 0xff, 0xff]
|
||||
}
|
||||
|
||||
fn default_electra_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
|
||||
@@ -1386,19 +1429,27 @@ impl Config {
|
||||
altair_fork_epoch: spec
|
||||
.altair_fork_epoch
|
||||
.map(|epoch| MaybeQuoted { value: epoch }),
|
||||
|
||||
bellatrix_fork_version: spec.bellatrix_fork_version,
|
||||
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 }),
|
||||
|
||||
deneb_fork_version: spec.deneb_fork_version,
|
||||
deneb_fork_epoch: spec
|
||||
.deneb_fork_epoch
|
||||
.map(|epoch| MaybeQuoted { value: epoch }),
|
||||
|
||||
electra_fork_version: spec.electra_fork_version,
|
||||
electra_fork_epoch: spec
|
||||
.electra_fork_epoch
|
||||
.map(|epoch| MaybeQuoted { value: epoch }),
|
||||
|
||||
seconds_per_slot: spec.seconds_per_slot,
|
||||
seconds_per_eth1_block: spec.seconds_per_eth1_block,
|
||||
min_validator_withdrawability_delay: spec.min_validator_withdrawability_delay,
|
||||
@@ -1468,6 +1519,8 @@ impl Config {
|
||||
capella_fork_version,
|
||||
deneb_fork_epoch,
|
||||
deneb_fork_version,
|
||||
electra_fork_epoch,
|
||||
electra_fork_version,
|
||||
seconds_per_slot,
|
||||
seconds_per_eth1_block,
|
||||
min_validator_withdrawability_delay,
|
||||
@@ -1522,6 +1575,8 @@ impl Config {
|
||||
capella_fork_version,
|
||||
deneb_fork_epoch: deneb_fork_epoch.map(|q| q.value),
|
||||
deneb_fork_version,
|
||||
electra_fork_epoch: electra_fork_epoch.map(|q| q.value),
|
||||
electra_fork_version,
|
||||
seconds_per_slot,
|
||||
seconds_per_eth1_block,
|
||||
min_validator_withdrawability_delay,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
consts::altair, AltairPreset, BasePreset, BellatrixPreset, CapellaPreset, ChainSpec, Config,
|
||||
DenebPreset, EthSpec, ForkName,
|
||||
DenebPreset, ElectraPreset, EthSpec, ForkName,
|
||||
};
|
||||
use maplit::hashmap;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -12,7 +12,7 @@ use superstruct::superstruct;
|
||||
///
|
||||
/// Mostly useful for the API.
|
||||
#[superstruct(
|
||||
variants(Capella, Deneb),
|
||||
variants(Capella, Deneb, Electra),
|
||||
variant_attributes(derive(Serialize, Deserialize, Debug, PartialEq, Clone))
|
||||
)]
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
|
||||
@@ -29,9 +29,12 @@ pub struct ConfigAndPreset {
|
||||
pub bellatrix_preset: BellatrixPreset,
|
||||
#[serde(flatten)]
|
||||
pub capella_preset: CapellaPreset,
|
||||
#[superstruct(only(Deneb))]
|
||||
#[superstruct(only(Deneb, Electra))]
|
||||
#[serde(flatten)]
|
||||
pub deneb_preset: DenebPreset,
|
||||
#[superstruct(only(Electra))]
|
||||
#[serde(flatten)]
|
||||
pub electra_preset: ElectraPreset,
|
||||
/// The `extra_fields` map allows us to gracefully decode fields intended for future hard forks.
|
||||
#[serde(flatten)]
|
||||
pub extra_fields: HashMap<String, Value>,
|
||||
@@ -46,11 +49,29 @@ impl ConfigAndPreset {
|
||||
let capella_preset = CapellaPreset::from_chain_spec::<T>(spec);
|
||||
let extra_fields = get_extra_fields(spec);
|
||||
|
||||
if spec.deneb_fork_epoch.is_some()
|
||||
if spec.electra_fork_epoch.is_some()
|
||||
|| fork_name.is_none()
|
||||
|| fork_name == Some(ForkName::Electra)
|
||||
{
|
||||
let deneb_preset = DenebPreset::from_chain_spec::<T>(spec);
|
||||
let electra_preset = ElectraPreset::from_chain_spec::<T>(spec);
|
||||
|
||||
ConfigAndPreset::Electra(ConfigAndPresetElectra {
|
||||
config,
|
||||
base_preset,
|
||||
altair_preset,
|
||||
bellatrix_preset,
|
||||
capella_preset,
|
||||
deneb_preset,
|
||||
electra_preset,
|
||||
extra_fields,
|
||||
})
|
||||
} else if spec.deneb_fork_epoch.is_some()
|
||||
|| fork_name.is_none()
|
||||
|| fork_name == Some(ForkName::Deneb)
|
||||
{
|
||||
let deneb_preset = DenebPreset::from_chain_spec::<T>(spec);
|
||||
|
||||
ConfigAndPreset::Deneb(ConfigAndPresetDeneb {
|
||||
config,
|
||||
base_preset,
|
||||
@@ -136,8 +157,8 @@ mod test {
|
||||
.write(false)
|
||||
.open(tmp_file.as_ref())
|
||||
.expect("error while opening the file");
|
||||
let from: ConfigAndPresetDeneb =
|
||||
let from: ConfigAndPresetElectra =
|
||||
serde_yaml::from_reader(reader).expect("error while deserializing");
|
||||
assert_eq!(ConfigAndPreset::Deneb(from), yamlconfig);
|
||||
assert_eq!(ConfigAndPreset::Electra(from), yamlconfig);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,6 +134,11 @@ pub trait EthSpec:
|
||||
/// Must be set to `BytesPerFieldElement * FieldElementsPerBlob`.
|
||||
type BytesPerBlob: Unsigned + Clone + Sync + Send + Debug + PartialEq;
|
||||
|
||||
/*
|
||||
* New in Electra
|
||||
*/
|
||||
type ElectraPlaceholder: Unsigned + Clone + Sync + Send + Debug + PartialEq;
|
||||
|
||||
fn default_spec() -> ChainSpec;
|
||||
|
||||
fn spec_name() -> EthSpecId;
|
||||
@@ -273,10 +278,15 @@ pub trait EthSpec:
|
||||
fn bytes_per_blob() -> usize {
|
||||
Self::BytesPerBlob::to_usize()
|
||||
}
|
||||
|
||||
/// Returns the `KZG_COMMITMENT_INCLUSION_PROOF_DEPTH` preset for this specification.
|
||||
fn kzg_proof_inclusion_proof_depth() -> usize {
|
||||
Self::KzgCommitmentInclusionProofDepth::to_usize()
|
||||
}
|
||||
|
||||
fn electra_placeholder() -> usize {
|
||||
Self::ElectraPlaceholder::to_usize()
|
||||
}
|
||||
}
|
||||
|
||||
/// Macro to inherit some type values from another EthSpec.
|
||||
@@ -327,6 +337,7 @@ impl EthSpec for MainnetEthSpec {
|
||||
type SlotsPerEth1VotingPeriod = U2048; // 64 epochs * 32 slots per epoch
|
||||
type MaxBlsToExecutionChanges = U16;
|
||||
type MaxWithdrawalsPerPayload = U16;
|
||||
type ElectraPlaceholder = U16;
|
||||
|
||||
fn default_spec() -> ChainSpec {
|
||||
ChainSpec::mainnet()
|
||||
@@ -378,7 +389,8 @@ impl EthSpec for MinimalEthSpec {
|
||||
MaxExtraDataBytes,
|
||||
MaxBlsToExecutionChanges,
|
||||
MaxBlobsPerBlock,
|
||||
BytesPerFieldElement
|
||||
BytesPerFieldElement,
|
||||
ElectraPlaceholder
|
||||
});
|
||||
|
||||
fn default_spec() -> ChainSpec {
|
||||
@@ -430,6 +442,7 @@ impl EthSpec for GnosisEthSpec {
|
||||
type BytesPerFieldElement = U32;
|
||||
type BytesPerBlob = U131072;
|
||||
type KzgCommitmentInclusionProofDepth = U17;
|
||||
type ElectraPlaceholder = U16;
|
||||
|
||||
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, Deneb),
|
||||
variants(Merge, Capella, Deneb, Electra),
|
||||
variant_attributes(
|
||||
derive(
|
||||
Default,
|
||||
@@ -81,12 +81,12 @@ pub struct ExecutionPayload<T: EthSpec> {
|
||||
pub block_hash: ExecutionBlockHash,
|
||||
#[serde(with = "ssz_types::serde_utils::list_of_hex_var_list")]
|
||||
pub transactions: Transactions<T>,
|
||||
#[superstruct(only(Capella, Deneb))]
|
||||
#[superstruct(only(Capella, Deneb, Electra))]
|
||||
pub withdrawals: Withdrawals<T>,
|
||||
#[superstruct(only(Deneb), partial_getter(copy))]
|
||||
#[superstruct(only(Deneb, Electra), partial_getter(copy))]
|
||||
#[serde(with = "serde_utils::quoted_u64")]
|
||||
pub blob_gas_used: u64,
|
||||
#[superstruct(only(Deneb), partial_getter(copy))]
|
||||
#[superstruct(only(Deneb, Electra), partial_getter(copy))]
|
||||
#[serde(with = "serde_utils::quoted_u64")]
|
||||
pub excess_blob_gas: u64,
|
||||
}
|
||||
@@ -110,6 +110,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::Deneb => ExecutionPayloadDeneb::from_ssz_bytes(bytes).map(Self::Deneb),
|
||||
ForkName::Electra => ExecutionPayloadElectra::from_ssz_bytes(bytes).map(Self::Electra),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,6 +150,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::arithmetic_side_effects)]
|
||||
/// Returns the maximum size of an execution payload.
|
||||
pub fn max_execution_payload_electra_size() -> usize {
|
||||
// Fixed part
|
||||
ExecutionPayloadElectra::<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> {
|
||||
@@ -164,6 +178,7 @@ impl<T: EthSpec> ForkVersionDeserialize for ExecutionPayload<T> {
|
||||
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::Deneb => Self::Deneb(serde_json::from_value(value).map_err(convert_err)?),
|
||||
ForkName::Electra => Self::Electra(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 '{}'",
|
||||
@@ -180,6 +195,7 @@ impl<T: EthSpec> ExecutionPayload<T> {
|
||||
ExecutionPayload::Merge(_) => ForkName::Merge,
|
||||
ExecutionPayload::Capella(_) => ForkName::Capella,
|
||||
ExecutionPayload::Deneb(_) => ForkName::Deneb,
|
||||
ExecutionPayload::Electra(_) => ForkName::Electra,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ use tree_hash::TreeHash;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
#[superstruct(
|
||||
variants(Merge, Capella, Deneb),
|
||||
variants(Merge, Capella, Deneb, Electra),
|
||||
variant_attributes(
|
||||
derive(
|
||||
Default,
|
||||
@@ -76,14 +76,14 @@ pub struct ExecutionPayloadHeader<T: EthSpec> {
|
||||
pub block_hash: ExecutionBlockHash,
|
||||
#[superstruct(getter(copy))]
|
||||
pub transactions_root: Hash256,
|
||||
#[superstruct(only(Capella, Deneb))]
|
||||
#[superstruct(only(Capella, Deneb, Electra))]
|
||||
#[superstruct(getter(copy))]
|
||||
pub withdrawals_root: Hash256,
|
||||
#[superstruct(only(Deneb))]
|
||||
#[superstruct(only(Deneb, Electra))]
|
||||
#[serde(with = "serde_utils::quoted_u64")]
|
||||
#[superstruct(getter(copy))]
|
||||
pub blob_gas_used: u64,
|
||||
#[superstruct(only(Deneb))]
|
||||
#[superstruct(only(Deneb, Electra))]
|
||||
#[serde(with = "serde_utils::quoted_u64")]
|
||||
#[superstruct(getter(copy))]
|
||||
pub excess_blob_gas: u64,
|
||||
@@ -104,6 +104,9 @@ impl<T: EthSpec> ExecutionPayloadHeader<T> {
|
||||
ExecutionPayloadHeaderCapella::from_ssz_bytes(bytes).map(Self::Capella)
|
||||
}
|
||||
ForkName::Deneb => ExecutionPayloadHeaderDeneb::from_ssz_bytes(bytes).map(Self::Deneb),
|
||||
ForkName::Electra => {
|
||||
ExecutionPayloadHeaderElectra::from_ssz_bytes(bytes).map(Self::Electra)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -163,6 +166,30 @@ impl<T: EthSpec> ExecutionPayloadHeaderCapella<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: EthSpec> ExecutionPayloadHeaderDeneb<T> {
|
||||
pub fn upgrade_to_electra(&self) -> ExecutionPayloadHeaderElectra<T> {
|
||||
ExecutionPayloadHeaderElectra {
|
||||
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: self.withdrawals_root,
|
||||
blob_gas_used: self.blob_gas_used,
|
||||
excess_blob_gas: self.excess_blob_gas,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: EthSpec> From<&'a ExecutionPayloadMerge<T>> for ExecutionPayloadHeaderMerge<T> {
|
||||
fn from(payload: &'a ExecutionPayloadMerge<T>) -> Self {
|
||||
Self {
|
||||
@@ -183,6 +210,7 @@ impl<'a, T: EthSpec> From<&'a ExecutionPayloadMerge<T>> for ExecutionPayloadHead
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: EthSpec> From<&'a ExecutionPayloadCapella<T>> for ExecutionPayloadHeaderCapella<T> {
|
||||
fn from(payload: &'a ExecutionPayloadCapella<T>) -> Self {
|
||||
Self {
|
||||
@@ -229,6 +257,30 @@ impl<'a, T: EthSpec> From<&'a ExecutionPayloadDeneb<T>> for ExecutionPayloadHead
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: EthSpec> From<&'a ExecutionPayloadElectra<T>> for ExecutionPayloadHeaderElectra<T> {
|
||||
fn from(payload: &'a ExecutionPayloadElectra<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(),
|
||||
blob_gas_used: payload.blob_gas_used,
|
||||
excess_blob_gas: payload.excess_blob_gas,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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> {
|
||||
@@ -249,6 +301,12 @@ impl<'a, T: EthSpec> From<&'a Self> for ExecutionPayloadHeaderDeneb<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: EthSpec> From<&'a Self> for ExecutionPayloadHeaderElectra<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!(
|
||||
@@ -289,6 +347,18 @@ impl<T: EthSpec> TryFrom<ExecutionPayloadHeader<T>> for ExecutionPayloadHeaderDe
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: EthSpec> TryFrom<ExecutionPayloadHeader<T>> for ExecutionPayloadHeaderElectra<T> {
|
||||
type Error = BeaconStateError;
|
||||
fn try_from(header: ExecutionPayloadHeader<T>) -> Result<Self, Self::Error> {
|
||||
match header {
|
||||
ExecutionPayloadHeader::Electra(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,
|
||||
@@ -305,6 +375,7 @@ impl<T: EthSpec> ForkVersionDeserialize for ExecutionPayloadHeader<T> {
|
||||
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::Deneb => Self::Deneb(serde_json::from_value(value).map_err(convert_err)?),
|
||||
ForkName::Electra => Self::Electra(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 '{}'",
|
||||
|
||||
@@ -62,6 +62,13 @@ impl ForkContext {
|
||||
));
|
||||
}
|
||||
|
||||
if spec.electra_fork_epoch.is_some() {
|
||||
fork_to_digest.push((
|
||||
ForkName::Electra,
|
||||
ChainSpec::compute_fork_digest(spec.electra_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
|
||||
|
||||
@@ -14,6 +14,7 @@ pub enum ForkName {
|
||||
Merge,
|
||||
Capella,
|
||||
Deneb,
|
||||
Electra,
|
||||
}
|
||||
|
||||
impl ForkName {
|
||||
@@ -24,6 +25,7 @@ impl ForkName {
|
||||
ForkName::Merge,
|
||||
ForkName::Capella,
|
||||
ForkName::Deneb,
|
||||
ForkName::Electra,
|
||||
]
|
||||
}
|
||||
|
||||
@@ -42,6 +44,7 @@ impl ForkName {
|
||||
spec.bellatrix_fork_epoch = None;
|
||||
spec.capella_fork_epoch = None;
|
||||
spec.deneb_fork_epoch = None;
|
||||
spec.electra_fork_epoch = None;
|
||||
spec
|
||||
}
|
||||
ForkName::Altair => {
|
||||
@@ -49,6 +52,7 @@ impl ForkName {
|
||||
spec.bellatrix_fork_epoch = None;
|
||||
spec.capella_fork_epoch = None;
|
||||
spec.deneb_fork_epoch = None;
|
||||
spec.electra_fork_epoch = None;
|
||||
spec
|
||||
}
|
||||
ForkName::Merge => {
|
||||
@@ -56,6 +60,7 @@ impl ForkName {
|
||||
spec.bellatrix_fork_epoch = Some(Epoch::new(0));
|
||||
spec.capella_fork_epoch = None;
|
||||
spec.deneb_fork_epoch = None;
|
||||
spec.electra_fork_epoch = None;
|
||||
spec
|
||||
}
|
||||
ForkName::Capella => {
|
||||
@@ -63,6 +68,7 @@ impl ForkName {
|
||||
spec.bellatrix_fork_epoch = Some(Epoch::new(0));
|
||||
spec.capella_fork_epoch = Some(Epoch::new(0));
|
||||
spec.deneb_fork_epoch = None;
|
||||
spec.electra_fork_epoch = None;
|
||||
spec
|
||||
}
|
||||
ForkName::Deneb => {
|
||||
@@ -70,6 +76,15 @@ impl ForkName {
|
||||
spec.bellatrix_fork_epoch = Some(Epoch::new(0));
|
||||
spec.capella_fork_epoch = Some(Epoch::new(0));
|
||||
spec.deneb_fork_epoch = Some(Epoch::new(0));
|
||||
spec.electra_fork_epoch = None;
|
||||
spec
|
||||
}
|
||||
ForkName::Electra => {
|
||||
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.deneb_fork_epoch = Some(Epoch::new(0));
|
||||
spec.electra_fork_epoch = Some(Epoch::new(0));
|
||||
spec
|
||||
}
|
||||
}
|
||||
@@ -85,6 +100,7 @@ impl ForkName {
|
||||
ForkName::Merge => Some(ForkName::Altair),
|
||||
ForkName::Capella => Some(ForkName::Merge),
|
||||
ForkName::Deneb => Some(ForkName::Capella),
|
||||
ForkName::Electra => Some(ForkName::Deneb),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,7 +113,8 @@ impl ForkName {
|
||||
ForkName::Altair => Some(ForkName::Merge),
|
||||
ForkName::Merge => Some(ForkName::Capella),
|
||||
ForkName::Capella => Some(ForkName::Deneb),
|
||||
ForkName::Deneb => None,
|
||||
ForkName::Deneb => Some(ForkName::Electra),
|
||||
ForkName::Electra => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -147,6 +164,10 @@ macro_rules! map_fork_name_with {
|
||||
let (value, extra_data) = $body;
|
||||
($t::Deneb(value), extra_data)
|
||||
}
|
||||
ForkName::Electra => {
|
||||
let (value, extra_data) = $body;
|
||||
($t::Electra(value), extra_data)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -161,6 +182,7 @@ impl FromStr for ForkName {
|
||||
"bellatrix" | "merge" => ForkName::Merge,
|
||||
"capella" => ForkName::Capella,
|
||||
"deneb" => ForkName::Deneb,
|
||||
"electra" => ForkName::Electra,
|
||||
_ => return Err(format!("unknown fork name: {}", fork_name)),
|
||||
})
|
||||
}
|
||||
@@ -174,6 +196,7 @@ impl Display for ForkName {
|
||||
ForkName::Merge => "bellatrix".fmt(f),
|
||||
ForkName::Capella => "capella".fmt(f),
|
||||
ForkName::Deneb => "deneb".fmt(f),
|
||||
ForkName::Electra => "electra".fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,11 +112,13 @@ pub use crate::attestation_duty::AttestationDuty;
|
||||
pub use crate::attester_slashing::AttesterSlashing;
|
||||
pub use crate::beacon_block::{
|
||||
BeaconBlock, BeaconBlockAltair, BeaconBlockBase, BeaconBlockCapella, BeaconBlockDeneb,
|
||||
BeaconBlockMerge, BeaconBlockRef, BeaconBlockRefMut, BlindedBeaconBlock, EmptyBlock,
|
||||
BeaconBlockElectra, BeaconBlockMerge, BeaconBlockRef, BeaconBlockRefMut, BlindedBeaconBlock,
|
||||
EmptyBlock,
|
||||
};
|
||||
pub use crate::beacon_block_body::{
|
||||
BeaconBlockBody, BeaconBlockBodyAltair, BeaconBlockBodyBase, BeaconBlockBodyCapella,
|
||||
BeaconBlockBodyDeneb, BeaconBlockBodyMerge, BeaconBlockBodyRef, BeaconBlockBodyRefMut,
|
||||
BeaconBlockBodyDeneb, BeaconBlockBodyElectra, BeaconBlockBodyMerge, BeaconBlockBodyRef,
|
||||
BeaconBlockBodyRefMut,
|
||||
};
|
||||
pub use crate::beacon_block_header::BeaconBlockHeader;
|
||||
pub use crate::beacon_committee::{BeaconCommittee, OwnedBeaconCommittee};
|
||||
@@ -125,7 +127,9 @@ pub use crate::blob_sidecar::{BlobSidecar, BlobSidecarList, BlobsList};
|
||||
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, ConfigAndPresetCapella, ConfigAndPresetDeneb};
|
||||
pub use crate::config_and_preset::{
|
||||
ConfigAndPreset, ConfigAndPresetCapella, ConfigAndPresetDeneb, ConfigAndPresetElectra,
|
||||
};
|
||||
pub use crate::contribution_and_proof::ContributionAndProof;
|
||||
pub use crate::deposit::{Deposit, DEPOSIT_TREE_DEPTH};
|
||||
pub use crate::deposit_data::DepositData;
|
||||
@@ -137,12 +141,13 @@ 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, ExecutionPayloadDeneb, ExecutionPayloadMerge,
|
||||
ExecutionPayloadRef, Transaction, Transactions, Withdrawals,
|
||||
ExecutionPayload, ExecutionPayloadCapella, ExecutionPayloadDeneb, ExecutionPayloadElectra,
|
||||
ExecutionPayloadMerge, ExecutionPayloadRef, Transaction, Transactions, Withdrawals,
|
||||
};
|
||||
pub use crate::execution_payload_header::{
|
||||
ExecutionPayloadHeader, ExecutionPayloadHeaderCapella, ExecutionPayloadHeaderDeneb,
|
||||
ExecutionPayloadHeaderMerge, ExecutionPayloadHeaderRef, ExecutionPayloadHeaderRefMut,
|
||||
ExecutionPayloadHeaderElectra, ExecutionPayloadHeaderMerge, ExecutionPayloadHeaderRef,
|
||||
ExecutionPayloadHeaderRefMut,
|
||||
};
|
||||
pub use crate::fork::Fork;
|
||||
pub use crate::fork_context::ForkContext;
|
||||
@@ -175,11 +180,14 @@ pub use crate::participation_flags::ParticipationFlags;
|
||||
pub use crate::participation_list::ParticipationList;
|
||||
pub use crate::payload::{
|
||||
AbstractExecPayload, BlindedPayload, BlindedPayloadCapella, BlindedPayloadDeneb,
|
||||
BlindedPayloadMerge, BlindedPayloadRef, BlockType, ExecPayload, FullPayload,
|
||||
FullPayloadCapella, FullPayloadDeneb, FullPayloadMerge, FullPayloadRef, OwnedExecPayload,
|
||||
BlindedPayloadElectra, BlindedPayloadMerge, BlindedPayloadRef, BlockType, ExecPayload,
|
||||
FullPayload, FullPayloadCapella, FullPayloadDeneb, FullPayloadElectra, FullPayloadMerge,
|
||||
FullPayloadRef, OwnedExecPayload,
|
||||
};
|
||||
pub use crate::pending_attestation::PendingAttestation;
|
||||
pub use crate::preset::{AltairPreset, BasePreset, BellatrixPreset, CapellaPreset, DenebPreset};
|
||||
pub use crate::preset::{
|
||||
AltairPreset, BasePreset, BellatrixPreset, CapellaPreset, DenebPreset, ElectraPreset,
|
||||
};
|
||||
pub use crate::proposer_preparation_data::ProposerPreparationData;
|
||||
pub use crate::proposer_slashing::ProposerSlashing;
|
||||
pub use crate::relative_epoch::{Error as RelativeEpochError, RelativeEpoch};
|
||||
@@ -190,8 +198,8 @@ pub use crate::signed_aggregate_and_proof::SignedAggregateAndProof;
|
||||
pub use crate::signed_beacon_block::{
|
||||
ssz_tagged_signed_beacon_block, ssz_tagged_signed_beacon_block_arc, SignedBeaconBlock,
|
||||
SignedBeaconBlockAltair, SignedBeaconBlockBase, SignedBeaconBlockCapella,
|
||||
SignedBeaconBlockDeneb, SignedBeaconBlockHash, SignedBeaconBlockMerge,
|
||||
SignedBlindedBeaconBlock,
|
||||
SignedBeaconBlockDeneb, SignedBeaconBlockElectra, SignedBeaconBlockHash,
|
||||
SignedBeaconBlockMerge, SignedBlindedBeaconBlock,
|
||||
};
|
||||
pub use crate::signed_beacon_block_header::SignedBeaconBlockHeader;
|
||||
pub use crate::signed_bls_to_execution_change::SignedBlsToExecutionChange;
|
||||
|
||||
@@ -69,16 +69,11 @@ impl<E: EthSpec> LightClientBootstrap<E> {
|
||||
pub fn from_ssz_bytes(bytes: &[u8], fork_name: ForkName) -> Result<Self, ssz::DecodeError> {
|
||||
let bootstrap = match fork_name {
|
||||
ForkName::Altair | ForkName::Merge => {
|
||||
let header = LightClientBootstrapAltair::from_ssz_bytes(bytes)?;
|
||||
Self::Altair(header)
|
||||
Self::Altair(LightClientBootstrapAltair::from_ssz_bytes(bytes)?)
|
||||
}
|
||||
ForkName::Capella => {
|
||||
let header = LightClientBootstrapCapella::from_ssz_bytes(bytes)?;
|
||||
Self::Capella(header)
|
||||
}
|
||||
ForkName::Deneb => {
|
||||
let header = LightClientBootstrapDeneb::from_ssz_bytes(bytes)?;
|
||||
Self::Deneb(header)
|
||||
ForkName::Capella => Self::Capella(LightClientBootstrapCapella::from_ssz_bytes(bytes)?),
|
||||
ForkName::Deneb | ForkName::Electra => {
|
||||
Self::Deneb(LightClientBootstrapDeneb::from_ssz_bytes(bytes)?)
|
||||
}
|
||||
ForkName::Base => {
|
||||
return Err(ssz::DecodeError::BytesInvalid(format!(
|
||||
@@ -117,7 +112,7 @@ impl<E: EthSpec> LightClientBootstrap<E> {
|
||||
current_sync_committee,
|
||||
current_sync_committee_branch,
|
||||
}),
|
||||
ForkName::Deneb => Self::Deneb(LightClientBootstrapDeneb {
|
||||
ForkName::Deneb | ForkName::Electra => Self::Deneb(LightClientBootstrapDeneb {
|
||||
header: LightClientHeaderDeneb::block_to_light_client_header(block)?,
|
||||
current_sync_committee,
|
||||
current_sync_committee_branch,
|
||||
@@ -134,14 +129,12 @@ impl<E: EthSpec> ForkVersionDeserialize for LightClientBootstrap<E> {
|
||||
fork_name: ForkName,
|
||||
) -> Result<Self, D::Error> {
|
||||
match fork_name {
|
||||
ForkName::Altair | ForkName::Merge | ForkName::Capella | ForkName::Deneb => {
|
||||
Ok(serde_json::from_value::<LightClientBootstrap<E>>(value)
|
||||
.map_err(serde::de::Error::custom))?
|
||||
}
|
||||
ForkName::Base => Err(serde::de::Error::custom(format!(
|
||||
"LightClientBootstrap failed to deserialize: unsupported fork '{}'",
|
||||
fork_name
|
||||
))),
|
||||
_ => Ok(serde_json::from_value::<LightClientBootstrap<E>>(value)
|
||||
.map_err(serde::de::Error::custom))?,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ impl<E: EthSpec> LightClientFinalityUpdate<E> {
|
||||
};
|
||||
Self::Capella(finality_update)
|
||||
}
|
||||
ForkName::Deneb => {
|
||||
ForkName::Deneb | ForkName::Electra => {
|
||||
let finality_update = LightClientFinalityUpdateDeneb {
|
||||
attested_header: LightClientHeaderDeneb::block_to_light_client_header(
|
||||
attested_block,
|
||||
@@ -136,16 +136,13 @@ impl<E: EthSpec> LightClientFinalityUpdate<E> {
|
||||
pub fn from_ssz_bytes(bytes: &[u8], fork_name: ForkName) -> Result<Self, ssz::DecodeError> {
|
||||
let finality_update = match fork_name {
|
||||
ForkName::Altair | ForkName::Merge => {
|
||||
let finality_update = LightClientFinalityUpdateAltair::from_ssz_bytes(bytes)?;
|
||||
Self::Altair(finality_update)
|
||||
Self::Altair(LightClientFinalityUpdateAltair::from_ssz_bytes(bytes)?)
|
||||
}
|
||||
ForkName::Capella => {
|
||||
let finality_update = LightClientFinalityUpdateCapella::from_ssz_bytes(bytes)?;
|
||||
Self::Capella(finality_update)
|
||||
Self::Capella(LightClientFinalityUpdateCapella::from_ssz_bytes(bytes)?)
|
||||
}
|
||||
ForkName::Deneb => {
|
||||
let finality_update = LightClientFinalityUpdateDeneb::from_ssz_bytes(bytes)?;
|
||||
Self::Deneb(finality_update)
|
||||
ForkName::Deneb | ForkName::Electra => {
|
||||
Self::Deneb(LightClientFinalityUpdateDeneb::from_ssz_bytes(bytes)?)
|
||||
}
|
||||
ForkName::Base => {
|
||||
return Err(ssz::DecodeError::BytesInvalid(format!(
|
||||
@@ -164,14 +161,14 @@ impl<E: EthSpec> ForkVersionDeserialize for LightClientFinalityUpdate<E> {
|
||||
fork_name: ForkName,
|
||||
) -> Result<Self, D::Error> {
|
||||
match fork_name {
|
||||
ForkName::Altair | ForkName::Merge | ForkName::Capella | ForkName::Deneb => Ok(
|
||||
serde_json::from_value::<LightClientFinalityUpdate<E>>(value)
|
||||
.map_err(serde::de::Error::custom),
|
||||
)?,
|
||||
ForkName::Base => Err(serde::de::Error::custom(format!(
|
||||
"LightClientFinalityUpdate failed to deserialize: unsupported fork '{}'",
|
||||
fork_name
|
||||
))),
|
||||
_ => Ok(
|
||||
serde_json::from_value::<LightClientFinalityUpdate<E>>(value)
|
||||
.map_err(serde::de::Error::custom),
|
||||
)?,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ impl<E: EthSpec> LightClientHeader<E> {
|
||||
ForkName::Capella => LightClientHeader::Capella(
|
||||
LightClientHeaderCapella::block_to_light_client_header(block)?,
|
||||
),
|
||||
ForkName::Deneb => LightClientHeader::Deneb(
|
||||
ForkName::Deneb | ForkName::Electra => LightClientHeader::Deneb(
|
||||
LightClientHeaderDeneb::block_to_light_client_header(block)?,
|
||||
),
|
||||
};
|
||||
@@ -91,16 +91,13 @@ impl<E: EthSpec> LightClientHeader<E> {
|
||||
pub fn from_ssz_bytes(bytes: &[u8], fork_name: ForkName) -> Result<Self, ssz::DecodeError> {
|
||||
let header = match fork_name {
|
||||
ForkName::Altair | ForkName::Merge => {
|
||||
let header = LightClientHeaderAltair::from_ssz_bytes(bytes)?;
|
||||
LightClientHeader::Altair(header)
|
||||
LightClientHeader::Altair(LightClientHeaderAltair::from_ssz_bytes(bytes)?)
|
||||
}
|
||||
ForkName::Capella => {
|
||||
let header = LightClientHeaderCapella::from_ssz_bytes(bytes)?;
|
||||
LightClientHeader::Capella(header)
|
||||
LightClientHeader::Capella(LightClientHeaderCapella::from_ssz_bytes(bytes)?)
|
||||
}
|
||||
ForkName::Deneb => {
|
||||
let header = LightClientHeaderDeneb::from_ssz_bytes(bytes)?;
|
||||
LightClientHeader::Deneb(header)
|
||||
ForkName::Deneb | ForkName::Electra => {
|
||||
LightClientHeader::Deneb(LightClientHeaderDeneb::from_ssz_bytes(bytes)?)
|
||||
}
|
||||
ForkName::Base => {
|
||||
return Err(ssz::DecodeError::BytesInvalid(format!(
|
||||
@@ -198,7 +195,7 @@ impl<T: EthSpec> ForkVersionDeserialize for LightClientHeader<T> {
|
||||
ForkName::Capella => serde_json::from_value(value)
|
||||
.map(|light_client_header| Self::Capella(light_client_header))
|
||||
.map_err(serde::de::Error::custom),
|
||||
ForkName::Deneb => serde_json::from_value(value)
|
||||
ForkName::Deneb | ForkName::Electra => serde_json::from_value(value)
|
||||
.map(|light_client_header| Self::Deneb(light_client_header))
|
||||
.map_err(serde::de::Error::custom),
|
||||
ForkName::Base => Err(serde::de::Error::custom(format!(
|
||||
|
||||
@@ -70,36 +70,27 @@ impl<E: EthSpec> LightClientOptimisticUpdate<E> {
|
||||
.fork_name(chain_spec)
|
||||
.map_err(|_| Error::InconsistentFork)?
|
||||
{
|
||||
ForkName::Altair | ForkName::Merge => {
|
||||
let optimistic_update = LightClientOptimisticUpdateAltair {
|
||||
attested_header: LightClientHeaderAltair::block_to_light_client_header(
|
||||
attested_block,
|
||||
)?,
|
||||
sync_aggregate,
|
||||
signature_slot,
|
||||
};
|
||||
Self::Altair(optimistic_update)
|
||||
}
|
||||
ForkName::Capella => {
|
||||
let optimistic_update = LightClientOptimisticUpdateCapella {
|
||||
attested_header: LightClientHeaderCapella::block_to_light_client_header(
|
||||
attested_block,
|
||||
)?,
|
||||
sync_aggregate,
|
||||
signature_slot,
|
||||
};
|
||||
Self::Capella(optimistic_update)
|
||||
}
|
||||
ForkName::Deneb => {
|
||||
let optimistic_update = LightClientOptimisticUpdateDeneb {
|
||||
attested_header: LightClientHeaderDeneb::block_to_light_client_header(
|
||||
attested_block,
|
||||
)?,
|
||||
sync_aggregate,
|
||||
signature_slot,
|
||||
};
|
||||
Self::Deneb(optimistic_update)
|
||||
}
|
||||
ForkName::Altair | ForkName::Merge => Self::Altair(LightClientOptimisticUpdateAltair {
|
||||
attested_header: LightClientHeaderAltair::block_to_light_client_header(
|
||||
attested_block,
|
||||
)?,
|
||||
sync_aggregate,
|
||||
signature_slot,
|
||||
}),
|
||||
ForkName::Capella => Self::Capella(LightClientOptimisticUpdateCapella {
|
||||
attested_header: LightClientHeaderCapella::block_to_light_client_header(
|
||||
attested_block,
|
||||
)?,
|
||||
sync_aggregate,
|
||||
signature_slot,
|
||||
}),
|
||||
ForkName::Deneb | ForkName::Electra => Self::Deneb(LightClientOptimisticUpdateDeneb {
|
||||
attested_header: LightClientHeaderDeneb::block_to_light_client_header(
|
||||
attested_block,
|
||||
)?,
|
||||
sync_aggregate,
|
||||
signature_slot,
|
||||
}),
|
||||
ForkName::Base => return Err(Error::AltairForkNotActive),
|
||||
};
|
||||
|
||||
@@ -130,16 +121,13 @@ impl<E: EthSpec> LightClientOptimisticUpdate<E> {
|
||||
pub fn from_ssz_bytes(bytes: &[u8], fork_name: ForkName) -> Result<Self, ssz::DecodeError> {
|
||||
let optimistic_update = match fork_name {
|
||||
ForkName::Altair | ForkName::Merge => {
|
||||
let optimistic_update = LightClientOptimisticUpdateAltair::from_ssz_bytes(bytes)?;
|
||||
Self::Altair(optimistic_update)
|
||||
Self::Altair(LightClientOptimisticUpdateAltair::from_ssz_bytes(bytes)?)
|
||||
}
|
||||
ForkName::Capella => {
|
||||
let optimistic_update = LightClientOptimisticUpdateCapella::from_ssz_bytes(bytes)?;
|
||||
Self::Capella(optimistic_update)
|
||||
Self::Capella(LightClientOptimisticUpdateCapella::from_ssz_bytes(bytes)?)
|
||||
}
|
||||
ForkName::Deneb => {
|
||||
let optimistic_update = LightClientOptimisticUpdateDeneb::from_ssz_bytes(bytes)?;
|
||||
Self::Deneb(optimistic_update)
|
||||
ForkName::Deneb | ForkName::Electra => {
|
||||
Self::Deneb(LightClientOptimisticUpdateDeneb::from_ssz_bytes(bytes)?)
|
||||
}
|
||||
ForkName::Base => {
|
||||
return Err(ssz::DecodeError::BytesInvalid(format!(
|
||||
@@ -158,14 +146,14 @@ impl<T: EthSpec> ForkVersionDeserialize for LightClientOptimisticUpdate<T> {
|
||||
fork_name: ForkName,
|
||||
) -> Result<Self, D::Error> {
|
||||
match fork_name {
|
||||
ForkName::Altair | ForkName::Merge | ForkName::Capella | ForkName::Deneb => Ok(
|
||||
serde_json::from_value::<LightClientOptimisticUpdate<T>>(value)
|
||||
.map_err(serde::de::Error::custom),
|
||||
)?,
|
||||
ForkName::Base => Err(serde::de::Error::custom(format!(
|
||||
"LightClientOptimisticUpdate failed to deserialize: unsupported fork '{}'",
|
||||
fork_name
|
||||
))),
|
||||
_ => Ok(
|
||||
serde_json::from_value::<LightClientOptimisticUpdate<T>>(value)
|
||||
.map_err(serde::de::Error::custom),
|
||||
)?,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,14 +129,12 @@ impl<E: EthSpec> ForkVersionDeserialize for LightClientUpdate<E> {
|
||||
fork_name: ForkName,
|
||||
) -> Result<Self, D::Error> {
|
||||
match fork_name {
|
||||
ForkName::Altair | ForkName::Merge | ForkName::Capella | ForkName::Deneb => {
|
||||
Ok(serde_json::from_value::<LightClientUpdate<E>>(value)
|
||||
.map_err(serde::de::Error::custom))?
|
||||
}
|
||||
ForkName::Base => Err(serde::de::Error::custom(format!(
|
||||
"LightClientUpdate failed to deserialize: unsupported fork '{}'",
|
||||
fork_name
|
||||
))),
|
||||
_ => Ok(serde_json::from_value::<LightClientUpdate<E>>(value)
|
||||
.map_err(serde::de::Error::custom))?,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -216,7 +214,7 @@ impl<E: EthSpec> LightClientUpdate<E> {
|
||||
signature_slot: block.slot(),
|
||||
})
|
||||
}
|
||||
ForkName::Deneb => {
|
||||
ForkName::Deneb | ForkName::Electra => {
|
||||
let attested_header =
|
||||
LightClientHeaderDeneb::block_to_light_client_header(attested_block)?;
|
||||
let finalized_header =
|
||||
@@ -239,16 +237,11 @@ impl<E: EthSpec> LightClientUpdate<E> {
|
||||
pub fn from_ssz_bytes(bytes: &[u8], fork_name: ForkName) -> Result<Self, ssz::DecodeError> {
|
||||
let update = match fork_name {
|
||||
ForkName::Altair | ForkName::Merge => {
|
||||
let update = LightClientUpdateAltair::from_ssz_bytes(bytes)?;
|
||||
Self::Altair(update)
|
||||
Self::Altair(LightClientUpdateAltair::from_ssz_bytes(bytes)?)
|
||||
}
|
||||
ForkName::Capella => {
|
||||
let update = LightClientUpdateCapella::from_ssz_bytes(bytes)?;
|
||||
Self::Capella(update)
|
||||
}
|
||||
ForkName::Deneb => {
|
||||
let update = LightClientUpdateDeneb::from_ssz_bytes(bytes)?;
|
||||
Self::Deneb(update)
|
||||
ForkName::Capella => Self::Capella(LightClientUpdateCapella::from_ssz_bytes(bytes)?),
|
||||
ForkName::Deneb | ForkName::Electra => {
|
||||
Self::Deneb(LightClientUpdateDeneb::from_ssz_bytes(bytes)?)
|
||||
}
|
||||
ForkName::Base => {
|
||||
return Err(ssz::DecodeError::BytesInvalid(format!(
|
||||
|
||||
@@ -82,12 +82,14 @@ pub trait AbstractExecPayload<T: EthSpec>:
|
||||
+ TryInto<Self::Merge>
|
||||
+ TryInto<Self::Capella>
|
||||
+ TryInto<Self::Deneb>
|
||||
+ TryInto<Self::Electra>
|
||||
{
|
||||
type Ref<'a>: ExecPayload<T>
|
||||
+ Copy
|
||||
+ From<&'a Self::Merge>
|
||||
+ From<&'a Self::Capella>
|
||||
+ From<&'a Self::Deneb>;
|
||||
+ From<&'a Self::Deneb>
|
||||
+ From<&'a Self::Electra>;
|
||||
|
||||
type Merge: OwnedExecPayload<T>
|
||||
+ Into<Self>
|
||||
@@ -101,10 +103,14 @@ pub trait AbstractExecPayload<T: EthSpec>:
|
||||
+ Into<Self>
|
||||
+ for<'a> From<Cow<'a, ExecutionPayloadDeneb<T>>>
|
||||
+ TryFrom<ExecutionPayloadHeaderDeneb<T>>;
|
||||
type Electra: OwnedExecPayload<T>
|
||||
+ Into<Self>
|
||||
+ for<'a> From<Cow<'a, ExecutionPayloadElectra<T>>>
|
||||
+ TryFrom<ExecutionPayloadHeaderElectra<T>>;
|
||||
}
|
||||
|
||||
#[superstruct(
|
||||
variants(Merge, Capella, Deneb),
|
||||
variants(Merge, Capella, Deneb, Electra),
|
||||
variant_attributes(
|
||||
derive(
|
||||
Debug,
|
||||
@@ -145,6 +151,8 @@ pub struct FullPayload<T: EthSpec> {
|
||||
pub execution_payload: ExecutionPayloadCapella<T>,
|
||||
#[superstruct(only(Deneb), partial_getter(rename = "execution_payload_deneb"))]
|
||||
pub execution_payload: ExecutionPayloadDeneb<T>,
|
||||
#[superstruct(only(Electra), partial_getter(rename = "execution_payload_electra"))]
|
||||
pub execution_payload: ExecutionPayloadElectra<T>,
|
||||
}
|
||||
|
||||
impl<T: EthSpec> From<FullPayload<T>> for ExecutionPayload<T> {
|
||||
@@ -251,6 +259,9 @@ impl<T: EthSpec> ExecPayload<T> for FullPayload<T> {
|
||||
FullPayload::Deneb(ref inner) => {
|
||||
Ok(inner.execution_payload.withdrawals.tree_hash_root())
|
||||
}
|
||||
FullPayload::Electra(ref inner) => {
|
||||
Ok(inner.execution_payload.withdrawals.tree_hash_root())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -258,6 +269,7 @@ impl<T: EthSpec> ExecPayload<T> for FullPayload<T> {
|
||||
match self {
|
||||
FullPayload::Merge(_) | FullPayload::Capella(_) => Err(Error::IncorrectStateVariant),
|
||||
FullPayload::Deneb(ref inner) => Ok(inner.execution_payload.blob_gas_used),
|
||||
FullPayload::Electra(ref inner) => Ok(inner.execution_payload.blob_gas_used),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -287,6 +299,7 @@ impl<T: EthSpec> FullPayload<T> {
|
||||
ForkName::Merge => Ok(FullPayloadMerge::default().into()),
|
||||
ForkName::Capella => Ok(FullPayloadCapella::default().into()),
|
||||
ForkName::Deneb => Ok(FullPayloadDeneb::default().into()),
|
||||
ForkName::Electra => Ok(FullPayloadElectra::default().into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -376,6 +389,9 @@ impl<'b, T: EthSpec> ExecPayload<T> for FullPayloadRef<'b, T> {
|
||||
FullPayloadRef::Deneb(inner) => {
|
||||
Ok(inner.execution_payload.withdrawals.tree_hash_root())
|
||||
}
|
||||
FullPayloadRef::Electra(inner) => {
|
||||
Ok(inner.execution_payload.withdrawals.tree_hash_root())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -385,6 +401,7 @@ impl<'b, T: EthSpec> ExecPayload<T> for FullPayloadRef<'b, T> {
|
||||
Err(Error::IncorrectStateVariant)
|
||||
}
|
||||
FullPayloadRef::Deneb(inner) => Ok(inner.execution_payload.blob_gas_used),
|
||||
FullPayloadRef::Electra(inner) => Ok(inner.execution_payload.blob_gas_used),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -406,6 +423,7 @@ impl<T: EthSpec> AbstractExecPayload<T> for FullPayload<T> {
|
||||
type Merge = FullPayloadMerge<T>;
|
||||
type Capella = FullPayloadCapella<T>;
|
||||
type Deneb = FullPayloadDeneb<T>;
|
||||
type Electra = FullPayloadElectra<T>;
|
||||
}
|
||||
|
||||
impl<T: EthSpec> From<ExecutionPayload<T>> for FullPayload<T> {
|
||||
@@ -424,7 +442,7 @@ impl<T: EthSpec> TryFrom<ExecutionPayloadHeader<T>> for FullPayload<T> {
|
||||
}
|
||||
|
||||
#[superstruct(
|
||||
variants(Merge, Capella, Deneb),
|
||||
variants(Merge, Capella, Deneb, Electra),
|
||||
variant_attributes(
|
||||
derive(
|
||||
Debug,
|
||||
@@ -464,6 +482,8 @@ pub struct BlindedPayload<T: EthSpec> {
|
||||
pub execution_payload_header: ExecutionPayloadHeaderCapella<T>,
|
||||
#[superstruct(only(Deneb), partial_getter(rename = "execution_payload_deneb"))]
|
||||
pub execution_payload_header: ExecutionPayloadHeaderDeneb<T>,
|
||||
#[superstruct(only(Electra), partial_getter(rename = "execution_payload_electra"))]
|
||||
pub execution_payload_header: ExecutionPayloadHeaderElectra<T>,
|
||||
}
|
||||
|
||||
impl<'a, T: EthSpec> From<BlindedPayloadRef<'a, T>> for BlindedPayload<T> {
|
||||
@@ -546,6 +566,9 @@ impl<T: EthSpec> ExecPayload<T> for BlindedPayload<T> {
|
||||
Ok(inner.execution_payload_header.withdrawals_root)
|
||||
}
|
||||
BlindedPayload::Deneb(ref inner) => Ok(inner.execution_payload_header.withdrawals_root),
|
||||
BlindedPayload::Electra(ref inner) => {
|
||||
Ok(inner.execution_payload_header.withdrawals_root)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -555,6 +578,7 @@ impl<T: EthSpec> ExecPayload<T> for BlindedPayload<T> {
|
||||
Err(Error::IncorrectStateVariant)
|
||||
}
|
||||
BlindedPayload::Deneb(ref inner) => Ok(inner.execution_payload_header.blob_gas_used),
|
||||
BlindedPayload::Electra(ref inner) => Ok(inner.execution_payload_header.blob_gas_used),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -643,6 +667,9 @@ impl<'b, T: EthSpec> ExecPayload<T> for BlindedPayloadRef<'b, T> {
|
||||
Ok(inner.execution_payload_header.withdrawals_root)
|
||||
}
|
||||
BlindedPayloadRef::Deneb(inner) => Ok(inner.execution_payload_header.withdrawals_root),
|
||||
BlindedPayloadRef::Electra(inner) => {
|
||||
Ok(inner.execution_payload_header.withdrawals_root)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -652,6 +679,7 @@ impl<'b, T: EthSpec> ExecPayload<T> for BlindedPayloadRef<'b, T> {
|
||||
Err(Error::IncorrectStateVariant)
|
||||
}
|
||||
BlindedPayloadRef::Deneb(inner) => Ok(inner.execution_payload_header.blob_gas_used),
|
||||
BlindedPayloadRef::Electra(inner) => Ok(inner.execution_payload_header.blob_gas_used),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -944,12 +972,20 @@ impl_exec_payload_for_fork!(
|
||||
ExecutionPayloadDeneb,
|
||||
Deneb
|
||||
);
|
||||
impl_exec_payload_for_fork!(
|
||||
BlindedPayloadElectra,
|
||||
FullPayloadElectra,
|
||||
ExecutionPayloadHeaderElectra,
|
||||
ExecutionPayloadElectra,
|
||||
Electra
|
||||
);
|
||||
|
||||
impl<T: EthSpec> AbstractExecPayload<T> for BlindedPayload<T> {
|
||||
type Ref<'a> = BlindedPayloadRef<'a, T>;
|
||||
type Merge = BlindedPayloadMerge<T>;
|
||||
type Capella = BlindedPayloadCapella<T>;
|
||||
type Deneb = BlindedPayloadDeneb<T>;
|
||||
type Electra = BlindedPayloadElectra<T>;
|
||||
}
|
||||
|
||||
impl<T: EthSpec> From<ExecutionPayload<T>> for BlindedPayload<T> {
|
||||
@@ -981,6 +1017,11 @@ impl<T: EthSpec> From<ExecutionPayloadHeader<T>> for BlindedPayload<T> {
|
||||
execution_payload_header,
|
||||
})
|
||||
}
|
||||
ExecutionPayloadHeader::Electra(execution_payload_header) => {
|
||||
Self::Electra(BlindedPayloadElectra {
|
||||
execution_payload_header,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -997,6 +1038,9 @@ impl<T: EthSpec> From<BlindedPayload<T>> for ExecutionPayloadHeader<T> {
|
||||
BlindedPayload::Deneb(blinded_payload) => {
|
||||
ExecutionPayloadHeader::Deneb(blinded_payload.execution_payload_header)
|
||||
}
|
||||
BlindedPayload::Electra(blinded_payload) => {
|
||||
ExecutionPayloadHeader::Electra(blinded_payload.execution_payload_header)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,6 +226,21 @@ impl DenebPreset {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "UPPERCASE")]
|
||||
pub struct ElectraPreset {
|
||||
#[serde(with = "serde_utils::quoted_u64")]
|
||||
pub electra_placeholder: u64,
|
||||
}
|
||||
|
||||
impl ElectraPreset {
|
||||
pub fn from_chain_spec<T: EthSpec>(_spec: &ChainSpec) -> Self {
|
||||
Self {
|
||||
electra_placeholder: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
@@ -267,6 +282,9 @@ mod test {
|
||||
|
||||
let deneb: DenebPreset = preset_from_file(&preset_name, "deneb.yaml");
|
||||
assert_eq!(deneb, DenebPreset::from_chain_spec::<E>(&spec));
|
||||
|
||||
let electra: ElectraPreset = preset_from_file(&preset_name, "electra.yaml");
|
||||
assert_eq!(electra, ElectraPreset::from_chain_spec::<E>(&spec));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -37,7 +37,7 @@ impl From<SignedBeaconBlockHash> for Hash256 {
|
||||
|
||||
/// A `BeaconBlock` and a signature from its proposer.
|
||||
#[superstruct(
|
||||
variants(Base, Altair, Merge, Capella, Deneb),
|
||||
variants(Base, Altair, Merge, Capella, Deneb, Electra),
|
||||
variant_attributes(
|
||||
derive(
|
||||
Debug,
|
||||
@@ -78,6 +78,8 @@ pub struct SignedBeaconBlock<E: EthSpec, Payload: AbstractExecPayload<E> = FullP
|
||||
pub message: BeaconBlockCapella<E, Payload>,
|
||||
#[superstruct(only(Deneb), partial_getter(rename = "message_deneb"))]
|
||||
pub message: BeaconBlockDeneb<E, Payload>,
|
||||
#[superstruct(only(Electra), partial_getter(rename = "message_electra"))]
|
||||
pub message: BeaconBlockElectra<E, Payload>,
|
||||
pub signature: Signature,
|
||||
}
|
||||
|
||||
@@ -157,6 +159,9 @@ impl<E: EthSpec, Payload: AbstractExecPayload<E>> SignedBeaconBlock<E, Payload>
|
||||
BeaconBlock::Deneb(message) => {
|
||||
SignedBeaconBlock::Deneb(SignedBeaconBlockDeneb { message, signature })
|
||||
}
|
||||
BeaconBlock::Electra(message) => {
|
||||
SignedBeaconBlock::Electra(SignedBeaconBlockElectra { message, signature })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -467,6 +472,62 @@ impl<E: EthSpec> SignedBeaconBlockDeneb<E, BlindedPayload<E>> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EthSpec> SignedBeaconBlockElectra<E, BlindedPayload<E>> {
|
||||
pub fn into_full_block(
|
||||
self,
|
||||
execution_payload: ExecutionPayloadElectra<E>,
|
||||
) -> SignedBeaconBlockElectra<E, FullPayload<E>> {
|
||||
let SignedBeaconBlockElectra {
|
||||
message:
|
||||
BeaconBlockElectra {
|
||||
slot,
|
||||
proposer_index,
|
||||
parent_root,
|
||||
state_root,
|
||||
body:
|
||||
BeaconBlockBodyElectra {
|
||||
randao_reveal,
|
||||
eth1_data,
|
||||
graffiti,
|
||||
proposer_slashings,
|
||||
attester_slashings,
|
||||
attestations,
|
||||
deposits,
|
||||
voluntary_exits,
|
||||
sync_aggregate,
|
||||
execution_payload: BlindedPayloadElectra { .. },
|
||||
bls_to_execution_changes,
|
||||
blob_kzg_commitments,
|
||||
},
|
||||
},
|
||||
signature,
|
||||
} = self;
|
||||
SignedBeaconBlockElectra {
|
||||
message: BeaconBlockElectra {
|
||||
slot,
|
||||
proposer_index,
|
||||
parent_root,
|
||||
state_root,
|
||||
body: BeaconBlockBodyElectra {
|
||||
randao_reveal,
|
||||
eth1_data,
|
||||
graffiti,
|
||||
proposer_slashings,
|
||||
attester_slashings,
|
||||
attestations,
|
||||
deposits,
|
||||
voluntary_exits,
|
||||
sync_aggregate,
|
||||
execution_payload: FullPayloadElectra { execution_payload },
|
||||
bls_to_execution_changes,
|
||||
blob_kzg_commitments,
|
||||
},
|
||||
},
|
||||
signature,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EthSpec> SignedBeaconBlock<E, BlindedPayload<E>> {
|
||||
pub fn try_into_full_block(
|
||||
self,
|
||||
@@ -484,11 +545,15 @@ impl<E: EthSpec> SignedBeaconBlock<E, BlindedPayload<E>> {
|
||||
(SignedBeaconBlock::Deneb(block), Some(ExecutionPayload::Deneb(payload))) => {
|
||||
SignedBeaconBlock::Deneb(block.into_full_block(payload))
|
||||
}
|
||||
(SignedBeaconBlock::Electra(block), Some(ExecutionPayload::Electra(payload))) => {
|
||||
SignedBeaconBlock::Electra(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::Deneb(_), _) => return None,
|
||||
(SignedBeaconBlock::Electra(_), _) => return None,
|
||||
};
|
||||
Some(full_block)
|
||||
}
|
||||
@@ -631,6 +696,9 @@ pub mod ssz_tagged_signed_beacon_block {
|
||||
ForkName::Deneb => Ok(SignedBeaconBlock::Deneb(
|
||||
SignedBeaconBlockDeneb::from_ssz_bytes(body)?,
|
||||
)),
|
||||
ForkName::Electra => Ok(SignedBeaconBlock::Electra(
|
||||
SignedBeaconBlockElectra::from_ssz_bytes(body)?,
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -722,7 +790,14 @@ mod test {
|
||||
BeaconBlock::Capella(BeaconBlockCapella::empty(spec)),
|
||||
sig.clone(),
|
||||
),
|
||||
SignedBeaconBlock::from_block(BeaconBlock::Deneb(BeaconBlockDeneb::empty(spec)), sig),
|
||||
SignedBeaconBlock::from_block(
|
||||
BeaconBlock::Deneb(BeaconBlockDeneb::empty(spec)),
|
||||
sig.clone(),
|
||||
),
|
||||
SignedBeaconBlock::from_block(
|
||||
BeaconBlock::Electra(BeaconBlockElectra::empty(spec)),
|
||||
sig,
|
||||
),
|
||||
];
|
||||
|
||||
for block in blocks {
|
||||
|
||||
@@ -46,7 +46,7 @@ impl VoluntaryExit {
|
||||
spec.fork_version_for_name(fork_name)
|
||||
}
|
||||
// EIP-7044
|
||||
ForkName::Deneb => spec.fork_version_for_name(ForkName::Capella),
|
||||
ForkName::Deneb | ForkName::Electra => spec.fork_version_for_name(ForkName::Capella),
|
||||
};
|
||||
let domain =
|
||||
spec.compute_domain(Domain::VoluntaryExit, fork_version, genesis_validators_root);
|
||||
|
||||
Reference in New Issue
Block a user