mirror of
https://github.com/sigp/lighthouse.git
synced 2026-05-01 03:33:47 +00:00
Initial merge changes
Added Execution Payload from Rayonism Fork Updated new Containers to match Merge Spec Updated BeaconBlockBody for Merge Spec Completed updating BeaconState and BeaconBlockBody Modified ExecutionPayload<T> to use Transaction<T> Mostly Finished Changes for beacon-chain.md Added some things for fork-choice.md Update to match new fork-choice.md/fork.md changes ran cargo fmt Added Missing Pieces in eth2_libp2p for Merge fix ef test Various Changes to Conform Closer to Merge Spec
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
use crate::beacon_block_body::{
|
||||
BeaconBlockBodyAltair, BeaconBlockBodyBase, BeaconBlockBodyRef, BeaconBlockBodyRefMut,
|
||||
BeaconBlockBodyAltair, BeaconBlockBodyBase, BeaconBlockBodyMerge, BeaconBlockBodyRef,
|
||||
BeaconBlockBodyRefMut,
|
||||
};
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::*;
|
||||
@@ -14,7 +15,7 @@ use tree_hash_derive::TreeHash;
|
||||
|
||||
/// A block of the `BeaconChain`.
|
||||
#[superstruct(
|
||||
variants(Base, Altair),
|
||||
variants(Base, Altair, Merge),
|
||||
variant_attributes(
|
||||
derive(
|
||||
Debug,
|
||||
@@ -55,6 +56,8 @@ pub struct BeaconBlock<T: EthSpec> {
|
||||
pub body: BeaconBlockBodyBase<T>,
|
||||
#[superstruct(only(Altair), partial_getter(rename = "body_altair"))]
|
||||
pub body: BeaconBlockBodyAltair<T>,
|
||||
#[superstruct(only(Merge), partial_getter(rename = "body_merge"))]
|
||||
pub body: BeaconBlockBodyMerge<T>,
|
||||
}
|
||||
|
||||
impl<T: EthSpec> SignedRoot for BeaconBlock<T> {}
|
||||
@@ -63,7 +66,9 @@ impl<'a, T: EthSpec> SignedRoot for BeaconBlockRef<'a, T> {}
|
||||
impl<T: EthSpec> BeaconBlock<T> {
|
||||
/// Returns an empty block to be used during genesis.
|
||||
pub fn empty(spec: &ChainSpec) -> Self {
|
||||
if spec.altair_fork_epoch == Some(T::genesis_epoch()) {
|
||||
if spec.merge_fork_epoch == Some(T::genesis_epoch()) {
|
||||
Self::Merge(BeaconBlockMerge::empty(spec))
|
||||
} else if spec.altair_fork_epoch == Some(T::genesis_epoch()) {
|
||||
Self::Altair(BeaconBlockAltair::empty(spec))
|
||||
} else {
|
||||
Self::Base(BeaconBlockBase::empty(spec))
|
||||
@@ -174,6 +179,7 @@ impl<'a, T: EthSpec> BeaconBlockRef<'a, T> {
|
||||
let object_fork = match self {
|
||||
BeaconBlockRef::Base { .. } => ForkName::Base,
|
||||
BeaconBlockRef::Altair { .. } => ForkName::Altair,
|
||||
BeaconBlockRef::Merge { .. } => ForkName::Merge,
|
||||
};
|
||||
|
||||
if fork_at_slot == object_fork {
|
||||
@@ -191,6 +197,7 @@ impl<'a, T: EthSpec> BeaconBlockRef<'a, T> {
|
||||
match self {
|
||||
BeaconBlockRef::Base(block) => BeaconBlockBodyRef::Base(&block.body),
|
||||
BeaconBlockRef::Altair(block) => BeaconBlockBodyRef::Altair(&block.body),
|
||||
BeaconBlockRef::Merge(block) => BeaconBlockBodyRef::Merge(&block.body),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,6 +206,7 @@ impl<'a, T: EthSpec> BeaconBlockRef<'a, T> {
|
||||
match self {
|
||||
BeaconBlockRef::Base(block) => block.body.tree_hash_root(),
|
||||
BeaconBlockRef::Altair(block) => block.body.tree_hash_root(),
|
||||
BeaconBlockRef::Merge(block) => block.body.tree_hash_root(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -233,6 +241,7 @@ impl<'a, T: EthSpec> BeaconBlockRefMut<'a, T> {
|
||||
match self {
|
||||
BeaconBlockRefMut::Base(block) => BeaconBlockBodyRefMut::Base(&mut block.body),
|
||||
BeaconBlockRefMut::Altair(block) => BeaconBlockBodyRefMut::Altair(&mut block.body),
|
||||
BeaconBlockRefMut::Merge(block) => BeaconBlockBodyRefMut::Merge(&mut block.body),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -414,6 +423,61 @@ impl<T: EthSpec> BeaconBlockAltair<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: EthSpec> BeaconBlockMerge<T> {
|
||||
/// Returns an empty Merge block to be used during genesis.
|
||||
pub fn empty(spec: &ChainSpec) -> Self {
|
||||
BeaconBlockMerge {
|
||||
slot: spec.genesis_slot,
|
||||
proposer_index: 0,
|
||||
parent_root: Hash256::zero(),
|
||||
state_root: Hash256::zero(),
|
||||
body: BeaconBlockBodyMerge {
|
||||
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: ExecutionPayload::empty(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Return an Merge block where the block has maximum size.
|
||||
pub fn full(spec: &ChainSpec) -> Self {
|
||||
let altair_block = BeaconBlockAltair::full(spec);
|
||||
BeaconBlockMerge {
|
||||
slot: spec.genesis_slot,
|
||||
proposer_index: 0,
|
||||
parent_root: Hash256::zero(),
|
||||
state_root: Hash256::zero(),
|
||||
body: BeaconBlockBodyMerge {
|
||||
proposer_slashings: altair_block.body.proposer_slashings,
|
||||
attester_slashings: altair_block.body.attester_slashings,
|
||||
attestations: altair_block.body.attestations,
|
||||
deposits: altair_block.body.deposits,
|
||||
voluntary_exits: altair_block.body.voluntary_exits,
|
||||
sync_aggregate: altair_block.body.sync_aggregate,
|
||||
randao_reveal: Signature::empty(),
|
||||
eth1_data: Eth1Data {
|
||||
deposit_root: Hash256::zero(),
|
||||
block_hash: Hash256::zero(),
|
||||
deposit_count: 0,
|
||||
},
|
||||
graffiti: Graffiti::default(),
|
||||
execution_payload: ExecutionPayload::default(),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
@@ -11,7 +11,7 @@ use tree_hash_derive::TreeHash;
|
||||
///
|
||||
/// This *superstruct* abstracts over the hard-fork.
|
||||
#[superstruct(
|
||||
variants(Base, Altair),
|
||||
variants(Base, Altair, Merge),
|
||||
variant_attributes(
|
||||
derive(
|
||||
Debug,
|
||||
@@ -26,7 +26,9 @@ use tree_hash_derive::TreeHash;
|
||||
),
|
||||
serde(bound = "T: EthSpec", deny_unknown_fields),
|
||||
cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))
|
||||
)
|
||||
),
|
||||
cast_error(ty = "Error", expr = "Error::IncorrectStateVariant"),
|
||||
partial_getter_error(ty = "Error", expr = "Error::IncorrectStateVariant")
|
||||
)]
|
||||
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
@@ -41,8 +43,10 @@ pub struct BeaconBlockBody<T: EthSpec> {
|
||||
pub attestations: VariableList<Attestation<T>, T::MaxAttestations>,
|
||||
pub deposits: VariableList<Deposit, T::MaxDeposits>,
|
||||
pub voluntary_exits: VariableList<SignedVoluntaryExit, T::MaxVoluntaryExits>,
|
||||
#[superstruct(only(Altair))]
|
||||
#[superstruct(only(Altair, Merge))]
|
||||
pub sync_aggregate: SyncAggregate<T>,
|
||||
#[superstruct(only(Merge))]
|
||||
pub execution_payload: ExecutionPayload<T>,
|
||||
}
|
||||
|
||||
impl<'a, T: EthSpec> BeaconBlockBodyRef<'a, T> {
|
||||
@@ -51,6 +55,25 @@ impl<'a, T: EthSpec> BeaconBlockBodyRef<'a, T> {
|
||||
match self {
|
||||
BeaconBlockBodyRef::Base(_) => None,
|
||||
BeaconBlockBodyRef::Altair(inner) => Some(&inner.sync_aggregate),
|
||||
BeaconBlockBodyRef::Merge(inner) => Some(&inner.sync_aggregate),
|
||||
}
|
||||
}
|
||||
|
||||
/// Access the execution payload from the block's body, if one exists.
|
||||
pub fn execution_payload(self) -> Option<&'a ExecutionPayload<T>> {
|
||||
match self {
|
||||
BeaconBlockBodyRef::Base(_) => None,
|
||||
BeaconBlockBodyRef::Altair(_) => None,
|
||||
BeaconBlockBodyRef::Merge(inner) => Some(&inner.execution_payload),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the fork_name of this object
|
||||
pub fn fork_name(self) -> ForkName {
|
||||
match self {
|
||||
BeaconBlockBodyRef::Base { .. } => ForkName::Base,
|
||||
BeaconBlockBodyRef::Altair { .. } => ForkName::Altair,
|
||||
BeaconBlockBodyRef::Merge { .. } => ForkName::Merge,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,7 +172,7 @@ impl From<BeaconStateHash> for Hash256 {
|
||||
|
||||
/// The state of the `BeaconChain` at some slot.
|
||||
#[superstruct(
|
||||
variants(Base, Altair),
|
||||
variants(Base, Altair, Merge),
|
||||
variant_attributes(
|
||||
derive(
|
||||
Derivative,
|
||||
@@ -250,9 +250,9 @@ where
|
||||
pub current_epoch_attestations: VariableList<PendingAttestation<T>, T::MaxPendingAttestations>,
|
||||
|
||||
// Participation (Altair and later)
|
||||
#[superstruct(only(Altair))]
|
||||
#[superstruct(only(Altair, Merge))]
|
||||
pub previous_epoch_participation: VariableList<ParticipationFlags, T::ValidatorRegistryLimit>,
|
||||
#[superstruct(only(Altair))]
|
||||
#[superstruct(only(Altair, Merge))]
|
||||
pub current_epoch_participation: VariableList<ParticipationFlags, T::ValidatorRegistryLimit>,
|
||||
|
||||
// Finality
|
||||
@@ -266,15 +266,19 @@ where
|
||||
pub finalized_checkpoint: Checkpoint,
|
||||
|
||||
// Inactivity
|
||||
#[superstruct(only(Altair))]
|
||||
#[superstruct(only(Altair, Merge))]
|
||||
pub inactivity_scores: VariableList<u64, T::ValidatorRegistryLimit>,
|
||||
|
||||
// Light-client sync committees
|
||||
#[superstruct(only(Altair))]
|
||||
#[superstruct(only(Altair, Merge))]
|
||||
pub current_sync_committee: Arc<SyncCommittee<T>>,
|
||||
#[superstruct(only(Altair))]
|
||||
#[superstruct(only(Altair, Merge))]
|
||||
pub next_sync_committee: Arc<SyncCommittee<T>>,
|
||||
|
||||
// Execution
|
||||
#[superstruct(only(Merge))]
|
||||
pub latest_execution_payload_header: ExecutionPayloadHeader<T>,
|
||||
|
||||
// Caching (not in the spec)
|
||||
#[serde(skip_serializing, skip_deserializing)]
|
||||
#[ssz(skip_serializing, skip_deserializing)]
|
||||
@@ -383,6 +387,7 @@ impl<T: EthSpec> BeaconState<T> {
|
||||
let object_fork = match self {
|
||||
BeaconState::Base { .. } => ForkName::Base,
|
||||
BeaconState::Altair { .. } => ForkName::Altair,
|
||||
BeaconState::Merge { .. } => ForkName::Merge,
|
||||
};
|
||||
|
||||
if fork_at_slot == object_fork {
|
||||
@@ -1091,6 +1096,7 @@ impl<T: EthSpec> BeaconState<T> {
|
||||
match self {
|
||||
BeaconState::Base(state) => (&mut state.validators, &mut state.balances),
|
||||
BeaconState::Altair(state) => (&mut state.validators, &mut state.balances),
|
||||
BeaconState::Merge(state) => (&mut state.validators, &mut state.balances),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1286,11 +1292,13 @@ impl<T: EthSpec> BeaconState<T> {
|
||||
match self {
|
||||
BeaconState::Base(_) => Err(BeaconStateError::IncorrectStateVariant),
|
||||
BeaconState::Altair(state) => Ok(&mut state.current_epoch_participation),
|
||||
BeaconState::Merge(state) => Ok(&mut state.current_epoch_participation),
|
||||
}
|
||||
} else if epoch == self.previous_epoch() {
|
||||
match self {
|
||||
BeaconState::Base(_) => Err(BeaconStateError::IncorrectStateVariant),
|
||||
BeaconState::Altair(state) => Ok(&mut state.previous_epoch_participation),
|
||||
BeaconState::Merge(state) => Ok(&mut state.previous_epoch_participation),
|
||||
}
|
||||
} else {
|
||||
Err(BeaconStateError::EpochOutOfBounds)
|
||||
@@ -1574,6 +1582,7 @@ impl<T: EthSpec> BeaconState<T> {
|
||||
let mut res = match self {
|
||||
BeaconState::Base(inner) => BeaconState::Base(inner.clone()),
|
||||
BeaconState::Altair(inner) => BeaconState::Altair(inner.clone()),
|
||||
BeaconState::Merge(inner) => BeaconState::Merge(inner.clone()),
|
||||
};
|
||||
if config.committee_caches {
|
||||
*res.committee_caches_mut() = self.committee_caches().clone();
|
||||
|
||||
@@ -127,6 +127,10 @@ pub struct ChainSpec {
|
||||
pub altair_fork_version: [u8; 4],
|
||||
/// The Altair fork epoch is optional, with `None` representing "Altair never happens".
|
||||
pub altair_fork_epoch: Option<Epoch>,
|
||||
pub merge_fork_version: [u8; 4],
|
||||
/// The Merge fork epoch is optional, with `None` representing "Merge never happens".
|
||||
pub merge_fork_epoch: Option<Epoch>,
|
||||
pub terminal_total_difficulty: Uint256,
|
||||
|
||||
/*
|
||||
* Networking
|
||||
@@ -156,7 +160,7 @@ impl ChainSpec {
|
||||
) -> EnrForkId {
|
||||
EnrForkId {
|
||||
fork_digest: self.fork_digest::<T>(slot, genesis_validators_root),
|
||||
next_fork_version: self.next_fork_version(),
|
||||
next_fork_version: self.next_fork_version::<T>(slot),
|
||||
next_fork_epoch: self
|
||||
.next_fork_epoch::<T>(slot)
|
||||
.map(|(_, e)| e)
|
||||
@@ -178,10 +182,12 @@ impl ChainSpec {
|
||||
|
||||
/// Returns the `next_fork_version`.
|
||||
///
|
||||
/// Since `next_fork_version = current_fork_version` if no future fork is planned,
|
||||
/// this function returns `altair_fork_version` until the next fork is planned.
|
||||
pub fn next_fork_version(&self) -> [u8; 4] {
|
||||
self.altair_fork_version
|
||||
/// `next_fork_version = current_fork_version` if no future fork is planned,
|
||||
pub fn next_fork_version<E: EthSpec>(&self, slot: Slot) -> [u8; 4] {
|
||||
match self.next_fork_epoch::<E>(slot) {
|
||||
Some((fork, _)) => self.fork_version_for_name(fork),
|
||||
None => self.fork_version_for_name(self.fork_name_at_slot::<E>(slot)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the epoch of the next scheduled fork along with its corresponding `ForkName`.
|
||||
@@ -201,9 +207,12 @@ 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.altair_fork_epoch {
|
||||
Some(fork_epoch) if epoch >= fork_epoch => ForkName::Altair,
|
||||
_ => ForkName::Base,
|
||||
match self.merge_fork_epoch {
|
||||
Some(fork_epoch) if epoch >= fork_epoch => ForkName::Merge,
|
||||
_ => match self.altair_fork_epoch {
|
||||
Some(fork_epoch) if epoch >= fork_epoch => ForkName::Altair,
|
||||
_ => ForkName::Base,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,6 +221,7 @@ impl ChainSpec {
|
||||
match fork_name {
|
||||
ForkName::Base => self.genesis_fork_version,
|
||||
ForkName::Altair => self.altair_fork_version,
|
||||
ForkName::Merge => self.merge_fork_version,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,6 +230,7 @@ impl ChainSpec {
|
||||
match fork_name {
|
||||
ForkName::Base => Some(Epoch::new(0)),
|
||||
ForkName::Altair => self.altair_fork_epoch,
|
||||
ForkName::Merge => self.merge_fork_epoch,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -467,6 +478,9 @@ impl ChainSpec {
|
||||
domain_contribution_and_proof: 9,
|
||||
altair_fork_version: [0x01, 0x00, 0x00, 0x00],
|
||||
altair_fork_epoch: Some(Epoch::new(74240)),
|
||||
merge_fork_version: [0x02, 0x00, 0x00, 0x00],
|
||||
merge_fork_epoch: None,
|
||||
terminal_total_difficulty: Uint256::MAX,
|
||||
|
||||
/*
|
||||
* Network specific
|
||||
|
||||
@@ -19,3 +19,13 @@ pub mod altair {
|
||||
|
||||
pub const NUM_FLAG_INDICES: usize = 3;
|
||||
}
|
||||
|
||||
pub mod merge_testing {
|
||||
use ethereum_types::H256;
|
||||
pub const GENESIS_GAS_LIMIT: u64 = 30_000_000;
|
||||
pub const GENESIS_BASE_FEE_PER_GAS: H256 = H256([
|
||||
0x00, 0xca, 0x9a, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00,
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -9,6 +9,9 @@ use ssz_types::typenum::{
|
||||
use std::fmt::{self, Debug};
|
||||
use std::str::FromStr;
|
||||
|
||||
use ssz_types::typenum::{bit::B0, UInt, U1048576, U16384, U256, U625};
|
||||
pub type U5000 = UInt<UInt<UInt<U625, B0>, B0>, B0>; // 625 * 8 = 5000
|
||||
|
||||
const MAINNET: &str = "mainnet";
|
||||
const MINIMAL: &str = "minimal";
|
||||
|
||||
@@ -80,6 +83,14 @@ pub trait EthSpec: 'static + Default + Sync + Send + Clone + Debug + PartialEq +
|
||||
type SyncCommitteeSize: Unsigned + Clone + Sync + Send + Debug + PartialEq;
|
||||
/// The number of `sync_committee` subnets.
|
||||
type SyncCommitteeSubnetCount: Unsigned + Clone + Sync + Send + Debug + PartialEq;
|
||||
/*
|
||||
* New in Merge
|
||||
*/
|
||||
type MaxBytesPerOpaqueTransaction: Unsigned + Clone + Sync + Send + Debug + PartialEq;
|
||||
type MaxTransactionsPerPayload: Unsigned + Clone + Sync + Send + Debug + PartialEq;
|
||||
type BytesPerLogsBloom: Unsigned + Clone + Sync + Send + Debug + PartialEq;
|
||||
type GasLimitDenominator: Unsigned + Clone + Sync + Send + Debug + PartialEq;
|
||||
type MinGasLimit: Unsigned + Clone + Sync + Send + Debug + PartialEq;
|
||||
/*
|
||||
* Derived values (set these CAREFULLY)
|
||||
*/
|
||||
@@ -187,6 +198,31 @@ pub trait EthSpec: 'static + Default + Sync + Send + Clone + Debug + PartialEq +
|
||||
fn sync_subcommittee_size() -> usize {
|
||||
Self::SyncSubcommitteeSize::to_usize()
|
||||
}
|
||||
|
||||
/// Returns the `MAX_BYTES_PER_OPAQUE_TRANSACTION` constant for this specification.
|
||||
fn max_bytes_per_opaque_transaction() -> usize {
|
||||
Self::MaxBytesPerOpaqueTransaction::to_usize()
|
||||
}
|
||||
|
||||
/// Returns the `MAX_TRANSACTIONS_PER_PAYLOAD` constant for this specification.
|
||||
fn max_transactions_per_payload() -> usize {
|
||||
Self::MaxTransactionsPerPayload::to_usize()
|
||||
}
|
||||
|
||||
/// Returns the `BYTES_PER_LOGS_BLOOM` constant for this specification.
|
||||
fn bytes_per_logs_bloom() -> usize {
|
||||
Self::BytesPerLogsBloom::to_usize()
|
||||
}
|
||||
|
||||
/// Returns the `GAS_LIMIT_DENOMINATOR` constant for this specification.
|
||||
fn gas_limit_denominator() -> u64 {
|
||||
Self::GasLimitDenominator::to_u64()
|
||||
}
|
||||
|
||||
/// Returns the `MIN_GAS_LIMIT` constant for this specification.
|
||||
fn min_gas_limit() -> u64 {
|
||||
Self::MinGasLimit::to_u64()
|
||||
}
|
||||
}
|
||||
|
||||
/// Macro to inherit some type values from another EthSpec.
|
||||
@@ -221,6 +257,11 @@ impl EthSpec for MainnetEthSpec {
|
||||
type MaxVoluntaryExits = U16;
|
||||
type SyncCommitteeSize = U512;
|
||||
type SyncCommitteeSubnetCount = U4;
|
||||
type MaxBytesPerOpaqueTransaction = U1048576;
|
||||
type MaxTransactionsPerPayload = U16384;
|
||||
type BytesPerLogsBloom = U256;
|
||||
type GasLimitDenominator = U1024;
|
||||
type MinGasLimit = U5000;
|
||||
type SyncSubcommitteeSize = U128; // 512 committee size / 4 sync committee subnet count
|
||||
type MaxPendingAttestations = U4096; // 128 max attestations * 32 slots per epoch
|
||||
type SlotsPerEth1VotingPeriod = U2048; // 64 epochs * 32 slots per epoch
|
||||
@@ -262,7 +303,12 @@ impl EthSpec for MinimalEthSpec {
|
||||
MaxAttesterSlashings,
|
||||
MaxAttestations,
|
||||
MaxDeposits,
|
||||
MaxVoluntaryExits
|
||||
MaxVoluntaryExits,
|
||||
MaxBytesPerOpaqueTransaction,
|
||||
MaxTransactionsPerPayload,
|
||||
BytesPerLogsBloom,
|
||||
GasLimitDenominator,
|
||||
MinGasLimit
|
||||
});
|
||||
|
||||
fn default_spec() -> ChainSpec {
|
||||
|
||||
174
consensus/types/src/execution_payload.rs
Normal file
174
consensus/types/src/execution_payload.rs
Normal file
@@ -0,0 +1,174 @@
|
||||
use crate::{test_utils::TestRandom, *};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use std::{ops::Index, slice::SliceIndex};
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode, TreeHash)]
|
||||
#[ssz(enum_behaviour = "union")]
|
||||
#[tree_hash(enum_behaviour = "union")]
|
||||
pub enum Transaction<T: EthSpec> {
|
||||
OpaqueTransaction(VariableList<u8, T::MaxBytesPerOpaqueTransaction>),
|
||||
}
|
||||
|
||||
impl<T: EthSpec, I: SliceIndex<[u8]>> Index<I> for Transaction<T> {
|
||||
type Output = I::Output;
|
||||
|
||||
#[inline]
|
||||
fn index(&self, index: I) -> &Self::Output {
|
||||
match self {
|
||||
Self::OpaqueTransaction(v) => Index::index(v, index),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: EthSpec> From<VariableList<u8, T::MaxBytesPerOpaqueTransaction>> for Transaction<T> {
|
||||
fn from(list: VariableList<u8, <T as EthSpec>::MaxBytesPerOpaqueTransaction>) -> Self {
|
||||
Self::OpaqueTransaction(list)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(
|
||||
Default, Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom,
|
||||
)]
|
||||
pub struct ExecutionPayload<T: EthSpec> {
|
||||
pub parent_hash: Hash256,
|
||||
pub coinbase: Address,
|
||||
pub state_root: Hash256,
|
||||
pub receipt_root: Hash256,
|
||||
#[serde(with = "serde_logs_bloom")]
|
||||
pub logs_bloom: FixedVector<u8, T::BytesPerLogsBloom>,
|
||||
pub random: Hash256,
|
||||
#[serde(with = "eth2_serde_utils::quoted_u64")]
|
||||
pub block_number: u64,
|
||||
#[serde(with = "eth2_serde_utils::quoted_u64")]
|
||||
pub gas_limit: u64,
|
||||
#[serde(with = "eth2_serde_utils::quoted_u64")]
|
||||
pub gas_used: u64,
|
||||
#[serde(with = "eth2_serde_utils::quoted_u64")]
|
||||
pub timestamp: u64,
|
||||
pub base_fee_per_gas: Hash256,
|
||||
pub block_hash: Hash256,
|
||||
#[serde(with = "serde_transactions")]
|
||||
#[test_random(default)]
|
||||
pub transactions: VariableList<Transaction<T>, T::MaxTransactionsPerPayload>,
|
||||
}
|
||||
|
||||
impl<T: EthSpec> ExecutionPayload<T> {
|
||||
// TODO: check this whole thing later
|
||||
pub fn empty() -> Self {
|
||||
Self {
|
||||
parent_hash: Hash256::zero(),
|
||||
coinbase: Address::default(),
|
||||
state_root: Hash256::zero(),
|
||||
receipt_root: Hash256::zero(),
|
||||
logs_bloom: FixedVector::default(),
|
||||
random: Hash256::zero(),
|
||||
block_number: 0,
|
||||
gas_limit: 0,
|
||||
gas_used: 0,
|
||||
timestamp: 0,
|
||||
base_fee_per_gas: Hash256::zero(),
|
||||
block_hash: Hash256::zero(),
|
||||
transactions: VariableList::empty(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Serializes the `logs_bloom` field.
|
||||
pub mod serde_logs_bloom {
|
||||
use super::*;
|
||||
use eth2_serde_utils::hex::PrefixedHexVisitor;
|
||||
use serde::{Deserializer, Serializer};
|
||||
|
||||
pub fn serialize<S, U>(bytes: &FixedVector<u8, U>, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
U: Unsigned,
|
||||
{
|
||||
let mut hex_string: String = "0x".to_string();
|
||||
hex_string.push_str(&hex::encode(&bytes[..]));
|
||||
|
||||
serializer.serialize_str(&hex_string)
|
||||
}
|
||||
|
||||
pub fn deserialize<'de, D, U>(deserializer: D) -> Result<FixedVector<u8, U>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
U: Unsigned,
|
||||
{
|
||||
let vec = deserializer.deserialize_string(PrefixedHexVisitor)?;
|
||||
|
||||
FixedVector::new(vec)
|
||||
.map_err(|e| serde::de::Error::custom(format!("invalid logs bloom: {:?}", e)))
|
||||
}
|
||||
}
|
||||
|
||||
/// Serializes the `transactions` field.
|
||||
pub mod serde_transactions {
|
||||
use super::*;
|
||||
use eth2_serde_utils::hex;
|
||||
use serde::ser::SerializeSeq;
|
||||
use serde::{de, Deserializer, Serializer};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
pub struct ListOfBytesListVisitor<T: EthSpec> {
|
||||
_t: PhantomData<T>,
|
||||
}
|
||||
impl<'a, T> serde::de::Visitor<'a> for ListOfBytesListVisitor<T>
|
||||
where
|
||||
T: EthSpec,
|
||||
{
|
||||
type Value = VariableList<Transaction<T>, T::MaxTransactionsPerPayload>;
|
||||
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(formatter, "a list of 0x-prefixed byte lists")
|
||||
}
|
||||
|
||||
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
|
||||
where
|
||||
A: serde::de::SeqAccess<'a>,
|
||||
{
|
||||
let mut outer = VariableList::default();
|
||||
|
||||
while let Some(val) = seq.next_element::<String>()? {
|
||||
let inner_vec = hex::decode(&val).map_err(de::Error::custom)?;
|
||||
let inner = VariableList::new(inner_vec).map_err(|e| {
|
||||
serde::de::Error::custom(format!("invalid transaction: {:?}", e))
|
||||
})?;
|
||||
outer.push(inner.into()).map_err(|e| {
|
||||
serde::de::Error::custom(format!("too many transactions: {:?}", e))
|
||||
})?;
|
||||
}
|
||||
|
||||
Ok(outer)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn serialize<S, T>(
|
||||
value: &VariableList<Transaction<T>, T::MaxTransactionsPerPayload>,
|
||||
serializer: S,
|
||||
) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
T: EthSpec,
|
||||
{
|
||||
let mut seq = serializer.serialize_seq(Some(value.len()))?;
|
||||
for val in value {
|
||||
seq.serialize_element(&hex::encode(&val[..]))?;
|
||||
}
|
||||
seq.end()
|
||||
}
|
||||
|
||||
pub fn deserialize<'de, D, T>(
|
||||
deserializer: D,
|
||||
) -> Result<VariableList<Transaction<T>, T::MaxTransactionsPerPayload>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
T: EthSpec,
|
||||
{
|
||||
deserializer.deserialize_any(ListOfBytesListVisitor { _t: PhantomData })
|
||||
}
|
||||
}
|
||||
37
consensus/types/src/execution_payload_header.rs
Normal file
37
consensus/types/src/execution_payload_header.rs
Normal file
@@ -0,0 +1,37 @@
|
||||
use crate::{execution_payload::serde_logs_bloom, test_utils::TestRandom, *};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(
|
||||
Default, Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom,
|
||||
)]
|
||||
pub struct ExecutionPayloadHeader<T: EthSpec> {
|
||||
pub parent_hash: Hash256,
|
||||
pub coinbase: Address,
|
||||
pub state_root: Hash256,
|
||||
pub receipt_root: Hash256,
|
||||
#[serde(with = "serde_logs_bloom")]
|
||||
pub logs_bloom: FixedVector<u8, T::BytesPerLogsBloom>,
|
||||
pub random: Hash256,
|
||||
#[serde(with = "eth2_serde_utils::quoted_u64")]
|
||||
pub block_number: u64,
|
||||
#[serde(with = "eth2_serde_utils::quoted_u64")]
|
||||
pub gas_limit: u64,
|
||||
#[serde(with = "eth2_serde_utils::quoted_u64")]
|
||||
pub gas_used: u64,
|
||||
#[serde(with = "eth2_serde_utils::quoted_u64")]
|
||||
pub timestamp: u64,
|
||||
pub base_fee_per_gas: Hash256,
|
||||
pub block_hash: Hash256,
|
||||
pub transactions_root: Hash256,
|
||||
}
|
||||
|
||||
impl<T: EthSpec> ExecutionPayloadHeader<T> {
|
||||
// TODO: check this whole thing later
|
||||
pub fn empty() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
}
|
||||
@@ -35,6 +35,15 @@ impl ForkContext {
|
||||
));
|
||||
}
|
||||
|
||||
// Only add Merge to list of forks if it's enabled
|
||||
// Note: `merge_fork_epoch == None` implies merge hasn't been activated yet on the config.
|
||||
if spec.merge_fork_epoch.is_some() {
|
||||
fork_to_digest.push((
|
||||
ForkName::Merge,
|
||||
ChainSpec::compute_fork_digest(spec.merge_fork_version, genesis_validators_root),
|
||||
));
|
||||
}
|
||||
|
||||
let fork_to_digest: HashMap<ForkName, [u8; 4]> = fork_to_digest.into_iter().collect();
|
||||
|
||||
let digest_to_fork = fork_to_digest
|
||||
|
||||
@@ -10,6 +10,7 @@ use std::str::FromStr;
|
||||
pub enum ForkName {
|
||||
Base,
|
||||
Altair,
|
||||
Merge,
|
||||
}
|
||||
|
||||
impl ForkName {
|
||||
@@ -24,10 +25,17 @@ impl ForkName {
|
||||
match self {
|
||||
ForkName::Base => {
|
||||
spec.altair_fork_epoch = None;
|
||||
spec.merge_fork_epoch = None;
|
||||
spec
|
||||
}
|
||||
ForkName::Altair => {
|
||||
spec.altair_fork_epoch = Some(Epoch::new(0));
|
||||
spec.merge_fork_epoch = None;
|
||||
spec
|
||||
}
|
||||
ForkName::Merge => {
|
||||
spec.altair_fork_epoch = None;
|
||||
spec.merge_fork_epoch = Some(Epoch::new(0));
|
||||
spec
|
||||
}
|
||||
}
|
||||
@@ -40,6 +48,7 @@ impl ForkName {
|
||||
match self {
|
||||
ForkName::Base => None,
|
||||
ForkName::Altair => Some(ForkName::Base),
|
||||
ForkName::Merge => Some(ForkName::Altair),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +58,8 @@ impl ForkName {
|
||||
pub fn next_fork(self) -> Option<ForkName> {
|
||||
match self {
|
||||
ForkName::Base => Some(ForkName::Altair),
|
||||
ForkName::Altair => None,
|
||||
ForkName::Altair => Some(ForkName::Merge),
|
||||
ForkName::Merge => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -61,6 +71,7 @@ impl FromStr for ForkName {
|
||||
Ok(match fork_name.to_lowercase().as_ref() {
|
||||
"phase0" | "base" => ForkName::Base,
|
||||
"altair" => ForkName::Altair,
|
||||
"merge" => ForkName::Merge,
|
||||
_ => return Err(()),
|
||||
})
|
||||
}
|
||||
@@ -71,6 +82,7 @@ impl Display for ForkName {
|
||||
match self {
|
||||
ForkName::Base => "phase0".fmt(f),
|
||||
ForkName::Altair => "altair".fmt(f),
|
||||
ForkName::Merge => "merge".fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -102,7 +114,7 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn previous_and_next_fork_consistent() {
|
||||
assert_eq!(ForkName::Altair.next_fork(), None);
|
||||
assert_eq!(ForkName::Merge.next_fork(), None);
|
||||
assert_eq!(ForkName::Base.previous_fork(), None);
|
||||
|
||||
for (prev_fork, fork) in ForkName::list_all().into_iter().tuple_windows() {
|
||||
|
||||
@@ -37,6 +37,8 @@ pub mod deposit_message;
|
||||
pub mod enr_fork_id;
|
||||
pub mod eth1_data;
|
||||
pub mod eth_spec;
|
||||
pub mod execution_payload;
|
||||
pub mod execution_payload_header;
|
||||
pub mod fork;
|
||||
pub mod fork_data;
|
||||
pub mod fork_name;
|
||||
@@ -45,6 +47,7 @@ pub mod graffiti;
|
||||
pub mod historical_batch;
|
||||
pub mod indexed_attestation;
|
||||
pub mod pending_attestation;
|
||||
pub mod pow_block;
|
||||
pub mod proposer_slashing;
|
||||
pub mod relative_epoch;
|
||||
pub mod selection_proof;
|
||||
@@ -90,11 +93,12 @@ pub use crate::attestation_data::AttestationData;
|
||||
pub use crate::attestation_duty::AttestationDuty;
|
||||
pub use crate::attester_slashing::AttesterSlashing;
|
||||
pub use crate::beacon_block::{
|
||||
BeaconBlock, BeaconBlockAltair, BeaconBlockBase, BeaconBlockRef, BeaconBlockRefMut,
|
||||
BeaconBlock, BeaconBlockAltair, BeaconBlockBase, BeaconBlockMerge, BeaconBlockRef,
|
||||
BeaconBlockRefMut,
|
||||
};
|
||||
pub use crate::beacon_block_body::{
|
||||
BeaconBlockBody, BeaconBlockBodyAltair, BeaconBlockBodyBase, BeaconBlockBodyRef,
|
||||
BeaconBlockBodyRefMut,
|
||||
BeaconBlockBody, BeaconBlockBodyAltair, BeaconBlockBodyBase, BeaconBlockBodyMerge,
|
||||
BeaconBlockBodyRef, BeaconBlockBodyRefMut,
|
||||
};
|
||||
pub use crate::beacon_block_header::BeaconBlockHeader;
|
||||
pub use crate::beacon_committee::{BeaconCommittee, OwnedBeaconCommittee};
|
||||
@@ -109,6 +113,8 @@ pub use crate::deposit_message::DepositMessage;
|
||||
pub use crate::enr_fork_id::EnrForkId;
|
||||
pub use crate::eth1_data::Eth1Data;
|
||||
pub use crate::eth_spec::EthSpecId;
|
||||
pub use crate::execution_payload::ExecutionPayload;
|
||||
pub use crate::execution_payload_header::ExecutionPayloadHeader;
|
||||
pub use crate::fork::Fork;
|
||||
pub use crate::fork_context::ForkContext;
|
||||
pub use crate::fork_data::ForkData;
|
||||
@@ -120,6 +126,7 @@ pub use crate::indexed_attestation::IndexedAttestation;
|
||||
pub use crate::participation_flags::ParticipationFlags;
|
||||
pub use crate::participation_list::ParticipationList;
|
||||
pub use crate::pending_attestation::PendingAttestation;
|
||||
pub use crate::pow_block::PowBlock;
|
||||
pub use crate::preset::{AltairPreset, BasePreset};
|
||||
pub use crate::proposer_slashing::ProposerSlashing;
|
||||
pub use crate::relative_epoch::{Error as RelativeEpochError, RelativeEpoch};
|
||||
@@ -128,6 +135,7 @@ pub use crate::shuffling_id::AttestationShufflingId;
|
||||
pub use crate::signed_aggregate_and_proof::SignedAggregateAndProof;
|
||||
pub use crate::signed_beacon_block::{
|
||||
SignedBeaconBlock, SignedBeaconBlockAltair, SignedBeaconBlockBase, SignedBeaconBlockHash,
|
||||
SignedBeaconBlockMerge,
|
||||
};
|
||||
pub use crate::signed_beacon_block_header::SignedBeaconBlockHeader;
|
||||
pub use crate::signed_contribution_and_proof::SignedContributionAndProof;
|
||||
@@ -150,6 +158,7 @@ pub use crate::voluntary_exit::VoluntaryExit;
|
||||
|
||||
pub type CommitteeIndex = u64;
|
||||
pub type Hash256 = H256;
|
||||
pub type Uint256 = ethereum_types::U256;
|
||||
pub type Address = H160;
|
||||
pub type ForkVersion = [u8; 4];
|
||||
|
||||
|
||||
13
consensus/types/src/pow_block.rs
Normal file
13
consensus/types/src/pow_block.rs
Normal file
@@ -0,0 +1,13 @@
|
||||
use crate::*;
|
||||
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(Default, Debug, PartialEq, Clone)]
|
||||
pub struct PowBlock {
|
||||
pub block_hash: Hash256,
|
||||
pub parent_hash: Hash256,
|
||||
pub total_difficulty: Uint256,
|
||||
pub difficulty: Uint256,
|
||||
// needed to unify with other parts of codebase
|
||||
pub timestamp: u64,
|
||||
pub block_number: u64,
|
||||
}
|
||||
@@ -37,7 +37,7 @@ impl From<SignedBeaconBlockHash> for Hash256 {
|
||||
|
||||
/// A `BeaconBlock` and a signature from its proposer.
|
||||
#[superstruct(
|
||||
variants(Base, Altair),
|
||||
variants(Base, Altair, Merge),
|
||||
variant_attributes(
|
||||
derive(
|
||||
Debug,
|
||||
@@ -64,6 +64,8 @@ pub struct SignedBeaconBlock<E: EthSpec> {
|
||||
pub message: BeaconBlockBase<E>,
|
||||
#[superstruct(only(Altair), partial_getter(rename = "message_altair"))]
|
||||
pub message: BeaconBlockAltair<E>,
|
||||
#[superstruct(only(Merge), partial_getter(rename = "message_merge"))]
|
||||
pub message: BeaconBlockMerge<E>,
|
||||
pub signature: Signature,
|
||||
}
|
||||
|
||||
@@ -116,6 +118,9 @@ impl<E: EthSpec> SignedBeaconBlock<E> {
|
||||
BeaconBlock::Altair(message) => {
|
||||
SignedBeaconBlock::Altair(SignedBeaconBlockAltair { message, signature })
|
||||
}
|
||||
BeaconBlock::Merge(message) => {
|
||||
SignedBeaconBlock::Merge(SignedBeaconBlockMerge { message, signature })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,6 +134,7 @@ impl<E: EthSpec> SignedBeaconBlock<E> {
|
||||
SignedBeaconBlock::Altair(block) => {
|
||||
(BeaconBlock::Altair(block.message), block.signature)
|
||||
}
|
||||
SignedBeaconBlock::Merge(block) => (BeaconBlock::Merge(block.message), block.signature),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,6 +143,7 @@ impl<E: EthSpec> SignedBeaconBlock<E> {
|
||||
match self {
|
||||
SignedBeaconBlock::Base(inner) => BeaconBlockRef::Base(&inner.message),
|
||||
SignedBeaconBlock::Altair(inner) => BeaconBlockRef::Altair(&inner.message),
|
||||
SignedBeaconBlock::Merge(inner) => BeaconBlockRef::Merge(&inner.message),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,6 +152,7 @@ impl<E: EthSpec> SignedBeaconBlock<E> {
|
||||
match self {
|
||||
SignedBeaconBlock::Base(inner) => BeaconBlockRefMut::Base(&mut inner.message),
|
||||
SignedBeaconBlock::Altair(inner) => BeaconBlockRefMut::Altair(&mut inner.message),
|
||||
SignedBeaconBlock::Merge(inner) => BeaconBlockRefMut::Merge(&mut inner.message),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ mod public_key_bytes;
|
||||
mod secret_key;
|
||||
mod signature;
|
||||
mod signature_bytes;
|
||||
mod uint256;
|
||||
|
||||
pub fn test_random_instance<T: TestRandom>() -> T {
|
||||
let mut rng = XorShiftRng::from_seed([0x42; 16]);
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use super::*;
|
||||
use crate::Hash256;
|
||||
use crate::Uint256;
|
||||
|
||||
impl TestRandom for Hash256 {
|
||||
impl TestRandom for Uint256 {
|
||||
fn random_for_test(rng: &mut impl RngCore) -> Self {
|
||||
let mut key_bytes = vec![0; 32];
|
||||
let mut key_bytes = [0; 32];
|
||||
rng.fill_bytes(&mut key_bytes);
|
||||
Hash256::from_slice(&key_bytes[..])
|
||||
Self::from_little_endian(&key_bytes[..])
|
||||
}
|
||||
}
|
||||
|
||||
10
consensus/types/src/test_utils/test_random/uint256.rs
Normal file
10
consensus/types/src/test_utils/test_random/uint256.rs
Normal file
@@ -0,0 +1,10 @@
|
||||
use super::*;
|
||||
use crate::Hash256;
|
||||
|
||||
impl TestRandom for Hash256 {
|
||||
fn random_for_test(rng: &mut impl RngCore) -> Self {
|
||||
let mut key_bytes = vec![0; 32];
|
||||
rng.fill_bytes(&mut key_bytes);
|
||||
Hash256::from_slice(&key_bytes[..])
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user