Add Gloas boilerplate (#7728)

Adds the required boilerplate code for the Gloas (Glamsterdam) hard fork. This allows PRs testing Gloas-candidate features to test fork transition.

This also includes de-duplication of post-Bellatrix readiness notifiers from #6797 (credit to @dapplion)
This commit is contained in:
Mac L
2025-08-26 12:49:48 +10:00
committed by GitHub
parent daf1c7c3af
commit e438691683
75 changed files with 1801 additions and 917 deletions

View File

@@ -16,7 +16,7 @@ use self::indexed_attestation::IndexedAttestationBase;
/// A block of the `BeaconChain`.
#[superstruct(
variants(Base, Altair, Bellatrix, Capella, Deneb, Electra, Fulu),
variants(Base, Altair, Bellatrix, Capella, Deneb, Electra, Fulu, Gloas),
variant_attributes(
derive(
Debug,
@@ -82,6 +82,8 @@ pub struct BeaconBlock<E: EthSpec, Payload: AbstractExecPayload<E> = FullPayload
pub body: BeaconBlockBodyElectra<E, Payload>,
#[superstruct(only(Fulu), partial_getter(rename = "body_fulu"))]
pub body: BeaconBlockBodyFulu<E, Payload>,
#[superstruct(only(Gloas), partial_getter(rename = "body_gloas"))]
pub body: BeaconBlockBodyGloas<E, Payload>,
}
pub type BlindedBeaconBlock<E> = BeaconBlock<E, BlindedPayload<E>>;
@@ -134,8 +136,9 @@ impl<E: EthSpec, Payload: AbstractExecPayload<E>> BeaconBlock<E, 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> {
BeaconBlockFulu::from_ssz_bytes(bytes)
.map(BeaconBlock::Fulu)
BeaconBlockGloas::from_ssz_bytes(bytes)
.map(BeaconBlock::Gloas)
.or_else(|_| BeaconBlockFulu::from_ssz_bytes(bytes).map(BeaconBlock::Fulu))
.or_else(|_| 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))
@@ -235,6 +238,7 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload<E>> BeaconBlockRef<'a, E, Payl
BeaconBlockRef::Deneb { .. } => ForkName::Deneb,
BeaconBlockRef::Electra { .. } => ForkName::Electra,
BeaconBlockRef::Fulu { .. } => ForkName::Fulu,
BeaconBlockRef::Gloas { .. } => ForkName::Gloas,
}
}
@@ -646,6 +650,37 @@ impl<E: EthSpec, Payload: AbstractExecPayload<E>> EmptyBlock for BeaconBlockFulu
}
}
impl<E: EthSpec, Payload: AbstractExecPayload<E>> EmptyBlock for BeaconBlockGloas<E, Payload> {
/// Returns an empty Gloas block to be used during genesis.
fn empty(spec: &ChainSpec) -> Self {
BeaconBlockGloas {
slot: spec.genesis_slot,
proposer_index: 0,
parent_root: Hash256::zero(),
state_root: Hash256::zero(),
body: BeaconBlockBodyGloas {
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::Gloas::default(),
bls_to_execution_changes: VariableList::empty(),
blob_kzg_commitments: VariableList::empty(),
execution_requests: ExecutionRequests::default(),
},
}
}
}
// 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>>
@@ -728,6 +763,7 @@ impl_from!(BeaconBlockCapella, <E, FullPayload<E>>, <E, BlindedPayload<E>>, |bod
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());
impl_from!(BeaconBlockFulu, <E, FullPayload<E>>, <E, BlindedPayload<E>>, |body: BeaconBlockBodyFulu<_, _>| body.into());
impl_from!(BeaconBlockGloas, <E, FullPayload<E>>, <E, BlindedPayload<E>>, |body: BeaconBlockBodyGloas<_, _>| body.into());
// We can clone blocks with payloads to blocks without payloads, without cloning the payload.
macro_rules! impl_clone_as_blinded {
@@ -762,6 +798,7 @@ impl_clone_as_blinded!(BeaconBlockCapella, <E, FullPayload<E>>, <E, BlindedPaylo
impl_clone_as_blinded!(BeaconBlockDeneb, <E, FullPayload<E>>, <E, BlindedPayload<E>>);
impl_clone_as_blinded!(BeaconBlockElectra, <E, FullPayload<E>>, <E, BlindedPayload<E>>);
impl_clone_as_blinded!(BeaconBlockFulu, <E, FullPayload<E>>, <E, BlindedPayload<E>>);
impl_clone_as_blinded!(BeaconBlockGloas, <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.
@@ -950,6 +987,26 @@ mod tests {
});
}
#[test]
fn roundtrip_gloas_block() {
let rng = &mut XorShiftRng::from_seed([42; 16]);
let spec = &ForkName::Gloas.make_genesis_spec(MainnetEthSpec::default_spec());
let inner_block = BeaconBlockGloas {
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: BeaconBlockBodyGloas::random_for_test(rng),
};
let block = BeaconBlock::Gloas(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;
@@ -971,12 +1028,15 @@ mod tests {
let electra_slot = electra_epoch.start_slot(E::slots_per_epoch());
let fulu_epoch = electra_epoch + 1;
let fulu_slot = fulu_epoch.start_slot(E::slots_per_epoch());
let gloas_epoch = fulu_epoch + 1;
let gloas_slot = gloas_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);
spec.fulu_fork_epoch = Some(fulu_epoch);
spec.gloas_fork_epoch = Some(gloas_epoch);
// BeaconBlockBase
{
@@ -1101,5 +1161,30 @@ mod tests {
good_block
);
}
// BeaconBlockGloas
{
let good_block = BeaconBlock::Gloas(BeaconBlockGloas {
slot: gloas_slot,
..<_>::random_for_test(rng)
});
// It's invalid to have a Fulu block with a epoch lower than the fork epoch.
let _bad_block = {
let mut bad = good_block.clone();
*bad.slot_mut() = fulu_slot;
bad
};
assert_eq!(
BeaconBlock::from_ssz_bytes(&good_block.as_ssz_bytes(), &spec)
.expect("good gloas block can be decoded"),
good_block
);
// TODO(gloas): Uncomment once Gloas has features since without features
// and with a Fulu slot it decodes successfully to Fulu.
//BeaconBlock::from_ssz_bytes(&bad_block.as_ssz_bytes(), &spec)
// .expect_err("bad gloas block cannot be decoded");
}
}
}

View File

@@ -28,7 +28,7 @@ pub const BLOB_KZG_COMMITMENTS_INDEX: usize = 11;
///
/// This *superstruct* abstracts over the hard-fork.
#[superstruct(
variants(Base, Altair, Bellatrix, Capella, Deneb, Electra, Fulu),
variants(Base, Altair, Bellatrix, Capella, Deneb, Electra, Fulu, Gloas),
variant_attributes(
derive(
Debug,
@@ -60,7 +60,8 @@ pub const BLOB_KZG_COMMITMENTS_INDEX: usize = 11;
Capella(metastruct(mappings(beacon_block_body_capella_fields(groups(fields))))),
Deneb(metastruct(mappings(beacon_block_body_deneb_fields(groups(fields))))),
Electra(metastruct(mappings(beacon_block_body_electra_fields(groups(fields))))),
Fulu(metastruct(mappings(beacon_block_body_fulu_fields(groups(fields)))))
Fulu(metastruct(mappings(beacon_block_body_fulu_fields(groups(fields))))),
Gloas(metastruct(mappings(beacon_block_body_gloas_fields(groups(fields))))),
),
cast_error(ty = "Error", expr = "Error::IncorrectStateVariant"),
partial_getter_error(ty = "Error", expr = "Error::IncorrectStateVariant")
@@ -86,7 +87,7 @@ pub struct BeaconBlockBody<E: EthSpec, Payload: AbstractExecPayload<E> = FullPay
)]
pub attester_slashings: VariableList<AttesterSlashingBase<E>, E::MaxAttesterSlashings>,
#[superstruct(
only(Electra, Fulu),
only(Electra, Fulu, Gloas),
partial_getter(rename = "attester_slashings_electra")
)]
pub attester_slashings:
@@ -96,11 +97,14 @@ pub struct BeaconBlockBody<E: EthSpec, Payload: AbstractExecPayload<E> = FullPay
partial_getter(rename = "attestations_base")
)]
pub attestations: VariableList<AttestationBase<E>, E::MaxAttestations>,
#[superstruct(only(Electra, Fulu), partial_getter(rename = "attestations_electra"))]
#[superstruct(
only(Electra, Fulu, Gloas),
partial_getter(rename = "attestations_electra")
)]
pub attestations: VariableList<AttestationElectra<E>, E::MaxAttestationsElectra>,
pub deposits: VariableList<Deposit, E::MaxDeposits>,
pub voluntary_exits: VariableList<SignedVoluntaryExit, E::MaxVoluntaryExits>,
#[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Fulu))]
#[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Fulu, Gloas))]
pub sync_aggregate: SyncAggregate<E>,
// 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
@@ -123,12 +127,15 @@ pub struct BeaconBlockBody<E: EthSpec, Payload: AbstractExecPayload<E> = FullPay
#[superstruct(only(Fulu), partial_getter(rename = "execution_payload_fulu"))]
#[serde(flatten)]
pub execution_payload: Payload::Fulu,
#[superstruct(only(Capella, Deneb, Electra, Fulu))]
#[superstruct(only(Gloas), partial_getter(rename = "execution_payload_gloas"))]
#[serde(flatten)]
pub execution_payload: Payload::Gloas,
#[superstruct(only(Capella, Deneb, Electra, Fulu, Gloas))]
pub bls_to_execution_changes:
VariableList<SignedBlsToExecutionChange, E::MaxBlsToExecutionChanges>,
#[superstruct(only(Deneb, Electra, Fulu))]
#[superstruct(only(Deneb, Electra, Fulu, Gloas))]
pub blob_kzg_commitments: KzgCommitments<E>,
#[superstruct(only(Electra, Fulu))]
#[superstruct(only(Electra, Fulu, Gloas))]
pub execution_requests: ExecutionRequests<E>,
#[superstruct(only(Base, Altair))]
#[metastruct(exclude_from(fields))]
@@ -159,6 +166,7 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload<E>> BeaconBlockBodyRef<'a, E,
Self::Deneb(body) => Ok(Payload::Ref::from(&body.execution_payload)),
Self::Electra(body) => Ok(Payload::Ref::from(&body.execution_payload)),
Self::Fulu(body) => Ok(Payload::Ref::from(&body.execution_payload)),
Self::Gloas(body) => Ok(Payload::Ref::from(&body.execution_payload)),
}
}
@@ -193,6 +201,10 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload<E>> BeaconBlockBodyRef<'a, E,
beacon_block_body_fulu_fields!(body, |_, field| leaves
.push(field.tree_hash_root()));
}
Self::Gloas(body) => {
beacon_block_body_gloas_fields!(body, |_, field| leaves
.push(field.tree_hash_root()));
}
}
leaves
}
@@ -221,7 +233,7 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload<E>> BeaconBlockBodyRef<'a, E,
Self::Base(_) | Self::Altair(_) | Self::Bellatrix(_) | Self::Capella(_) => {
Err(Error::IncorrectStateVariant)
}
Self::Deneb(_) | Self::Electra(_) | Self::Fulu(_) => {
Self::Deneb(_) | Self::Electra(_) | Self::Fulu(_) | Self::Gloas(_) => {
// 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
@@ -314,6 +326,7 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload<E>> BeaconBlockBodyRef<'a, E,
Self::Deneb(body) => body.attestations.len(),
Self::Electra(body) => body.attestations.len(),
Self::Fulu(body) => body.attestations.len(),
Self::Gloas(body) => body.attestations.len(),
}
}
@@ -326,6 +339,7 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload<E>> BeaconBlockBodyRef<'a, E,
Self::Deneb(body) => body.attester_slashings.len(),
Self::Electra(body) => body.attester_slashings.len(),
Self::Fulu(body) => body.attester_slashings.len(),
Self::Gloas(body) => body.attester_slashings.len(),
}
}
@@ -338,6 +352,7 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload<E>> BeaconBlockBodyRef<'a, E,
Self::Deneb(body) => Box::new(body.attestations.iter().map(AttestationRef::Base)),
Self::Electra(body) => Box::new(body.attestations.iter().map(AttestationRef::Electra)),
Self::Fulu(body) => Box::new(body.attestations.iter().map(AttestationRef::Electra)),
Self::Gloas(body) => Box::new(body.attestations.iter().map(AttestationRef::Electra)),
}
}
@@ -378,6 +393,11 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload<E>> BeaconBlockBodyRef<'a, E,
.iter()
.map(AttesterSlashingRef::Electra),
),
Self::Gloas(body) => Box::new(
body.attester_slashings
.iter()
.map(AttesterSlashingRef::Electra),
),
}
}
}
@@ -406,6 +426,9 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload<E>> BeaconBlockBodyRefMut<'a,
Self::Fulu(body) => {
Box::new(body.attestations.iter_mut().map(AttestationRefMut::Electra))
}
Self::Gloas(body) => {
Box::new(body.attestations.iter_mut().map(AttestationRefMut::Electra))
}
}
}
}
@@ -421,6 +444,7 @@ impl<E: EthSpec, Payload: AbstractExecPayload<E>> BeaconBlockBodyRef<'_, E, Payl
BeaconBlockBodyRef::Deneb { .. } => ForkName::Deneb,
BeaconBlockBodyRef::Electra { .. } => ForkName::Electra,
BeaconBlockBodyRef::Fulu { .. } => ForkName::Fulu,
BeaconBlockBodyRef::Gloas { .. } => ForkName::Gloas,
}
}
}
@@ -781,6 +805,52 @@ impl<E: EthSpec> From<BeaconBlockBodyFulu<E, FullPayload<E>>>
}
}
impl<E: EthSpec> From<BeaconBlockBodyGloas<E, FullPayload<E>>>
for (
BeaconBlockBodyGloas<E, BlindedPayload<E>>,
Option<ExecutionPayloadGloas<E>>,
)
{
fn from(body: BeaconBlockBodyGloas<E, FullPayload<E>>) -> Self {
let BeaconBlockBodyGloas {
randao_reveal,
eth1_data,
graffiti,
proposer_slashings,
attester_slashings,
attestations,
deposits,
voluntary_exits,
sync_aggregate,
execution_payload: FullPayloadGloas { execution_payload },
bls_to_execution_changes,
blob_kzg_commitments,
execution_requests,
} = body;
(
BeaconBlockBodyGloas {
randao_reveal,
eth1_data,
graffiti,
proposer_slashings,
attester_slashings,
attestations,
deposits,
voluntary_exits,
sync_aggregate,
execution_payload: BlindedPayloadGloas {
execution_payload_header: From::from(&execution_payload),
},
bls_to_execution_changes,
blob_kzg_commitments: blob_kzg_commitments.clone(),
execution_requests,
},
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>> {
@@ -974,6 +1044,44 @@ impl<E: EthSpec> BeaconBlockBodyFulu<E, FullPayload<E>> {
}
}
impl<E: EthSpec> BeaconBlockBodyGloas<E, FullPayload<E>> {
pub fn clone_as_blinded(&self) -> BeaconBlockBodyGloas<E, BlindedPayload<E>> {
let BeaconBlockBodyGloas {
randao_reveal,
eth1_data,
graffiti,
proposer_slashings,
attester_slashings,
attestations,
deposits,
voluntary_exits,
sync_aggregate,
execution_payload: FullPayloadGloas { execution_payload },
bls_to_execution_changes,
blob_kzg_commitments,
execution_requests,
} = self;
BeaconBlockBodyGloas {
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: BlindedPayloadGloas {
execution_payload_header: execution_payload.into(),
},
bls_to_execution_changes: bls_to_execution_changes.clone(),
blob_kzg_commitments: blob_kzg_commitments.clone(),
execution_requests: execution_requests.clone(),
}
}
}
impl<E: EthSpec> From<BeaconBlockBody<E, FullPayload<E>>>
for (
BeaconBlockBody<E, BlindedPayload<E>>,

View File

@@ -229,7 +229,7 @@ impl From<BeaconStateHash> for Hash256 {
///
/// https://github.com/sigp/milhouse/issues/43
#[superstruct(
variants(Base, Altair, Bellatrix, Capella, Deneb, Electra, Fulu),
variants(Base, Altair, Bellatrix, Capella, Deneb, Electra, Fulu, Gloas),
variant_attributes(
derive(
Derivative,
@@ -349,6 +349,20 @@ impl From<BeaconStateHash> for Hash256 {
groups(tree_lists)
)),
num_fields(all()),
)),
Gloas(metastruct(
mappings(
map_beacon_state_gloas_fields(),
map_beacon_state_gloas_tree_list_fields(mutable, fallible, groups(tree_lists)),
map_beacon_state_gloas_tree_list_fields_immutable(groups(tree_lists)),
),
bimappings(bimap_beacon_state_gloas_tree_list_fields(
other_type = "BeaconStateGloas",
self_mutable,
fallible,
groups(tree_lists)
)),
num_fields(all()),
))
),
cast_error(ty = "Error", expr = "Error::IncorrectStateVariant"),
@@ -435,11 +449,11 @@ where
// Participation (Altair and later)
#[compare_fields(as_iter)]
#[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Fulu))]
#[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Fulu, Gloas))]
#[test_random(default)]
#[compare_fields(as_iter)]
pub previous_epoch_participation: List<ParticipationFlags, E::ValidatorRegistryLimit>,
#[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Fulu))]
#[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Fulu, Gloas))]
#[test_random(default)]
pub current_epoch_participation: List<ParticipationFlags, E::ValidatorRegistryLimit>,
@@ -459,15 +473,15 @@ where
// Inactivity
#[serde(with = "ssz_types::serde_utils::quoted_u64_var_list")]
#[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Fulu))]
#[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Fulu, Gloas))]
#[test_random(default)]
pub inactivity_scores: List<u64, E::ValidatorRegistryLimit>,
// Light-client sync committees
#[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Fulu))]
#[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Fulu, Gloas))]
#[metastruct(exclude_from(tree_lists))]
pub current_sync_committee: Arc<SyncCommittee<E>>,
#[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Fulu))]
#[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Fulu, Gloas))]
#[metastruct(exclude_from(tree_lists))]
pub next_sync_committee: Arc<SyncCommittee<E>>,
@@ -502,64 +516,72 @@ where
)]
#[metastruct(exclude_from(tree_lists))]
pub latest_execution_payload_header: ExecutionPayloadHeaderFulu<E>,
#[superstruct(
only(Gloas),
partial_getter(rename = "latest_execution_payload_header_gloas")
)]
#[metastruct(exclude_from(tree_lists))]
pub latest_execution_payload_header: ExecutionPayloadHeaderGloas<E>,
// Capella
#[superstruct(only(Capella, Deneb, Electra, Fulu), partial_getter(copy))]
#[superstruct(only(Capella, Deneb, Electra, Fulu, Gloas), partial_getter(copy))]
#[serde(with = "serde_utils::quoted_u64")]
#[metastruct(exclude_from(tree_lists))]
pub next_withdrawal_index: u64,
#[superstruct(only(Capella, Deneb, Electra, Fulu), partial_getter(copy))]
#[superstruct(only(Capella, Deneb, Electra, Fulu, Gloas), partial_getter(copy))]
#[serde(with = "serde_utils::quoted_u64")]
#[metastruct(exclude_from(tree_lists))]
pub next_withdrawal_validator_index: u64,
// Deep history valid from Capella onwards.
#[superstruct(only(Capella, Deneb, Electra, Fulu))]
#[superstruct(only(Capella, Deneb, Electra, Fulu, Gloas))]
#[test_random(default)]
pub historical_summaries: List<HistoricalSummary, E::HistoricalRootsLimit>,
// Electra
#[superstruct(only(Electra, Fulu), partial_getter(copy))]
#[superstruct(only(Electra, Fulu, Gloas), partial_getter(copy))]
#[metastruct(exclude_from(tree_lists))]
#[serde(with = "serde_utils::quoted_u64")]
pub deposit_requests_start_index: u64,
#[superstruct(only(Electra, Fulu), partial_getter(copy))]
#[superstruct(only(Electra, Fulu, Gloas), partial_getter(copy))]
#[metastruct(exclude_from(tree_lists))]
#[serde(with = "serde_utils::quoted_u64")]
pub deposit_balance_to_consume: u64,
#[superstruct(only(Electra, Fulu), partial_getter(copy))]
#[superstruct(only(Electra, Fulu, Gloas), partial_getter(copy))]
#[metastruct(exclude_from(tree_lists))]
#[serde(with = "serde_utils::quoted_u64")]
pub exit_balance_to_consume: u64,
#[superstruct(only(Electra, Fulu), partial_getter(copy))]
#[superstruct(only(Electra, Fulu, Gloas), partial_getter(copy))]
#[metastruct(exclude_from(tree_lists))]
pub earliest_exit_epoch: Epoch,
#[superstruct(only(Electra, Fulu), partial_getter(copy))]
#[superstruct(only(Electra, Fulu, Gloas), partial_getter(copy))]
#[metastruct(exclude_from(tree_lists))]
#[serde(with = "serde_utils::quoted_u64")]
pub consolidation_balance_to_consume: u64,
#[superstruct(only(Electra, Fulu), partial_getter(copy))]
#[superstruct(only(Electra, Fulu, Gloas), partial_getter(copy))]
#[metastruct(exclude_from(tree_lists))]
pub earliest_consolidation_epoch: Epoch,
#[compare_fields(as_iter)]
#[test_random(default)]
#[superstruct(only(Electra, Fulu))]
#[superstruct(only(Electra, Fulu, Gloas))]
pub pending_deposits: List<PendingDeposit, E::PendingDepositsLimit>,
#[compare_fields(as_iter)]
#[test_random(default)]
#[superstruct(only(Electra, Fulu))]
#[superstruct(only(Electra, Fulu, Gloas))]
pub pending_partial_withdrawals:
List<PendingPartialWithdrawal, E::PendingPartialWithdrawalsLimit>,
#[compare_fields(as_iter)]
#[test_random(default)]
#[superstruct(only(Electra, Fulu))]
#[superstruct(only(Electra, Fulu, Gloas))]
pub pending_consolidations: List<PendingConsolidation, E::PendingConsolidationsLimit>,
// Fulu
#[compare_fields(as_iter)]
#[test_random(default)]
#[superstruct(only(Fulu))]
#[superstruct(only(Fulu, Gloas))]
pub proposer_lookahead: Vector<u64, E::ProposerLookaheadSlots>,
// Gloas
// Caching (not in the spec)
#[serde(skip_serializing, skip_deserializing)]
#[ssz(skip_serializing, skip_deserializing)]
@@ -699,6 +721,7 @@ impl<E: EthSpec> BeaconState<E> {
BeaconState::Deneb { .. } => ForkName::Deneb,
BeaconState::Electra { .. } => ForkName::Electra,
BeaconState::Fulu { .. } => ForkName::Fulu,
BeaconState::Gloas { .. } => ForkName::Gloas,
}
}
@@ -1048,6 +1071,9 @@ impl<E: EthSpec> BeaconState<E> {
BeaconState::Fulu(state) => Ok(ExecutionPayloadHeaderRef::Fulu(
&state.latest_execution_payload_header,
)),
BeaconState::Gloas(state) => Ok(ExecutionPayloadHeaderRef::Gloas(
&state.latest_execution_payload_header,
)),
}
}
@@ -1071,6 +1097,9 @@ impl<E: EthSpec> BeaconState<E> {
BeaconState::Fulu(state) => Ok(ExecutionPayloadHeaderRefMut::Fulu(
&mut state.latest_execution_payload_header,
)),
BeaconState::Gloas(state) => Ok(ExecutionPayloadHeaderRefMut::Gloas(
&mut state.latest_execution_payload_header,
)),
}
}
@@ -1616,6 +1645,16 @@ impl<E: EthSpec> BeaconState<E> {
&mut state.exit_cache,
&mut state.epoch_cache,
)),
BeaconState::Gloas(state) => Ok((
&mut state.validators,
&mut state.balances,
&state.previous_epoch_participation,
&state.current_epoch_participation,
&mut state.inactivity_scores,
&mut state.progressive_balances_cache,
&mut state.exit_cache,
&mut state.epoch_cache,
)),
}
}
@@ -1797,12 +1836,13 @@ impl<E: EthSpec> BeaconState<E> {
| BeaconState::Altair(_)
| BeaconState::Bellatrix(_)
| BeaconState::Capella(_) => self.get_validator_churn_limit(spec)?,
BeaconState::Deneb(_) | BeaconState::Electra(_) | BeaconState::Fulu(_) => {
std::cmp::min(
spec.max_per_epoch_activation_churn_limit,
self.get_validator_churn_limit(spec)?,
)
}
BeaconState::Deneb(_)
| BeaconState::Electra(_)
| BeaconState::Fulu(_)
| BeaconState::Gloas(_) => std::cmp::min(
spec.max_per_epoch_activation_churn_limit,
self.get_validator_churn_limit(spec)?,
),
})
}
@@ -1922,6 +1962,7 @@ impl<E: EthSpec> BeaconState<E> {
BeaconState::Deneb(state) => Ok(&mut state.current_epoch_participation),
BeaconState::Electra(state) => Ok(&mut state.current_epoch_participation),
BeaconState::Fulu(state) => Ok(&mut state.current_epoch_participation),
BeaconState::Gloas(state) => Ok(&mut state.current_epoch_participation),
}
} else if epoch == previous_epoch {
match self {
@@ -1932,6 +1973,7 @@ impl<E: EthSpec> BeaconState<E> {
BeaconState::Deneb(state) => Ok(&mut state.previous_epoch_participation),
BeaconState::Electra(state) => Ok(&mut state.previous_epoch_participation),
BeaconState::Fulu(state) => Ok(&mut state.previous_epoch_participation),
BeaconState::Gloas(state) => Ok(&mut state.previous_epoch_participation),
}
} else {
Err(BeaconStateError::EpochOutOfBounds)
@@ -2196,6 +2238,11 @@ impl<E: EthSpec> BeaconState<E> {
any_pending_mutations |= self_field.has_pending_updates();
});
}
Self::Gloas(self_inner) => {
map_beacon_state_gloas_tree_list_fields_immutable!(self_inner, |_, self_field| {
any_pending_mutations |= self_field.has_pending_updates();
});
}
};
any_pending_mutations
}
@@ -2396,7 +2443,7 @@ impl<E: EthSpec> BeaconState<E> {
| BeaconState::Bellatrix(_)
| BeaconState::Capella(_)
| BeaconState::Deneb(_) => Err(Error::IncorrectStateVariant),
BeaconState::Electra(_) | BeaconState::Fulu(_) => {
BeaconState::Electra(_) | BeaconState::Fulu(_) | BeaconState::Gloas(_) => {
// Consume the balance and update state variables
*self.exit_balance_to_consume_mut()? =
exit_balance_to_consume.safe_sub(exit_balance)?;
@@ -2443,7 +2490,7 @@ impl<E: EthSpec> BeaconState<E> {
| BeaconState::Bellatrix(_)
| BeaconState::Capella(_)
| BeaconState::Deneb(_) => Err(Error::IncorrectStateVariant),
BeaconState::Electra(_) | BeaconState::Fulu(_) => {
BeaconState::Electra(_) | BeaconState::Fulu(_) | BeaconState::Gloas(_) => {
// Consume the balance and update state variables.
*self.consolidation_balance_to_consume_mut()? =
consolidation_balance_to_consume.safe_sub(consolidation_balance)?;
@@ -2514,6 +2561,14 @@ impl<E: EthSpec> BeaconState<E> {
);
}
(Self::Fulu(_), _) => (),
(Self::Gloas(self_inner), Self::Gloas(base_inner)) => {
bimap_beacon_state_gloas_tree_list_fields!(
self_inner,
base_inner,
|_, self_field, base_field| { self_field.rebase_on(base_field) }
);
}
(Self::Gloas(_), _) => (),
}
// Use sync committees from `base` if they are equal.
@@ -2591,6 +2646,7 @@ impl<E: EthSpec> BeaconState<E> {
ForkName::Deneb => BeaconStateDeneb::<E>::NUM_FIELDS.next_power_of_two(),
ForkName::Electra => BeaconStateElectra::<E>::NUM_FIELDS.next_power_of_two(),
ForkName::Fulu => BeaconStateFulu::<E>::NUM_FIELDS.next_power_of_two(),
ForkName::Gloas => BeaconStateGloas::<E>::NUM_FIELDS.next_power_of_two(),
}
}
@@ -2642,6 +2698,9 @@ impl<E: EthSpec> BeaconState<E> {
Self::Fulu(inner) => {
map_beacon_state_fulu_tree_list_fields!(inner, |_, x| { x.apply_updates() })
}
Self::Gloas(inner) => {
map_beacon_state_gloas_tree_list_fields!(inner, |_, x| { x.apply_updates() })
}
}
Ok(())
}
@@ -2755,6 +2814,11 @@ impl<E: EthSpec> BeaconState<E> {
leaves.push(field.tree_hash_root());
});
}
BeaconState::Gloas(state) => {
map_beacon_state_gloas_fields!(state, |_, field| {
leaves.push(field.tree_hash_root());
});
}
};
leaves
@@ -2813,6 +2877,7 @@ impl<E: EthSpec> CompareFields for BeaconState<E> {
(BeaconState::Deneb(x), BeaconState::Deneb(y)) => x.compare_fields(y),
(BeaconState::Electra(x), BeaconState::Electra(y)) => x.compare_fields(y),
(BeaconState::Fulu(x), BeaconState::Fulu(y)) => x.compare_fields(y),
(BeaconState::Gloas(x), BeaconState::Gloas(y)) => x.compare_fields(y),
_ => panic!("compare_fields: mismatched state variants",),
}
}

View File

@@ -2,8 +2,9 @@ use crate::beacon_block_body::KzgCommitments;
use crate::{
ChainSpec, ContextDeserialize, EthSpec, ExecutionPayloadHeaderBellatrix,
ExecutionPayloadHeaderCapella, ExecutionPayloadHeaderDeneb, ExecutionPayloadHeaderElectra,
ExecutionPayloadHeaderFulu, ExecutionPayloadHeaderRef, ExecutionPayloadHeaderRefMut,
ExecutionRequests, ForkName, ForkVersionDecode, SignedRoot, Uint256, test_utils::TestRandom,
ExecutionPayloadHeaderFulu, ExecutionPayloadHeaderGloas, ExecutionPayloadHeaderRef,
ExecutionPayloadHeaderRefMut, ExecutionRequests, ForkName, ForkVersionDecode, SignedRoot,
Uint256, test_utils::TestRandom,
};
use bls::PublicKeyBytes;
use bls::Signature;
@@ -15,7 +16,7 @@ use test_random_derive::TestRandom;
use tree_hash_derive::TreeHash;
#[superstruct(
variants(Bellatrix, Capella, Deneb, Electra, Fulu),
variants(Bellatrix, Capella, Deneb, Electra, Fulu, Gloas),
variant_attributes(
derive(
PartialEq,
@@ -48,9 +49,11 @@ pub struct BuilderBid<E: EthSpec> {
pub header: ExecutionPayloadHeaderElectra<E>,
#[superstruct(only(Fulu), partial_getter(rename = "header_fulu"))]
pub header: ExecutionPayloadHeaderFulu<E>,
#[superstruct(only(Deneb, Electra, Fulu))]
#[superstruct(only(Gloas), partial_getter(rename = "header_gloas"))]
pub header: ExecutionPayloadHeaderGloas<E>,
#[superstruct(only(Deneb, Electra, Fulu, Gloas))]
pub blob_kzg_commitments: KzgCommitments<E>,
#[superstruct(only(Electra, Fulu))]
#[superstruct(only(Electra, Fulu, Gloas))]
pub execution_requests: ExecutionRequests<E>,
#[serde(with = "serde_utils::quoted_u256")]
pub value: Uint256,
@@ -95,6 +98,7 @@ impl<E: EthSpec> ForkVersionDecode for BuilderBid<E> {
ForkName::Deneb => BuilderBid::Deneb(BuilderBidDeneb::from_ssz_bytes(bytes)?),
ForkName::Electra => BuilderBid::Electra(BuilderBidElectra::from_ssz_bytes(bytes)?),
ForkName::Fulu => BuilderBid::Fulu(BuilderBidFulu::from_ssz_bytes(bytes)?),
ForkName::Gloas => BuilderBid::Gloas(BuilderBidGloas::from_ssz_bytes(bytes)?),
};
Ok(builder_bid)
}
@@ -150,6 +154,9 @@ impl<'de, E: EthSpec> ContextDeserialize<'de, ForkName> for BuilderBid<E> {
ForkName::Fulu => {
Self::Fulu(Deserialize::deserialize(deserializer).map_err(convert_err)?)
}
ForkName::Gloas => {
Self::Gloas(Deserialize::deserialize(deserializer).map_err(convert_err)?)
}
ForkName::Base | ForkName::Altair => {
return Err(serde::de::Error::custom(format!(
"BuilderBid failed to deserialize: unsupported fork '{}'",

View File

@@ -208,6 +208,13 @@ pub struct ChainSpec {
pub validator_custody_requirement: u64,
pub balance_per_additional_custody_group: u64,
/*
* Gloas hard fork params
*/
pub gloas_fork_version: [u8; 4],
/// The Gloas fork epoch is optional, with `None` representing "Gloas never happens".
pub gloas_fork_epoch: Option<Epoch>,
/*
* Networking
*/
@@ -250,6 +257,10 @@ pub struct ChainSpec {
pub(crate) blob_schedule: BlobSchedule,
min_epochs_for_data_column_sidecars_requests: u64,
/*
* Networking Gloas
*/
/*
* Networking Derived
*
@@ -321,25 +332,26 @@ 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.fulu_fork_epoch {
Some(fork_epoch) if epoch >= fork_epoch => ForkName::Fulu,
_ => 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::Bellatrix,
_ => match self.altair_fork_epoch {
Some(fork_epoch) if epoch >= fork_epoch => ForkName::Altair,
_ => ForkName::Base,
},
},
},
},
},
let forks = [
(self.gloas_fork_epoch, ForkName::Gloas),
(self.fulu_fork_epoch, ForkName::Fulu),
(self.electra_fork_epoch, ForkName::Electra),
(self.deneb_fork_epoch, ForkName::Deneb),
(self.capella_fork_epoch, ForkName::Capella),
(self.bellatrix_fork_epoch, ForkName::Bellatrix),
(self.altair_fork_epoch, ForkName::Altair),
];
// Find the first fork where `epoch` is >= `fork_epoch`.
for (fork_epoch_opt, fork_name) in forks.iter() {
if let Some(fork_epoch) = fork_epoch_opt
&& epoch >= *fork_epoch
{
return *fork_name;
}
}
ForkName::Base
}
/// Returns the fork version for a named fork.
@@ -352,6 +364,7 @@ impl ChainSpec {
ForkName::Deneb => self.deneb_fork_version,
ForkName::Electra => self.electra_fork_version,
ForkName::Fulu => self.fulu_fork_version,
ForkName::Gloas => self.gloas_fork_version,
}
}
@@ -370,6 +383,7 @@ impl ChainSpec {
ForkName::Deneb => self.deneb_fork_epoch,
ForkName::Electra => self.electra_fork_epoch,
ForkName::Fulu => self.fulu_fork_epoch,
ForkName::Gloas => self.gloas_fork_epoch,
}
}
@@ -453,6 +467,12 @@ impl ChainSpec {
.is_some_and(|fulu_fork_epoch| fulu_fork_epoch != self.far_future_epoch)
}
/// Returns true if `GLOAS_FORK_EPOCH` is set and is not set to `FAR_FUTURE_EPOCH`.
pub fn is_gloas_scheduled(&self) -> bool {
self.gloas_fork_epoch
.is_some_and(|gloas_fork_epoch| gloas_fork_epoch != self.far_future_epoch)
}
/// Returns a full `Fork` struct for a given epoch.
pub fn fork_at_epoch(&self, epoch: Epoch) -> Fork {
let current_fork_name = self.fork_name_at_epoch(epoch);
@@ -1050,6 +1070,12 @@ impl ChainSpec {
validator_custody_requirement: 8,
balance_per_additional_custody_group: 32000000000,
/*
* Gloas hard fork params
*/
gloas_fork_version: [0x07, 0x00, 0x00, 0x00],
gloas_fork_epoch: None,
/*
* Network specific
*/
@@ -1173,6 +1199,9 @@ impl ChainSpec {
// Fulu
fulu_fork_version: [0x06, 0x00, 0x00, 0x01],
fulu_fork_epoch: None,
// Gloas
gloas_fork_version: [0x07, 0x00, 0x00, 0x00],
gloas_fork_epoch: None,
// Other
network_id: 2, // lighthouse testnet network id
deposit_chain_id: 5,
@@ -1387,6 +1416,12 @@ impl ChainSpec {
validator_custody_requirement: 8,
balance_per_additional_custody_group: 32000000000,
/*
* Gloas hard fork params
*/
gloas_fork_version: [0x07, 0x00, 0x00, 0x64],
gloas_fork_epoch: None,
/*
* Network specific
*/
@@ -1648,6 +1683,14 @@ pub struct Config {
#[serde(deserialize_with = "deserialize_fork_epoch")]
pub fulu_fork_epoch: Option<MaybeQuoted<Epoch>>,
#[serde(default = "default_gloas_fork_version")]
#[serde(with = "serde_utils::bytes_4_hex")]
gloas_fork_version: [u8; 4],
#[serde(default)]
#[serde(serialize_with = "serialize_fork_epoch")]
#[serde(deserialize_with = "deserialize_fork_epoch")]
pub gloas_fork_epoch: Option<MaybeQuoted<Epoch>>,
#[serde(with = "serde_utils::quoted_u64")]
seconds_per_slot: u64,
#[serde(with = "serde_utils::quoted_u64")]
@@ -1805,6 +1848,11 @@ fn default_fulu_fork_version() -> [u8; 4] {
[0xff, 0xff, 0xff, 0xff]
}
fn default_gloas_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
@@ -2101,6 +2149,11 @@ impl Config {
.fulu_fork_epoch
.map(|epoch| MaybeQuoted { value: epoch }),
gloas_fork_version: spec.gloas_fork_version,
gloas_fork_epoch: spec
.gloas_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,
@@ -2190,6 +2243,8 @@ impl Config {
electra_fork_version,
fulu_fork_epoch,
fulu_fork_version,
gloas_fork_version,
gloas_fork_epoch,
seconds_per_slot,
seconds_per_eth1_block,
min_validator_withdrawability_delay,
@@ -2261,6 +2316,8 @@ impl Config {
electra_fork_version,
fulu_fork_epoch: fulu_fork_epoch.map(|q| q.value),
fulu_fork_version,
gloas_fork_version,
gloas_fork_epoch: gloas_fork_epoch.map(|q| q.value),
seconds_per_slot,
seconds_per_eth1_block,
min_validator_withdrawability_delay,
@@ -2548,6 +2605,8 @@ mod yaml_tests {
ELECTRA_FORK_EPOCH: 128
FULU_FORK_VERSION: 0x70355025
FULU_FORK_EPOCH: 256
GLOAS_FORK_VERSION: 0x80355025
GLOAS_FORK_EPOCH: 512
BLOB_SCHEDULE:
- EPOCH: 512
MAX_BLOBS_PER_BLOCK: 12

View File

@@ -1,6 +1,6 @@
use crate::{
AltairPreset, BasePreset, BellatrixPreset, CapellaPreset, ChainSpec, Config, DenebPreset,
ElectraPreset, EthSpec, FuluPreset, consts::altair, consts::deneb,
ElectraPreset, EthSpec, FuluPreset, GloasPreset, consts::altair, consts::deneb,
};
use maplit::hashmap;
use serde::{Deserialize, Serialize};
@@ -12,7 +12,7 @@ use superstruct::superstruct;
///
/// Mostly useful for the API.
#[superstruct(
variants(Deneb, Electra, Fulu),
variants(Deneb, Electra, Fulu, Gloas),
variant_attributes(derive(Serialize, Deserialize, Debug, PartialEq, Clone))
)]
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
@@ -31,12 +31,15 @@ pub struct ConfigAndPreset {
pub capella_preset: CapellaPreset,
#[serde(flatten)]
pub deneb_preset: DenebPreset,
#[superstruct(only(Electra, Fulu))]
#[superstruct(only(Electra, Fulu, Gloas))]
#[serde(flatten)]
pub electra_preset: ElectraPreset,
#[superstruct(only(Fulu))]
#[superstruct(only(Fulu, Gloas))]
#[serde(flatten)]
pub fulu_preset: FuluPreset,
#[superstruct(only(Gloas))]
#[serde(flatten)]
pub gloas_preset: GloasPreset,
/// The `extra_fields` map allows us to gracefully decode fields intended for future hard forks.
#[serde(flatten)]
pub extra_fields: HashMap<String, Value>,
@@ -52,7 +55,24 @@ impl ConfigAndPreset {
let deneb_preset = DenebPreset::from_chain_spec::<E>(spec);
let extra_fields = get_extra_fields(spec);
if spec.is_fulu_scheduled() {
if spec.is_gloas_scheduled() {
let electra_preset = ElectraPreset::from_chain_spec::<E>(spec);
let fulu_preset = FuluPreset::from_chain_spec::<E>(spec);
let gloas_preset = GloasPreset::from_chain_spec::<E>(spec);
ConfigAndPreset::Gloas(ConfigAndPresetGloas {
config,
base_preset,
altair_preset,
bellatrix_preset,
capella_preset,
deneb_preset,
electra_preset,
fulu_preset,
gloas_preset,
extra_fields,
})
} else if spec.is_fulu_scheduled() {
let electra_preset = ElectraPreset::from_chain_spec::<E>(spec);
let fulu_preset = FuluPreset::from_chain_spec::<E>(spec);
@@ -139,8 +159,8 @@ mod test {
.open(tmp_file.as_ref())
.expect("error opening file");
let mut mainnet_spec = ChainSpec::mainnet();
// setting fulu_fork_epoch because we are roundtripping a fulu config
mainnet_spec.fulu_fork_epoch = Some(Epoch::new(42));
// setting gloas_fork_epoch because we are roundtripping a gloas config
mainnet_spec.gloas_fork_epoch = Some(Epoch::new(42));
let mut yamlconfig = ConfigAndPreset::from_chain_spec::<MainnetEthSpec>(&mainnet_spec);
let (k1, v1) = ("SAMPLE_HARDFORK_KEY1", "123456789");
let (k2, v2) = ("SAMPLE_HARDFORK_KEY2", "987654321");
@@ -158,8 +178,8 @@ mod test {
.write(false)
.open(tmp_file.as_ref())
.expect("error while opening the file");
let from: ConfigAndPresetFulu =
let from: ConfigAndPresetGloas =
serde_yaml::from_reader(reader).expect("error while deserializing");
assert_eq!(ConfigAndPreset::Fulu(from), yamlconfig);
assert_eq!(ConfigAndPreset::Gloas(from), yamlconfig);
}
}

View File

@@ -15,7 +15,7 @@ pub type Transactions<E> = VariableList<
pub type Withdrawals<E> = VariableList<Withdrawal, <E as EthSpec>::MaxWithdrawalsPerPayload>;
#[superstruct(
variants(Bellatrix, Capella, Deneb, Electra, Fulu),
variants(Bellatrix, Capella, Deneb, Electra, Fulu, Gloas),
variant_attributes(
derive(
Default,
@@ -88,12 +88,12 @@ pub struct ExecutionPayload<E: EthSpec> {
pub block_hash: ExecutionBlockHash,
#[serde(with = "ssz_types::serde_utils::list_of_hex_var_list")]
pub transactions: Transactions<E>,
#[superstruct(only(Capella, Deneb, Electra, Fulu))]
#[superstruct(only(Capella, Deneb, Electra, Fulu, Gloas))]
pub withdrawals: Withdrawals<E>,
#[superstruct(only(Deneb, Electra, Fulu), partial_getter(copy))]
#[superstruct(only(Deneb, Electra, Fulu, Gloas), partial_getter(copy))]
#[serde(with = "serde_utils::quoted_u64")]
pub blob_gas_used: u64,
#[superstruct(only(Deneb, Electra, Fulu), partial_getter(copy))]
#[superstruct(only(Deneb, Electra, Fulu, Gloas), partial_getter(copy))]
#[serde(with = "serde_utils::quoted_u64")]
pub excess_blob_gas: u64,
}
@@ -122,6 +122,7 @@ impl<E: EthSpec> ForkVersionDecode for ExecutionPayload<E> {
ForkName::Deneb => ExecutionPayloadDeneb::from_ssz_bytes(bytes).map(Self::Deneb),
ForkName::Electra => ExecutionPayloadElectra::from_ssz_bytes(bytes).map(Self::Electra),
ForkName::Fulu => ExecutionPayloadFulu::from_ssz_bytes(bytes).map(Self::Fulu),
ForkName::Gloas => ExecutionPayloadGloas::from_ssz_bytes(bytes).map(Self::Gloas),
}
}
}
@@ -169,6 +170,9 @@ impl<'de, E: EthSpec> ContextDeserialize<'de, ForkName> for ExecutionPayload<E>
ForkName::Fulu => {
Self::Fulu(Deserialize::deserialize(deserializer).map_err(convert_err)?)
}
ForkName::Gloas => {
Self::Gloas(Deserialize::deserialize(deserializer).map_err(convert_err)?)
}
})
}
}
@@ -181,6 +185,7 @@ impl<E: EthSpec> ExecutionPayload<E> {
ExecutionPayload::Deneb(_) => ForkName::Deneb,
ExecutionPayload::Electra(_) => ForkName::Electra,
ExecutionPayload::Fulu(_) => ForkName::Fulu,
ExecutionPayload::Gloas(_) => ForkName::Gloas,
}
}
}

View File

@@ -8,7 +8,7 @@ use tree_hash::TreeHash;
use tree_hash_derive::TreeHash;
#[superstruct(
variants(Bellatrix, Capella, Deneb, Electra, Fulu),
variants(Bellatrix, Capella, Deneb, Electra, Fulu, Gloas),
variant_attributes(
derive(
Default,
@@ -84,12 +84,12 @@ pub struct ExecutionPayloadHeader<E: EthSpec> {
pub block_hash: ExecutionBlockHash,
#[superstruct(getter(copy))]
pub transactions_root: Hash256,
#[superstruct(only(Capella, Deneb, Electra, Fulu), partial_getter(copy))]
#[superstruct(only(Capella, Deneb, Electra, Fulu, Gloas), partial_getter(copy))]
pub withdrawals_root: Hash256,
#[superstruct(only(Deneb, Electra, Fulu), partial_getter(copy))]
#[superstruct(only(Deneb, Electra, Fulu, Gloas), partial_getter(copy))]
#[serde(with = "serde_utils::quoted_u64")]
pub blob_gas_used: u64,
#[superstruct(only(Deneb, Electra, Fulu), partial_getter(copy))]
#[superstruct(only(Deneb, Electra, Fulu, Gloas), partial_getter(copy))]
#[serde(with = "serde_utils::quoted_u64")]
pub excess_blob_gas: u64,
}
@@ -115,6 +115,7 @@ impl<E: EthSpec> ExecutionPayloadHeader<E> {
ExecutionPayloadHeaderElectra::from_ssz_bytes(bytes).map(Self::Electra)
}
ForkName::Fulu => ExecutionPayloadHeaderFulu::from_ssz_bytes(bytes).map(Self::Fulu),
ForkName::Gloas => ExecutionPayloadHeaderGloas::from_ssz_bytes(bytes).map(Self::Gloas),
}
}
@@ -136,6 +137,7 @@ impl<E: EthSpec> ExecutionPayloadHeader<E> {
ExecutionPayloadHeader::Deneb(_) => ForkName::Deneb,
ExecutionPayloadHeader::Electra(_) => ForkName::Electra,
ExecutionPayloadHeader::Fulu(_) => ForkName::Fulu,
ExecutionPayloadHeader::Gloas(_) => ForkName::Gloas,
}
}
}
@@ -243,6 +245,30 @@ impl<E: EthSpec> ExecutionPayloadHeaderElectra<E> {
}
}
impl<E: EthSpec> ExecutionPayloadHeaderFulu<E> {
pub fn upgrade_to_gloas(&self) -> ExecutionPayloadHeaderGloas<E> {
ExecutionPayloadHeaderGloas {
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, E: EthSpec> From<&'a ExecutionPayloadBellatrix<E>> for ExecutionPayloadHeaderBellatrix<E> {
fn from(payload: &'a ExecutionPayloadBellatrix<E>) -> Self {
Self {
@@ -358,6 +384,30 @@ impl<'a, E: EthSpec> From<&'a ExecutionPayloadFulu<E>> for ExecutionPayloadHeade
}
}
impl<'a, E: EthSpec> From<&'a ExecutionPayloadGloas<E>> for ExecutionPayloadHeaderGloas<E> {
fn from(payload: &'a ExecutionPayloadGloas<E>) -> 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, E: EthSpec> From<&'a Self> for ExecutionPayloadHeaderBellatrix<E> {
@@ -390,6 +440,12 @@ impl<'a, E: EthSpec> From<&'a Self> for ExecutionPayloadHeaderFulu<E> {
}
}
impl<'a, E: EthSpec> From<&'a Self> for ExecutionPayloadHeaderGloas<E> {
fn from(payload: &'a Self) -> Self {
payload.clone()
}
}
impl<'a, E: EthSpec> From<ExecutionPayloadRef<'a, E>> for ExecutionPayloadHeader<E> {
fn from(payload: ExecutionPayloadRef<'a, E>) -> Self {
map_execution_payload_ref_into_execution_payload_header!(
@@ -451,6 +507,9 @@ impl<E: EthSpec> ExecutionPayloadHeaderRefMut<'_, E> {
ExecutionPayloadHeaderRefMut::Fulu(mut_ref) => {
*mut_ref = header.try_into()?;
}
ExecutionPayloadHeaderRefMut::Gloas(mut_ref) => {
*mut_ref = header.try_into()?;
}
}
Ok(())
}
@@ -478,6 +537,16 @@ impl<E: EthSpec> TryFrom<ExecutionPayloadHeader<E>> for ExecutionPayloadHeaderFu
}
}
impl<E: EthSpec> TryFrom<ExecutionPayloadHeader<E>> for ExecutionPayloadHeaderGloas<E> {
type Error = BeaconStateError;
fn try_from(header: ExecutionPayloadHeader<E>) -> Result<Self, Self::Error> {
match header {
ExecutionPayloadHeader::Gloas(execution_payload_header) => Ok(execution_payload_header),
_ => Err(BeaconStateError::IncorrectStateVariant),
}
}
}
impl<'de, E: EthSpec> ContextDeserialize<'de, ForkName> for ExecutionPayloadHeader<E> {
fn context_deserialize<D>(deserializer: D, context: ForkName) -> Result<Self, D::Error>
where
@@ -511,6 +580,9 @@ impl<'de, E: EthSpec> ContextDeserialize<'de, ForkName> for ExecutionPayloadHead
ForkName::Fulu => {
Self::Fulu(Deserialize::deserialize(deserializer).map_err(convert_err)?)
}
ForkName::Gloas => {
Self::Gloas(Deserialize::deserialize(deserializer).map_err(convert_err)?)
}
})
}
}

View File

@@ -18,6 +18,7 @@ pub enum ForkName {
Deneb,
Electra,
Fulu,
Gloas,
}
impl ForkName {
@@ -30,6 +31,7 @@ impl ForkName {
ForkName::Deneb,
ForkName::Electra,
ForkName::Fulu,
ForkName::Gloas,
]
}
@@ -64,6 +66,7 @@ impl ForkName {
spec.deneb_fork_epoch = None;
spec.electra_fork_epoch = None;
spec.fulu_fork_epoch = None;
spec.gloas_fork_epoch = None;
spec
}
ForkName::Altair => {
@@ -73,6 +76,7 @@ impl ForkName {
spec.deneb_fork_epoch = None;
spec.electra_fork_epoch = None;
spec.fulu_fork_epoch = None;
spec.gloas_fork_epoch = None;
spec
}
ForkName::Bellatrix => {
@@ -82,6 +86,7 @@ impl ForkName {
spec.deneb_fork_epoch = None;
spec.electra_fork_epoch = None;
spec.fulu_fork_epoch = None;
spec.gloas_fork_epoch = None;
spec
}
ForkName::Capella => {
@@ -91,6 +96,7 @@ impl ForkName {
spec.deneb_fork_epoch = None;
spec.electra_fork_epoch = None;
spec.fulu_fork_epoch = None;
spec.gloas_fork_epoch = None;
spec
}
ForkName::Deneb => {
@@ -100,6 +106,7 @@ impl ForkName {
spec.deneb_fork_epoch = Some(Epoch::new(0));
spec.electra_fork_epoch = None;
spec.fulu_fork_epoch = None;
spec.gloas_fork_epoch = None;
spec
}
ForkName::Electra => {
@@ -109,6 +116,7 @@ impl ForkName {
spec.deneb_fork_epoch = Some(Epoch::new(0));
spec.electra_fork_epoch = Some(Epoch::new(0));
spec.fulu_fork_epoch = None;
spec.gloas_fork_epoch = None;
spec
}
ForkName::Fulu => {
@@ -118,6 +126,17 @@ impl ForkName {
spec.deneb_fork_epoch = Some(Epoch::new(0));
spec.electra_fork_epoch = Some(Epoch::new(0));
spec.fulu_fork_epoch = Some(Epoch::new(0));
spec.gloas_fork_epoch = None;
spec
}
ForkName::Gloas => {
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.fulu_fork_epoch = Some(Epoch::new(0));
spec.gloas_fork_epoch = Some(Epoch::new(0));
spec
}
}
@@ -135,6 +154,7 @@ impl ForkName {
ForkName::Deneb => Some(ForkName::Capella),
ForkName::Electra => Some(ForkName::Deneb),
ForkName::Fulu => Some(ForkName::Electra),
ForkName::Gloas => Some(ForkName::Fulu),
}
}
@@ -149,7 +169,8 @@ impl ForkName {
ForkName::Capella => Some(ForkName::Deneb),
ForkName::Deneb => Some(ForkName::Electra),
ForkName::Electra => Some(ForkName::Fulu),
ForkName::Fulu => None,
ForkName::Fulu => Some(ForkName::Gloas),
ForkName::Gloas => None,
}
}
@@ -176,6 +197,10 @@ impl ForkName {
pub fn fulu_enabled(self) -> bool {
self >= ForkName::Fulu
}
pub fn gloas_enabled(self) -> bool {
self >= ForkName::Gloas
}
}
/// Map a fork name into a fork-versioned superstruct type like `BeaconBlock`.
@@ -231,6 +256,10 @@ macro_rules! map_fork_name_with {
let (value, extra_data) = $body;
($t::Fulu(value), extra_data)
}
ForkName::Gloas => {
let (value, extra_data) = $body;
($t::Gloas(value), extra_data)
}
}
};
}
@@ -247,6 +276,7 @@ impl FromStr for ForkName {
"deneb" => ForkName::Deneb,
"electra" => ForkName::Electra,
"fulu" => ForkName::Fulu,
"gloas" => ForkName::Gloas,
_ => return Err(format!("unknown fork name: {}", fork_name)),
})
}
@@ -262,6 +292,7 @@ impl Display for ForkName {
ForkName::Deneb => "deneb".fmt(f),
ForkName::Electra => "electra".fmt(f),
ForkName::Fulu => "fulu".fmt(f),
ForkName::Gloas => "gloas".fmt(f),
}
}
}

View File

@@ -128,13 +128,13 @@ pub use crate::attester_slashing::{
};
pub use crate::beacon_block::{
BeaconBlock, BeaconBlockAltair, BeaconBlockBase, BeaconBlockBellatrix, BeaconBlockCapella,
BeaconBlockDeneb, BeaconBlockElectra, BeaconBlockFulu, BeaconBlockRef, BeaconBlockRefMut,
BlindedBeaconBlock, BlockImportSource, EmptyBlock,
BeaconBlockDeneb, BeaconBlockElectra, BeaconBlockFulu, BeaconBlockGloas, BeaconBlockRef,
BeaconBlockRefMut, BlindedBeaconBlock, BlockImportSource, EmptyBlock,
};
pub use crate::beacon_block_body::{
BeaconBlockBody, BeaconBlockBodyAltair, BeaconBlockBodyBase, BeaconBlockBodyBellatrix,
BeaconBlockBodyCapella, BeaconBlockBodyDeneb, BeaconBlockBodyElectra, BeaconBlockBodyFulu,
BeaconBlockBodyRef, BeaconBlockBodyRefMut,
BeaconBlockBodyGloas, BeaconBlockBodyRef, BeaconBlockBodyRefMut,
};
pub use crate::beacon_block_header::BeaconBlockHeader;
pub use crate::beacon_committee::{BeaconCommittee, OwnedBeaconCommittee};
@@ -148,6 +148,7 @@ pub use crate::chain_spec::{ChainSpec, Config, Domain};
pub use crate::checkpoint::Checkpoint;
pub use crate::config_and_preset::{
ConfigAndPreset, ConfigAndPresetDeneb, ConfigAndPresetElectra, ConfigAndPresetFulu,
ConfigAndPresetGloas,
};
pub use crate::consolidation_request::ConsolidationRequest;
pub use crate::contribution_and_proof::ContributionAndProof;
@@ -168,13 +169,13 @@ pub use crate::execution_block_hash::ExecutionBlockHash;
pub use crate::execution_block_header::{EncodableExecutionBlockHeader, ExecutionBlockHeader};
pub use crate::execution_payload::{
ExecutionPayload, ExecutionPayloadBellatrix, ExecutionPayloadCapella, ExecutionPayloadDeneb,
ExecutionPayloadElectra, ExecutionPayloadFulu, ExecutionPayloadRef, Transaction, Transactions,
Withdrawals,
ExecutionPayloadElectra, ExecutionPayloadFulu, ExecutionPayloadGloas, ExecutionPayloadRef,
Transaction, Transactions, Withdrawals,
};
pub use crate::execution_payload_header::{
ExecutionPayloadHeader, ExecutionPayloadHeaderBellatrix, ExecutionPayloadHeaderCapella,
ExecutionPayloadHeaderDeneb, ExecutionPayloadHeaderElectra, ExecutionPayloadHeaderFulu,
ExecutionPayloadHeaderRef, ExecutionPayloadHeaderRefMut,
ExecutionPayloadHeaderGloas, ExecutionPayloadHeaderRef, ExecutionPayloadHeaderRefMut,
};
pub use crate::execution_requests::{ExecutionRequests, RequestType};
pub use crate::fork::Fork;
@@ -189,32 +190,35 @@ pub use crate::indexed_attestation::{
pub use crate::light_client_bootstrap::{
LightClientBootstrap, LightClientBootstrapAltair, LightClientBootstrapCapella,
LightClientBootstrapDeneb, LightClientBootstrapElectra, LightClientBootstrapFulu,
LightClientBootstrapGloas,
};
pub use crate::light_client_finality_update::{
LightClientFinalityUpdate, LightClientFinalityUpdateAltair, LightClientFinalityUpdateCapella,
LightClientFinalityUpdateDeneb, LightClientFinalityUpdateElectra,
LightClientFinalityUpdateFulu,
LightClientFinalityUpdateFulu, LightClientFinalityUpdateGloas,
};
pub use crate::light_client_header::{
LightClientHeader, LightClientHeaderAltair, LightClientHeaderCapella, LightClientHeaderDeneb,
LightClientHeaderElectra, LightClientHeaderFulu,
LightClientHeaderElectra, LightClientHeaderFulu, LightClientHeaderGloas,
};
pub use crate::light_client_optimistic_update::{
LightClientOptimisticUpdate, LightClientOptimisticUpdateAltair,
LightClientOptimisticUpdateCapella, LightClientOptimisticUpdateDeneb,
LightClientOptimisticUpdateElectra, LightClientOptimisticUpdateFulu,
LightClientOptimisticUpdateGloas,
};
pub use crate::light_client_update::{
Error as LightClientUpdateError, LightClientUpdate, LightClientUpdateAltair,
LightClientUpdateCapella, LightClientUpdateDeneb, LightClientUpdateElectra,
LightClientUpdateFulu, MerkleProof,
LightClientUpdateFulu, LightClientUpdateGloas, MerkleProof,
};
pub use crate::participation_flags::ParticipationFlags;
pub use crate::payload::{
AbstractExecPayload, BlindedPayload, BlindedPayloadBellatrix, BlindedPayloadCapella,
BlindedPayloadDeneb, BlindedPayloadElectra, BlindedPayloadFulu, BlindedPayloadRef, BlockType,
ExecPayload, FullPayload, FullPayloadBellatrix, FullPayloadCapella, FullPayloadDeneb,
FullPayloadElectra, FullPayloadFulu, FullPayloadRef, OwnedExecPayload,
BlindedPayloadDeneb, BlindedPayloadElectra, BlindedPayloadFulu, BlindedPayloadGloas,
BlindedPayloadRef, BlockType, ExecPayload, FullPayload, FullPayloadBellatrix,
FullPayloadCapella, FullPayloadDeneb, FullPayloadElectra, FullPayloadFulu, FullPayloadGloas,
FullPayloadRef, OwnedExecPayload,
};
pub use crate::pending_attestation::PendingAttestation;
pub use crate::pending_consolidation::PendingConsolidation;
@@ -222,7 +226,7 @@ pub use crate::pending_deposit::PendingDeposit;
pub use crate::pending_partial_withdrawal::PendingPartialWithdrawal;
pub use crate::preset::{
AltairPreset, BasePreset, BellatrixPreset, CapellaPreset, DenebPreset, ElectraPreset,
FuluPreset,
FuluPreset, GloasPreset,
};
pub use crate::proposer_preparation_data::ProposerPreparationData;
pub use crate::proposer_slashing::ProposerSlashing;
@@ -237,7 +241,7 @@ pub use crate::signed_aggregate_and_proof::{
pub use crate::signed_beacon_block::{
SignedBeaconBlock, SignedBeaconBlockAltair, SignedBeaconBlockBase, SignedBeaconBlockBellatrix,
SignedBeaconBlockCapella, SignedBeaconBlockDeneb, SignedBeaconBlockElectra,
SignedBeaconBlockFulu, SignedBeaconBlockHash, SignedBlindedBeaconBlock,
SignedBeaconBlockFulu, SignedBeaconBlockGloas, SignedBeaconBlockHash, SignedBlindedBeaconBlock,
ssz_tagged_signed_beacon_block, ssz_tagged_signed_beacon_block_arc,
};
pub use crate::signed_beacon_block_header::SignedBeaconBlockHeader;

View File

@@ -2,8 +2,8 @@ use crate::context_deserialize;
use crate::{
BeaconState, ChainSpec, ContextDeserialize, EthSpec, FixedVector, ForkName, Hash256,
LightClientHeader, LightClientHeaderAltair, LightClientHeaderCapella, LightClientHeaderDeneb,
LightClientHeaderElectra, LightClientHeaderFulu, SignedBlindedBeaconBlock, Slot, SyncCommittee,
light_client_update::*, test_utils::TestRandom,
LightClientHeaderElectra, LightClientHeaderFulu, LightClientHeaderGloas,
SignedBlindedBeaconBlock, Slot, SyncCommittee, light_client_update::*, test_utils::TestRandom,
};
use derivative::Derivative;
use serde::{Deserialize, Deserializer, Serialize};
@@ -17,7 +17,7 @@ use tree_hash_derive::TreeHash;
/// A LightClientBootstrap is the initializer we send over to light_client nodes
/// that are trying to generate their basic storage when booting up.
#[superstruct(
variants(Altair, Capella, Deneb, Electra, Fulu),
variants(Altair, Capella, Deneb, Electra, Fulu, Gloas),
variant_attributes(
derive(
Debug,
@@ -62,6 +62,8 @@ pub struct LightClientBootstrap<E: EthSpec> {
pub header: LightClientHeaderElectra<E>,
#[superstruct(only(Fulu), partial_getter(rename = "header_fulu"))]
pub header: LightClientHeaderFulu<E>,
#[superstruct(only(Gloas), partial_getter(rename = "header_gloas"))]
pub header: LightClientHeaderGloas<E>,
/// The `SyncCommittee` used in the requested period.
pub current_sync_committee: Arc<SyncCommittee<E>>,
/// Merkle proof for sync committee
@@ -71,7 +73,7 @@ pub struct LightClientBootstrap<E: EthSpec> {
)]
pub current_sync_committee_branch: FixedVector<Hash256, CurrentSyncCommitteeProofLen>,
#[superstruct(
only(Electra, Fulu),
only(Electra, Fulu, Gloas),
partial_getter(rename = "current_sync_committee_branch_electra")
)]
pub current_sync_committee_branch: FixedVector<Hash256, CurrentSyncCommitteeProofLenElectra>,
@@ -88,6 +90,7 @@ impl<E: EthSpec> LightClientBootstrap<E> {
Self::Deneb(_) => func(ForkName::Deneb),
Self::Electra(_) => func(ForkName::Electra),
Self::Fulu(_) => func(ForkName::Fulu),
Self::Gloas(_) => func(ForkName::Gloas),
}
}
@@ -107,6 +110,7 @@ impl<E: EthSpec> LightClientBootstrap<E> {
ForkName::Deneb => Self::Deneb(LightClientBootstrapDeneb::from_ssz_bytes(bytes)?),
ForkName::Electra => Self::Electra(LightClientBootstrapElectra::from_ssz_bytes(bytes)?),
ForkName::Fulu => Self::Fulu(LightClientBootstrapFulu::from_ssz_bytes(bytes)?),
ForkName::Gloas => Self::Gloas(LightClientBootstrapGloas::from_ssz_bytes(bytes)?),
ForkName::Base => {
return Err(ssz::DecodeError::BytesInvalid(format!(
"LightClientBootstrap decoding for {fork_name} not implemented"
@@ -128,6 +132,7 @@ impl<E: EthSpec> LightClientBootstrap<E> {
ForkName::Deneb => <LightClientBootstrapDeneb<E> as Encode>::ssz_fixed_len(),
ForkName::Electra => <LightClientBootstrapElectra<E> as Encode>::ssz_fixed_len(),
ForkName::Fulu => <LightClientBootstrapFulu<E> as Encode>::ssz_fixed_len(),
ForkName::Gloas => <LightClientBootstrapGloas<E> as Encode>::ssz_fixed_len(),
};
fixed_len + LightClientHeader::<E>::ssz_max_var_len_for_fork(fork_name)
}
@@ -168,6 +173,11 @@ impl<E: EthSpec> LightClientBootstrap<E> {
current_sync_committee,
current_sync_committee_branch: current_sync_committee_branch.into(),
}),
ForkName::Gloas => Self::Gloas(LightClientBootstrapGloas {
header: LightClientHeaderGloas::block_to_light_client_header(block)?,
current_sync_committee,
current_sync_committee_branch: current_sync_committee_branch.into(),
}),
};
Ok(light_client_bootstrap)
@@ -213,6 +223,11 @@ impl<E: EthSpec> LightClientBootstrap<E> {
current_sync_committee,
current_sync_committee_branch: current_sync_committee_branch.into(),
}),
ForkName::Gloas => Self::Gloas(LightClientBootstrapGloas {
header: LightClientHeaderGloas::block_to_light_client_header(block)?,
current_sync_committee,
current_sync_committee_branch: current_sync_committee_branch.into(),
}),
};
Ok(light_client_bootstrap)
@@ -252,6 +267,9 @@ impl<'de, E: EthSpec> ContextDeserialize<'de, ForkName> for LightClientBootstrap
ForkName::Fulu => {
Self::Fulu(Deserialize::deserialize(deserializer).map_err(convert_err)?)
}
ForkName::Gloas => {
Self::Gloas(Deserialize::deserialize(deserializer).map_err(convert_err)?)
}
})
}
}
@@ -288,4 +306,10 @@ mod tests {
use crate::{LightClientBootstrapFulu, MainnetEthSpec};
ssz_tests!(LightClientBootstrapFulu<MainnetEthSpec>);
}
#[cfg(test)]
mod gloas {
use crate::{LightClientBootstrapGloas, MainnetEthSpec};
ssz_tests!(LightClientBootstrapGloas<MainnetEthSpec>);
}
}

View File

@@ -4,7 +4,8 @@ use crate::context_deserialize;
use crate::{
ContextDeserialize, ForkName, LightClientHeaderAltair, LightClientHeaderCapella,
LightClientHeaderDeneb, LightClientHeaderElectra, LightClientHeaderFulu,
SignedBlindedBeaconBlock, light_client_update::*, test_utils::TestRandom,
LightClientHeaderGloas, SignedBlindedBeaconBlock, light_client_update::*,
test_utils::TestRandom,
};
use derivative::Derivative;
use serde::{Deserialize, Deserializer, Serialize};
@@ -16,7 +17,7 @@ use test_random_derive::TestRandom;
use tree_hash_derive::TreeHash;
#[superstruct(
variants(Altair, Capella, Deneb, Electra, Fulu),
variants(Altair, Capella, Deneb, Electra, Fulu, Gloas),
variant_attributes(
derive(
Debug,
@@ -61,6 +62,8 @@ pub struct LightClientFinalityUpdate<E: EthSpec> {
pub attested_header: LightClientHeaderElectra<E>,
#[superstruct(only(Fulu), partial_getter(rename = "attested_header_fulu"))]
pub attested_header: LightClientHeaderFulu<E>,
#[superstruct(only(Gloas), partial_getter(rename = "attested_header_gloas"))]
pub attested_header: LightClientHeaderGloas<E>,
/// The last `BeaconBlockHeader` from the last attested finalized block (end of epoch).
#[superstruct(only(Altair), partial_getter(rename = "finalized_header_altair"))]
pub finalized_header: LightClientHeaderAltair<E>,
@@ -72,6 +75,8 @@ pub struct LightClientFinalityUpdate<E: EthSpec> {
pub finalized_header: LightClientHeaderElectra<E>,
#[superstruct(only(Fulu), partial_getter(rename = "finalized_header_fulu"))]
pub finalized_header: LightClientHeaderFulu<E>,
#[superstruct(only(Gloas), partial_getter(rename = "finalized_header_gloas"))]
pub finalized_header: LightClientHeaderGloas<E>,
/// Merkle proof attesting finalized header.
#[superstruct(
only(Altair, Capella, Deneb),
@@ -79,7 +84,7 @@ pub struct LightClientFinalityUpdate<E: EthSpec> {
)]
pub finality_branch: FixedVector<Hash256, FinalizedRootProofLen>,
#[superstruct(
only(Electra, Fulu),
only(Electra, Fulu, Gloas),
partial_getter(rename = "finality_branch_electra")
)]
pub finality_branch: FixedVector<Hash256, FinalizedRootProofLenElectra>,
@@ -160,6 +165,17 @@ impl<E: EthSpec> LightClientFinalityUpdate<E> {
sync_aggregate,
signature_slot,
}),
ForkName::Gloas => Self::Gloas(LightClientFinalityUpdateGloas {
attested_header: LightClientHeaderGloas::block_to_light_client_header(
attested_block,
)?,
finalized_header: LightClientHeaderGloas::block_to_light_client_header(
finalized_block,
)?,
finality_branch: finality_branch.into(),
sync_aggregate,
signature_slot,
}),
ForkName::Base => return Err(Error::AltairForkNotActive),
};
@@ -177,6 +193,7 @@ impl<E: EthSpec> LightClientFinalityUpdate<E> {
Self::Deneb(_) => func(ForkName::Deneb),
Self::Electra(_) => func(ForkName::Electra),
Self::Fulu(_) => func(ForkName::Fulu),
Self::Gloas(_) => func(ForkName::Gloas),
}
}
@@ -214,6 +231,7 @@ impl<E: EthSpec> LightClientFinalityUpdate<E> {
Self::Electra(LightClientFinalityUpdateElectra::from_ssz_bytes(bytes)?)
}
ForkName::Fulu => Self::Fulu(LightClientFinalityUpdateFulu::from_ssz_bytes(bytes)?),
ForkName::Gloas => Self::Gloas(LightClientFinalityUpdateGloas::from_ssz_bytes(bytes)?),
ForkName::Base => {
return Err(ssz::DecodeError::BytesInvalid(format!(
"LightClientFinalityUpdate decoding for {fork_name} not implemented"
@@ -235,6 +253,7 @@ impl<E: EthSpec> LightClientFinalityUpdate<E> {
ForkName::Deneb => <LightClientFinalityUpdateDeneb<E> as Encode>::ssz_fixed_len(),
ForkName::Electra => <LightClientFinalityUpdateElectra<E> as Encode>::ssz_fixed_len(),
ForkName::Fulu => <LightClientFinalityUpdateFulu<E> as Encode>::ssz_fixed_len(),
ForkName::Gloas => <LightClientFinalityUpdateGloas<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)
@@ -287,6 +306,9 @@ impl<'de, E: EthSpec> ContextDeserialize<'de, ForkName> for LightClientFinalityU
ForkName::Fulu => {
Self::Fulu(Deserialize::deserialize(deserializer).map_err(convert_err)?)
}
ForkName::Gloas => {
Self::Gloas(Deserialize::deserialize(deserializer).map_err(convert_err)?)
}
})
}
}
@@ -323,4 +345,10 @@ mod tests {
use crate::{LightClientFinalityUpdateFulu, MainnetEthSpec};
ssz_tests!(LightClientFinalityUpdateFulu<MainnetEthSpec>);
}
#[cfg(test)]
mod gloas {
use crate::{LightClientFinalityUpdateGloas, MainnetEthSpec};
ssz_tests!(LightClientFinalityUpdateGloas<MainnetEthSpec>);
}
}

View File

@@ -5,8 +5,8 @@ use crate::{BeaconBlockHeader, ExecutionPayloadHeader};
use crate::{ContextDeserialize, ForkName};
use crate::{
EthSpec, ExecutionPayloadHeaderCapella, ExecutionPayloadHeaderDeneb,
ExecutionPayloadHeaderElectra, ExecutionPayloadHeaderFulu, FixedVector, Hash256,
SignedBlindedBeaconBlock, test_utils::TestRandom,
ExecutionPayloadHeaderElectra, ExecutionPayloadHeaderFulu, ExecutionPayloadHeaderGloas,
FixedVector, Hash256, SignedBlindedBeaconBlock, test_utils::TestRandom,
};
use derivative::Derivative;
use serde::{Deserialize, Deserializer, Serialize};
@@ -18,7 +18,7 @@ use test_random_derive::TestRandom;
use tree_hash_derive::TreeHash;
#[superstruct(
variants(Altair, Capella, Deneb, Electra, Fulu),
variants(Altair, Capella, Deneb, Electra, Fulu, Gloas),
variant_attributes(
derive(
Debug,
@@ -68,8 +68,10 @@ pub struct LightClientHeader<E: EthSpec> {
pub execution: ExecutionPayloadHeaderElectra<E>,
#[superstruct(only(Fulu), partial_getter(rename = "execution_payload_header_fulu"))]
pub execution: ExecutionPayloadHeaderFulu<E>,
#[superstruct(only(Gloas), partial_getter(rename = "execution_payload_header_gloas"))]
pub execution: ExecutionPayloadHeaderGloas<E>,
#[superstruct(only(Capella, Deneb, Electra, Fulu))]
#[superstruct(only(Capella, Deneb, Electra, Fulu, Gloas))]
pub execution_branch: FixedVector<Hash256, ExecutionPayloadProofLen>,
#[ssz(skip_serializing, skip_deserializing)]
@@ -104,6 +106,9 @@ impl<E: EthSpec> LightClientHeader<E> {
ForkName::Fulu => {
LightClientHeader::Fulu(LightClientHeaderFulu::block_to_light_client_header(block)?)
}
ForkName::Gloas => LightClientHeader::Gloas(
LightClientHeaderGloas::block_to_light_client_header(block)?,
),
};
Ok(header)
}
@@ -125,6 +130,9 @@ impl<E: EthSpec> LightClientHeader<E> {
ForkName::Fulu => {
LightClientHeader::Fulu(LightClientHeaderFulu::from_ssz_bytes(bytes)?)
}
ForkName::Gloas => {
LightClientHeader::Gloas(LightClientHeaderGloas::from_ssz_bytes(bytes)?)
}
ForkName::Base => {
return Err(ssz::DecodeError::BytesInvalid(format!(
"LightClientHeader decoding for {fork_name} not implemented"
@@ -340,6 +348,48 @@ impl<E: EthSpec> Default for LightClientHeaderFulu<E> {
}
}
impl<E: EthSpec> LightClientHeaderGloas<E> {
pub fn block_to_light_client_header(
block: &SignedBlindedBeaconBlock<E>,
) -> Result<Self, Error> {
let payload = block
.message()
.execution_payload()?
.execution_payload_gloas()?;
let header = ExecutionPayloadHeaderGloas::from(payload);
let beacon_block_body = BeaconBlockBody::from(
block
.message()
.body_gloas()
.map_err(|_| Error::BeaconBlockBodyError)?
.to_owned(),
);
let execution_branch = beacon_block_body
.to_ref()
.block_body_merkle_proof(EXECUTION_PAYLOAD_INDEX)?;
Ok(LightClientHeaderGloas {
beacon: block.message().block_header(),
execution: header,
execution_branch: FixedVector::new(execution_branch)?,
_phantom_data: PhantomData,
})
}
}
impl<E: EthSpec> Default for LightClientHeaderGloas<E> {
fn default() -> Self {
Self {
beacon: BeaconBlockHeader::empty(),
execution: ExecutionPayloadHeaderGloas::default(),
execution_branch: FixedVector::default(),
_phantom_data: PhantomData,
}
}
}
impl<'de, E: EthSpec> ContextDeserialize<'de, ForkName> for LightClientHeader<E> {
fn context_deserialize<D>(deserializer: D, context: ForkName) -> Result<Self, D::Error>
where
@@ -373,6 +423,9 @@ impl<'de, E: EthSpec> ContextDeserialize<'de, ForkName> for LightClientHeader<E>
ForkName::Fulu => {
Self::Fulu(Deserialize::deserialize(deserializer).map_err(convert_err)?)
}
ForkName::Gloas => {
Self::Gloas(Deserialize::deserialize(deserializer).map_err(convert_err)?)
}
})
}
}
@@ -403,4 +456,16 @@ mod tests {
use crate::{LightClientHeaderElectra, MainnetEthSpec};
ssz_tests!(LightClientHeaderElectra<MainnetEthSpec>);
}
#[cfg(test)]
mod fulu {
use crate::{LightClientHeaderFulu, MainnetEthSpec};
ssz_tests!(LightClientHeaderFulu<MainnetEthSpec>);
}
#[cfg(test)]
mod gloas {
use crate::{LightClientHeaderGloas, MainnetEthSpec};
ssz_tests!(LightClientHeaderGloas<MainnetEthSpec>);
}
}

View File

@@ -3,8 +3,8 @@ use crate::context_deserialize;
use crate::test_utils::TestRandom;
use crate::{
ChainSpec, LightClientHeaderAltair, LightClientHeaderCapella, LightClientHeaderDeneb,
LightClientHeaderElectra, LightClientHeaderFulu, SignedBlindedBeaconBlock,
light_client_update::*,
LightClientHeaderElectra, LightClientHeaderFulu, LightClientHeaderGloas,
SignedBlindedBeaconBlock, light_client_update::*,
};
use derivative::Derivative;
use serde::{Deserialize, Deserializer, Serialize};
@@ -19,7 +19,7 @@ use tree_hash_derive::TreeHash;
/// A LightClientOptimisticUpdate is the update we send on each slot,
/// it is based off the current unfinalized epoch is verified only against BLS signature.
#[superstruct(
variants(Altair, Capella, Deneb, Electra, Fulu),
variants(Altair, Capella, Deneb, Electra, Fulu, Gloas),
variant_attributes(
derive(
Debug,
@@ -64,6 +64,8 @@ pub struct LightClientOptimisticUpdate<E: EthSpec> {
pub attested_header: LightClientHeaderElectra<E>,
#[superstruct(only(Fulu), partial_getter(rename = "attested_header_fulu"))]
pub attested_header: LightClientHeaderFulu<E>,
#[superstruct(only(Gloas), partial_getter(rename = "attested_header_gloas"))]
pub attested_header: LightClientHeaderGloas<E>,
/// current sync aggregate
pub sync_aggregate: SyncAggregate<E>,
/// Slot of the sync aggregated signature
@@ -119,6 +121,13 @@ impl<E: EthSpec> LightClientOptimisticUpdate<E> {
sync_aggregate,
signature_slot,
}),
ForkName::Gloas => Self::Gloas(LightClientOptimisticUpdateGloas {
attested_header: LightClientHeaderGloas::block_to_light_client_header(
attested_block,
)?,
sync_aggregate,
signature_slot,
}),
ForkName::Base => return Err(Error::AltairForkNotActive),
};
@@ -135,6 +144,7 @@ impl<E: EthSpec> LightClientOptimisticUpdate<E> {
Self::Deneb(_) => func(ForkName::Deneb),
Self::Electra(_) => func(ForkName::Electra),
Self::Fulu(_) => func(ForkName::Fulu),
Self::Gloas(_) => func(ForkName::Gloas),
}
}
@@ -174,6 +184,9 @@ impl<E: EthSpec> LightClientOptimisticUpdate<E> {
Self::Electra(LightClientOptimisticUpdateElectra::from_ssz_bytes(bytes)?)
}
ForkName::Fulu => Self::Fulu(LightClientOptimisticUpdateFulu::from_ssz_bytes(bytes)?),
ForkName::Gloas => {
Self::Gloas(LightClientOptimisticUpdateGloas::from_ssz_bytes(bytes)?)
}
ForkName::Base => {
return Err(ssz::DecodeError::BytesInvalid(format!(
"LightClientOptimisticUpdate decoding for {fork_name} not implemented"
@@ -195,6 +208,7 @@ impl<E: EthSpec> LightClientOptimisticUpdate<E> {
ForkName::Deneb => <LightClientOptimisticUpdateDeneb<E> as Encode>::ssz_fixed_len(),
ForkName::Electra => <LightClientOptimisticUpdateElectra<E> as Encode>::ssz_fixed_len(),
ForkName::Fulu => <LightClientOptimisticUpdateFulu<E> as Encode>::ssz_fixed_len(),
ForkName::Gloas => <LightClientOptimisticUpdateGloas<E> as Encode>::ssz_fixed_len(),
};
fixed_len + LightClientHeader::<E>::ssz_max_var_len_for_fork(fork_name)
}
@@ -246,6 +260,9 @@ impl<'de, E: EthSpec> ContextDeserialize<'de, ForkName> for LightClientOptimisti
ForkName::Fulu => {
Self::Fulu(Deserialize::deserialize(deserializer).map_err(convert_err)?)
}
ForkName::Gloas => {
Self::Gloas(Deserialize::deserialize(deserializer).map_err(convert_err)?)
}
})
}
}
@@ -282,4 +299,10 @@ mod tests {
use crate::{LightClientOptimisticUpdateFulu, MainnetEthSpec};
ssz_tests!(LightClientOptimisticUpdateFulu<MainnetEthSpec>);
}
#[cfg(test)]
mod gloas {
use crate::{LightClientOptimisticUpdateGloas, MainnetEthSpec};
ssz_tests!(LightClientOptimisticUpdateGloas<MainnetEthSpec>);
}
}

View File

@@ -5,7 +5,7 @@ use crate::light_client_header::LightClientHeaderElectra;
use crate::{
ChainSpec, ContextDeserialize, Epoch, ForkName, LightClientHeaderAltair,
LightClientHeaderCapella, LightClientHeaderDeneb, LightClientHeaderFulu,
SignedBlindedBeaconBlock, beacon_state, test_utils::TestRandom,
LightClientHeaderGloas, SignedBlindedBeaconBlock, beacon_state, test_utils::TestRandom,
};
use derivative::Derivative;
use safe_arith::ArithError;
@@ -100,7 +100,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
/// we go over, note: there is no need to keep all of the updates from [ALTAIR_PERIOD, CURRENT_PERIOD].
#[superstruct(
variants(Altair, Capella, Deneb, Electra, Fulu),
variants(Altair, Capella, Deneb, Electra, Fulu, Gloas),
variant_attributes(
derive(
Debug,
@@ -145,6 +145,8 @@ pub struct LightClientUpdate<E: EthSpec> {
pub attested_header: LightClientHeaderElectra<E>,
#[superstruct(only(Fulu), partial_getter(rename = "attested_header_fulu"))]
pub attested_header: LightClientHeaderFulu<E>,
#[superstruct(only(Gloas), partial_getter(rename = "attested_header_gloas"))]
pub attested_header: LightClientHeaderGloas<E>,
/// The `SyncCommittee` used in the next period.
pub next_sync_committee: Arc<SyncCommittee<E>>,
// Merkle proof for next sync committee
@@ -154,7 +156,7 @@ pub struct LightClientUpdate<E: EthSpec> {
)]
pub next_sync_committee_branch: NextSyncCommitteeBranch,
#[superstruct(
only(Electra, Fulu),
only(Electra, Fulu, Gloas),
partial_getter(rename = "next_sync_committee_branch_electra")
)]
pub next_sync_committee_branch: NextSyncCommitteeBranchElectra,
@@ -169,6 +171,8 @@ pub struct LightClientUpdate<E: EthSpec> {
pub finalized_header: LightClientHeaderElectra<E>,
#[superstruct(only(Fulu), partial_getter(rename = "finalized_header_fulu"))]
pub finalized_header: LightClientHeaderFulu<E>,
#[superstruct(only(Gloas), partial_getter(rename = "finalized_header_gloas"))]
pub finalized_header: LightClientHeaderGloas<E>,
/// Merkle proof attesting finalized header.
#[superstruct(
only(Altair, Capella, Deneb),
@@ -176,7 +180,7 @@ pub struct LightClientUpdate<E: EthSpec> {
)]
pub finality_branch: FinalityBranch,
#[superstruct(
only(Electra, Fulu),
only(Electra, Fulu, Gloas),
partial_getter(rename = "finality_branch_electra")
)]
pub finality_branch: FinalityBranchElectra,
@@ -216,6 +220,9 @@ impl<'de, E: EthSpec> ContextDeserialize<'de, ForkName> for LightClientUpdate<E>
ForkName::Fulu => {
Self::Fulu(Deserialize::deserialize(deserializer).map_err(convert_err)?)
}
ForkName::Gloas => {
Self::Gloas(Deserialize::deserialize(deserializer).map_err(convert_err)?)
}
})
}
}
@@ -356,6 +363,30 @@ impl<E: EthSpec> LightClientUpdate<E> {
sync_aggregate: sync_aggregate.clone(),
signature_slot: block_slot,
})
}
fork_name @ ForkName::Gloas => {
let attested_header =
LightClientHeaderGloas::block_to_light_client_header(attested_block)?;
let finalized_header = if let Some(finalized_block) = finalized_block {
if finalized_block.fork_name_unchecked() == fork_name {
LightClientHeaderGloas::block_to_light_client_header(finalized_block)?
} else {
LightClientHeaderGloas::default()
}
} else {
LightClientHeaderGloas::default()
};
Self::Gloas(LightClientUpdateGloas {
attested_header,
next_sync_committee,
next_sync_committee_branch: next_sync_committee_branch.into(),
finalized_header,
finality_branch: finality_branch.into(),
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 LightClientUpdate variant only
// if you need to test or support lightclient usages
@@ -373,6 +404,7 @@ impl<E: EthSpec> LightClientUpdate<E> {
ForkName::Deneb => Self::Deneb(LightClientUpdateDeneb::from_ssz_bytes(bytes)?),
ForkName::Electra => Self::Electra(LightClientUpdateElectra::from_ssz_bytes(bytes)?),
ForkName::Fulu => Self::Fulu(LightClientUpdateFulu::from_ssz_bytes(bytes)?),
ForkName::Gloas => Self::Gloas(LightClientUpdateGloas::from_ssz_bytes(bytes)?),
ForkName::Base => {
return Err(ssz::DecodeError::BytesInvalid(format!(
"LightClientUpdate decoding for {fork_name} not implemented"
@@ -390,6 +422,7 @@ impl<E: EthSpec> LightClientUpdate<E> {
LightClientUpdate::Deneb(update) => update.attested_header.beacon.slot,
LightClientUpdate::Electra(update) => update.attested_header.beacon.slot,
LightClientUpdate::Fulu(update) => update.attested_header.beacon.slot,
LightClientUpdate::Gloas(update) => update.attested_header.beacon.slot,
}
}
@@ -400,6 +433,7 @@ impl<E: EthSpec> LightClientUpdate<E> {
LightClientUpdate::Deneb(update) => update.finalized_header.beacon.slot,
LightClientUpdate::Electra(update) => update.finalized_header.beacon.slot,
LightClientUpdate::Fulu(update) => update.finalized_header.beacon.slot,
LightClientUpdate::Gloas(update) => update.finalized_header.beacon.slot,
}
}
@@ -520,6 +554,7 @@ impl<E: EthSpec> LightClientUpdate<E> {
ForkName::Deneb => <LightClientUpdateDeneb<E> as Encode>::ssz_fixed_len(),
ForkName::Electra => <LightClientUpdateElectra<E> as Encode>::ssz_fixed_len(),
ForkName::Fulu => <LightClientUpdateFulu<E> as Encode>::ssz_fixed_len(),
ForkName::Gloas => <LightClientUpdateGloas<E> as Encode>::ssz_fixed_len(),
};
fixed_len + 2 * LightClientHeader::<E>::ssz_max_var_len_for_fork(fork_name)
}
@@ -534,6 +569,7 @@ impl<E: EthSpec> LightClientUpdate<E> {
Self::Deneb(_) => func(ForkName::Deneb),
Self::Electra(_) => func(ForkName::Electra),
Self::Fulu(_) => func(ForkName::Fulu),
Self::Gloas(_) => func(ForkName::Gloas),
}
}
}
@@ -596,6 +632,13 @@ mod tests {
ssz_tests!(LightClientUpdateFulu<MainnetEthSpec>);
}
#[cfg(test)]
mod gloas {
use super::*;
use crate::MainnetEthSpec;
ssz_tests!(LightClientUpdateGloas<MainnetEthSpec>);
}
#[test]
fn finalized_root_params() {
assert!(2usize.pow(FINALIZED_ROOT_PROOF_LEN as u32) <= FINALIZED_ROOT_INDEX);

View File

@@ -105,6 +105,7 @@ pub trait AbstractExecPayload<E: EthSpec>:
+ TryInto<Self::Deneb>
+ TryInto<Self::Electra>
+ TryInto<Self::Fulu>
+ TryInto<Self::Gloas>
+ Sync
{
type Ref<'a>: ExecPayload<E>
@@ -113,7 +114,8 @@ pub trait AbstractExecPayload<E: EthSpec>:
+ From<&'a Self::Capella>
+ From<&'a Self::Deneb>
+ From<&'a Self::Electra>
+ From<&'a Self::Fulu>;
+ From<&'a Self::Fulu>
+ From<&'a Self::Gloas>;
type Bellatrix: OwnedExecPayload<E>
+ Into<Self>
@@ -140,10 +142,15 @@ pub trait AbstractExecPayload<E: EthSpec>:
+ for<'a> From<Cow<'a, ExecutionPayloadFulu<E>>>
+ TryFrom<ExecutionPayloadHeaderFulu<E>>
+ Sync;
type Gloas: OwnedExecPayload<E>
+ Into<Self>
+ for<'a> From<Cow<'a, ExecutionPayloadGloas<E>>>
+ TryFrom<ExecutionPayloadHeaderGloas<E>>
+ Sync;
}
#[superstruct(
variants(Bellatrix, Capella, Deneb, Electra, Fulu),
variants(Bellatrix, Capella, Deneb, Electra, Fulu, Gloas),
variant_attributes(
derive(
Debug,
@@ -198,6 +205,8 @@ pub struct FullPayload<E: EthSpec> {
pub execution_payload: ExecutionPayloadElectra<E>,
#[superstruct(only(Fulu), partial_getter(rename = "execution_payload_fulu"))]
pub execution_payload: ExecutionPayloadFulu<E>,
#[superstruct(only(Gloas), partial_getter(rename = "execution_payload_gloas"))]
pub execution_payload: ExecutionPayloadGloas<E>,
}
impl<E: EthSpec> From<FullPayload<E>> for ExecutionPayload<E> {
@@ -309,6 +318,7 @@ impl<E: EthSpec> ExecPayload<E> for FullPayload<E> {
FullPayload::Deneb(inner) => Ok(inner.execution_payload.withdrawals.tree_hash_root()),
FullPayload::Electra(inner) => Ok(inner.execution_payload.withdrawals.tree_hash_root()),
FullPayload::Fulu(inner) => Ok(inner.execution_payload.withdrawals.tree_hash_root()),
FullPayload::Gloas(inner) => Ok(inner.execution_payload.withdrawals.tree_hash_root()),
}
}
@@ -320,6 +330,7 @@ impl<E: EthSpec> ExecPayload<E> for FullPayload<E> {
FullPayload::Deneb(inner) => Ok(inner.execution_payload.blob_gas_used),
FullPayload::Electra(inner) => Ok(inner.execution_payload.blob_gas_used),
FullPayload::Fulu(inner) => Ok(inner.execution_payload.blob_gas_used),
FullPayload::Gloas(inner) => Ok(inner.execution_payload.blob_gas_used),
}
}
@@ -351,6 +362,7 @@ impl<E: EthSpec> FullPayload<E> {
ForkName::Deneb => Ok(FullPayloadDeneb::default().into()),
ForkName::Electra => Ok(FullPayloadElectra::default().into()),
ForkName::Fulu => Ok(FullPayloadFulu::default().into()),
ForkName::Gloas => Ok(FullPayloadGloas::default().into()),
}
}
}
@@ -451,6 +463,9 @@ impl<E: EthSpec> ExecPayload<E> for FullPayloadRef<'_, E> {
Ok(inner.execution_payload.withdrawals.tree_hash_root())
}
FullPayloadRef::Fulu(inner) => Ok(inner.execution_payload.withdrawals.tree_hash_root()),
FullPayloadRef::Gloas(inner) => {
Ok(inner.execution_payload.withdrawals.tree_hash_root())
}
}
}
@@ -462,6 +477,7 @@ impl<E: EthSpec> ExecPayload<E> for FullPayloadRef<'_, E> {
FullPayloadRef::Deneb(inner) => Ok(inner.execution_payload.blob_gas_used),
FullPayloadRef::Electra(inner) => Ok(inner.execution_payload.blob_gas_used),
FullPayloadRef::Fulu(inner) => Ok(inner.execution_payload.blob_gas_used),
FullPayloadRef::Gloas(inner) => Ok(inner.execution_payload.blob_gas_used),
}
}
@@ -485,6 +501,7 @@ impl<E: EthSpec> AbstractExecPayload<E> for FullPayload<E> {
type Deneb = FullPayloadDeneb<E>;
type Electra = FullPayloadElectra<E>;
type Fulu = FullPayloadFulu<E>;
type Gloas = FullPayloadGloas<E>;
}
impl<E: EthSpec> From<ExecutionPayload<E>> for FullPayload<E> {
@@ -503,7 +520,7 @@ impl<E: EthSpec> TryFrom<ExecutionPayloadHeader<E>> for FullPayload<E> {
}
#[superstruct(
variants(Bellatrix, Capella, Deneb, Electra, Fulu),
variants(Bellatrix, Capella, Deneb, Electra, Fulu, Gloas),
variant_attributes(
derive(
Debug,
@@ -557,6 +574,8 @@ pub struct BlindedPayload<E: EthSpec> {
pub execution_payload_header: ExecutionPayloadHeaderElectra<E>,
#[superstruct(only(Fulu), partial_getter(rename = "execution_payload_fulu"))]
pub execution_payload_header: ExecutionPayloadHeaderFulu<E>,
#[superstruct(only(Gloas), partial_getter(rename = "execution_payload_gloas"))]
pub execution_payload_header: ExecutionPayloadHeaderGloas<E>,
}
impl<'a, E: EthSpec> From<BlindedPayloadRef<'a, E>> for BlindedPayload<E> {
@@ -646,6 +665,7 @@ impl<E: EthSpec> ExecPayload<E> for BlindedPayload<E> {
BlindedPayload::Deneb(inner) => Ok(inner.execution_payload_header.withdrawals_root),
BlindedPayload::Electra(inner) => Ok(inner.execution_payload_header.withdrawals_root),
BlindedPayload::Fulu(inner) => Ok(inner.execution_payload_header.withdrawals_root),
BlindedPayload::Gloas(inner) => Ok(inner.execution_payload_header.withdrawals_root),
}
}
@@ -657,6 +677,7 @@ impl<E: EthSpec> ExecPayload<E> for BlindedPayload<E> {
BlindedPayload::Deneb(inner) => Ok(inner.execution_payload_header.blob_gas_used),
BlindedPayload::Electra(inner) => Ok(inner.execution_payload_header.blob_gas_used),
BlindedPayload::Fulu(inner) => Ok(inner.execution_payload_header.blob_gas_used),
BlindedPayload::Gloas(inner) => Ok(inner.execution_payload_header.blob_gas_used),
}
}
@@ -756,6 +777,7 @@ impl<'b, E: EthSpec> ExecPayload<E> for BlindedPayloadRef<'b, E> {
Ok(inner.execution_payload_header.withdrawals_root)
}
BlindedPayloadRef::Fulu(inner) => Ok(inner.execution_payload_header.withdrawals_root),
BlindedPayloadRef::Gloas(inner) => Ok(inner.execution_payload_header.withdrawals_root),
}
}
@@ -767,6 +789,7 @@ impl<'b, E: EthSpec> ExecPayload<E> for BlindedPayloadRef<'b, E> {
BlindedPayloadRef::Deneb(inner) => Ok(inner.execution_payload_header.blob_gas_used),
BlindedPayloadRef::Electra(inner) => Ok(inner.execution_payload_header.blob_gas_used),
BlindedPayloadRef::Fulu(inner) => Ok(inner.execution_payload_header.blob_gas_used),
BlindedPayloadRef::Gloas(inner) => Ok(inner.execution_payload_header.blob_gas_used),
}
}
@@ -1077,6 +1100,13 @@ impl_exec_payload_for_fork!(
ExecutionPayloadFulu,
Fulu
);
impl_exec_payload_for_fork!(
BlindedPayloadGloas,
FullPayloadGloas,
ExecutionPayloadHeaderGloas,
ExecutionPayloadGloas,
Gloas
);
impl<E: EthSpec> AbstractExecPayload<E> for BlindedPayload<E> {
type Ref<'a> = BlindedPayloadRef<'a, E>;
@@ -1085,6 +1115,7 @@ impl<E: EthSpec> AbstractExecPayload<E> for BlindedPayload<E> {
type Deneb = BlindedPayloadDeneb<E>;
type Electra = BlindedPayloadElectra<E>;
type Fulu = BlindedPayloadFulu<E>;
type Gloas = BlindedPayloadGloas<E>;
}
impl<E: EthSpec> From<ExecutionPayload<E>> for BlindedPayload<E> {
@@ -1126,6 +1157,11 @@ impl<E: EthSpec> From<ExecutionPayloadHeader<E>> for BlindedPayload<E> {
execution_payload_header,
})
}
ExecutionPayloadHeader::Gloas(execution_payload_header) => {
Self::Gloas(BlindedPayloadGloas {
execution_payload_header,
})
}
}
}
}
@@ -1148,6 +1184,9 @@ impl<E: EthSpec> From<BlindedPayload<E>> for ExecutionPayloadHeader<E> {
BlindedPayload::Fulu(blinded_payload) => {
ExecutionPayloadHeader::Fulu(blinded_payload.execution_payload_header)
}
BlindedPayload::Gloas(blinded_payload) => {
ExecutionPayloadHeader::Gloas(blinded_payload.execution_payload_header)
}
}
}
}

View File

@@ -316,6 +316,16 @@ impl FuluPreset {
}
}
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
#[serde(rename_all = "UPPERCASE")]
pub struct GloasPreset {}
impl GloasPreset {
pub fn from_chain_spec<E: EthSpec>(_spec: &ChainSpec) -> Self {
Self {}
}
}
#[cfg(test)]
mod test {
use super::*;
@@ -363,6 +373,9 @@ mod test {
let fulu: FuluPreset = preset_from_file(&preset_name, "fulu.yaml");
assert_eq!(fulu, FuluPreset::from_chain_spec::<E>(&spec));
let gloas: GloasPreset = preset_from_file(&preset_name, "gloas.yaml");
assert_eq!(gloas, GloasPreset::from_chain_spec::<E>(&spec));
}
#[test]

View File

@@ -41,7 +41,7 @@ impl From<SignedBeaconBlockHash> for Hash256 {
/// A `BeaconBlock` and a signature from its proposer.
#[superstruct(
variants(Base, Altair, Bellatrix, Capella, Deneb, Electra, Fulu),
variants(Base, Altair, Bellatrix, Capella, Deneb, Electra, Fulu, Gloas),
variant_attributes(
derive(
Debug,
@@ -92,6 +92,8 @@ pub struct SignedBeaconBlock<E: EthSpec, Payload: AbstractExecPayload<E> = FullP
pub message: BeaconBlockElectra<E, Payload>,
#[superstruct(only(Fulu), partial_getter(rename = "message_fulu"))]
pub message: BeaconBlockFulu<E, Payload>,
#[superstruct(only(Gloas), partial_getter(rename = "message_gloas"))]
pub message: BeaconBlockGloas<E, Payload>,
pub signature: Signature,
}
@@ -178,6 +180,9 @@ impl<E: EthSpec, Payload: AbstractExecPayload<E>> SignedBeaconBlock<E, Payload>
BeaconBlock::Fulu(message) => {
SignedBeaconBlock::Fulu(SignedBeaconBlockFulu { message, signature })
}
BeaconBlock::Gloas(message) => {
SignedBeaconBlock::Gloas(SignedBeaconBlockGloas { message, signature })
}
}
}
@@ -643,6 +648,64 @@ impl<E: EthSpec> SignedBeaconBlockFulu<E, BlindedPayload<E>> {
}
}
impl<E: EthSpec> SignedBeaconBlockGloas<E, BlindedPayload<E>> {
pub fn into_full_block(
self,
execution_payload: ExecutionPayloadGloas<E>,
) -> SignedBeaconBlockGloas<E, FullPayload<E>> {
let SignedBeaconBlockGloas {
message:
BeaconBlockGloas {
slot,
proposer_index,
parent_root,
state_root,
body:
BeaconBlockBodyGloas {
randao_reveal,
eth1_data,
graffiti,
proposer_slashings,
attester_slashings,
attestations,
deposits,
voluntary_exits,
sync_aggregate,
execution_payload: BlindedPayloadGloas { .. },
bls_to_execution_changes,
blob_kzg_commitments,
execution_requests,
},
},
signature,
} = self;
SignedBeaconBlockGloas {
message: BeaconBlockGloas {
slot,
proposer_index,
parent_root,
state_root,
body: BeaconBlockBodyGloas {
randao_reveal,
eth1_data,
graffiti,
proposer_slashings,
attester_slashings,
attestations,
deposits,
voluntary_exits,
sync_aggregate,
execution_payload: FullPayloadGloas { execution_payload },
bls_to_execution_changes,
blob_kzg_commitments,
execution_requests,
},
},
signature,
}
}
}
impl<E: EthSpec> SignedBeaconBlock<E, BlindedPayload<E>> {
pub fn try_into_full_block(
self,
@@ -666,6 +729,9 @@ impl<E: EthSpec> SignedBeaconBlock<E, BlindedPayload<E>> {
(SignedBeaconBlock::Fulu(block), Some(ExecutionPayload::Fulu(payload))) => {
SignedBeaconBlock::Fulu(block.into_full_block(payload))
}
(SignedBeaconBlock::Gloas(block), Some(ExecutionPayload::Gloas(payload))) => {
SignedBeaconBlock::Gloas(block.into_full_block(payload))
}
// avoid wildcard matching forks so that compiler will
// direct us here when a new fork has been added
(SignedBeaconBlock::Bellatrix(_), _) => return None,
@@ -673,6 +739,7 @@ impl<E: EthSpec> SignedBeaconBlock<E, BlindedPayload<E>> {
(SignedBeaconBlock::Deneb(_), _) => return None,
(SignedBeaconBlock::Electra(_), _) => return None,
(SignedBeaconBlock::Fulu(_), _) => return None,
(SignedBeaconBlock::Gloas(_), _) => return None,
};
Some(full_block)
}
@@ -818,6 +885,9 @@ pub mod ssz_tagged_signed_beacon_block {
ForkName::Fulu => Ok(SignedBeaconBlock::Fulu(
SignedBeaconBlockFulu::from_ssz_bytes(body)?,
)),
ForkName::Gloas => Ok(SignedBeaconBlock::Gloas(
SignedBeaconBlockGloas::from_ssz_bytes(body)?,
)),
}
}
}
@@ -897,6 +967,7 @@ mod test {
chain_spec.deneb_fork_epoch = Some(Epoch::new(4));
chain_spec.electra_fork_epoch = Some(Epoch::new(5));
chain_spec.fulu_fork_epoch = Some(Epoch::new(6));
chain_spec.gloas_fork_epoch = Some(Epoch::new(7));
// check that we have all forks covered
assert!(chain_spec.fork_epoch(ForkName::latest()).is_some());
@@ -934,7 +1005,11 @@ mod test {
BeaconBlock::Electra(BeaconBlockElectra::empty(spec)),
sig.clone(),
),
SignedBeaconBlock::from_block(BeaconBlock::Fulu(BeaconBlockFulu::empty(spec)), sig),
SignedBeaconBlock::from_block(
BeaconBlock::Fulu(BeaconBlockFulu::empty(spec)),
sig.clone(),
),
SignedBeaconBlock::from_block(BeaconBlock::Gloas(BeaconBlockGloas::empty(spec)), sig),
];
for block in blocks {