Add electra lightclient types

This commit is contained in:
dapplion
2024-06-21 14:36:02 +02:00
parent 27ed90e4dc
commit 8715589e40
7 changed files with 181 additions and 92 deletions

View File

@@ -118,12 +118,8 @@ impl<E: EthSpec> ExecutionPayloadHeader<E> {
pub fn ssz_max_var_len_for_fork(fork_name: ForkName) -> usize { pub fn ssz_max_var_len_for_fork(fork_name: ForkName) -> usize {
// Matching here in case variable fields are added in future forks. // Matching here in case variable fields are added in future forks.
match fork_name { match fork_name {
ForkName::Base ForkName::Base | ForkName::Altair => 0,
| ForkName::Altair ForkName::Bellatrix | ForkName::Capella | ForkName::Deneb | ForkName::Electra => {
| ForkName::Bellatrix
| ForkName::Capella
| ForkName::Deneb
| ForkName::Electra => {
// Max size of variable length `extra_data` field // Max size of variable length `extra_data` field
E::max_extra_data_bytes() * <u8 as Encode>::ssz_fixed_len() E::max_extra_data_bytes() * <u8 as Encode>::ssz_fixed_len()
} }

View File

@@ -181,22 +181,24 @@ pub use crate::indexed_attestation::{
}; };
pub use crate::light_client_bootstrap::{ pub use crate::light_client_bootstrap::{
LightClientBootstrap, LightClientBootstrapAltair, LightClientBootstrapCapella, LightClientBootstrap, LightClientBootstrapAltair, LightClientBootstrapCapella,
LightClientBootstrapDeneb, LightClientBootstrapDeneb, LightClientBootstrapElectra,
}; };
pub use crate::light_client_finality_update::{ pub use crate::light_client_finality_update::{
LightClientFinalityUpdate, LightClientFinalityUpdateAltair, LightClientFinalityUpdateCapella, LightClientFinalityUpdate, LightClientFinalityUpdateAltair, LightClientFinalityUpdateCapella,
LightClientFinalityUpdateDeneb, LightClientFinalityUpdateDeneb, LightClientFinalityUpdateElectra,
}; };
pub use crate::light_client_header::{ pub use crate::light_client_header::{
LightClientHeader, LightClientHeaderAltair, LightClientHeaderCapella, LightClientHeaderDeneb, LightClientHeader, LightClientHeaderAltair, LightClientHeaderCapella, LightClientHeaderDeneb,
LightClientHeaderElectra,
}; };
pub use crate::light_client_optimistic_update::{ pub use crate::light_client_optimistic_update::{
LightClientOptimisticUpdate, LightClientOptimisticUpdateAltair, LightClientOptimisticUpdate, LightClientOptimisticUpdateAltair,
LightClientOptimisticUpdateCapella, LightClientOptimisticUpdateDeneb, LightClientOptimisticUpdateCapella, LightClientOptimisticUpdateDeneb,
LightClientOptimisticUpdateElectra,
}; };
pub use crate::light_client_update::{ pub use crate::light_client_update::{
Error as LightClientError, LightClientUpdate, LightClientUpdateAltair, Error as LightClientError, LightClientUpdate, LightClientUpdateAltair,
LightClientUpdateCapella, LightClientUpdateDeneb, LightClientUpdateCapella, LightClientUpdateDeneb, LightClientUpdateElectra,
}; };
pub use crate::participation_flags::ParticipationFlags; pub use crate::participation_flags::ParticipationFlags;
pub use crate::participation_list::ParticipationList; pub use crate::participation_list::ParticipationList;

View File

@@ -1,7 +1,8 @@
use crate::{ use crate::{
light_client_update::*, test_utils::TestRandom, BeaconState, ChainSpec, EthSpec, FixedVector, light_client_update::*, test_utils::TestRandom, BeaconState, ChainSpec, EthSpec, FixedVector,
ForkName, ForkVersionDeserialize, Hash256, LightClientHeader, LightClientHeaderAltair, ForkName, ForkVersionDeserialize, Hash256, LightClientHeader, LightClientHeaderAltair,
LightClientHeaderCapella, LightClientHeaderDeneb, SignedBeaconBlock, Slot, SyncCommittee, LightClientHeaderCapella, LightClientHeaderDeneb, LightClientHeaderElectra, SignedBeaconBlock,
Slot, SyncCommittee,
}; };
use derivative::Derivative; use derivative::Derivative;
use serde::{Deserialize, Deserializer, Serialize}; use serde::{Deserialize, Deserializer, Serialize};
@@ -16,7 +17,7 @@ use tree_hash_derive::TreeHash;
/// A LightClientBootstrap is the initializer we send over to light_client nodes /// A LightClientBootstrap is the initializer we send over to light_client nodes
/// that are trying to generate their basic storage when booting up. /// that are trying to generate their basic storage when booting up.
#[superstruct( #[superstruct(
variants(Altair, Capella, Deneb), variants(Altair, Capella, Deneb, Electra),
variant_attributes( variant_attributes(
derive( derive(
Debug, Debug,
@@ -51,6 +52,8 @@ pub struct LightClientBootstrap<E: EthSpec> {
pub header: LightClientHeaderCapella<E>, pub header: LightClientHeaderCapella<E>,
#[superstruct(only(Deneb), partial_getter(rename = "header_deneb"))] #[superstruct(only(Deneb), partial_getter(rename = "header_deneb"))]
pub header: LightClientHeaderDeneb<E>, pub header: LightClientHeaderDeneb<E>,
#[superstruct(only(Electra), partial_getter(rename = "header_electra"))]
pub header: LightClientHeaderElectra<E>,
/// The `SyncCommittee` used in the requested period. /// The `SyncCommittee` used in the requested period.
pub current_sync_committee: Arc<SyncCommittee<E>>, pub current_sync_committee: Arc<SyncCommittee<E>>,
/// Merkle proof for sync committee /// Merkle proof for sync committee
@@ -66,6 +69,7 @@ impl<E: EthSpec> LightClientBootstrap<E> {
Self::Altair(_) => func(ForkName::Altair), Self::Altair(_) => func(ForkName::Altair),
Self::Capella(_) => func(ForkName::Capella), Self::Capella(_) => func(ForkName::Capella),
Self::Deneb(_) => func(ForkName::Deneb), Self::Deneb(_) => func(ForkName::Deneb),
Self::Electra(_) => func(ForkName::Electra),
} }
} }
@@ -82,9 +86,8 @@ impl<E: EthSpec> LightClientBootstrap<E> {
Self::Altair(LightClientBootstrapAltair::from_ssz_bytes(bytes)?) Self::Altair(LightClientBootstrapAltair::from_ssz_bytes(bytes)?)
} }
ForkName::Capella => Self::Capella(LightClientBootstrapCapella::from_ssz_bytes(bytes)?), ForkName::Capella => Self::Capella(LightClientBootstrapCapella::from_ssz_bytes(bytes)?),
ForkName::Deneb | ForkName::Electra => { ForkName::Deneb => Self::Deneb(LightClientBootstrapDeneb::from_ssz_bytes(bytes)?),
Self::Deneb(LightClientBootstrapDeneb::from_ssz_bytes(bytes)?) ForkName::Electra => Self::Electra(LightClientBootstrapElectra::from_ssz_bytes(bytes)?),
}
ForkName::Base => { ForkName::Base => {
return Err(ssz::DecodeError::BytesInvalid(format!( return Err(ssz::DecodeError::BytesInvalid(format!(
"LightClientBootstrap decoding for {fork_name} not implemented" "LightClientBootstrap decoding for {fork_name} not implemented"
@@ -97,18 +100,16 @@ impl<E: EthSpec> LightClientBootstrap<E> {
#[allow(clippy::arithmetic_side_effects)] #[allow(clippy::arithmetic_side_effects)]
pub fn ssz_max_len_for_fork(fork_name: ForkName) -> usize { pub fn ssz_max_len_for_fork(fork_name: ForkName) -> usize {
// TODO(electra): review electra changes let fixed_len = match fork_name {
match fork_name {
ForkName::Base => 0, ForkName::Base => 0,
ForkName::Altair ForkName::Altair | ForkName::Bellatrix => {
| ForkName::Bellatrix
| ForkName::Capella
| ForkName::Deneb
| ForkName::Electra => {
<LightClientBootstrapAltair<E> as Encode>::ssz_fixed_len() <LightClientBootstrapAltair<E> as Encode>::ssz_fixed_len()
+ LightClientHeader::<E>::ssz_max_var_len_for_fork(fork_name)
}
} }
ForkName::Capella => <LightClientBootstrapCapella<E> as Encode>::ssz_fixed_len(),
ForkName::Deneb => <LightClientBootstrapDeneb<E> as Encode>::ssz_fixed_len(),
ForkName::Electra => <LightClientBootstrapElectra<E> as Encode>::ssz_fixed_len(),
};
fixed_len + LightClientHeader::<E>::ssz_max_var_len_for_fork(fork_name)
} }
pub fn from_beacon_state( pub fn from_beacon_state(
@@ -138,11 +139,16 @@ impl<E: EthSpec> LightClientBootstrap<E> {
current_sync_committee, current_sync_committee,
current_sync_committee_branch, current_sync_committee_branch,
}), }),
ForkName::Deneb | ForkName::Electra => Self::Deneb(LightClientBootstrapDeneb { ForkName::Deneb => Self::Deneb(LightClientBootstrapDeneb {
header: LightClientHeaderDeneb::block_to_light_client_header(block)?, header: LightClientHeaderDeneb::block_to_light_client_header(block)?,
current_sync_committee, current_sync_committee,
current_sync_committee_branch, current_sync_committee_branch,
}), }),
ForkName::Electra => Self::Electra(LightClientBootstrapElectra {
header: LightClientHeaderElectra::block_to_light_client_header(block)?,
current_sync_committee,
current_sync_committee_branch,
}),
}; };
Ok(light_client_bootstrap) Ok(light_client_bootstrap)

View File

@@ -2,7 +2,8 @@ use super::{EthSpec, FixedVector, Hash256, LightClientHeader, Slot, SyncAggregat
use crate::ChainSpec; use crate::ChainSpec;
use crate::{ use crate::{
light_client_update::*, test_utils::TestRandom, ForkName, ForkVersionDeserialize, light_client_update::*, test_utils::TestRandom, ForkName, ForkVersionDeserialize,
LightClientHeaderAltair, LightClientHeaderCapella, LightClientHeaderDeneb, SignedBeaconBlock, LightClientHeaderAltair, LightClientHeaderCapella, LightClientHeaderDeneb,
LightClientHeaderElectra, SignedBeaconBlock,
}; };
use derivative::Derivative; use derivative::Derivative;
use serde::{Deserialize, Deserializer, Serialize}; use serde::{Deserialize, Deserializer, Serialize};
@@ -15,7 +16,7 @@ use test_random_derive::TestRandom;
use tree_hash_derive::TreeHash; use tree_hash_derive::TreeHash;
#[superstruct( #[superstruct(
variants(Altair, Capella, Deneb), variants(Altair, Capella, Deneb, Electra),
variant_attributes( variant_attributes(
derive( derive(
Debug, Debug,
@@ -50,6 +51,8 @@ pub struct LightClientFinalityUpdate<E: EthSpec> {
pub attested_header: LightClientHeaderCapella<E>, pub attested_header: LightClientHeaderCapella<E>,
#[superstruct(only(Deneb), partial_getter(rename = "attested_header_deneb"))] #[superstruct(only(Deneb), partial_getter(rename = "attested_header_deneb"))]
pub attested_header: LightClientHeaderDeneb<E>, pub attested_header: LightClientHeaderDeneb<E>,
#[superstruct(only(Electra), partial_getter(rename = "attested_header_electra"))]
pub attested_header: LightClientHeaderElectra<E>,
/// The last `BeaconBlockHeader` from the last attested finalized block (end of epoch). /// The last `BeaconBlockHeader` from the last attested finalized block (end of epoch).
#[superstruct(only(Altair), partial_getter(rename = "finalized_header_altair"))] #[superstruct(only(Altair), partial_getter(rename = "finalized_header_altair"))]
pub finalized_header: LightClientHeaderAltair<E>, pub finalized_header: LightClientHeaderAltair<E>,
@@ -57,6 +60,8 @@ pub struct LightClientFinalityUpdate<E: EthSpec> {
pub finalized_header: LightClientHeaderCapella<E>, pub finalized_header: LightClientHeaderCapella<E>,
#[superstruct(only(Deneb), partial_getter(rename = "finalized_header_deneb"))] #[superstruct(only(Deneb), partial_getter(rename = "finalized_header_deneb"))]
pub finalized_header: LightClientHeaderDeneb<E>, pub finalized_header: LightClientHeaderDeneb<E>,
#[superstruct(only(Electra), partial_getter(rename = "finalized_header_electra"))]
pub finalized_header: LightClientHeaderElectra<E>,
/// Merkle proof attesting finalized header. /// Merkle proof attesting finalized header.
#[test_random(default)] #[test_random(default)]
pub finality_branch: FixedVector<Hash256, FinalizedRootProofLen>, pub finality_branch: FixedVector<Hash256, FinalizedRootProofLen>,
@@ -80,7 +85,7 @@ impl<E: EthSpec> LightClientFinalityUpdate<E> {
.map_err(|_| Error::InconsistentFork)? .map_err(|_| Error::InconsistentFork)?
{ {
ForkName::Altair | ForkName::Bellatrix => { ForkName::Altair | ForkName::Bellatrix => {
let finality_update = LightClientFinalityUpdateAltair { Self::Altair(LightClientFinalityUpdateAltair {
attested_header: LightClientHeaderAltair::block_to_light_client_header( attested_header: LightClientHeaderAltair::block_to_light_client_header(
attested_block, attested_block,
)?, )?,
@@ -90,11 +95,9 @@ impl<E: EthSpec> LightClientFinalityUpdate<E> {
finality_branch, finality_branch,
sync_aggregate, sync_aggregate,
signature_slot, signature_slot,
}; })
Self::Altair(finality_update)
} }
ForkName::Capella => { ForkName::Capella => Self::Capella(LightClientFinalityUpdateCapella {
let finality_update = LightClientFinalityUpdateCapella {
attested_header: LightClientHeaderCapella::block_to_light_client_header( attested_header: LightClientHeaderCapella::block_to_light_client_header(
attested_block, attested_block,
)?, )?,
@@ -104,11 +107,8 @@ impl<E: EthSpec> LightClientFinalityUpdate<E> {
finality_branch, finality_branch,
sync_aggregate, sync_aggregate,
signature_slot, signature_slot,
}; }),
Self::Capella(finality_update) ForkName::Deneb => Self::Deneb(LightClientFinalityUpdateDeneb {
}
ForkName::Deneb | ForkName::Electra => {
let finality_update = LightClientFinalityUpdateDeneb {
attested_header: LightClientHeaderDeneb::block_to_light_client_header( attested_header: LightClientHeaderDeneb::block_to_light_client_header(
attested_block, attested_block,
)?, )?,
@@ -118,9 +118,19 @@ impl<E: EthSpec> LightClientFinalityUpdate<E> {
finality_branch, finality_branch,
sync_aggregate, sync_aggregate,
signature_slot, signature_slot,
}; }),
Self::Deneb(finality_update) ForkName::Electra => Self::Electra(LightClientFinalityUpdateElectra {
} attested_header: LightClientHeaderElectra::block_to_light_client_header(
attested_block,
)?,
finalized_header: LightClientHeaderElectra::block_to_light_client_header(
finalized_block,
)?,
finality_branch,
sync_aggregate,
signature_slot,
}),
ForkName::Base => return Err(Error::AltairForkNotActive), ForkName::Base => return Err(Error::AltairForkNotActive),
}; };
@@ -135,6 +145,7 @@ impl<E: EthSpec> LightClientFinalityUpdate<E> {
Self::Altair(_) => func(ForkName::Altair), Self::Altair(_) => func(ForkName::Altair),
Self::Capella(_) => func(ForkName::Capella), Self::Capella(_) => func(ForkName::Capella),
Self::Deneb(_) => func(ForkName::Deneb), Self::Deneb(_) => func(ForkName::Deneb),
Self::Electra(_) => func(ForkName::Electra),
} }
} }
@@ -153,8 +164,9 @@ impl<E: EthSpec> LightClientFinalityUpdate<E> {
ForkName::Capella => { ForkName::Capella => {
Self::Capella(LightClientFinalityUpdateCapella::from_ssz_bytes(bytes)?) Self::Capella(LightClientFinalityUpdateCapella::from_ssz_bytes(bytes)?)
} }
ForkName::Deneb | ForkName::Electra => { ForkName::Deneb => Self::Deneb(LightClientFinalityUpdateDeneb::from_ssz_bytes(bytes)?),
Self::Deneb(LightClientFinalityUpdateDeneb::from_ssz_bytes(bytes)?) ForkName::Electra => {
Self::Electra(LightClientFinalityUpdateElectra::from_ssz_bytes(bytes)?)
} }
ForkName::Base => { ForkName::Base => {
return Err(ssz::DecodeError::BytesInvalid(format!( return Err(ssz::DecodeError::BytesInvalid(format!(
@@ -168,18 +180,17 @@ impl<E: EthSpec> LightClientFinalityUpdate<E> {
#[allow(clippy::arithmetic_side_effects)] #[allow(clippy::arithmetic_side_effects)]
pub fn ssz_max_len_for_fork(fork_name: ForkName) -> usize { pub fn ssz_max_len_for_fork(fork_name: ForkName) -> usize {
// TODO(electra): review electra changes let fixed_size = match fork_name {
match fork_name {
ForkName::Base => 0, ForkName::Base => 0,
ForkName::Altair ForkName::Altair | ForkName::Bellatrix => {
| ForkName::Bellatrix
| ForkName::Capella
| ForkName::Deneb
| ForkName::Electra => {
<LightClientFinalityUpdateAltair<E> as Encode>::ssz_fixed_len() <LightClientFinalityUpdateAltair<E> as Encode>::ssz_fixed_len()
+ 2 * LightClientHeader::<E>::ssz_max_var_len_for_fork(fork_name)
}
} }
ForkName::Capella => <LightClientFinalityUpdateCapella<E> as Encode>::ssz_fixed_len(),
ForkName::Deneb => <LightClientFinalityUpdateDeneb<E> as Encode>::ssz_fixed_len(),
ForkName::Electra => <LightClientFinalityUpdateElectra<E> as Encode>::ssz_fixed_len(),
};
// `2 *` because there are two headers in the update
fixed_size + 2 * LightClientHeader::<E>::ssz_max_var_len_for_fork(fork_name)
} }
} }

View File

@@ -4,7 +4,7 @@ use crate::ForkVersionDeserialize;
use crate::{light_client_update::*, BeaconBlockBody}; use crate::{light_client_update::*, BeaconBlockBody};
use crate::{ use crate::{
test_utils::TestRandom, EthSpec, ExecutionPayloadHeaderCapella, ExecutionPayloadHeaderDeneb, test_utils::TestRandom, EthSpec, ExecutionPayloadHeaderCapella, ExecutionPayloadHeaderDeneb,
FixedVector, Hash256, SignedBeaconBlock, ExecutionPayloadHeaderElectra, FixedVector, Hash256, SignedBeaconBlock,
}; };
use crate::{BeaconBlockHeader, ExecutionPayloadHeader}; use crate::{BeaconBlockHeader, ExecutionPayloadHeader};
use derivative::Derivative; use derivative::Derivative;
@@ -17,7 +17,7 @@ use test_random_derive::TestRandom;
use tree_hash_derive::TreeHash; use tree_hash_derive::TreeHash;
#[superstruct( #[superstruct(
variants(Altair, Capella, Deneb), variants(Altair, Capella, Deneb, Electra),
variant_attributes( variant_attributes(
derive( derive(
Debug, Debug,
@@ -54,8 +54,13 @@ pub struct LightClientHeader<E: EthSpec> {
pub execution: ExecutionPayloadHeaderCapella<E>, pub execution: ExecutionPayloadHeaderCapella<E>,
#[superstruct(only(Deneb), partial_getter(rename = "execution_payload_header_deneb"))] #[superstruct(only(Deneb), partial_getter(rename = "execution_payload_header_deneb"))]
pub execution: ExecutionPayloadHeaderDeneb<E>, pub execution: ExecutionPayloadHeaderDeneb<E>,
#[superstruct(
only(Electra),
partial_getter(rename = "execution_payload_header_electra")
)]
pub execution: ExecutionPayloadHeaderElectra<E>,
#[superstruct(only(Capella, Deneb))] #[superstruct(only(Capella, Deneb, Electra))]
pub execution_branch: FixedVector<Hash256, ExecutionPayloadProofLen>, pub execution_branch: FixedVector<Hash256, ExecutionPayloadProofLen>,
#[ssz(skip_serializing, skip_deserializing)] #[ssz(skip_serializing, skip_deserializing)]
@@ -81,9 +86,12 @@ impl<E: EthSpec> LightClientHeader<E> {
ForkName::Capella => LightClientHeader::Capella( ForkName::Capella => LightClientHeader::Capella(
LightClientHeaderCapella::block_to_light_client_header(block)?, LightClientHeaderCapella::block_to_light_client_header(block)?,
), ),
ForkName::Deneb | ForkName::Electra => LightClientHeader::Deneb( ForkName::Deneb => LightClientHeader::Deneb(
LightClientHeaderDeneb::block_to_light_client_header(block)?, LightClientHeaderDeneb::block_to_light_client_header(block)?,
), ),
ForkName::Electra => LightClientHeader::Electra(
LightClientHeaderElectra::block_to_light_client_header(block)?,
),
}; };
Ok(header) Ok(header)
} }
@@ -96,9 +104,12 @@ impl<E: EthSpec> LightClientHeader<E> {
ForkName::Capella => { ForkName::Capella => {
LightClientHeader::Capella(LightClientHeaderCapella::from_ssz_bytes(bytes)?) LightClientHeader::Capella(LightClientHeaderCapella::from_ssz_bytes(bytes)?)
} }
ForkName::Deneb | ForkName::Electra => { ForkName::Deneb => {
LightClientHeader::Deneb(LightClientHeaderDeneb::from_ssz_bytes(bytes)?) LightClientHeader::Deneb(LightClientHeaderDeneb::from_ssz_bytes(bytes)?)
} }
ForkName::Electra => {
LightClientHeader::Electra(LightClientHeaderElectra::from_ssz_bytes(bytes)?)
}
ForkName::Base => { ForkName::Base => {
return Err(ssz::DecodeError::BytesInvalid(format!( return Err(ssz::DecodeError::BytesInvalid(format!(
"LightClientHeader decoding for {fork_name} not implemented" "LightClientHeader decoding for {fork_name} not implemented"
@@ -192,6 +203,34 @@ impl<E: EthSpec> LightClientHeaderDeneb<E> {
} }
} }
impl<E: EthSpec> LightClientHeaderElectra<E> {
pub fn block_to_light_client_header(block: &SignedBeaconBlock<E>) -> Result<Self, Error> {
let payload = block
.message()
.execution_payload()?
.execution_payload_electra()?;
let header = ExecutionPayloadHeaderElectra::from(payload);
let beacon_block_body = BeaconBlockBody::from(
block
.message()
.body_electra()
.map_err(|_| Error::BeaconBlockBodyError)?
.to_owned(),
);
let execution_branch =
beacon_block_body.block_body_merkle_proof(EXECUTION_PAYLOAD_INDEX)?;
Ok(LightClientHeaderElectra {
beacon: block.message().block_header(),
execution: header,
execution_branch: FixedVector::new(execution_branch)?,
_phantom_data: PhantomData,
})
}
}
impl<E: EthSpec> ForkVersionDeserialize for LightClientHeader<E> { impl<E: EthSpec> ForkVersionDeserialize for LightClientHeader<E> {
fn deserialize_by_fork<'de, D: serde::Deserializer<'de>>( fn deserialize_by_fork<'de, D: serde::Deserializer<'de>>(
value: serde_json::value::Value, value: serde_json::value::Value,
@@ -204,9 +243,12 @@ impl<E: EthSpec> ForkVersionDeserialize for LightClientHeader<E> {
ForkName::Capella => serde_json::from_value(value) ForkName::Capella => serde_json::from_value(value)
.map(|light_client_header| Self::Capella(light_client_header)) .map(|light_client_header| Self::Capella(light_client_header))
.map_err(serde::de::Error::custom), .map_err(serde::de::Error::custom),
ForkName::Deneb | ForkName::Electra => serde_json::from_value(value) ForkName::Deneb => serde_json::from_value(value)
.map(|light_client_header| Self::Deneb(light_client_header)) .map(|light_client_header| Self::Deneb(light_client_header))
.map_err(serde::de::Error::custom), .map_err(serde::de::Error::custom),
ForkName::Electra => serde_json::from_value(value)
.map(|light_client_header| Self::Electra(light_client_header))
.map_err(serde::de::Error::custom),
ForkName::Base => Err(serde::de::Error::custom(format!( ForkName::Base => Err(serde::de::Error::custom(format!(
"LightClientHeader deserialization for {fork_name} not implemented" "LightClientHeader deserialization for {fork_name} not implemented"
))), ))),

View File

@@ -2,7 +2,7 @@ use super::{EthSpec, ForkName, ForkVersionDeserialize, LightClientHeader, Slot,
use crate::test_utils::TestRandom; use crate::test_utils::TestRandom;
use crate::{ use crate::{
light_client_update::*, ChainSpec, LightClientHeaderAltair, LightClientHeaderCapella, light_client_update::*, ChainSpec, LightClientHeaderAltair, LightClientHeaderCapella,
LightClientHeaderDeneb, SignedBeaconBlock, LightClientHeaderDeneb, LightClientHeaderElectra, SignedBeaconBlock,
}; };
use derivative::Derivative; use derivative::Derivative;
use serde::{Deserialize, Deserializer, Serialize}; use serde::{Deserialize, Deserializer, Serialize};
@@ -18,7 +18,7 @@ use tree_hash_derive::TreeHash;
/// A LightClientOptimisticUpdate is the update we send on each slot, /// A LightClientOptimisticUpdate is the update we send on each slot,
/// it is based off the current unfinalized epoch is verified only against BLS signature. /// it is based off the current unfinalized epoch is verified only against BLS signature.
#[superstruct( #[superstruct(
variants(Altair, Capella, Deneb), variants(Altair, Capella, Deneb, Electra),
variant_attributes( variant_attributes(
derive( derive(
Debug, Debug,
@@ -53,6 +53,8 @@ pub struct LightClientOptimisticUpdate<E: EthSpec> {
pub attested_header: LightClientHeaderCapella<E>, pub attested_header: LightClientHeaderCapella<E>,
#[superstruct(only(Deneb), partial_getter(rename = "attested_header_deneb"))] #[superstruct(only(Deneb), partial_getter(rename = "attested_header_deneb"))]
pub attested_header: LightClientHeaderDeneb<E>, pub attested_header: LightClientHeaderDeneb<E>,
#[superstruct(only(Electra), partial_getter(rename = "attested_header_electra"))]
pub attested_header: LightClientHeaderElectra<E>,
/// current sync aggregate /// current sync aggregate
pub sync_aggregate: SyncAggregate<E>, pub sync_aggregate: SyncAggregate<E>,
/// Slot of the sync aggregated signature /// Slot of the sync aggregated signature
@@ -86,13 +88,20 @@ impl<E: EthSpec> LightClientOptimisticUpdate<E> {
sync_aggregate, sync_aggregate,
signature_slot, signature_slot,
}), }),
ForkName::Deneb | ForkName::Electra => Self::Deneb(LightClientOptimisticUpdateDeneb { ForkName::Deneb => Self::Deneb(LightClientOptimisticUpdateDeneb {
attested_header: LightClientHeaderDeneb::block_to_light_client_header( attested_header: LightClientHeaderDeneb::block_to_light_client_header(
attested_block, attested_block,
)?, )?,
sync_aggregate, sync_aggregate,
signature_slot, signature_slot,
}), }),
ForkName::Electra => Self::Electra(LightClientOptimisticUpdateElectra {
attested_header: LightClientHeaderElectra::block_to_light_client_header(
attested_block,
)?,
sync_aggregate,
signature_slot,
}),
ForkName::Base => return Err(Error::AltairForkNotActive), ForkName::Base => return Err(Error::AltairForkNotActive),
}; };
@@ -107,6 +116,7 @@ impl<E: EthSpec> LightClientOptimisticUpdate<E> {
Self::Altair(_) => func(ForkName::Altair), Self::Altair(_) => func(ForkName::Altair),
Self::Capella(_) => func(ForkName::Capella), Self::Capella(_) => func(ForkName::Capella),
Self::Deneb(_) => func(ForkName::Deneb), Self::Deneb(_) => func(ForkName::Deneb),
Self::Electra(_) => func(ForkName::Electra),
} }
} }
@@ -139,9 +149,12 @@ impl<E: EthSpec> LightClientOptimisticUpdate<E> {
ForkName::Capella => { ForkName::Capella => {
Self::Capella(LightClientOptimisticUpdateCapella::from_ssz_bytes(bytes)?) Self::Capella(LightClientOptimisticUpdateCapella::from_ssz_bytes(bytes)?)
} }
ForkName::Deneb | ForkName::Electra => { ForkName::Deneb => {
Self::Deneb(LightClientOptimisticUpdateDeneb::from_ssz_bytes(bytes)?) Self::Deneb(LightClientOptimisticUpdateDeneb::from_ssz_bytes(bytes)?)
} }
ForkName::Electra => {
Self::Electra(LightClientOptimisticUpdateElectra::from_ssz_bytes(bytes)?)
}
ForkName::Base => { ForkName::Base => {
return Err(ssz::DecodeError::BytesInvalid(format!( return Err(ssz::DecodeError::BytesInvalid(format!(
"LightClientOptimisticUpdate decoding for {fork_name} not implemented" "LightClientOptimisticUpdate decoding for {fork_name} not implemented"
@@ -154,18 +167,16 @@ impl<E: EthSpec> LightClientOptimisticUpdate<E> {
#[allow(clippy::arithmetic_side_effects)] #[allow(clippy::arithmetic_side_effects)]
pub fn ssz_max_len_for_fork(fork_name: ForkName) -> usize { pub fn ssz_max_len_for_fork(fork_name: ForkName) -> usize {
// TODO(electra): review electra changes let fixed_len = match fork_name {
match fork_name {
ForkName::Base => 0, ForkName::Base => 0,
ForkName::Altair ForkName::Altair | ForkName::Bellatrix => {
| ForkName::Bellatrix
| ForkName::Capella
| ForkName::Deneb
| ForkName::Electra => {
<LightClientOptimisticUpdateAltair<E> as Encode>::ssz_fixed_len() <LightClientOptimisticUpdateAltair<E> as Encode>::ssz_fixed_len()
+ LightClientHeader::<E>::ssz_max_var_len_for_fork(fork_name)
}
} }
ForkName::Capella => <LightClientOptimisticUpdateCapella<E> as Encode>::ssz_fixed_len(),
ForkName::Deneb => <LightClientOptimisticUpdateDeneb<E> as Encode>::ssz_fixed_len(),
ForkName::Electra => <LightClientOptimisticUpdateElectra<E> as Encode>::ssz_fixed_len(),
};
fixed_len + LightClientHeader::<E>::ssz_max_var_len_for_fork(fork_name)
} }
} }

View File

@@ -1,4 +1,5 @@
use super::{EthSpec, FixedVector, Hash256, Slot, SyncAggregate, SyncCommittee}; use super::{EthSpec, FixedVector, Hash256, Slot, SyncAggregate, SyncCommittee};
use crate::light_client_header::LightClientHeaderElectra;
use crate::{ use crate::{
beacon_state, test_utils::TestRandom, BeaconBlock, BeaconBlockHeader, BeaconState, ChainSpec, beacon_state, test_utils::TestRandom, BeaconBlock, BeaconBlockHeader, BeaconState, ChainSpec,
ForkName, ForkVersionDeserialize, LightClientHeaderAltair, LightClientHeaderCapella, ForkName, ForkVersionDeserialize, LightClientHeaderAltair, LightClientHeaderCapella,
@@ -76,7 +77,7 @@ impl From<milhouse::Error> for Error {
/// or to sync up to the last committee period, we need to have one ready for each ALTAIR period /// or to sync up to the last committee period, we need to have one ready for each ALTAIR period
/// we go over, note: there is no need to keep all of the updates from [ALTAIR_PERIOD, CURRENT_PERIOD]. /// we go over, note: there is no need to keep all of the updates from [ALTAIR_PERIOD, CURRENT_PERIOD].
#[superstruct( #[superstruct(
variants(Altair, Capella, Deneb), variants(Altair, Capella, Deneb, Electra),
variant_attributes( variant_attributes(
derive( derive(
Debug, Debug,
@@ -111,6 +112,8 @@ pub struct LightClientUpdate<E: EthSpec> {
pub attested_header: LightClientHeaderCapella<E>, pub attested_header: LightClientHeaderCapella<E>,
#[superstruct(only(Deneb), partial_getter(rename = "attested_header_deneb"))] #[superstruct(only(Deneb), partial_getter(rename = "attested_header_deneb"))]
pub attested_header: LightClientHeaderDeneb<E>, pub attested_header: LightClientHeaderDeneb<E>,
#[superstruct(only(Electra), partial_getter(rename = "attested_header_electra"))]
pub attested_header: LightClientHeaderElectra<E>,
/// The `SyncCommittee` used in the next period. /// The `SyncCommittee` used in the next period.
pub next_sync_committee: Arc<SyncCommittee<E>>, pub next_sync_committee: Arc<SyncCommittee<E>>,
/// Merkle proof for next sync committee /// Merkle proof for next sync committee
@@ -122,6 +125,8 @@ pub struct LightClientUpdate<E: EthSpec> {
pub finalized_header: LightClientHeaderCapella<E>, pub finalized_header: LightClientHeaderCapella<E>,
#[superstruct(only(Deneb), partial_getter(rename = "finalized_header_deneb"))] #[superstruct(only(Deneb), partial_getter(rename = "finalized_header_deneb"))]
pub finalized_header: LightClientHeaderDeneb<E>, pub finalized_header: LightClientHeaderDeneb<E>,
#[superstruct(only(Electra), partial_getter(rename = "finalized_header_electra"))]
pub finalized_header: LightClientHeaderElectra<E>,
/// Merkle proof attesting finalized header. /// Merkle proof attesting finalized header.
pub finality_branch: FixedVector<Hash256, FinalizedRootProofLen>, pub finality_branch: FixedVector<Hash256, FinalizedRootProofLen>,
/// current sync aggreggate /// current sync aggreggate
@@ -221,7 +226,7 @@ impl<E: EthSpec> LightClientUpdate<E> {
signature_slot: block.slot(), signature_slot: block.slot(),
}) })
} }
ForkName::Deneb | ForkName::Electra => { ForkName::Deneb => {
let attested_header = let attested_header =
LightClientHeaderDeneb::block_to_light_client_header(attested_block)?; LightClientHeaderDeneb::block_to_light_client_header(attested_block)?;
let finalized_header = let finalized_header =
@@ -236,6 +241,23 @@ impl<E: EthSpec> LightClientUpdate<E> {
signature_slot: block.slot(), signature_slot: block.slot(),
}) })
} }
ForkName::Electra => {
let attested_header =
LightClientHeaderElectra::block_to_light_client_header(attested_block)?;
let finalized_header =
LightClientHeaderElectra::block_to_light_client_header(finalized_block)?;
Self::Electra(LightClientUpdateElectra {
attested_header,
next_sync_committee: attested_state.next_sync_committee()?.clone(),
next_sync_committee_branch: FixedVector::new(next_sync_committee_branch)?,
finalized_header,
finality_branch: FixedVector::new(finality_branch)?,
sync_aggregate: sync_aggregate.clone(),
signature_slot: block.slot(),
})
} // To add a new fork, just append the new fork variant on the latest fork. Forks that
// have a distinct execution header will need a new LightClientUdpate variant only
// if you need to test or support lightclient usages
}; };
Ok(light_client_update) Ok(light_client_update)
@@ -247,9 +269,8 @@ impl<E: EthSpec> LightClientUpdate<E> {
Self::Altair(LightClientUpdateAltair::from_ssz_bytes(bytes)?) Self::Altair(LightClientUpdateAltair::from_ssz_bytes(bytes)?)
} }
ForkName::Capella => Self::Capella(LightClientUpdateCapella::from_ssz_bytes(bytes)?), ForkName::Capella => Self::Capella(LightClientUpdateCapella::from_ssz_bytes(bytes)?),
ForkName::Deneb | ForkName::Electra => { ForkName::Deneb => Self::Deneb(LightClientUpdateDeneb::from_ssz_bytes(bytes)?),
Self::Deneb(LightClientUpdateDeneb::from_ssz_bytes(bytes)?) ForkName::Electra => Self::Electra(LightClientUpdateElectra::from_ssz_bytes(bytes)?),
}
ForkName::Base => { ForkName::Base => {
return Err(ssz::DecodeError::BytesInvalid(format!( return Err(ssz::DecodeError::BytesInvalid(format!(
"LightClientUpdate decoding for {fork_name} not implemented" "LightClientUpdate decoding for {fork_name} not implemented"