mirror of
https://github.com/sigp/lighthouse.git
synced 2026-05-30 12:47:05 +00:00
Resolve merge conflicts
This commit is contained in:
@@ -1,29 +1,40 @@
|
||||
[package]
|
||||
name = "types"
|
||||
version = "0.2.1"
|
||||
authors = ["Paul Hauner <paul@paulhauner.com>", "Age Manning <Age@AgeManning.com>"]
|
||||
authors = [
|
||||
"Paul Hauner <paul@paulhauner.com>",
|
||||
"Age Manning <Age@AgeManning.com>",
|
||||
]
|
||||
edition = { workspace = true }
|
||||
|
||||
[[bench]]
|
||||
name = "benches"
|
||||
harness = false
|
||||
[features]
|
||||
default = ["sqlite", "legacy-arith"]
|
||||
# Allow saturating arithmetic on slots and epochs. Enabled by default, but deprecated.
|
||||
legacy-arith = []
|
||||
sqlite = ["dep:rusqlite"]
|
||||
arbitrary = [
|
||||
"dep:arbitrary",
|
||||
"bls/arbitrary",
|
||||
"ethereum_ssz/arbitrary",
|
||||
"milhouse/arbitrary",
|
||||
"ssz_types/arbitrary",
|
||||
"swap_or_not_shuffle/arbitrary",
|
||||
]
|
||||
arbitrary-fuzz = ["arbitrary"]
|
||||
portable = ["bls/supranational-portable"]
|
||||
|
||||
[dependencies]
|
||||
alloy-primitives = { workspace = true }
|
||||
alloy-rlp = { version = "0.3.4", features = ["derive"] }
|
||||
# The arbitrary dependency is enabled by default since Capella to avoid complexity introduced by
|
||||
# `AbstractExecPayload`
|
||||
arbitrary = { workspace = true, features = ["derive"] }
|
||||
bls = { workspace = true, features = ["arbitrary"] }
|
||||
alloy-rlp = { workspace = true, features = ["derive"] }
|
||||
arbitrary = { workspace = true, features = ["derive"], optional = true }
|
||||
bls = { workspace = true }
|
||||
compare_fields = { workspace = true }
|
||||
compare_fields_derive = { workspace = true }
|
||||
context_deserialize = { workspace = true }
|
||||
context_deserialize_derive = { workspace = true }
|
||||
derivative = { workspace = true }
|
||||
educe = { workspace = true }
|
||||
eth2_interop_keypairs = { path = "../../common/eth2_interop_keypairs" }
|
||||
ethereum_hashing = { workspace = true }
|
||||
ethereum_serde_utils = { workspace = true }
|
||||
ethereum_ssz = { workspace = true, features = ["arbitrary"] }
|
||||
ethereum_ssz = { workspace = true }
|
||||
ethereum_ssz_derive = { workspace = true }
|
||||
fixed_bytes = { workspace = true }
|
||||
hex = { workspace = true }
|
||||
@@ -36,7 +47,7 @@ metastruct = "0.1.0"
|
||||
milhouse = { workspace = true }
|
||||
parking_lot = { workspace = true }
|
||||
rand = { workspace = true }
|
||||
rand_xorshift = "0.3.0"
|
||||
rand_xorshift = "0.4.0"
|
||||
rayon = { workspace = true }
|
||||
regex = { workspace = true }
|
||||
rpds = { workspace = true }
|
||||
@@ -46,14 +57,15 @@ serde = { workspace = true, features = ["rc"] }
|
||||
serde_json = { workspace = true }
|
||||
serde_yaml = { workspace = true }
|
||||
smallvec = { workspace = true }
|
||||
ssz_types = { workspace = true, features = ["arbitrary"] }
|
||||
ssz_types = { workspace = true }
|
||||
superstruct = { workspace = true }
|
||||
swap_or_not_shuffle = { workspace = true, features = ["arbitrary"] }
|
||||
swap_or_not_shuffle = { workspace = true }
|
||||
tempfile = { workspace = true }
|
||||
test_random_derive = { path = "../../common/test_random_derive" }
|
||||
tracing = { workspace = true }
|
||||
tree_hash = { workspace = true }
|
||||
tree_hash_derive = { workspace = true }
|
||||
typenum = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
beacon_chain = { workspace = true }
|
||||
@@ -62,12 +74,9 @@ paste = { workspace = true }
|
||||
state_processing = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
|
||||
[features]
|
||||
default = ["sqlite", "legacy-arith"]
|
||||
# Allow saturating arithmetic on slots and epochs. Enabled by default, but deprecated.
|
||||
legacy-arith = []
|
||||
sqlite = ["dep:rusqlite"]
|
||||
# The `arbitrary-fuzz` feature is a no-op provided for backwards compatibility.
|
||||
# For simplicity `Arbitrary` is now derived regardless of the feature's presence.
|
||||
arbitrary-fuzz = []
|
||||
portable = ["bls/supranational-portable"]
|
||||
[lints.clippy]
|
||||
module_inception = "allow"
|
||||
|
||||
[[bench]]
|
||||
name = "benches"
|
||||
harness = false
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
use criterion::{black_box, criterion_group, criterion_main, BatchSize, BenchmarkId, Criterion};
|
||||
use criterion::{BatchSize, BenchmarkId, Criterion, black_box, criterion_group, criterion_main};
|
||||
use fixed_bytes::FixedBytesExtended;
|
||||
use milhouse::List;
|
||||
use rayon::prelude::*;
|
||||
use ssz::Encode;
|
||||
use std::sync::Arc;
|
||||
use types::{
|
||||
test_utils::generate_deterministic_keypair, BeaconState, Epoch, Eth1Data, EthSpec,
|
||||
FixedBytesExtended, Hash256, MainnetEthSpec, Validator,
|
||||
BeaconState, Epoch, Eth1Data, EthSpec, Hash256, MainnetEthSpec, Validator,
|
||||
test_utils::generate_deterministic_keypair,
|
||||
};
|
||||
|
||||
fn get_state<E: EthSpec>(validator_count: usize) -> BeaconState<E> {
|
||||
|
||||
@@ -41,8 +41,7 @@ MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD: 16
|
||||
|
||||
# Withdrawals processing
|
||||
# ---------------------------------------------------------------
|
||||
# 2**3 ( = 8) pending withdrawals
|
||||
MAX_PENDING_PARTIALS_PER_WITHDRAWALS_SWEEP: 8
|
||||
MAX_PENDING_PARTIALS_PER_WITHDRAWALS_SWEEP: 6
|
||||
|
||||
# Pending deposits processing
|
||||
# ---------------------------------------------------------------
|
||||
|
||||
@@ -8,3 +8,7 @@ FIELD_ELEMENTS_PER_CELL: 64
|
||||
FIELD_ELEMENTS_PER_EXT_BLOB: 8192
|
||||
# uint64(floorlog2(get_generalized_index(BeaconBlockBody, 'blob_kzg_commitments'))
|
||||
KZG_COMMITMENTS_INCLUSION_PROOF_DEPTH: 4
|
||||
# FIELD_ELEMENTS_PER_EXT_BLOB // FIELD_ELEMENTS_PER_CELL (= 128)
|
||||
CELLS_PER_EXT_BLOB: 128
|
||||
# CELLS_PER_EXT_BLOB (= 128)
|
||||
NUMBER_OF_COLUMNS: 128
|
||||
1
consensus/types/presets/gnosis/gloas.yaml
Normal file
1
consensus/types/presets/gnosis/gloas.yaml
Normal file
@@ -0,0 +1 @@
|
||||
# Gnosis preset - Gloas
|
||||
@@ -8,3 +8,7 @@ FIELD_ELEMENTS_PER_CELL: 64
|
||||
FIELD_ELEMENTS_PER_EXT_BLOB: 8192
|
||||
# uint64(floorlog2(get_generalized_index(BeaconBlockBody, 'blob_kzg_commitments'))
|
||||
KZG_COMMITMENTS_INCLUSION_PROOF_DEPTH: 4
|
||||
# FIELD_ELEMENTS_PER_EXT_BLOB // FIELD_ELEMENTS_PER_CELL (= 128)
|
||||
CELLS_PER_EXT_BLOB: 128
|
||||
# CELLS_PER_EXT_BLOB (= 128)
|
||||
NUMBER_OF_COLUMNS: 128
|
||||
1
consensus/types/presets/mainnet/gloas.yaml
Normal file
1
consensus/types/presets/mainnet/gloas.yaml
Normal file
@@ -0,0 +1 @@
|
||||
# Mainnet preset - Gloas
|
||||
@@ -4,7 +4,7 @@
|
||||
# ---------------------------------------------------------------
|
||||
# `uint64(4096)`
|
||||
FIELD_ELEMENTS_PER_BLOB: 4096
|
||||
# [customized]
|
||||
MAX_BLOB_COMMITMENTS_PER_BLOCK: 32
|
||||
# [customized] `floorlog2(get_generalized_index(BeaconBlockBody, 'blob_kzg_commitments')) + 1 + ceillog2(MAX_BLOB_COMMITMENTS_PER_BLOCK)` = 4 + 1 + 5 = 10
|
||||
KZG_COMMITMENT_INCLUSION_PROOF_DEPTH: 10
|
||||
# `uint64(4096)`
|
||||
MAX_BLOB_COMMITMENTS_PER_BLOCK: 4096
|
||||
# `floorlog2(get_generalized_index(BeaconBlockBody, 'blob_kzg_commitments')) + 1 + ceillog2(MAX_BLOB_COMMITMENTS_PER_BLOCK)` = 4 + 1 + 12 = 17
|
||||
KZG_COMMITMENT_INCLUSION_PROOF_DEPTH: 17
|
||||
|
||||
@@ -32,10 +32,10 @@ MAX_ATTESTATIONS_ELECTRA: 8
|
||||
|
||||
# Execution
|
||||
# ---------------------------------------------------------------
|
||||
# [customized] 2**2 (= 4) deposit requests
|
||||
MAX_DEPOSIT_REQUESTS_PER_PAYLOAD: 4
|
||||
# [customized] 2**1 (= 2) withdrawal requests
|
||||
MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD: 2
|
||||
# 2**13 (= 8,192) deposit requests
|
||||
MAX_DEPOSIT_REQUESTS_PER_PAYLOAD: 8192
|
||||
# 2**4 (= 16) withdrawal requests
|
||||
MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD: 16
|
||||
# 2**1 (= 2) consolidation requests
|
||||
MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD: 2
|
||||
|
||||
|
||||
@@ -8,3 +8,7 @@ FIELD_ELEMENTS_PER_CELL: 64
|
||||
FIELD_ELEMENTS_PER_EXT_BLOB: 8192
|
||||
# uint64(floorlog2(get_generalized_index(BeaconBlockBody, 'blob_kzg_commitments'))
|
||||
KZG_COMMITMENTS_INCLUSION_PROOF_DEPTH: 4
|
||||
# FIELD_ELEMENTS_PER_EXT_BLOB // FIELD_ELEMENTS_PER_CELL (= 128)
|
||||
CELLS_PER_EXT_BLOB: 128
|
||||
# CELLS_PER_EXT_BLOB (= 128)
|
||||
NUMBER_OF_COLUMNS: 128
|
||||
1
consensus/types/presets/minimal/gloas.yaml
Normal file
1
consensus/types/presets/minimal/gloas.yaml
Normal file
@@ -0,0 +1 @@
|
||||
# Minimal preset - Gloas
|
||||
@@ -1,22 +1,24 @@
|
||||
use super::{AttestationBase, AttestationElectra, AttestationRef};
|
||||
use super::{
|
||||
ChainSpec, Domain, EthSpec, Fork, ForkName, Hash256, PublicKey, SecretKey, SelectionProof,
|
||||
Signature, SignedRoot,
|
||||
};
|
||||
use crate::context_deserialize;
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::Attestation;
|
||||
use bls::{PublicKey, SecretKey, Signature};
|
||||
use context_deserialize::context_deserialize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use superstruct::superstruct;
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
use crate::{
|
||||
attestation::{
|
||||
Attestation, AttestationBase, AttestationElectra, AttestationRef, SelectionProof,
|
||||
},
|
||||
core::{ChainSpec, Domain, EthSpec, Hash256, SignedRoot},
|
||||
fork::{Fork, ForkName},
|
||||
test_utils::TestRandom,
|
||||
};
|
||||
|
||||
#[superstruct(
|
||||
variants(Base, Electra),
|
||||
variant_attributes(
|
||||
derive(
|
||||
arbitrary::Arbitrary,
|
||||
Debug,
|
||||
Clone,
|
||||
PartialEq,
|
||||
@@ -29,23 +31,29 @@ use tree_hash_derive::TreeHash;
|
||||
),
|
||||
context_deserialize(ForkName),
|
||||
serde(bound = "E: EthSpec"),
|
||||
arbitrary(bound = "E: EthSpec"),
|
||||
cfg_attr(
|
||||
feature = "arbitrary",
|
||||
derive(arbitrary::Arbitrary),
|
||||
arbitrary(bound = "E: EthSpec"),
|
||||
),
|
||||
),
|
||||
ref_attributes(
|
||||
derive(Debug, PartialEq, TreeHash, Serialize,),
|
||||
derive(Debug, PartialEq, TreeHash, Serialize),
|
||||
serde(untagged, bound = "E: EthSpec"),
|
||||
tree_hash(enum_behaviour = "transparent")
|
||||
),
|
||||
map_ref_into(AttestationRef)
|
||||
)]
|
||||
#[derive(
|
||||
arbitrary::Arbitrary, Debug, Clone, PartialEq, Serialize, Deserialize, Encode, TreeHash,
|
||||
#[cfg_attr(
|
||||
feature = "arbitrary",
|
||||
derive(arbitrary::Arbitrary),
|
||||
arbitrary(bound = "E: EthSpec")
|
||||
)]
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, TreeHash)]
|
||||
#[serde(untagged)]
|
||||
#[tree_hash(enum_behaviour = "transparent")]
|
||||
#[ssz(enum_behaviour = "transparent")]
|
||||
#[serde(bound = "E: EthSpec", deny_unknown_fields)]
|
||||
#[arbitrary(bound = "E: EthSpec")]
|
||||
pub struct AggregateAndProof<E: EthSpec> {
|
||||
/// The index of the validator that created the attestation.
|
||||
#[serde(with = "serde_utils::quoted_u64")]
|
||||
@@ -1,20 +1,26 @@
|
||||
use crate::context_deserialize;
|
||||
use crate::slot_data::SlotData;
|
||||
use crate::{test_utils::TestRandom, Hash256, Slot};
|
||||
use crate::{Checkpoint, ContextDeserialize, ForkName};
|
||||
use derivative::Derivative;
|
||||
use std::{
|
||||
collections::HashSet,
|
||||
hash::{Hash, Hasher},
|
||||
};
|
||||
|
||||
use bls::{AggregateSignature, SecretKey, Signature};
|
||||
use context_deserialize::{ContextDeserialize, context_deserialize};
|
||||
use educe::Educe;
|
||||
use serde::{Deserialize, Deserializer, Serialize};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use ssz_types::BitVector;
|
||||
use std::collections::HashSet;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use ssz_types::{BitList, BitVector};
|
||||
use superstruct::superstruct;
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
use super::{
|
||||
AggregateSignature, AttestationData, BitList, ChainSpec, Domain, EthSpec, Fork, SecretKey,
|
||||
Signature, SignedRoot,
|
||||
use crate::{
|
||||
attestation::{
|
||||
AttestationData, Checkpoint, IndexedAttestation, IndexedAttestationBase,
|
||||
IndexedAttestationElectra,
|
||||
},
|
||||
core::{ChainSpec, Domain, EthSpec, Hash256, SignedRoot, Slot, SlotData},
|
||||
fork::{Fork, ForkName},
|
||||
test_utils::TestRandom,
|
||||
};
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
@@ -44,35 +50,33 @@ impl From<ssz_types::Error> for Error {
|
||||
Decode,
|
||||
Encode,
|
||||
TestRandom,
|
||||
Derivative,
|
||||
arbitrary::Arbitrary,
|
||||
Educe,
|
||||
TreeHash,
|
||||
),
|
||||
context_deserialize(ForkName),
|
||||
derivative(PartialEq, Hash(bound = "E: EthSpec")),
|
||||
educe(PartialEq, Hash(bound(E: EthSpec))),
|
||||
serde(bound = "E: EthSpec", deny_unknown_fields),
|
||||
arbitrary(bound = "E: EthSpec"),
|
||||
cfg_attr(
|
||||
feature = "arbitrary",
|
||||
derive(arbitrary::Arbitrary),
|
||||
arbitrary(bound = "E: EthSpec")
|
||||
)
|
||||
),
|
||||
ref_attributes(derive(TreeHash), tree_hash(enum_behaviour = "transparent")),
|
||||
cast_error(ty = "Error", expr = "Error::IncorrectStateVariant"),
|
||||
partial_getter_error(ty = "Error", expr = "Error::IncorrectStateVariant")
|
||||
)]
|
||||
#[derive(
|
||||
Debug,
|
||||
Clone,
|
||||
Serialize,
|
||||
TreeHash,
|
||||
Encode,
|
||||
Derivative,
|
||||
Deserialize,
|
||||
arbitrary::Arbitrary,
|
||||
PartialEq,
|
||||
#[cfg_attr(
|
||||
feature = "arbitrary",
|
||||
derive(arbitrary::Arbitrary),
|
||||
arbitrary(bound = "E: EthSpec")
|
||||
)]
|
||||
#[derive(Debug, Clone, Serialize, TreeHash, Encode, Educe, Deserialize)]
|
||||
#[educe(PartialEq)]
|
||||
#[serde(untagged)]
|
||||
#[tree_hash(enum_behaviour = "transparent")]
|
||||
#[ssz(enum_behaviour = "transparent")]
|
||||
#[serde(bound = "E: EthSpec", deny_unknown_fields)]
|
||||
#[arbitrary(bound = "E: EthSpec")]
|
||||
pub struct Attestation<E: EthSpec> {
|
||||
#[superstruct(only(Base), partial_getter(rename = "aggregation_bits_base"))]
|
||||
pub aggregation_bits: BitList<E::MaxValidatorsPerCommittee>,
|
||||
@@ -246,10 +250,17 @@ impl<E: EthSpec> Attestation<E> {
|
||||
attester_index: u64,
|
||||
) -> Result<SingleAttestation, Error> {
|
||||
match self {
|
||||
Self::Base(_) => Err(Error::IncorrectStateVariant),
|
||||
Self::Base(attn) => attn.to_single_attestation_with_attester_index(attester_index),
|
||||
Self::Electra(attn) => attn.to_single_attestation_with_attester_index(attester_index),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_aggregation_bits(&self) -> Vec<u64> {
|
||||
match self {
|
||||
Self::Base(attn) => attn.get_aggregation_bits(),
|
||||
Self::Electra(attn) => attn.get_aggregation_bits(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EthSpec> AttestationRef<'_, E> {
|
||||
@@ -461,6 +472,26 @@ impl<E: EthSpec> AttestationBase<E> {
|
||||
) -> Result<BitList<E::MaxValidatorsPerSlot>, ssz::BitfieldError> {
|
||||
self.aggregation_bits.resize::<E::MaxValidatorsPerSlot>()
|
||||
}
|
||||
|
||||
pub fn get_aggregation_bits(&self) -> Vec<u64> {
|
||||
self.aggregation_bits
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(index, bit)| if bit { Some(index as u64) } else { None })
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn to_single_attestation_with_attester_index(
|
||||
&self,
|
||||
attester_index: u64,
|
||||
) -> Result<SingleAttestation, Error> {
|
||||
Ok(SingleAttestation {
|
||||
committee_index: self.data.index,
|
||||
attester_index,
|
||||
data: self.data.clone(),
|
||||
signature: self.signature.clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EthSpec> SlotData for Attestation<E> {
|
||||
@@ -483,7 +514,7 @@ pub enum AttestationOnDisk<E: EthSpec> {
|
||||
}
|
||||
|
||||
impl<E: EthSpec> AttestationOnDisk<E> {
|
||||
pub fn to_ref(&self) -> AttestationRefOnDisk<E> {
|
||||
pub fn to_ref(&self) -> AttestationRefOnDisk<'_, E> {
|
||||
match self {
|
||||
AttestationOnDisk::Base(att) => AttestationRefOnDisk::Base(att),
|
||||
AttestationOnDisk::Electra(att) => AttestationRefOnDisk::Electra(att),
|
||||
@@ -573,19 +604,8 @@ impl<'de, E: EthSpec> ContextDeserialize<'de, ForkName> for Vec<Attestation<E>>
|
||||
}
|
||||
*/
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Clone,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Decode,
|
||||
Encode,
|
||||
TestRandom,
|
||||
Derivative,
|
||||
arbitrary::Arbitrary,
|
||||
TreeHash,
|
||||
PartialEq,
|
||||
)]
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Decode, Encode, TestRandom, TreeHash, PartialEq)]
|
||||
#[context_deserialize(ForkName)]
|
||||
pub struct SingleAttestation {
|
||||
#[serde(with = "serde_utils::quoted_u64")]
|
||||
@@ -596,6 +616,27 @@ pub struct SingleAttestation {
|
||||
pub signature: AggregateSignature,
|
||||
}
|
||||
|
||||
impl SingleAttestation {
|
||||
pub fn to_indexed<E: EthSpec>(
|
||||
&self,
|
||||
fork_name: ForkName,
|
||||
) -> Result<IndexedAttestation<E>, ssz_types::Error> {
|
||||
if fork_name.electra_enabled() {
|
||||
Ok(IndexedAttestation::Electra(IndexedAttestationElectra {
|
||||
attesting_indices: vec![self.attester_index].try_into()?,
|
||||
data: self.data.clone(),
|
||||
signature: self.signature.clone(),
|
||||
}))
|
||||
} else {
|
||||
Ok(IndexedAttestation::Base(IndexedAttestationBase {
|
||||
attesting_indices: vec![self.attester_index].try_into()?,
|
||||
data: self.data.clone(),
|
||||
signature: self.signature.clone(),
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -615,12 +656,12 @@ mod tests {
|
||||
let attestation_data = size_of::<AttestationData>();
|
||||
let signature = size_of::<AggregateSignature>();
|
||||
|
||||
assert_eq!(aggregation_bits, 152);
|
||||
assert_eq!(aggregation_bits, 144);
|
||||
assert_eq!(attestation_data, 128);
|
||||
assert_eq!(signature, 288 + 16);
|
||||
|
||||
let attestation_expected = aggregation_bits + attestation_data + signature;
|
||||
assert_eq!(attestation_expected, 584);
|
||||
assert_eq!(attestation_expected, 576);
|
||||
assert_eq!(
|
||||
size_of::<AttestationBase<MainnetEthSpec>>(),
|
||||
attestation_expected
|
||||
@@ -638,13 +679,13 @@ mod tests {
|
||||
size_of::<BitList<<MainnetEthSpec as EthSpec>::MaxCommitteesPerSlot>>();
|
||||
let signature = size_of::<AggregateSignature>();
|
||||
|
||||
assert_eq!(aggregation_bits, 152);
|
||||
assert_eq!(committee_bits, 152);
|
||||
assert_eq!(aggregation_bits, 144);
|
||||
assert_eq!(committee_bits, 144);
|
||||
assert_eq!(attestation_data, 128);
|
||||
assert_eq!(signature, 288 + 16);
|
||||
|
||||
let attestation_expected = aggregation_bits + committee_bits + attestation_data + signature;
|
||||
assert_eq!(attestation_expected, 736);
|
||||
assert_eq!(attestation_expected, 720);
|
||||
assert_eq!(
|
||||
size_of::<AttestationElectra<MainnetEthSpec>>(),
|
||||
attestation_expected
|
||||
@@ -1,16 +1,21 @@
|
||||
use crate::slot_data::SlotData;
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::{Checkpoint, ForkName, Hash256, SignedRoot, Slot};
|
||||
use context_deserialize_derive::context_deserialize;
|
||||
use context_deserialize::context_deserialize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
use crate::{
|
||||
attestation::Checkpoint,
|
||||
core::{Hash256, SignedRoot, Slot, SlotData},
|
||||
fork::ForkName,
|
||||
test_utils::TestRandom,
|
||||
};
|
||||
|
||||
/// The data upon which an attestation is based.
|
||||
///
|
||||
/// Spec v0.12.1
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
#[derive(
|
||||
arbitrary::Arbitrary,
|
||||
Debug,
|
||||
Clone,
|
||||
PartialEq,
|
||||
@@ -1,7 +1,9 @@
|
||||
use crate::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(arbitrary::Arbitrary, Debug, PartialEq, Clone, Copy, Default, Serialize, Deserialize)]
|
||||
use crate::{attestation::CommitteeIndex, core::Slot};
|
||||
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
#[derive(Debug, PartialEq, Clone, Copy, Default, Serialize, Deserialize)]
|
||||
pub struct AttestationDuty {
|
||||
/// The slot during which the attester must attest.
|
||||
pub slot: Slot,
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::*;
|
||||
use crate::{attestation::CommitteeIndex, core::Slot};
|
||||
|
||||
#[derive(Default, Clone, Debug, PartialEq)]
|
||||
pub struct BeaconCommittee<'a> {
|
||||
@@ -17,7 +17,8 @@ impl BeaconCommittee<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(arbitrary::Arbitrary, Default, Clone, Debug, PartialEq)]
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
#[derive(Default, Clone, Debug, PartialEq)]
|
||||
pub struct OwnedBeaconCommittee {
|
||||
pub slot: Slot,
|
||||
pub index: CommitteeIndex,
|
||||
@@ -1,16 +1,20 @@
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::{Epoch, ForkName, Hash256};
|
||||
use context_deserialize_derive::context_deserialize;
|
||||
use context_deserialize::context_deserialize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
use crate::{
|
||||
core::{Epoch, Hash256},
|
||||
fork::ForkName,
|
||||
test_utils::TestRandom,
|
||||
};
|
||||
|
||||
/// Casper FFG checkpoint, used in attestations.
|
||||
///
|
||||
/// Spec v0.12.1
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
#[derive(
|
||||
arbitrary::Arbitrary,
|
||||
Debug,
|
||||
Clone,
|
||||
Copy,
|
||||
@@ -1,17 +1,21 @@
|
||||
use crate::context_deserialize;
|
||||
use crate::{
|
||||
test_utils::TestRandom, AggregateSignature, AttestationData, EthSpec, ForkName, VariableList,
|
||||
use std::{
|
||||
hash::{Hash, Hasher},
|
||||
slice::Iter,
|
||||
};
|
||||
use core::slice::Iter;
|
||||
use derivative::Derivative;
|
||||
|
||||
use bls::AggregateSignature;
|
||||
use context_deserialize::context_deserialize;
|
||||
use educe::Educe;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz::Encode;
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use std::hash::{Hash, Hasher};
|
||||
use ssz_types::VariableList;
|
||||
use superstruct::superstruct;
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
use crate::{attestation::AttestationData, core::EthSpec, fork::ForkName, test_utils::TestRandom};
|
||||
|
||||
/// Details an attestation that can be slashable.
|
||||
///
|
||||
/// To be included in an `AttesterSlashing`.
|
||||
@@ -28,32 +32,30 @@ use tree_hash_derive::TreeHash;
|
||||
Decode,
|
||||
Encode,
|
||||
TestRandom,
|
||||
Derivative,
|
||||
arbitrary::Arbitrary,
|
||||
Educe,
|
||||
TreeHash,
|
||||
),
|
||||
context_deserialize(ForkName),
|
||||
derivative(PartialEq, Hash(bound = "E: EthSpec")),
|
||||
educe(PartialEq, Hash(bound(E: EthSpec))),
|
||||
serde(bound = "E: EthSpec", deny_unknown_fields),
|
||||
arbitrary(bound = "E: EthSpec"),
|
||||
cfg_attr(
|
||||
feature = "arbitrary",
|
||||
derive(arbitrary::Arbitrary),
|
||||
arbitrary(bound = "E: EthSpec"),
|
||||
),
|
||||
)
|
||||
)]
|
||||
#[derive(
|
||||
Debug,
|
||||
Clone,
|
||||
Serialize,
|
||||
TreeHash,
|
||||
Encode,
|
||||
Derivative,
|
||||
Deserialize,
|
||||
arbitrary::Arbitrary,
|
||||
PartialEq,
|
||||
#[cfg_attr(
|
||||
feature = "arbitrary",
|
||||
derive(arbitrary::Arbitrary),
|
||||
arbitrary(bound = "E: EthSpec")
|
||||
)]
|
||||
#[derive(Debug, Clone, Serialize, TreeHash, Encode, Educe, Deserialize)]
|
||||
#[educe(PartialEq)]
|
||||
#[serde(untagged)]
|
||||
#[tree_hash(enum_behaviour = "transparent")]
|
||||
#[ssz(enum_behaviour = "transparent")]
|
||||
#[serde(bound = "E: EthSpec", deny_unknown_fields)]
|
||||
#[arbitrary(bound = "E: EthSpec")]
|
||||
pub struct IndexedAttestation<E: EthSpec> {
|
||||
/// Lists validator registry indices, not committee indices.
|
||||
#[superstruct(only(Base), partial_getter(rename = "attesting_indices_base"))]
|
||||
@@ -210,9 +212,10 @@ impl<E: EthSpec> Hash for IndexedAttestation<E> {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::slot_epoch::Epoch;
|
||||
use crate::test_utils::{SeedableRng, XorShiftRng};
|
||||
use crate::MainnetEthSpec;
|
||||
use crate::{
|
||||
core::{Epoch, MainnetEthSpec},
|
||||
test_utils::{SeedableRng, XorShiftRng},
|
||||
};
|
||||
|
||||
#[test]
|
||||
pub fn test_is_double_vote_true() {
|
||||
@@ -0,0 +1,36 @@
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::{EthSpec, ForkName, PayloadAttestationData};
|
||||
use bls::AggregateSignature;
|
||||
use context_deserialize::context_deserialize;
|
||||
use core::slice::Iter;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use ssz_types::VariableList;
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
#[derive(TestRandom, TreeHash, Debug, Clone, PartialEq, Encode, Decode, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
#[serde(bound = "E: EthSpec", deny_unknown_fields)]
|
||||
#[cfg_attr(feature = "arbitrary", arbitrary(bound = "E: EthSpec"))]
|
||||
#[context_deserialize(ForkName)]
|
||||
pub struct IndexedPayloadAttestation<E: EthSpec> {
|
||||
#[serde(with = "ssz_types::serde_utils::quoted_u64_var_list")]
|
||||
pub attesting_indices: VariableList<u64, E::PTCSize>,
|
||||
pub data: PayloadAttestationData,
|
||||
pub signature: AggregateSignature,
|
||||
}
|
||||
|
||||
impl<E: EthSpec> IndexedPayloadAttestation<E> {
|
||||
pub fn attesting_indices_iter(&self) -> Iter<'_, u64> {
|
||||
self.attesting_indices.iter()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::MainnetEthSpec;
|
||||
|
||||
ssz_and_tree_hash_tests!(IndexedPayloadAttestation<MainnetEthSpec>);
|
||||
}
|
||||
47
consensus/types/src/attestation/mod.rs
Normal file
47
consensus/types/src/attestation/mod.rs
Normal file
@@ -0,0 +1,47 @@
|
||||
mod aggregate_and_proof;
|
||||
mod attestation;
|
||||
mod attestation_data;
|
||||
mod attestation_duty;
|
||||
mod beacon_committee;
|
||||
mod checkpoint;
|
||||
mod indexed_attestation;
|
||||
mod indexed_payload_attestation;
|
||||
mod participation_flags;
|
||||
mod payload_attestation;
|
||||
mod payload_attestation_data;
|
||||
mod payload_attestation_message;
|
||||
mod pending_attestation;
|
||||
mod selection_proof;
|
||||
mod shuffling_id;
|
||||
mod signed_aggregate_and_proof;
|
||||
mod subnet_id;
|
||||
|
||||
pub use aggregate_and_proof::{
|
||||
AggregateAndProof, AggregateAndProofBase, AggregateAndProofElectra, AggregateAndProofRef,
|
||||
};
|
||||
pub use attestation::{
|
||||
Attestation, AttestationBase, AttestationElectra, AttestationOnDisk, AttestationRef,
|
||||
AttestationRefMut, AttestationRefOnDisk, Error as AttestationError, SingleAttestation,
|
||||
};
|
||||
pub use attestation_data::AttestationData;
|
||||
pub use attestation_duty::AttestationDuty;
|
||||
pub use beacon_committee::{BeaconCommittee, OwnedBeaconCommittee};
|
||||
pub use checkpoint::Checkpoint;
|
||||
pub use indexed_attestation::{
|
||||
IndexedAttestation, IndexedAttestationBase, IndexedAttestationElectra, IndexedAttestationRef,
|
||||
};
|
||||
pub use indexed_payload_attestation::IndexedPayloadAttestation;
|
||||
pub use participation_flags::ParticipationFlags;
|
||||
pub use payload_attestation::PayloadAttestation;
|
||||
pub use payload_attestation_data::PayloadAttestationData;
|
||||
pub use payload_attestation_message::PayloadAttestationMessage;
|
||||
pub use pending_attestation::PendingAttestation;
|
||||
pub use selection_proof::SelectionProof;
|
||||
pub use shuffling_id::AttestationShufflingId;
|
||||
pub use signed_aggregate_and_proof::{
|
||||
SignedAggregateAndProof, SignedAggregateAndProofBase, SignedAggregateAndProofElectra,
|
||||
SignedAggregateAndProofRefMut,
|
||||
};
|
||||
pub use subnet_id::SubnetId;
|
||||
|
||||
pub type CommitteeIndex = u64;
|
||||
@@ -1,13 +1,17 @@
|
||||
use crate::{consts::altair::NUM_FLAG_INDICES, test_utils::TestRandom, Hash256};
|
||||
use safe_arith::{ArithError, SafeArith};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz::{Decode, DecodeError, Encode};
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash::{PackedEncoding, TreeHash, TreeHashType};
|
||||
|
||||
use crate::{
|
||||
core::{Hash256, consts::altair::NUM_FLAG_INDICES},
|
||||
test_utils::TestRandom,
|
||||
};
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy, PartialEq, Deserialize, Serialize, TestRandom)]
|
||||
#[serde(transparent)]
|
||||
#[derive(arbitrary::Arbitrary)]
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
pub struct ParticipationFlags {
|
||||
#[serde(with = "serde_utils::quoted_u8")]
|
||||
bits: u8,
|
||||
31
consensus/types/src/attestation/payload_attestation.rs
Normal file
31
consensus/types/src/attestation/payload_attestation.rs
Normal file
@@ -0,0 +1,31 @@
|
||||
use crate::attestation::payload_attestation_data::PayloadAttestationData;
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::{EthSpec, ForkName};
|
||||
use bls::AggregateSignature;
|
||||
use context_deserialize::context_deserialize;
|
||||
use educe::Educe;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz::BitList;
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
#[derive(TestRandom, TreeHash, Debug, Clone, Encode, Decode, Serialize, Deserialize, Educe)]
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
#[serde(bound = "E: EthSpec", deny_unknown_fields)]
|
||||
#[cfg_attr(feature = "arbitrary", arbitrary(bound = "E: EthSpec"))]
|
||||
#[educe(PartialEq, Hash)]
|
||||
#[context_deserialize(ForkName)]
|
||||
pub struct PayloadAttestation<E: EthSpec> {
|
||||
pub aggregation_bits: BitList<E::PTCSize>,
|
||||
pub data: PayloadAttestationData,
|
||||
pub signature: AggregateSignature,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod payload_attestation_tests {
|
||||
use super::*;
|
||||
use crate::MinimalEthSpec;
|
||||
|
||||
ssz_and_tree_hash_tests!(PayloadAttestation<MinimalEthSpec>);
|
||||
}
|
||||
28
consensus/types/src/attestation/payload_attestation_data.rs
Normal file
28
consensus/types/src/attestation/payload_attestation_data.rs
Normal file
@@ -0,0 +1,28 @@
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::{ForkName, Hash256, SignedRoot, Slot};
|
||||
use context_deserialize::context_deserialize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
#[derive(
|
||||
TestRandom, TreeHash, Debug, Clone, PartialEq, Eq, Encode, Decode, Serialize, Deserialize, Hash,
|
||||
)]
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
#[context_deserialize(ForkName)]
|
||||
pub struct PayloadAttestationData {
|
||||
pub beacon_block_root: Hash256,
|
||||
pub slot: Slot,
|
||||
pub payload_present: bool,
|
||||
pub blob_data_available: bool,
|
||||
}
|
||||
|
||||
impl SignedRoot for PayloadAttestationData {}
|
||||
|
||||
#[cfg(test)]
|
||||
mod payload_attestation_data_tests {
|
||||
use super::*;
|
||||
|
||||
ssz_and_tree_hash_tests!(PayloadAttestationData);
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
use crate::ForkName;
|
||||
use crate::attestation::payload_attestation_data::PayloadAttestationData;
|
||||
use crate::test_utils::TestRandom;
|
||||
use bls::Signature;
|
||||
use context_deserialize::context_deserialize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
#[derive(TestRandom, TreeHash, Debug, Clone, PartialEq, Encode, Decode, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
#[context_deserialize(ForkName)]
|
||||
pub struct PayloadAttestationMessage {
|
||||
#[serde(with = "serde_utils::quoted_u64")]
|
||||
pub validator_index: u64,
|
||||
pub data: PayloadAttestationData,
|
||||
pub signature: Signature,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
ssz_and_tree_hash_tests!(PayloadAttestationMessage);
|
||||
}
|
||||
@@ -1,27 +1,21 @@
|
||||
use crate::context_deserialize;
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::{AttestationData, BitList, EthSpec, ForkName};
|
||||
use context_deserialize::context_deserialize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use ssz_types::BitList;
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
use crate::{attestation::AttestationData, core::EthSpec, fork::ForkName, test_utils::TestRandom};
|
||||
|
||||
/// An attestation that has been included in the state but not yet fully processed.
|
||||
///
|
||||
/// Spec v0.12.1
|
||||
#[derive(
|
||||
Debug,
|
||||
Clone,
|
||||
PartialEq,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
TreeHash,
|
||||
TestRandom,
|
||||
arbitrary::Arbitrary,
|
||||
#[cfg_attr(
|
||||
feature = "arbitrary",
|
||||
derive(arbitrary::Arbitrary),
|
||||
arbitrary(bound = "E: EthSpec")
|
||||
)]
|
||||
#[arbitrary(bound = "E: EthSpec")]
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)]
|
||||
#[context_deserialize(ForkName)]
|
||||
pub struct PendingAttestation<E: EthSpec> {
|
||||
pub aggregation_bits: BitList<E::MaxValidatorsPerCommittee>,
|
||||
@@ -1,12 +1,19 @@
|
||||
use crate::{
|
||||
ChainSpec, Domain, EthSpec, Fork, Hash256, PublicKey, SecretKey, Signature, SignedRoot, Slot,
|
||||
};
|
||||
use ethereum_hashing::hash;
|
||||
use safe_arith::{ArithError, SafeArith};
|
||||
use ssz::Encode;
|
||||
use std::cmp;
|
||||
|
||||
#[derive(arbitrary::Arbitrary, PartialEq, Debug, Clone)]
|
||||
use bls::{PublicKey, SecretKey, Signature};
|
||||
use ethereum_hashing::hash;
|
||||
use safe_arith::{ArithError, SafeArith};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz::Encode;
|
||||
|
||||
use crate::{
|
||||
core::{ChainSpec, Domain, EthSpec, Hash256, SignedRoot, Slot},
|
||||
fork::Fork,
|
||||
};
|
||||
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct SelectionProof(Signature);
|
||||
|
||||
impl SelectionProof {
|
||||
@@ -1,7 +1,12 @@
|
||||
use crate::*;
|
||||
use std::hash::Hash;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use std::hash::Hash;
|
||||
|
||||
use crate::{
|
||||
core::{Epoch, EthSpec, Hash256, RelativeEpoch},
|
||||
state::{BeaconState, BeaconStateError},
|
||||
};
|
||||
|
||||
/// Can be used to key (ID) the shuffling in some chain, in some epoch.
|
||||
///
|
||||
@@ -1,18 +1,21 @@
|
||||
use super::{
|
||||
AggregateAndProof, AggregateAndProofBase, AggregateAndProofElectra, AggregateAndProofRef,
|
||||
};
|
||||
use super::{
|
||||
Attestation, AttestationRef, ChainSpec, Domain, EthSpec, Fork, ForkName, Hash256, SecretKey,
|
||||
SelectionProof, Signature, SignedRoot,
|
||||
};
|
||||
use crate::context_deserialize;
|
||||
use crate::test_utils::TestRandom;
|
||||
use bls::{SecretKey, Signature};
|
||||
use context_deserialize::context_deserialize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use superstruct::superstruct;
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
use crate::{
|
||||
attestation::{
|
||||
AggregateAndProof, AggregateAndProofBase, AggregateAndProofElectra, AggregateAndProofRef,
|
||||
Attestation, AttestationRef, SelectionProof,
|
||||
},
|
||||
core::{ChainSpec, Domain, EthSpec, Hash256, SignedRoot},
|
||||
fork::{Fork, ForkName},
|
||||
test_utils::TestRandom,
|
||||
};
|
||||
|
||||
/// A Validators signed aggregate proof to publish on the `beacon_aggregate_and_proof`
|
||||
/// gossipsub topic.
|
||||
///
|
||||
@@ -21,7 +24,6 @@ use tree_hash_derive::TreeHash;
|
||||
variants(Base, Electra),
|
||||
variant_attributes(
|
||||
derive(
|
||||
arbitrary::Arbitrary,
|
||||
Debug,
|
||||
Clone,
|
||||
PartialEq,
|
||||
@@ -34,19 +36,25 @@ use tree_hash_derive::TreeHash;
|
||||
),
|
||||
context_deserialize(ForkName),
|
||||
serde(bound = "E: EthSpec"),
|
||||
arbitrary(bound = "E: EthSpec"),
|
||||
cfg_attr(
|
||||
feature = "arbitrary",
|
||||
derive(arbitrary::Arbitrary),
|
||||
arbitrary(bound = "E: EthSpec"),
|
||||
),
|
||||
),
|
||||
map_into(Attestation),
|
||||
map_ref_into(AggregateAndProofRef)
|
||||
)]
|
||||
#[derive(
|
||||
arbitrary::Arbitrary, Debug, Clone, PartialEq, Serialize, Deserialize, Encode, TreeHash,
|
||||
#[cfg_attr(
|
||||
feature = "arbitrary",
|
||||
derive(arbitrary::Arbitrary),
|
||||
arbitrary(bound = "E: EthSpec")
|
||||
)]
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, TreeHash)]
|
||||
#[serde(untagged)]
|
||||
#[tree_hash(enum_behaviour = "transparent")]
|
||||
#[ssz(enum_behaviour = "transparent")]
|
||||
#[serde(bound = "E: EthSpec", deny_unknown_fields)]
|
||||
#[arbitrary(bound = "E: EthSpec")]
|
||||
pub struct SignedAggregateAndProof<E: EthSpec> {
|
||||
/// The `AggregateAndProof` that was signed.
|
||||
#[superstruct(flatten)]
|
||||
@@ -1,17 +1,23 @@
|
||||
//! Identifies each shard by an integer identifier.
|
||||
use crate::SingleAttestation;
|
||||
use crate::{AttestationRef, ChainSpec, CommitteeIndex, EthSpec, Slot};
|
||||
use alloy_primitives::{bytes::Buf, U256};
|
||||
use std::{
|
||||
ops::{Deref, DerefMut},
|
||||
sync::LazyLock,
|
||||
};
|
||||
|
||||
use alloy_primitives::{U256, bytes::Buf};
|
||||
use safe_arith::{ArithError, SafeArith};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::sync::LazyLock;
|
||||
|
||||
use crate::{
|
||||
attestation::{AttestationRef, CommitteeIndex, SingleAttestation},
|
||||
core::{ChainSpec, EthSpec, Slot},
|
||||
};
|
||||
|
||||
const MAX_SUBNET_ID: usize = 64;
|
||||
|
||||
/// The number of bits in a Discovery `NodeId`. This is used for binary operations on the node-id
|
||||
/// data.
|
||||
const NODE_ID_BITS: u64 = 256;
|
||||
const NODE_ID_BITS: u32 = 256;
|
||||
|
||||
static SUBNET_ID_TO_STRING: LazyLock<Vec<String>> = LazyLock::new(|| {
|
||||
let mut v = Vec::with_capacity(MAX_SUBNET_ID);
|
||||
@@ -22,7 +28,8 @@ static SUBNET_ID_TO_STRING: LazyLock<Vec<String>> = LazyLock::new(|| {
|
||||
v
|
||||
});
|
||||
|
||||
#[derive(arbitrary::Arbitrary, Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct SubnetId(#[serde(with = "serde_utils::quoted_u64")] u64);
|
||||
|
||||
@@ -101,7 +108,7 @@ impl SubnetId {
|
||||
spec: &ChainSpec,
|
||||
) -> impl Iterator<Item = SubnetId> {
|
||||
// The bits of the node-id we are using to define the subnets.
|
||||
let prefix_bits = spec.attestation_subnet_prefix_bits as u64;
|
||||
let prefix_bits = spec.attestation_subnet_prefix_bits as u32;
|
||||
|
||||
let node_id = U256::from_be_slice(&raw_node_id);
|
||||
// calculate the prefixes used to compute the subnet and shuffling
|
||||
@@ -1,239 +0,0 @@
|
||||
use crate::{ContextDeserialize, ForkName};
|
||||
use serde::de::DeserializeOwned;
|
||||
use serde::{Deserialize, Deserializer, Serialize};
|
||||
use serde_json::value::Value;
|
||||
|
||||
pub trait ForkVersionDecode: Sized {
|
||||
/// SSZ decode with explicit fork variant.
|
||||
fn from_ssz_bytes_by_fork(bytes: &[u8], fork_name: ForkName) -> Result<Self, ssz::DecodeError>;
|
||||
}
|
||||
|
||||
/// The metadata of type M should be set to `EmptyMetadata` if you don't care about adding fields other than
|
||||
/// version. If you *do* care about adding other fields you can mix in any type that implements
|
||||
/// `Deserialize`.
|
||||
#[derive(Debug, PartialEq, Clone, Serialize)]
|
||||
pub struct ForkVersionedResponse<T, M = EmptyMetadata> {
|
||||
pub version: ForkName,
|
||||
#[serde(flatten)]
|
||||
pub metadata: M,
|
||||
pub data: T,
|
||||
}
|
||||
|
||||
// Used for responses to V1 endpoints that don't have a version field.
|
||||
/// The metadata of type M should be set to `EmptyMetadata` if you don't care about adding fields other than
|
||||
/// version. If you *do* care about adding other fields you can mix in any type that implements
|
||||
/// `Deserialize`.
|
||||
#[derive(Debug, PartialEq, Clone, Serialize)]
|
||||
pub struct UnversionedResponse<T, M = EmptyMetadata> {
|
||||
pub metadata: M,
|
||||
pub data: T,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Serialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum BeaconResponse<T, M = EmptyMetadata> {
|
||||
ForkVersioned(ForkVersionedResponse<T, M>),
|
||||
Unversioned(UnversionedResponse<T, M>),
|
||||
}
|
||||
|
||||
impl<T, M> BeaconResponse<T, M> {
|
||||
pub fn version(&self) -> Option<ForkName> {
|
||||
match self {
|
||||
BeaconResponse::ForkVersioned(response) => Some(response.version),
|
||||
BeaconResponse::Unversioned(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn data(&self) -> &T {
|
||||
match self {
|
||||
BeaconResponse::ForkVersioned(response) => &response.data,
|
||||
BeaconResponse::Unversioned(response) => &response.data,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn metadata(&self) -> &M {
|
||||
match self {
|
||||
BeaconResponse::ForkVersioned(response) => &response.metadata,
|
||||
BeaconResponse::Unversioned(response) => &response.metadata,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Metadata type similar to unit (i.e. `()`) but deserializes from a map (`serde_json::Value`).
|
||||
///
|
||||
/// Unfortunately the braces are semantically significant, i.e. `struct EmptyMetadata;` does not
|
||||
/// work.
|
||||
#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||
pub struct EmptyMetadata {}
|
||||
|
||||
/// Fork versioned response with extra information about finalization & optimistic execution.
|
||||
pub type ExecutionOptimisticFinalizedBeaconResponse<T> =
|
||||
BeaconResponse<T, ExecutionOptimisticFinalizedMetadata>;
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
|
||||
pub struct ExecutionOptimisticFinalizedMetadata {
|
||||
pub execution_optimistic: Option<bool>,
|
||||
pub finalized: Option<bool>,
|
||||
}
|
||||
|
||||
impl<'de, T, M> Deserialize<'de> for ForkVersionedResponse<T, M>
|
||||
where
|
||||
T: ContextDeserialize<'de, ForkName>,
|
||||
M: DeserializeOwned,
|
||||
{
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
#[derive(Deserialize)]
|
||||
struct Helper {
|
||||
version: ForkName,
|
||||
#[serde(flatten)]
|
||||
metadata: Value,
|
||||
data: Value,
|
||||
}
|
||||
|
||||
let helper = Helper::deserialize(deserializer)?;
|
||||
|
||||
// Deserialize metadata
|
||||
let metadata = serde_json::from_value(helper.metadata).map_err(serde::de::Error::custom)?;
|
||||
|
||||
// Deserialize `data` using ContextDeserialize
|
||||
let data = T::context_deserialize(helper.data, helper.version)
|
||||
.map_err(serde::de::Error::custom)?;
|
||||
|
||||
Ok(ForkVersionedResponse {
|
||||
version: helper.version,
|
||||
metadata,
|
||||
data,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, T, M> Deserialize<'de> for UnversionedResponse<T, M>
|
||||
where
|
||||
T: DeserializeOwned,
|
||||
M: DeserializeOwned,
|
||||
{
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
#[derive(Deserialize)]
|
||||
struct Helper<T, M> {
|
||||
#[serde(flatten)]
|
||||
metadata: M,
|
||||
data: T,
|
||||
}
|
||||
|
||||
let helper = Helper::deserialize(deserializer)?;
|
||||
|
||||
Ok(UnversionedResponse {
|
||||
metadata: helper.metadata,
|
||||
data: helper.data,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, M> BeaconResponse<T, M> {
|
||||
pub fn map_data<U>(self, f: impl FnOnce(T) -> U) -> BeaconResponse<U, M> {
|
||||
match self {
|
||||
BeaconResponse::ForkVersioned(response) => {
|
||||
BeaconResponse::ForkVersioned(response.map_data(f))
|
||||
}
|
||||
BeaconResponse::Unversioned(response) => {
|
||||
BeaconResponse::Unversioned(response.map_data(f))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_data(self) -> T {
|
||||
match self {
|
||||
BeaconResponse::ForkVersioned(response) => response.data,
|
||||
BeaconResponse::Unversioned(response) => response.data,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, M> UnversionedResponse<T, M> {
|
||||
pub fn map_data<U>(self, f: impl FnOnce(T) -> U) -> UnversionedResponse<U, M> {
|
||||
let UnversionedResponse { metadata, data } = self;
|
||||
UnversionedResponse {
|
||||
metadata,
|
||||
data: f(data),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, M> ForkVersionedResponse<T, M> {
|
||||
/// Apply a function to the inner `data`, potentially changing its type.
|
||||
pub fn map_data<U>(self, f: impl FnOnce(T) -> U) -> ForkVersionedResponse<U, M> {
|
||||
let ForkVersionedResponse {
|
||||
version,
|
||||
metadata,
|
||||
data,
|
||||
} = self;
|
||||
ForkVersionedResponse {
|
||||
version,
|
||||
metadata,
|
||||
data: f(data),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, M> From<ForkVersionedResponse<T, M>> for BeaconResponse<T, M> {
|
||||
fn from(response: ForkVersionedResponse<T, M>) -> Self {
|
||||
BeaconResponse::ForkVersioned(response)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, M> From<UnversionedResponse<T, M>> for BeaconResponse<T, M> {
|
||||
fn from(response: UnversionedResponse<T, M>) -> Self {
|
||||
BeaconResponse::Unversioned(response)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod fork_version_response_tests {
|
||||
use crate::{
|
||||
ExecutionPayload, ExecutionPayloadBellatrix, ForkName, ForkVersionedResponse,
|
||||
MainnetEthSpec,
|
||||
};
|
||||
use serde_json::json;
|
||||
|
||||
#[test]
|
||||
fn fork_versioned_response_deserialize_correct_fork() {
|
||||
type E = MainnetEthSpec;
|
||||
|
||||
let response_json =
|
||||
serde_json::to_string(&json!(ForkVersionedResponse::<ExecutionPayload<E>> {
|
||||
version: ForkName::Bellatrix,
|
||||
metadata: Default::default(),
|
||||
data: ExecutionPayload::Bellatrix(ExecutionPayloadBellatrix::default()),
|
||||
}))
|
||||
.unwrap();
|
||||
|
||||
let result: Result<ForkVersionedResponse<ExecutionPayload<E>>, _> =
|
||||
serde_json::from_str(&response_json);
|
||||
|
||||
assert!(result.is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fork_versioned_response_deserialize_incorrect_fork() {
|
||||
type E = MainnetEthSpec;
|
||||
|
||||
let response_json =
|
||||
serde_json::to_string(&json!(ForkVersionedResponse::<ExecutionPayload<E>> {
|
||||
version: ForkName::Capella,
|
||||
metadata: Default::default(),
|
||||
data: ExecutionPayload::Bellatrix(ExecutionPayloadBellatrix::default()),
|
||||
}))
|
||||
.unwrap();
|
||||
|
||||
let result: Result<ForkVersionedResponse<ExecutionPayload<E>>, _> =
|
||||
serde_json::from_str(&response_json);
|
||||
|
||||
assert!(result.is_err());
|
||||
}
|
||||
}
|
||||
@@ -1,22 +1,45 @@
|
||||
use crate::attestation::AttestationBase;
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::*;
|
||||
use derivative::Derivative;
|
||||
use std::{fmt, marker::PhantomData};
|
||||
|
||||
use bls::{AggregateSignature, PublicKeyBytes, SecretKey, Signature, SignatureBytes};
|
||||
use context_deserialize::ContextDeserialize;
|
||||
use educe::Educe;
|
||||
use fixed_bytes::FixedBytesExtended;
|
||||
use serde::{Deserialize, Deserializer, Serialize};
|
||||
use ssz::{Decode, DecodeError};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use std::fmt;
|
||||
use std::marker::PhantomData;
|
||||
use ssz_types::{BitList, BitVector, FixedVector, VariableList};
|
||||
use superstruct::superstruct;
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash::TreeHash;
|
||||
use tree_hash_derive::TreeHash;
|
||||
use typenum::Unsigned;
|
||||
|
||||
use self::indexed_attestation::IndexedAttestationBase;
|
||||
use crate::{
|
||||
SignedExecutionPayloadBid,
|
||||
attestation::{AttestationBase, AttestationData, IndexedAttestationBase},
|
||||
block::{
|
||||
BeaconBlockBodyAltair, BeaconBlockBodyBase, BeaconBlockBodyBellatrix,
|
||||
BeaconBlockBodyCapella, BeaconBlockBodyDeneb, BeaconBlockBodyEip7805,
|
||||
BeaconBlockBodyElectra, BeaconBlockBodyFulu, BeaconBlockBodyGloas, BeaconBlockBodyRef,
|
||||
BeaconBlockBodyRefMut, BeaconBlockHeader, SignedBeaconBlock, SignedBeaconBlockHeader,
|
||||
},
|
||||
core::{ChainSpec, Domain, Epoch, EthSpec, Graffiti, Hash256, SignedRoot, Slot},
|
||||
deposit::{Deposit, DepositData},
|
||||
execution::{
|
||||
AbstractExecPayload, BlindedPayload, Eth1Data, ExecutionPayload, ExecutionRequests,
|
||||
FullPayload,
|
||||
},
|
||||
exit::{SignedVoluntaryExit, VoluntaryExit},
|
||||
fork::{Fork, ForkName, InconsistentFork, map_fork_name},
|
||||
slashing::{AttesterSlashingBase, ProposerSlashing},
|
||||
state::BeaconStateError,
|
||||
sync_committee::SyncAggregate,
|
||||
test_utils::TestRandom,
|
||||
};
|
||||
|
||||
/// A block of the `BeaconChain`.
|
||||
#[superstruct(
|
||||
variants(Base, Altair, Bellatrix, Capella, Deneb, Electra, Eip7805, Fulu),
|
||||
variants(Base, Altair, Bellatrix, Capella, Deneb, Electra, Fulu, Eip7805, Gloas),
|
||||
variant_attributes(
|
||||
derive(
|
||||
Debug,
|
||||
@@ -27,15 +50,18 @@ use self::indexed_attestation::IndexedAttestationBase;
|
||||
Decode,
|
||||
TreeHash,
|
||||
TestRandom,
|
||||
Derivative,
|
||||
arbitrary::Arbitrary
|
||||
Educe,
|
||||
),
|
||||
derivative(PartialEq, Hash(bound = "E: EthSpec, Payload: AbstractExecPayload<E>")),
|
||||
educe(PartialEq, Hash(bound(E: EthSpec, Payload: AbstractExecPayload<E>))),
|
||||
serde(
|
||||
bound = "E: EthSpec, Payload: AbstractExecPayload<E>",
|
||||
deny_unknown_fields
|
||||
),
|
||||
arbitrary(bound = "E: EthSpec, Payload: AbstractExecPayload<E>"),
|
||||
cfg_attr(
|
||||
feature = "arbitrary",
|
||||
derive(arbitrary::Arbitrary),
|
||||
arbitrary(bound = "E: EthSpec, Payload: AbstractExecPayload<E>")
|
||||
)
|
||||
),
|
||||
ref_attributes(
|
||||
derive(Debug, PartialEq, TreeHash),
|
||||
@@ -44,13 +70,15 @@ use self::indexed_attestation::IndexedAttestationBase;
|
||||
map_ref_into(BeaconBlockBodyRef, BeaconBlock),
|
||||
map_ref_mut_into(BeaconBlockBodyRefMut)
|
||||
)]
|
||||
#[derive(
|
||||
Debug, Clone, Serialize, Deserialize, Encode, TreeHash, Derivative, arbitrary::Arbitrary,
|
||||
#[cfg_attr(
|
||||
feature = "arbitrary",
|
||||
derive(arbitrary::Arbitrary),
|
||||
arbitrary(bound = "E: EthSpec, Payload: AbstractExecPayload<E>")
|
||||
)]
|
||||
#[derivative(PartialEq, Hash(bound = "E: EthSpec"))]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Encode, TreeHash, Educe)]
|
||||
#[educe(PartialEq, Hash(bound(E: EthSpec)))]
|
||||
#[serde(untagged)]
|
||||
#[serde(bound = "E: EthSpec, Payload: AbstractExecPayload<E>")]
|
||||
#[arbitrary(bound = "E: EthSpec, Payload: AbstractExecPayload<E>")]
|
||||
#[tree_hash(enum_behaviour = "transparent")]
|
||||
#[ssz(enum_behaviour = "transparent")]
|
||||
pub struct BeaconBlock<E: EthSpec, Payload: AbstractExecPayload<E> = FullPayload<E>> {
|
||||
@@ -75,10 +103,12 @@ pub struct BeaconBlock<E: EthSpec, Payload: AbstractExecPayload<E> = FullPayload
|
||||
pub body: BeaconBlockBodyDeneb<E, Payload>,
|
||||
#[superstruct(only(Electra), partial_getter(rename = "body_electra"))]
|
||||
pub body: BeaconBlockBodyElectra<E, Payload>,
|
||||
#[superstruct(only(Eip7805), partial_getter(rename = "body_eip7805"))]
|
||||
pub body: BeaconBlockBodyEip7805<E, Payload>,
|
||||
#[superstruct(only(Fulu), partial_getter(rename = "body_fulu"))]
|
||||
pub body: BeaconBlockBodyFulu<E, Payload>,
|
||||
#[superstruct(only(Eip7805), partial_getter(rename = "body_eip7805"))]
|
||||
pub body: BeaconBlockBodyEip7805<E, Payload>,
|
||||
#[superstruct(only(Gloas), partial_getter(rename = "body_gloas"))]
|
||||
pub body: BeaconBlockBodyGloas<E, Payload>,
|
||||
}
|
||||
|
||||
pub type BlindedBeaconBlock<E> = BeaconBlock<E, BlindedPayload<E>>;
|
||||
@@ -131,9 +161,10 @@ 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(|_| BeaconBlockEip7805::from_ssz_bytes(bytes).map(BeaconBlock::Eip7805))
|
||||
.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))
|
||||
@@ -232,8 +263,9 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload<E>> BeaconBlockRef<'a, E, Payl
|
||||
BeaconBlockRef::Capella { .. } => ForkName::Capella,
|
||||
BeaconBlockRef::Deneb { .. } => ForkName::Deneb,
|
||||
BeaconBlockRef::Electra { .. } => ForkName::Electra,
|
||||
BeaconBlockRef::Eip7805 { .. } => ForkName::Eip7805,
|
||||
BeaconBlockRef::Fulu { .. } => ForkName::Fulu,
|
||||
BeaconBlockRef::Eip7805 { .. } => ForkName::Eip7805,
|
||||
BeaconBlockRef::Gloas { .. } => ForkName::Gloas,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -278,7 +310,7 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload<E>> BeaconBlockRef<'a, E, Payl
|
||||
|
||||
/// Extracts a reference to an execution payload from a block, returning an error if the block
|
||||
/// is pre-merge.
|
||||
pub fn execution_payload(&self) -> Result<Payload::Ref<'a>, Error> {
|
||||
pub fn execution_payload(&self) -> Result<Payload::Ref<'a>, BeaconStateError> {
|
||||
self.body().execution_payload()
|
||||
}
|
||||
}
|
||||
@@ -418,7 +450,10 @@ impl<E: EthSpec, Payload: AbstractExecPayload<E>> EmptyBlock for BeaconBlockAlta
|
||||
/// Returns an empty Altair block to be used during genesis.
|
||||
fn empty(spec: &ChainSpec) -> Self {
|
||||
BeaconBlockAltair {
|
||||
slot: spec.genesis_slot,
|
||||
slot: spec
|
||||
.altair_fork_epoch
|
||||
.expect("altair enabled")
|
||||
.start_slot(E::slots_per_epoch()),
|
||||
proposer_index: 0,
|
||||
parent_root: Hash256::zero(),
|
||||
state_root: Hash256::zero(),
|
||||
@@ -451,7 +486,10 @@ impl<E: EthSpec, Payload: AbstractExecPayload<E>> BeaconBlockAltair<E, Payload>
|
||||
sync_committee_bits: BitVector::default(),
|
||||
};
|
||||
BeaconBlockAltair {
|
||||
slot: spec.genesis_slot,
|
||||
slot: spec
|
||||
.altair_fork_epoch
|
||||
.expect("altair enabled")
|
||||
.start_slot(E::slots_per_epoch()),
|
||||
proposer_index: 0,
|
||||
parent_root: Hash256::zero(),
|
||||
state_root: Hash256::zero(),
|
||||
@@ -479,7 +517,10 @@ impl<E: EthSpec, Payload: AbstractExecPayload<E>> EmptyBlock for BeaconBlockBell
|
||||
/// Returns an empty Bellatrix block to be used during genesis.
|
||||
fn empty(spec: &ChainSpec) -> Self {
|
||||
BeaconBlockBellatrix {
|
||||
slot: spec.genesis_slot,
|
||||
slot: spec
|
||||
.bellatrix_fork_epoch
|
||||
.expect("bellatrix enabled")
|
||||
.start_slot(E::slots_per_epoch()),
|
||||
proposer_index: 0,
|
||||
parent_root: Hash256::zero(),
|
||||
state_root: Hash256::zero(),
|
||||
@@ -507,7 +548,10 @@ impl<E: EthSpec, Payload: AbstractExecPayload<E>> EmptyBlock for BeaconBlockCape
|
||||
/// Returns an empty Capella block to be used during genesis.
|
||||
fn empty(spec: &ChainSpec) -> Self {
|
||||
BeaconBlockCapella {
|
||||
slot: spec.genesis_slot,
|
||||
slot: spec
|
||||
.capella_fork_epoch
|
||||
.expect("capella enabled")
|
||||
.start_slot(E::slots_per_epoch()),
|
||||
proposer_index: 0,
|
||||
parent_root: Hash256::zero(),
|
||||
state_root: Hash256::zero(),
|
||||
@@ -536,7 +580,10 @@ impl<E: EthSpec, Payload: AbstractExecPayload<E>> EmptyBlock for BeaconBlockDene
|
||||
/// Returns an empty Deneb block to be used during genesis.
|
||||
fn empty(spec: &ChainSpec) -> Self {
|
||||
BeaconBlockDeneb {
|
||||
slot: spec.genesis_slot,
|
||||
slot: spec
|
||||
.deneb_fork_epoch
|
||||
.expect("deneb enabled")
|
||||
.start_slot(E::slots_per_epoch()),
|
||||
proposer_index: 0,
|
||||
parent_root: Hash256::zero(),
|
||||
state_root: Hash256::zero(),
|
||||
@@ -566,7 +613,10 @@ impl<E: EthSpec, Payload: AbstractExecPayload<E>> EmptyBlock for BeaconBlockElec
|
||||
/// Returns an empty Electra block to be used during genesis.
|
||||
fn empty(spec: &ChainSpec) -> Self {
|
||||
BeaconBlockElectra {
|
||||
slot: spec.genesis_slot,
|
||||
slot: spec
|
||||
.electra_fork_epoch
|
||||
.expect("electra enabled")
|
||||
.start_slot(E::slots_per_epoch()),
|
||||
proposer_index: 0,
|
||||
parent_root: Hash256::zero(),
|
||||
state_root: Hash256::zero(),
|
||||
@@ -628,7 +678,10 @@ impl<E: EthSpec, Payload: AbstractExecPayload<E>> EmptyBlock for BeaconBlockFulu
|
||||
/// Returns an empty Fulu block to be used during genesis.
|
||||
fn empty(spec: &ChainSpec) -> Self {
|
||||
BeaconBlockFulu {
|
||||
slot: spec.genesis_slot,
|
||||
slot: spec
|
||||
.fulu_fork_epoch
|
||||
.expect("fulu enabled")
|
||||
.start_slot(E::slots_per_epoch()),
|
||||
proposer_index: 0,
|
||||
parent_root: Hash256::zero(),
|
||||
state_root: Hash256::zero(),
|
||||
@@ -655,6 +708,63 @@ 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(),
|
||||
bls_to_execution_changes: VariableList::empty(),
|
||||
signed_execution_payload_bid: SignedExecutionPayloadBid::empty(),
|
||||
payload_attestations: VariableList::empty(),
|
||||
_phantom: PhantomData,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(EIP-7732) Mark's branch had the following implementation but not sure if it's needed so will just add header below for reference
|
||||
// impl<E: EthSpec, Payload: AbstractExecPayload<E>> BeaconBlockEIP7732<E, Payload> {
|
||||
|
||||
// TODO(EIP-7732) Look into whether we can remove this in the future since no blinded blocks post-gloas
|
||||
impl<E: EthSpec> From<BeaconBlockGloas<E, BlindedPayload<E>>>
|
||||
for BeaconBlockGloas<E, FullPayload<E>>
|
||||
{
|
||||
fn from(block: BeaconBlockGloas<E, BlindedPayload<E>>) -> Self {
|
||||
let BeaconBlockGloas {
|
||||
slot,
|
||||
proposer_index,
|
||||
parent_root,
|
||||
state_root,
|
||||
body,
|
||||
} = block;
|
||||
|
||||
BeaconBlockGloas {
|
||||
slot,
|
||||
proposer_index,
|
||||
parent_root,
|
||||
state_root,
|
||||
body: body.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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>>
|
||||
@@ -738,6 +848,7 @@ impl_from!(BeaconBlockDeneb, <E, FullPayload<E>>, <E, BlindedPayload<E>>, |body:
|
||||
impl_from!(BeaconBlockElectra, <E, FullPayload<E>>, <E, BlindedPayload<E>>, |body: BeaconBlockBodyElectra<_, _>| body.into());
|
||||
impl_from!(BeaconBlockEip7805, <E, FullPayload<E>>, <E, BlindedPayload<E>>, |body: BeaconBlockBodyEip7805<_, _>| 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 {
|
||||
@@ -771,8 +882,9 @@ impl_clone_as_blinded!(BeaconBlockBellatrix, <E, FullPayload<E>>, <E, BlindedPay
|
||||
impl_clone_as_blinded!(BeaconBlockCapella, <E, FullPayload<E>>, <E, BlindedPayload<E>>);
|
||||
impl_clone_as_blinded!(BeaconBlockDeneb, <E, FullPayload<E>>, <E, BlindedPayload<E>>);
|
||||
impl_clone_as_blinded!(BeaconBlockElectra, <E, FullPayload<E>>, <E, BlindedPayload<E>>);
|
||||
impl_clone_as_blinded!(BeaconBlockEip7805, <E, FullPayload<E>>, <E, BlindedPayload<E>>);
|
||||
impl_clone_as_blinded!(BeaconBlockFulu, <E, FullPayload<E>>, <E, BlindedPayload<E>>);
|
||||
impl_clone_as_blinded!(BeaconBlockEip7805, <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.
|
||||
@@ -817,6 +929,7 @@ impl<'de, E: EthSpec, Payload: AbstractExecPayload<E>> ContextDeserialize<'de, F
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum BlockImportSource {
|
||||
Gossip,
|
||||
Lookup,
|
||||
@@ -838,7 +951,10 @@ impl fmt::Display for BlockImportSource {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::test_utils::{test_ssz_tree_hash_pair_with, SeedableRng, XorShiftRng};
|
||||
use crate::{
|
||||
core::MainnetEthSpec,
|
||||
test_utils::{SeedableRng, XorShiftRng, test_ssz_tree_hash_pair_with},
|
||||
};
|
||||
use ssz::Encode;
|
||||
|
||||
type BeaconBlock = super::BeaconBlock<MainnetEthSpec>;
|
||||
@@ -981,6 +1097,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;
|
||||
@@ -1004,6 +1140,8 @@ mod tests {
|
||||
let eip7805_slot = eip7805_epoch.start_slot(E::slots_per_epoch());
|
||||
let fulu_epoch = eip7805_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);
|
||||
@@ -1011,6 +1149,7 @@ mod tests {
|
||||
spec.electra_fork_epoch = Some(electra_epoch);
|
||||
spec.eip7805_fork_epoch = Some(eip7805_epoch);
|
||||
spec.fulu_fork_epoch = Some(fulu_epoch);
|
||||
spec.gloas_fork_epoch = Some(gloas_epoch);
|
||||
|
||||
// BeaconBlockBase
|
||||
{
|
||||
@@ -1150,22 +1289,37 @@ mod tests {
|
||||
slot: fulu_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() = electra_slot;
|
||||
bad
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
BeaconBlock::from_ssz_bytes(&good_block.as_ssz_bytes(), &spec)
|
||||
.expect("good fulu block can be decoded"),
|
||||
good_block
|
||||
);
|
||||
// TODO(fulu): Uncomment once Fulu has features since without features
|
||||
// and with an Electra slot it decodes successfully to Electra.
|
||||
}
|
||||
|
||||
// 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 fulu block cannot be decoded");
|
||||
// .expect_err("bad gloas block cannot be decoded");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,44 @@
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::*;
|
||||
use derivative::Derivative;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use bls::Signature;
|
||||
use context_deserialize::{ContextDeserialize, context_deserialize};
|
||||
use educe::Educe;
|
||||
use merkle_proof::{MerkleTree, MerkleTreeError};
|
||||
use metastruct::metastruct;
|
||||
use serde::{Deserialize, Deserializer, Serialize};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use std::marker::PhantomData;
|
||||
use ssz_types::{FixedVector, VariableList};
|
||||
use superstruct::superstruct;
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash::{TreeHash, BYTES_PER_CHUNK};
|
||||
use tree_hash::{BYTES_PER_CHUNK, TreeHash};
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
pub type KzgCommitments<E> =
|
||||
VariableList<KzgCommitment, <E as EthSpec>::MaxBlobCommitmentsPerBlock>;
|
||||
use crate::payload_attestation::PayloadAttestation;
|
||||
use crate::{
|
||||
SignedExecutionPayloadBid,
|
||||
attestation::{AttestationBase, AttestationElectra, AttestationRef, AttestationRefMut},
|
||||
core::{EthSpec, Graffiti, Hash256},
|
||||
deposit::Deposit,
|
||||
execution::{
|
||||
AbstractExecPayload, BlindedPayload, BlindedPayloadBellatrix, BlindedPayloadCapella,
|
||||
BlindedPayloadDeneb, BlindedPayloadEip7805, BlindedPayloadElectra, BlindedPayloadFulu,
|
||||
Eth1Data, ExecutionPayload, ExecutionPayloadBellatrix, ExecutionPayloadCapella,
|
||||
ExecutionPayloadDeneb, ExecutionPayloadEip7805, ExecutionPayloadElectra,
|
||||
ExecutionPayloadFulu, ExecutionPayloadGloas, ExecutionRequests, FullPayload,
|
||||
FullPayloadBellatrix, FullPayloadCapella, FullPayloadDeneb, FullPayloadEip7805,
|
||||
FullPayloadElectra, FullPayloadFulu, SignedBlsToExecutionChange,
|
||||
},
|
||||
exit::SignedVoluntaryExit,
|
||||
fork::{ForkName, map_fork_name},
|
||||
kzg_ext::KzgCommitments,
|
||||
light_client::consts::{EXECUTION_PAYLOAD_INDEX, EXECUTION_PAYLOAD_PROOF_LEN},
|
||||
slashing::{
|
||||
AttesterSlashingBase, AttesterSlashingElectra, AttesterSlashingRef, ProposerSlashing,
|
||||
},
|
||||
state::BeaconStateError,
|
||||
sync_committee::SyncAggregate,
|
||||
test_utils::TestRandom,
|
||||
};
|
||||
|
||||
/// The number of leaves (including padding) on the `BeaconBlockBody` Merkle tree.
|
||||
///
|
||||
@@ -28,7 +54,7 @@ pub const BLOB_KZG_COMMITMENTS_INDEX: usize = 11;
|
||||
///
|
||||
/// This *superstruct* abstracts over the hard-fork.
|
||||
#[superstruct(
|
||||
variants(Base, Altair, Bellatrix, Capella, Deneb, Electra, Eip7805, Fulu),
|
||||
variants(Base, Altair, Bellatrix, Capella, Deneb, Electra, Fulu, Eip7805, Gloas),
|
||||
variant_attributes(
|
||||
derive(
|
||||
Debug,
|
||||
@@ -39,15 +65,18 @@ pub const BLOB_KZG_COMMITMENTS_INDEX: usize = 11;
|
||||
Decode,
|
||||
TreeHash,
|
||||
TestRandom,
|
||||
Derivative,
|
||||
arbitrary::Arbitrary
|
||||
Educe,
|
||||
),
|
||||
derivative(PartialEq, Hash(bound = "E: EthSpec, Payload: AbstractExecPayload<E>")),
|
||||
educe(PartialEq, Hash(bound(E: EthSpec, Payload: AbstractExecPayload<E>))),
|
||||
serde(
|
||||
bound = "E: EthSpec, Payload: AbstractExecPayload<E>",
|
||||
deny_unknown_fields
|
||||
),
|
||||
arbitrary(bound = "E: EthSpec, Payload: AbstractExecPayload<E>"),
|
||||
cfg_attr(
|
||||
feature = "arbitrary",
|
||||
derive(arbitrary::Arbitrary),
|
||||
arbitrary(bound = "E: EthSpec, Payload: AbstractExecPayload<E>"),
|
||||
),
|
||||
context_deserialize(ForkName),
|
||||
),
|
||||
specific_variant_attributes(
|
||||
@@ -57,18 +86,29 @@ 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))))),
|
||||
Eip7805(metastruct(mappings(beacon_block_body_eip7805_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")
|
||||
cast_error(
|
||||
ty = "BeaconStateError",
|
||||
expr = "BeaconStateError::IncorrectStateVariant"
|
||||
),
|
||||
partial_getter_error(
|
||||
ty = "BeaconStateError",
|
||||
expr = "BeaconStateError::IncorrectStateVariant"
|
||||
)
|
||||
)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Derivative, TreeHash, arbitrary::Arbitrary)]
|
||||
#[derivative(PartialEq, Hash(bound = "E: EthSpec"))]
|
||||
#[cfg_attr(
|
||||
feature = "arbitrary",
|
||||
derive(arbitrary::Arbitrary),
|
||||
arbitrary(bound = "E: EthSpec, Payload: AbstractExecPayload<E>")
|
||||
)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Educe, TreeHash)]
|
||||
#[educe(PartialEq, Hash(bound(E: EthSpec)))]
|
||||
#[serde(untagged)]
|
||||
#[serde(bound = "E: EthSpec, Payload: AbstractExecPayload<E>")]
|
||||
#[tree_hash(enum_behaviour = "transparent")]
|
||||
#[arbitrary(bound = "E: EthSpec, Payload: AbstractExecPayload<E>")]
|
||||
pub struct BeaconBlockBody<E: EthSpec, Payload: AbstractExecPayload<E> = FullPayload<E>> {
|
||||
pub randao_reveal: Signature,
|
||||
pub eth1_data: Eth1Data,
|
||||
@@ -80,7 +120,7 @@ pub struct BeaconBlockBody<E: EthSpec, Payload: AbstractExecPayload<E> = FullPay
|
||||
)]
|
||||
pub attester_slashings: VariableList<AttesterSlashingBase<E>, E::MaxAttesterSlashings>,
|
||||
#[superstruct(
|
||||
only(Electra, Eip7805, Fulu),
|
||||
only(Electra, Fulu, Eip7805, Gloas),
|
||||
partial_getter(rename = "attester_slashings_electra")
|
||||
)]
|
||||
pub attester_slashings:
|
||||
@@ -91,13 +131,13 @@ pub struct BeaconBlockBody<E: EthSpec, Payload: AbstractExecPayload<E> = FullPay
|
||||
)]
|
||||
pub attestations: VariableList<AttestationBase<E>, E::MaxAttestations>,
|
||||
#[superstruct(
|
||||
only(Electra, Eip7805, Fulu),
|
||||
only(Electra, Fulu, Eip7805, 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, Eip7805, Fulu))]
|
||||
#[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Fulu, Eip7805, 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,24 +163,28 @@ 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, Eip7805, Fulu))]
|
||||
#[superstruct(only(Capella, Deneb, Electra, Fulu, Eip7805, Gloas))]
|
||||
pub bls_to_execution_changes:
|
||||
VariableList<SignedBlsToExecutionChange, E::MaxBlsToExecutionChanges>,
|
||||
#[superstruct(only(Deneb, Electra, Eip7805, Fulu))]
|
||||
pub blob_kzg_commitments: KzgCommitments<E>,
|
||||
#[superstruct(only(Electra, Eip7805, Fulu))]
|
||||
pub execution_requests: ExecutionRequests<E>,
|
||||
#[superstruct(only(Base, Altair))]
|
||||
#[superstruct(only(Gloas))]
|
||||
pub signed_execution_payload_bid: SignedExecutionPayloadBid,
|
||||
#[superstruct(only(Gloas))]
|
||||
pub payload_attestations: VariableList<PayloadAttestation<E>, E::MaxPayloadAttestations>,
|
||||
#[superstruct(only(Base, Altair, Gloas))]
|
||||
#[metastruct(exclude_from(fields))]
|
||||
#[ssz(skip_serializing, skip_deserializing)]
|
||||
#[tree_hash(skip_hashing)]
|
||||
#[serde(skip)]
|
||||
#[arbitrary(default)]
|
||||
#[cfg_attr(feature = "arbitrary", arbitrary(default))]
|
||||
pub _phantom: PhantomData<Payload>,
|
||||
}
|
||||
|
||||
impl<E: EthSpec, Payload: AbstractExecPayload<E>> BeaconBlockBody<E, Payload> {
|
||||
pub fn execution_payload(&self) -> Result<Payload::Ref<'_>, Error> {
|
||||
pub fn execution_payload(&self) -> Result<Payload::Ref<'_>, BeaconStateError> {
|
||||
self.to_ref().execution_payload()
|
||||
}
|
||||
|
||||
@@ -151,19 +195,20 @@ impl<E: EthSpec, Payload: AbstractExecPayload<E>> BeaconBlockBody<E, Payload> {
|
||||
}
|
||||
|
||||
impl<'a, E: EthSpec, Payload: AbstractExecPayload<E>> BeaconBlockBodyRef<'a, E, Payload> {
|
||||
pub fn execution_payload(&self) -> Result<Payload::Ref<'a>, Error> {
|
||||
pub fn execution_payload(&self) -> Result<Payload::Ref<'a>, BeaconStateError> {
|
||||
match self {
|
||||
Self::Base(_) | Self::Altair(_) => Err(Error::IncorrectStateVariant),
|
||||
Self::Base(_) | Self::Altair(_) => Err(BeaconStateError::IncorrectStateVariant),
|
||||
Self::Bellatrix(body) => Ok(Payload::Ref::from(&body.execution_payload)),
|
||||
Self::Capella(body) => Ok(Payload::Ref::from(&body.execution_payload)),
|
||||
Self::Deneb(body) => Ok(Payload::Ref::from(&body.execution_payload)),
|
||||
Self::Electra(body) => Ok(Payload::Ref::from(&body.execution_payload)),
|
||||
Self::Eip7805(body) => Ok(Payload::Ref::from(&body.execution_payload)),
|
||||
Self::Fulu(body) => Ok(Payload::Ref::from(&body.execution_payload)),
|
||||
Self::Gloas(_) => Err(BeaconStateError::IncorrectStateVariant),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn body_merkle_leaves(&self) -> Vec<Hash256> {
|
||||
pub fn body_merkle_leaves(&self) -> Vec<Hash256> {
|
||||
let mut leaves = vec![];
|
||||
match self {
|
||||
Self::Base(body) => {
|
||||
@@ -198,6 +243,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
|
||||
}
|
||||
@@ -209,7 +258,7 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload<E>> BeaconBlockBodyRef<'a, E,
|
||||
pub fn kzg_commitment_merkle_proof(
|
||||
&self,
|
||||
index: usize,
|
||||
) -> Result<FixedVector<Hash256, E::KzgCommitmentInclusionProofDepth>, Error> {
|
||||
) -> Result<FixedVector<Hash256, E::KzgCommitmentInclusionProofDepth>, BeaconStateError> {
|
||||
let kzg_commitments_proof = self.kzg_commitments_merkle_proof()?;
|
||||
let proof = self.complete_kzg_commitment_merkle_proof(index, &kzg_commitments_proof)?;
|
||||
Ok(proof)
|
||||
@@ -217,16 +266,19 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload<E>> BeaconBlockBodyRef<'a, E,
|
||||
|
||||
/// Produces the proof of inclusion for a `KzgCommitment` in `self.blob_kzg_commitments`
|
||||
/// at `index` using an existing proof for the `blob_kzg_commitments` field.
|
||||
/// TODO(EIP7732) Investigate calling functions since this will no longer work for glas since no block_kzg_commitments in the body anymore
|
||||
pub fn complete_kzg_commitment_merkle_proof(
|
||||
&self,
|
||||
index: usize,
|
||||
kzg_commitments_proof: &[Hash256],
|
||||
) -> Result<FixedVector<Hash256, E::KzgCommitmentInclusionProofDepth>, Error> {
|
||||
) -> Result<FixedVector<Hash256, E::KzgCommitmentInclusionProofDepth>, BeaconStateError> {
|
||||
match self {
|
||||
Self::Base(_) | Self::Altair(_) | Self::Bellatrix(_) | Self::Capella(_) => {
|
||||
Err(Error::IncorrectStateVariant)
|
||||
}
|
||||
Self::Deneb(_) | Self::Electra(_) | Self::Eip7805(_) | Self::Fulu(_) => {
|
||||
Self::Base(_)
|
||||
| Self::Altair(_)
|
||||
| Self::Bellatrix(_)
|
||||
| Self::Capella(_)
|
||||
| Self::Gloas(_) => Err(BeaconStateError::IncorrectStateVariant),
|
||||
Self::Deneb(_) | Self::Electra(_) | Self::Fulu(_) | Self::Eip7805(_) => {
|
||||
// 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
|
||||
@@ -246,7 +298,7 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload<E>> BeaconBlockBodyRef<'a, E,
|
||||
let tree = MerkleTree::create(&blob_leaves, depth as usize);
|
||||
let (_, mut proof) = tree
|
||||
.generate_proof(index, depth as usize)
|
||||
.map_err(Error::MerkleTreeError)?;
|
||||
.map_err(BeaconStateError::MerkleTreeError)?;
|
||||
|
||||
// Add the branch corresponding to the length mix-in.
|
||||
let length = blob_leaves.len();
|
||||
@@ -254,7 +306,9 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload<E>> BeaconBlockBodyRef<'a, E,
|
||||
let mut length_bytes = [0; BYTES_PER_CHUNK];
|
||||
length_bytes
|
||||
.get_mut(0..usize_len)
|
||||
.ok_or(Error::MerkleTreeError(MerkleTreeError::PleaseNotifyTheDevs))?
|
||||
.ok_or(BeaconStateError::MerkleTreeError(
|
||||
MerkleTreeError::PleaseNotifyTheDevs,
|
||||
))?
|
||||
.copy_from_slice(&length.to_le_bytes());
|
||||
let length_root = Hash256::from_slice(length_bytes.as_slice());
|
||||
proof.push(length_root);
|
||||
@@ -272,32 +326,41 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload<E>> BeaconBlockBodyRef<'a, E,
|
||||
/// Produces the proof of inclusion for `self.blob_kzg_commitments`.
|
||||
pub fn kzg_commitments_merkle_proof(
|
||||
&self,
|
||||
) -> Result<FixedVector<Hash256, E::KzgCommitmentsInclusionProofDepth>, Error> {
|
||||
) -> Result<FixedVector<Hash256, E::KzgCommitmentsInclusionProofDepth>, BeaconStateError> {
|
||||
let body_leaves = self.body_merkle_leaves();
|
||||
let beacon_block_body_depth = body_leaves.len().next_power_of_two().ilog2() as usize;
|
||||
let tree = MerkleTree::create(&body_leaves, beacon_block_body_depth);
|
||||
let (_, proof) = tree
|
||||
.generate_proof(BLOB_KZG_COMMITMENTS_INDEX, beacon_block_body_depth)
|
||||
.map_err(Error::MerkleTreeError)?;
|
||||
.map_err(BeaconStateError::MerkleTreeError)?;
|
||||
Ok(FixedVector::new(proof)?)
|
||||
}
|
||||
|
||||
pub fn block_body_merkle_proof(&self, generalized_index: usize) -> Result<Vec<Hash256>, Error> {
|
||||
pub fn block_body_merkle_proof(
|
||||
&self,
|
||||
generalized_index: usize,
|
||||
) -> Result<Vec<Hash256>, BeaconStateError> {
|
||||
let field_index = match generalized_index {
|
||||
light_client_update::EXECUTION_PAYLOAD_INDEX => {
|
||||
EXECUTION_PAYLOAD_INDEX => {
|
||||
// Execution payload is a top-level field, subtract off the generalized indices
|
||||
// for the internal nodes. Result should be 9, the field offset of the execution
|
||||
// payload in the `BeaconBlockBody`:
|
||||
// https://github.com/ethereum/consensus-specs/blob/dev/specs/deneb/beacon-chain.md#beaconblockbody
|
||||
generalized_index
|
||||
.checked_sub(NUM_BEACON_BLOCK_BODY_HASH_TREE_ROOT_LEAVES)
|
||||
.ok_or(Error::GeneralizedIndexNotSupported(generalized_index))?
|
||||
.ok_or(BeaconStateError::GeneralizedIndexNotSupported(
|
||||
generalized_index,
|
||||
))?
|
||||
}
|
||||
_ => {
|
||||
return Err(BeaconStateError::GeneralizedIndexNotSupported(
|
||||
generalized_index,
|
||||
));
|
||||
}
|
||||
_ => return Err(Error::GeneralizedIndexNotSupported(generalized_index)),
|
||||
};
|
||||
|
||||
let leaves = self.body_merkle_leaves();
|
||||
let depth = light_client_update::EXECUTION_PAYLOAD_PROOF_LEN;
|
||||
let depth = EXECUTION_PAYLOAD_PROOF_LEN;
|
||||
let tree = merkle_proof::MerkleTree::create(&leaves, depth);
|
||||
let (_, proof) = tree.generate_proof(field_index, depth)?;
|
||||
|
||||
@@ -311,29 +374,17 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload<E>> BeaconBlockBodyRef<'a, E,
|
||||
}
|
||||
|
||||
pub fn attestations_len(&self) -> usize {
|
||||
match self {
|
||||
Self::Base(body) => body.attestations.len(),
|
||||
Self::Altair(body) => body.attestations.len(),
|
||||
Self::Bellatrix(body) => body.attestations.len(),
|
||||
Self::Capella(body) => body.attestations.len(),
|
||||
Self::Deneb(body) => body.attestations.len(),
|
||||
Self::Electra(body) => body.attestations.len(),
|
||||
Self::Eip7805(body) => body.attestations.len(),
|
||||
Self::Fulu(body) => body.attestations.len(),
|
||||
}
|
||||
map_beacon_block_body_ref!(&'a _, self, |inner, cons| {
|
||||
cons(inner);
|
||||
inner.attestations.len()
|
||||
})
|
||||
}
|
||||
|
||||
pub fn attester_slashings_len(&self) -> usize {
|
||||
match self {
|
||||
Self::Base(body) => body.attester_slashings.len(),
|
||||
Self::Altair(body) => body.attester_slashings.len(),
|
||||
Self::Bellatrix(body) => body.attester_slashings.len(),
|
||||
Self::Capella(body) => body.attester_slashings.len(),
|
||||
Self::Deneb(body) => body.attester_slashings.len(),
|
||||
Self::Electra(body) => body.attester_slashings.len(),
|
||||
Self::Eip7805(body) => body.attester_slashings.len(),
|
||||
Self::Fulu(body) => body.attester_slashings.len(),
|
||||
}
|
||||
map_beacon_block_body_ref!(&'a _, self, |inner, cons| {
|
||||
cons(inner);
|
||||
inner.attester_slashings.len()
|
||||
})
|
||||
}
|
||||
|
||||
pub fn attestations(&self) -> Box<dyn Iterator<Item = AttestationRef<'a, E>> + 'a> {
|
||||
@@ -346,6 +397,7 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload<E>> BeaconBlockBodyRef<'a, E,
|
||||
Self::Electra(body) => Box::new(body.attestations.iter().map(AttestationRef::Electra)),
|
||||
Self::Eip7805(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)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -391,6 +443,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),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -422,6 +479,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))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -438,6 +498,7 @@ impl<E: EthSpec, Payload: AbstractExecPayload<E>> BeaconBlockBodyRef<'_, E, Payl
|
||||
BeaconBlockBodyRef::Electra { .. } => ForkName::Electra,
|
||||
BeaconBlockBodyRef::Eip7805 { .. } => ForkName::Eip7805,
|
||||
BeaconBlockBodyRef::Fulu { .. } => ForkName::Fulu,
|
||||
BeaconBlockBodyRef::Gloas { .. } => ForkName::Gloas,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -505,6 +566,46 @@ impl<E: EthSpec> From<BeaconBlockBodyAltair<E, BlindedPayload<E>>>
|
||||
}
|
||||
}
|
||||
|
||||
// Post-Fulu block bodies without payloads can be converted into block bodies with payloads
|
||||
// TODO(EIP-7732) Look into whether we can remove this in the future since no blinded blocks post-gloas
|
||||
impl<E: EthSpec> From<BeaconBlockBodyGloas<E, BlindedPayload<E>>>
|
||||
for BeaconBlockBodyGloas<E, FullPayload<E>>
|
||||
{
|
||||
fn from(body: BeaconBlockBodyGloas<E, BlindedPayload<E>>) -> Self {
|
||||
let BeaconBlockBodyGloas {
|
||||
randao_reveal,
|
||||
eth1_data,
|
||||
graffiti,
|
||||
proposer_slashings,
|
||||
attester_slashings,
|
||||
attestations,
|
||||
deposits,
|
||||
voluntary_exits,
|
||||
sync_aggregate,
|
||||
bls_to_execution_changes,
|
||||
signed_execution_payload_bid,
|
||||
payload_attestations,
|
||||
_phantom,
|
||||
} = body;
|
||||
|
||||
BeaconBlockBodyGloas {
|
||||
randao_reveal,
|
||||
eth1_data,
|
||||
graffiti,
|
||||
proposer_slashings,
|
||||
attester_slashings,
|
||||
attestations,
|
||||
deposits,
|
||||
voluntary_exits,
|
||||
sync_aggregate,
|
||||
bls_to_execution_changes,
|
||||
signed_execution_payload_bid,
|
||||
payload_attestations,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Likewise bodies with payloads can be transformed into bodies without.
|
||||
impl<E: EthSpec> From<BeaconBlockBodyBase<E, FullPayload<E>>>
|
||||
for (
|
||||
@@ -844,6 +945,50 @@ 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,
|
||||
bls_to_execution_changes,
|
||||
signed_execution_payload_bid,
|
||||
payload_attestations,
|
||||
_phantom,
|
||||
} = body;
|
||||
|
||||
(
|
||||
BeaconBlockBodyGloas {
|
||||
randao_reveal,
|
||||
eth1_data,
|
||||
graffiti,
|
||||
proposer_slashings,
|
||||
attester_slashings,
|
||||
attestations,
|
||||
deposits,
|
||||
voluntary_exits,
|
||||
sync_aggregate,
|
||||
bls_to_execution_changes,
|
||||
signed_execution_payload_bid,
|
||||
payload_attestations,
|
||||
_phantom: PhantomData,
|
||||
},
|
||||
None,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// 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>> {
|
||||
@@ -1075,6 +1220,13 @@ 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 (block_body, _payload) = self.clone().into();
|
||||
block_body
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EthSpec> From<BeaconBlockBody<E, FullPayload<E>>>
|
||||
for (
|
||||
BeaconBlockBody<E, BlindedPayload<E>>,
|
||||
@@ -1105,22 +1257,16 @@ impl<'de, E: EthSpec, Payload: AbstractExecPayload<E>> ContextDeserialize<'de, F
|
||||
}
|
||||
}
|
||||
|
||||
/// Util method helpful for logging.
|
||||
pub fn format_kzg_commitments(commitments: &[KzgCommitment]) -> String {
|
||||
let commitment_strings: Vec<String> = commitments.iter().map(|x| x.to_string()).collect();
|
||||
let commitments_joined = commitment_strings.join(", ");
|
||||
let surrounded_commitments = format!("[{}]", commitments_joined);
|
||||
surrounded_commitments
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
mod base {
|
||||
use super::super::*;
|
||||
use crate::core::MainnetEthSpec;
|
||||
ssz_and_tree_hash_tests!(BeaconBlockBodyBase<MainnetEthSpec>);
|
||||
}
|
||||
mod altair {
|
||||
use super::super::*;
|
||||
use crate::core::MainnetEthSpec;
|
||||
ssz_and_tree_hash_tests!(BeaconBlockBodyAltair<MainnetEthSpec>);
|
||||
}
|
||||
}
|
||||
@@ -1,29 +1,24 @@
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::*;
|
||||
|
||||
use context_deserialize_derive::context_deserialize;
|
||||
use bls::SecretKey;
|
||||
use context_deserialize::context_deserialize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash::TreeHash;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
use crate::{
|
||||
block::SignedBeaconBlockHeader,
|
||||
core::{ChainSpec, Domain, EthSpec, Hash256, SignedRoot, Slot},
|
||||
fork::{Fork, ForkName},
|
||||
test_utils::TestRandom,
|
||||
};
|
||||
|
||||
/// A header of a `BeaconBlock`.
|
||||
///
|
||||
/// Spec v0.12.1
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
#[derive(
|
||||
arbitrary::Arbitrary,
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
Hash,
|
||||
Clone,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
TreeHash,
|
||||
TestRandom,
|
||||
Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom,
|
||||
)]
|
||||
#[context_deserialize(ForkName)]
|
||||
pub struct BeaconBlockHeader {
|
||||
26
consensus/types/src/block/mod.rs
Normal file
26
consensus/types/src/block/mod.rs
Normal file
@@ -0,0 +1,26 @@
|
||||
mod beacon_block;
|
||||
mod beacon_block_body;
|
||||
mod beacon_block_header;
|
||||
mod signed_beacon_block;
|
||||
mod signed_beacon_block_header;
|
||||
|
||||
pub use beacon_block::{
|
||||
BeaconBlock, BeaconBlockAltair, BeaconBlockBase, BeaconBlockBellatrix, BeaconBlockCapella,
|
||||
BeaconBlockDeneb, BeaconBlockEip7805, BeaconBlockElectra, BeaconBlockFulu, BeaconBlockGloas,
|
||||
BeaconBlockRef, BeaconBlockRefMut, BlindedBeaconBlock, BlockImportSource, EmptyBlock,
|
||||
};
|
||||
pub use beacon_block_body::{
|
||||
BLOB_KZG_COMMITMENTS_INDEX, BeaconBlockBody, BeaconBlockBodyAltair, BeaconBlockBodyBase,
|
||||
BeaconBlockBodyBellatrix, BeaconBlockBodyCapella, BeaconBlockBodyDeneb, BeaconBlockBodyEip7805,
|
||||
BeaconBlockBodyElectra, BeaconBlockBodyFulu, BeaconBlockBodyGloas, BeaconBlockBodyRef,
|
||||
BeaconBlockBodyRefMut, NUM_BEACON_BLOCK_BODY_HASH_TREE_ROOT_LEAVES,
|
||||
};
|
||||
pub use beacon_block_header::BeaconBlockHeader;
|
||||
|
||||
pub use signed_beacon_block::{
|
||||
SignedBeaconBlock, SignedBeaconBlockAltair, SignedBeaconBlockBase, SignedBeaconBlockBellatrix,
|
||||
SignedBeaconBlockCapella, SignedBeaconBlockDeneb, SignedBeaconBlockEip7805,
|
||||
SignedBeaconBlockElectra, SignedBeaconBlockFulu, SignedBeaconBlockGloas, SignedBeaconBlockHash,
|
||||
SignedBlindedBeaconBlock, ssz_tagged_signed_beacon_block, ssz_tagged_signed_beacon_block_arc,
|
||||
};
|
||||
pub use signed_beacon_block_header::SignedBeaconBlockHeader;
|
||||
@@ -1,17 +1,44 @@
|
||||
use crate::beacon_block_body::{format_kzg_commitments, BLOB_KZG_COMMITMENTS_INDEX};
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::*;
|
||||
use derivative::Derivative;
|
||||
use std::fmt;
|
||||
|
||||
use bls::{PublicKey, Signature};
|
||||
use context_deserialize::ContextDeserialize;
|
||||
use educe::Educe;
|
||||
use merkle_proof::MerkleTree;
|
||||
use serde::{Deserialize, Deserializer, Serialize};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use std::fmt;
|
||||
use ssz_types::FixedVector;
|
||||
use superstruct::superstruct;
|
||||
use test_random_derive::TestRandom;
|
||||
use tracing::instrument;
|
||||
use tree_hash::TreeHash;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
#[derive(arbitrary::Arbitrary, PartialEq, Eq, Hash, Clone, Copy)]
|
||||
use crate::{
|
||||
block::{
|
||||
BLOB_KZG_COMMITMENTS_INDEX, BeaconBlock, BeaconBlockAltair, BeaconBlockBase,
|
||||
BeaconBlockBellatrix, BeaconBlockBodyBellatrix, BeaconBlockBodyCapella,
|
||||
BeaconBlockBodyDeneb, BeaconBlockBodyEip7805, BeaconBlockBodyElectra, BeaconBlockBodyFulu,
|
||||
BeaconBlockCapella, BeaconBlockDeneb, BeaconBlockEip7805, BeaconBlockElectra,
|
||||
BeaconBlockFulu, BeaconBlockGloas, BeaconBlockHeader, BeaconBlockRef, BeaconBlockRefMut,
|
||||
SignedBeaconBlockHeader,
|
||||
},
|
||||
core::{ChainSpec, Domain, Epoch, EthSpec, Hash256, SignedRoot, SigningData, Slot},
|
||||
execution::{
|
||||
AbstractExecPayload, BlindedPayload, BlindedPayloadBellatrix, BlindedPayloadCapella,
|
||||
BlindedPayloadDeneb, BlindedPayloadEip7805, BlindedPayloadElectra, BlindedPayloadFulu,
|
||||
ExecutionPayload, ExecutionPayloadBellatrix, ExecutionPayloadCapella,
|
||||
ExecutionPayloadDeneb, ExecutionPayloadEip7805, ExecutionPayloadElectra,
|
||||
ExecutionPayloadFulu, FullPayload, FullPayloadBellatrix, FullPayloadCapella,
|
||||
FullPayloadDeneb, FullPayloadEip7805, FullPayloadElectra, FullPayloadFulu,
|
||||
},
|
||||
fork::{Fork, ForkName, ForkVersionDecode, InconsistentFork, map_fork_name},
|
||||
kzg_ext::format_kzg_commitments,
|
||||
state::BeaconStateError,
|
||||
test_utils::TestRandom,
|
||||
};
|
||||
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
#[derive(PartialEq, Eq, Hash, Clone, Copy)]
|
||||
pub struct SignedBeaconBlockHash(Hash256);
|
||||
|
||||
impl fmt::Debug for SignedBeaconBlockHash {
|
||||
@@ -40,7 +67,7 @@ impl From<SignedBeaconBlockHash> for Hash256 {
|
||||
|
||||
/// A `BeaconBlock` and a signature from its proposer.
|
||||
#[superstruct(
|
||||
variants(Base, Altair, Bellatrix, Capella, Deneb, Electra, Eip7805, Fulu),
|
||||
variants(Base, Altair, Bellatrix, Capella, Deneb, Electra, Fulu, Eip7805, Gloas),
|
||||
variant_attributes(
|
||||
derive(
|
||||
Debug,
|
||||
@@ -50,25 +77,30 @@ impl From<SignedBeaconBlockHash> for Hash256 {
|
||||
Encode,
|
||||
Decode,
|
||||
TreeHash,
|
||||
Derivative,
|
||||
arbitrary::Arbitrary,
|
||||
Educe,
|
||||
TestRandom
|
||||
),
|
||||
derivative(PartialEq, Hash(bound = "E: EthSpec")),
|
||||
educe(PartialEq, Hash(bound(E: EthSpec))),
|
||||
serde(bound = "E: EthSpec, Payload: AbstractExecPayload<E>"),
|
||||
arbitrary(bound = "E: EthSpec, Payload: AbstractExecPayload<E>"),
|
||||
cfg_attr(
|
||||
feature = "arbitrary",
|
||||
derive(arbitrary::Arbitrary),
|
||||
arbitrary(bound = "E: EthSpec, Payload: AbstractExecPayload<E>"),
|
||||
),
|
||||
),
|
||||
map_into(BeaconBlock),
|
||||
map_ref_into(BeaconBlockRef),
|
||||
map_ref_mut_into(BeaconBlockRefMut)
|
||||
)]
|
||||
#[derive(
|
||||
Debug, Clone, Serialize, Deserialize, Encode, TreeHash, Derivative, arbitrary::Arbitrary,
|
||||
#[cfg_attr(
|
||||
feature = "arbitrary",
|
||||
derive(arbitrary::Arbitrary),
|
||||
arbitrary(bound = "E: EthSpec, Payload: AbstractExecPayload<E>")
|
||||
)]
|
||||
#[derivative(PartialEq, Hash(bound = "E: EthSpec"))]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Encode, TreeHash, Educe)]
|
||||
#[educe(PartialEq, Hash(bound(E: EthSpec)))]
|
||||
#[serde(untagged)]
|
||||
#[serde(bound = "E: EthSpec, Payload: AbstractExecPayload<E>")]
|
||||
#[arbitrary(bound = "E: EthSpec, Payload: AbstractExecPayload<E>")]
|
||||
#[tree_hash(enum_behaviour = "transparent")]
|
||||
#[ssz(enum_behaviour = "transparent")]
|
||||
pub struct SignedBeaconBlock<E: EthSpec, Payload: AbstractExecPayload<E> = FullPayload<E>> {
|
||||
@@ -88,6 +120,8 @@ pub struct SignedBeaconBlock<E: EthSpec, Payload: AbstractExecPayload<E> = FullP
|
||||
pub message: BeaconBlockEip7805<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,
|
||||
}
|
||||
|
||||
@@ -177,6 +211,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 })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -247,6 +284,7 @@ impl<E: EthSpec, Payload: AbstractExecPayload<E>> SignedBeaconBlock<E, Payload>
|
||||
}
|
||||
|
||||
/// Produce a signed beacon block header corresponding to this block.
|
||||
#[instrument(level = "debug", skip_all)]
|
||||
pub fn signed_block_header(&self) -> SignedBeaconBlockHeader {
|
||||
SignedBeaconBlockHeader {
|
||||
message: self.message().block_header(),
|
||||
@@ -264,7 +302,7 @@ impl<E: EthSpec, Payload: AbstractExecPayload<E>> SignedBeaconBlock<E, Payload>
|
||||
SignedBeaconBlockHeader,
|
||||
FixedVector<Hash256, E::KzgCommitmentsInclusionProofDepth>,
|
||||
),
|
||||
Error,
|
||||
BeaconStateError,
|
||||
> {
|
||||
// Create the block body merkle tree
|
||||
let body_leaves = self.message().body().body_merkle_leaves();
|
||||
@@ -274,7 +312,7 @@ impl<E: EthSpec, Payload: AbstractExecPayload<E>> SignedBeaconBlock<E, Payload>
|
||||
// Compute the KZG commitments inclusion proof
|
||||
let (_, proof) = body_merkle_tree
|
||||
.generate_proof(BLOB_KZG_COMMITMENTS_INDEX, beacon_block_body_depth)
|
||||
.map_err(Error::MerkleTreeError)?;
|
||||
.map_err(BeaconStateError::MerkleTreeError)?;
|
||||
let kzg_commitments_inclusion_proof = FixedVector::new(proof)?;
|
||||
|
||||
let block_header = BeaconBlockHeader {
|
||||
@@ -700,6 +738,20 @@ impl<E: EthSpec> SignedBeaconBlockFulu<E, BlindedPayload<E>> {
|
||||
}
|
||||
}
|
||||
|
||||
// We can convert gloas blocks without payloads into blocks "with" payloads.
|
||||
// TODO(EIP-7732) Look into whether we can remove this in the future since no blinded blocks post-gloas
|
||||
impl<E: EthSpec> From<SignedBeaconBlockGloas<E, BlindedPayload<E>>>
|
||||
for SignedBeaconBlockGloas<E, FullPayload<E>>
|
||||
{
|
||||
fn from(signed_block: SignedBeaconBlockGloas<E, BlindedPayload<E>>) -> Self {
|
||||
let SignedBeaconBlockGloas { message, signature } = signed_block;
|
||||
SignedBeaconBlockGloas {
|
||||
message: message.into(),
|
||||
signature,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EthSpec> SignedBeaconBlock<E, BlindedPayload<E>> {
|
||||
pub fn try_into_full_block(
|
||||
self,
|
||||
@@ -726,6 +778,7 @@ impl<E: EthSpec> SignedBeaconBlock<E, BlindedPayload<E>> {
|
||||
(SignedBeaconBlock::Fulu(block), Some(ExecutionPayload::Fulu(payload))) => {
|
||||
SignedBeaconBlock::Fulu(block.into_full_block(payload))
|
||||
}
|
||||
(SignedBeaconBlock::Gloas(block), _) => SignedBeaconBlock::Gloas(block.into()),
|
||||
// avoid wildcard matching forks so that compiler will
|
||||
// direct us here when a new fork has been added
|
||||
(SignedBeaconBlock::Bellatrix(_), _) => return None,
|
||||
@@ -734,6 +787,7 @@ impl<E: EthSpec> SignedBeaconBlock<E, BlindedPayload<E>> {
|
||||
(SignedBeaconBlock::Electra(_), _) => return None,
|
||||
(SignedBeaconBlock::Eip7805(_), _) => return None,
|
||||
(SignedBeaconBlock::Fulu(_), _) => return None,
|
||||
// TODO(EIP-7732) Determine if need a match arm for gloas here
|
||||
};
|
||||
Some(full_block)
|
||||
}
|
||||
@@ -882,6 +936,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)?,
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -911,6 +968,7 @@ pub mod ssz_tagged_signed_beacon_block_arc {
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::{block::EmptyBlock, core::MainnetEthSpec};
|
||||
|
||||
#[test]
|
||||
fn add_remove_payload_roundtrip() {
|
||||
@@ -953,11 +1011,26 @@ mod test {
|
||||
}
|
||||
}
|
||||
|
||||
fn spec_with_all_forks_enabled<E: EthSpec>() -> ChainSpec {
|
||||
let mut chain_spec = E::default_spec();
|
||||
chain_spec.altair_fork_epoch = Some(Epoch::new(1));
|
||||
chain_spec.bellatrix_fork_epoch = Some(Epoch::new(2));
|
||||
chain_spec.capella_fork_epoch = Some(Epoch::new(3));
|
||||
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());
|
||||
chain_spec
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ssz_tagged_signed_beacon_block() {
|
||||
type E = MainnetEthSpec;
|
||||
|
||||
let spec = &E::default_spec();
|
||||
let spec = &spec_with_all_forks_enabled::<E>();
|
||||
let sig = Signature::empty();
|
||||
let blocks = vec![
|
||||
SignedBeaconBlock::<E>::from_block(
|
||||
@@ -984,11 +1057,15 @@ mod test {
|
||||
BeaconBlock::Electra(BeaconBlockElectra::empty(spec)),
|
||||
sig.clone(),
|
||||
),
|
||||
SignedBeaconBlock::from_block(
|
||||
BeaconBlock::Fulu(BeaconBlockFulu::empty(spec)),
|
||||
sig.clone(),
|
||||
),
|
||||
SignedBeaconBlock::from_block(
|
||||
BeaconBlock::Eip7805(BeaconBlockEip7805::empty(spec)),
|
||||
sig.clone(),
|
||||
),
|
||||
SignedBeaconBlock::from_block(BeaconBlock::Fulu(BeaconBlockFulu::empty(spec)), sig),
|
||||
SignedBeaconBlock::from_block(BeaconBlock::Gloas(BeaconBlockGloas::empty(spec)), sig),
|
||||
];
|
||||
|
||||
for block in blocks {
|
||||
@@ -1,29 +1,23 @@
|
||||
use crate::context_deserialize;
|
||||
use crate::{
|
||||
test_utils::TestRandom, BeaconBlockHeader, ChainSpec, Domain, EthSpec, Fork, ForkName, Hash256,
|
||||
PublicKey, Signature, SignedRoot,
|
||||
};
|
||||
use bls::{PublicKey, Signature};
|
||||
use context_deserialize::context_deserialize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
use crate::{
|
||||
block::BeaconBlockHeader,
|
||||
core::{ChainSpec, Domain, EthSpec, Hash256, SignedRoot},
|
||||
fork::{Fork, ForkName},
|
||||
test_utils::TestRandom,
|
||||
};
|
||||
|
||||
/// A signed header of a `BeaconBlock`.
|
||||
///
|
||||
/// Spec v0.12.1
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
#[derive(
|
||||
arbitrary::Arbitrary,
|
||||
Debug,
|
||||
Clone,
|
||||
PartialEq,
|
||||
Eq,
|
||||
Hash,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
TreeHash,
|
||||
TestRandom,
|
||||
Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom,
|
||||
)]
|
||||
#[context_deserialize(ForkName)]
|
||||
pub struct SignedBeaconBlockHeader {
|
||||
@@ -1,14 +1,6 @@
|
||||
use crate::beacon_block_body::KzgCommitments;
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::{
|
||||
ChainSpec, ContextDeserialize, EthSpec, ExecutionPayloadHeaderBellatrix,
|
||||
ExecutionPayloadHeaderCapella, ExecutionPayloadHeaderDeneb, ExecutionPayloadHeaderEip7805,
|
||||
ExecutionPayloadHeaderElectra, ExecutionPayloadHeaderFulu, ExecutionPayloadHeaderRef,
|
||||
ExecutionPayloadHeaderRefMut, ExecutionRequests, ForkName, ForkVersionDecode, SignedRoot,
|
||||
Uint256,
|
||||
};
|
||||
use bls::PublicKeyBytes;
|
||||
use bls::Signature;
|
||||
use context_deserialize::ContextDeserialize;
|
||||
use serde::{Deserialize, Deserializer, Serialize};
|
||||
use ssz::Decode;
|
||||
use ssz_derive::{Decode, Encode};
|
||||
@@ -16,6 +8,19 @@ use superstruct::superstruct;
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
use crate::{
|
||||
core::{ChainSpec, EthSpec, SignedRoot, Uint256},
|
||||
execution::{
|
||||
ExecutionPayloadHeaderBellatrix, ExecutionPayloadHeaderCapella,
|
||||
ExecutionPayloadHeaderDeneb, ExecutionPayloadHeaderEip7805, ExecutionPayloadHeaderElectra,
|
||||
ExecutionPayloadHeaderFulu, ExecutionPayloadHeaderRef, ExecutionPayloadHeaderRefMut,
|
||||
ExecutionRequests,
|
||||
},
|
||||
fork::{ForkName, ForkVersionDecode},
|
||||
kzg_ext::KzgCommitments,
|
||||
test_utils::TestRandom,
|
||||
};
|
||||
|
||||
#[superstruct(
|
||||
variants(Bellatrix, Capella, Deneb, Electra, Eip7805, Fulu),
|
||||
variant_attributes(
|
||||
@@ -87,10 +92,10 @@ impl<E: EthSpec> ForkVersionDecode for BuilderBid<E> {
|
||||
/// SSZ decode with explicit fork variant.
|
||||
fn from_ssz_bytes_by_fork(bytes: &[u8], fork_name: ForkName) -> Result<Self, ssz::DecodeError> {
|
||||
let builder_bid = match fork_name {
|
||||
ForkName::Altair | ForkName::Base => {
|
||||
ForkName::Altair | ForkName::Base | ForkName::Gloas => {
|
||||
return Err(ssz::DecodeError::BytesInvalid(format!(
|
||||
"unsupported fork for ExecutionPayloadHeader: {fork_name}",
|
||||
)))
|
||||
)));
|
||||
}
|
||||
ForkName::Bellatrix => {
|
||||
BuilderBid::Bellatrix(BuilderBidBellatrix::from_ssz_bytes(bytes)?)
|
||||
@@ -158,7 +163,7 @@ impl<'de, E: EthSpec> ContextDeserialize<'de, ForkName> for BuilderBid<E> {
|
||||
ForkName::Fulu => {
|
||||
Self::Fulu(Deserialize::deserialize(deserializer).map_err(convert_err)?)
|
||||
}
|
||||
ForkName::Base | ForkName::Altair => {
|
||||
ForkName::Base | ForkName::Altair | ForkName::Gloas => {
|
||||
return Err(serde::de::Error::custom(format!(
|
||||
"BuilderBid failed to deserialize: unsupported fork '{}'",
|
||||
context
|
||||
36
consensus/types/src/builder/builder_pending_payment.rs
Normal file
36
consensus/types/src/builder/builder_pending_payment.rs
Normal file
@@ -0,0 +1,36 @@
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::{BuilderPendingWithdrawal, ForkName};
|
||||
use context_deserialize::context_deserialize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
Hash,
|
||||
Clone,
|
||||
Default,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
TreeHash,
|
||||
TestRandom,
|
||||
)]
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
#[context_deserialize(ForkName)]
|
||||
pub struct BuilderPendingPayment {
|
||||
#[serde(with = "serde_utils::quoted_u64")]
|
||||
pub weight: u64,
|
||||
pub withdrawal: BuilderPendingWithdrawal,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
ssz_and_tree_hash_tests!(BuilderPendingPayment);
|
||||
}
|
||||
@@ -1,17 +1,18 @@
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::*;
|
||||
use crate::{Address, Epoch, ForkName};
|
||||
use context_deserialize::context_deserialize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
#[derive(
|
||||
arbitrary::Arbitrary,
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
Hash,
|
||||
Clone,
|
||||
Default,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
@@ -19,21 +20,21 @@ use tree_hash_derive::TreeHash;
|
||||
TreeHash,
|
||||
TestRandom,
|
||||
)]
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
#[context_deserialize(ForkName)]
|
||||
pub struct Withdrawal {
|
||||
#[serde(with = "serde_utils::quoted_u64")]
|
||||
pub index: u64,
|
||||
#[serde(with = "serde_utils::quoted_u64")]
|
||||
pub validator_index: u64,
|
||||
pub struct BuilderPendingWithdrawal {
|
||||
#[serde(with = "serde_utils::address_hex")]
|
||||
pub address: Address,
|
||||
pub fee_recipient: Address,
|
||||
#[serde(with = "serde_utils::quoted_u64")]
|
||||
pub amount: u64,
|
||||
#[serde(with = "serde_utils::quoted_u64")]
|
||||
pub builder_index: u64,
|
||||
pub withdrawable_epoch: Epoch,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
ssz_and_tree_hash_tests!(Withdrawal);
|
||||
ssz_and_tree_hash_tests!(BuilderPendingWithdrawal);
|
||||
}
|
||||
10
consensus/types/src/builder/mod.rs
Normal file
10
consensus/types/src/builder/mod.rs
Normal file
@@ -0,0 +1,10 @@
|
||||
mod builder_bid;
|
||||
mod builder_pending_payment;
|
||||
mod builder_pending_withdrawal;
|
||||
|
||||
pub use builder_bid::{
|
||||
BuilderBid, BuilderBidBellatrix, BuilderBidCapella, BuilderBidDeneb, BuilderBidEip7805,
|
||||
BuilderBidElectra, BuilderBidFulu, SignedBuilderBid,
|
||||
};
|
||||
pub use builder_pending_payment::BuilderPendingPayment;
|
||||
pub use builder_pending_withdrawal::BuilderPendingWithdrawal;
|
||||
@@ -1,24 +1,20 @@
|
||||
use crate::context_deserialize;
|
||||
use crate::{test_utils::TestRandom, Address, ForkName, PublicKeyBytes, SignedRoot};
|
||||
use bls::PublicKeyBytes;
|
||||
use context_deserialize::context_deserialize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz::Encode;
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
use crate::{
|
||||
core::{Address, SignedRoot},
|
||||
fork::ForkName,
|
||||
test_utils::TestRandom,
|
||||
};
|
||||
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
#[derive(
|
||||
arbitrary::Arbitrary,
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
Hash,
|
||||
Clone,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
TreeHash,
|
||||
TestRandom,
|
||||
Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom,
|
||||
)]
|
||||
#[context_deserialize(ForkName)]
|
||||
pub struct ConsolidationRequest {
|
||||
5
consensus/types/src/consolidation/mod.rs
Normal file
5
consensus/types/src/consolidation/mod.rs
Normal file
@@ -0,0 +1,5 @@
|
||||
mod consolidation_request;
|
||||
mod pending_consolidation;
|
||||
|
||||
pub use consolidation_request::ConsolidationRequest;
|
||||
pub use pending_consolidation::PendingConsolidation;
|
||||
@@ -1,24 +1,14 @@
|
||||
use crate::context_deserialize;
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::ForkName;
|
||||
use context_deserialize::context_deserialize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
use crate::{fork::ForkName, test_utils::TestRandom};
|
||||
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
#[derive(
|
||||
arbitrary::Arbitrary,
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
Hash,
|
||||
Clone,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
TreeHash,
|
||||
TestRandom,
|
||||
Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom,
|
||||
)]
|
||||
#[context_deserialize(ForkName)]
|
||||
pub struct PendingConsolidation {
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,18 +1,19 @@
|
||||
use crate::{
|
||||
consts::altair, consts::deneb, AltairPreset, BasePreset, BellatrixPreset, CapellaPreset,
|
||||
ChainSpec, Config, DenebPreset, Eip7805Preset, ElectraPreset, EthSpec, ForkName, FuluPreset,
|
||||
};
|
||||
use maplit::hashmap;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
use std::collections::HashMap;
|
||||
use superstruct::superstruct;
|
||||
|
||||
use crate::core::{
|
||||
AltairPreset, BasePreset, BellatrixPreset, CapellaPreset, ChainSpec, Config, DenebPreset,
|
||||
Eip7805Preset, ElectraPreset, EthSpec, FuluPreset, GloasPreset, consts,
|
||||
};
|
||||
|
||||
/// Fusion of a runtime-config with the compile-time preset values.
|
||||
///
|
||||
/// Mostly useful for the API.
|
||||
#[superstruct(
|
||||
variants(Deneb, Electra, Eip7805, Fulu),
|
||||
variants(Deneb, Electra, Fulu, Eip7805, Gloas),
|
||||
variant_attributes(derive(Serialize, Deserialize, Debug, PartialEq, Clone))
|
||||
)]
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
|
||||
@@ -31,24 +32,26 @@ pub struct ConfigAndPreset {
|
||||
pub capella_preset: CapellaPreset,
|
||||
#[serde(flatten)]
|
||||
pub deneb_preset: DenebPreset,
|
||||
#[superstruct(only(Electra, Eip7805, Fulu))]
|
||||
#[superstruct(only(Electra, Fulu, Eip7805, Gloas))]
|
||||
#[serde(flatten)]
|
||||
pub electra_preset: ElectraPreset,
|
||||
#[superstruct(only(Eip7805, Fulu))]
|
||||
#[serde(flatten)]
|
||||
pub eip7805_preset: Eip7805Preset,
|
||||
#[superstruct(only(Fulu))]
|
||||
#[superstruct(only(Fulu, Eip7805, Gloas))]
|
||||
#[serde(flatten)]
|
||||
pub fulu_preset: FuluPreset,
|
||||
#[superstruct(only(Eip7805, Gloas))]
|
||||
#[serde(flatten)]
|
||||
pub eip7805_preset: Eip7805Preset,
|
||||
#[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>,
|
||||
}
|
||||
|
||||
impl ConfigAndPreset {
|
||||
// DEPRECATED: the `fork_name` argument is never used, we should remove it.
|
||||
pub fn from_chain_spec<E: EthSpec>(spec: &ChainSpec, fork_name: Option<ForkName>) -> Self {
|
||||
let config = Config::from_chain_spec::<E>(spec);
|
||||
pub fn from_chain_spec<E: EthSpec>(spec: &ChainSpec) -> Self {
|
||||
let mut config = Config::from_chain_spec::<E>(spec);
|
||||
let base_preset = BasePreset::from_chain_spec::<E>(spec);
|
||||
let altair_preset = AltairPreset::from_chain_spec::<E>(spec);
|
||||
let bellatrix_preset = BellatrixPreset::from_chain_spec::<E>(spec);
|
||||
@@ -56,12 +59,44 @@ impl ConfigAndPreset {
|
||||
let deneb_preset = DenebPreset::from_chain_spec::<E>(spec);
|
||||
let extra_fields = get_extra_fields(spec);
|
||||
|
||||
if spec.fulu_fork_epoch.is_some()
|
||||
|| fork_name.is_none()
|
||||
|| fork_name == Some(ForkName::Fulu)
|
||||
{
|
||||
if spec.is_gloas_scheduled() {
|
||||
let electra_preset = ElectraPreset::from_chain_spec::<E>(spec);
|
||||
let fulu_preset = FuluPreset::from_chain_spec::<E>(spec);
|
||||
let eip7805_preset = Eip7805Preset::from_chain_spec(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,
|
||||
eip7805_preset,
|
||||
gloas_preset,
|
||||
extra_fields,
|
||||
})
|
||||
} else if spec.is_focil_scheduled() {
|
||||
let electra_preset = ElectraPreset::from_chain_spec::<E>(spec);
|
||||
let fulu_preset = FuluPreset::from_chain_spec::<E>(spec);
|
||||
let eip7805_preset = Eip7805Preset::from_chain_spec(spec);
|
||||
|
||||
ConfigAndPreset::Eip7805(ConfigAndPresetEip7805 {
|
||||
config,
|
||||
base_preset,
|
||||
altair_preset,
|
||||
bellatrix_preset,
|
||||
capella_preset,
|
||||
deneb_preset,
|
||||
electra_preset,
|
||||
fulu_preset,
|
||||
eip7805_preset,
|
||||
extra_fields,
|
||||
})
|
||||
} else if spec.is_fulu_scheduled() {
|
||||
let electra_preset = ElectraPreset::from_chain_spec::<E>(spec);
|
||||
let eip7805_preset = Eip7805Preset::from_chain_spec::<E>(spec);
|
||||
let fulu_preset = FuluPreset::from_chain_spec::<E>(spec);
|
||||
|
||||
ConfigAndPreset::Fulu(ConfigAndPresetFulu {
|
||||
@@ -72,32 +107,13 @@ impl ConfigAndPreset {
|
||||
capella_preset,
|
||||
deneb_preset,
|
||||
electra_preset,
|
||||
eip7805_preset,
|
||||
fulu_preset,
|
||||
extra_fields,
|
||||
})
|
||||
} else if spec.electra_fork_epoch.is_some()
|
||||
|| fork_name.is_none()
|
||||
|| fork_name == Some(ForkName::Eip7805)
|
||||
{
|
||||
let electra_preset = ElectraPreset::from_chain_spec::<E>(spec);
|
||||
let eip7805_preset = Eip7805Preset::from_chain_spec::<E>(spec);
|
||||
} else {
|
||||
// Remove blob schedule for backwards-compatibility.
|
||||
config.blob_schedule.set_skip_serializing();
|
||||
|
||||
ConfigAndPreset::Eip7805(ConfigAndPresetEip7805 {
|
||||
config,
|
||||
base_preset,
|
||||
altair_preset,
|
||||
bellatrix_preset,
|
||||
capella_preset,
|
||||
deneb_preset,
|
||||
electra_preset,
|
||||
eip7805_preset,
|
||||
extra_fields,
|
||||
})
|
||||
} else if spec.electra_fork_epoch.is_some()
|
||||
|| fork_name.is_none()
|
||||
|| fork_name == Some(ForkName::Electra)
|
||||
{
|
||||
let electra_preset = ElectraPreset::from_chain_spec::<E>(spec);
|
||||
|
||||
ConfigAndPreset::Electra(ConfigAndPresetElectra {
|
||||
@@ -110,16 +126,6 @@ impl ConfigAndPreset {
|
||||
electra_preset,
|
||||
extra_fields,
|
||||
})
|
||||
} else {
|
||||
ConfigAndPreset::Deneb(ConfigAndPresetDeneb {
|
||||
config,
|
||||
base_preset,
|
||||
altair_preset,
|
||||
bellatrix_preset,
|
||||
capella_preset,
|
||||
deneb_preset,
|
||||
extra_fields,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -148,11 +154,11 @@ pub fn get_extra_fields(spec: &ChainSpec) -> HashMap<String, Value> {
|
||||
"domain_sync_committee_selection_proof".to_uppercase() =>
|
||||
u32_hex(spec.domain_sync_committee_selection_proof),
|
||||
"sync_committee_subnet_count".to_uppercase() =>
|
||||
altair::SYNC_COMMITTEE_SUBNET_COUNT.to_string().into(),
|
||||
consts::altair::SYNC_COMMITTEE_SUBNET_COUNT.to_string().into(),
|
||||
"target_aggregators_per_sync_subcommittee".to_uppercase() =>
|
||||
altair::TARGET_AGGREGATORS_PER_SYNC_SUBCOMMITTEE.to_string().into(),
|
||||
consts::altair::TARGET_AGGREGATORS_PER_SYNC_SUBCOMMITTEE.to_string().into(),
|
||||
// Deneb
|
||||
"versioned_hash_version_kzg".to_uppercase() => deneb::VERSIONED_HASH_VERSION_KZG.to_string().into(),
|
||||
"versioned_hash_version_kzg".to_uppercase() => consts::deneb::VERSIONED_HASH_VERSION_KZG.to_string().into(),
|
||||
// Electra
|
||||
"compounding_withdrawal_prefix".to_uppercase() => u8_hex(spec.compounding_withdrawal_prefix_byte),
|
||||
"unset_deposit_requests_start_index".to_uppercase() => spec.unset_deposit_requests_start_index.to_string().into(),
|
||||
@@ -163,7 +169,7 @@ pub fn get_extra_fields(spec: &ChainSpec) -> HashMap<String, Value> {
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::MainnetEthSpec;
|
||||
use crate::{Epoch, MainnetEthSpec};
|
||||
use std::fs::File;
|
||||
use tempfile::NamedTempFile;
|
||||
|
||||
@@ -175,9 +181,10 @@ mod test {
|
||||
.write(true)
|
||||
.open(tmp_file.as_ref())
|
||||
.expect("error opening file");
|
||||
let mainnet_spec = ChainSpec::mainnet();
|
||||
let mut yamlconfig =
|
||||
ConfigAndPreset::from_chain_spec::<MainnetEthSpec>(&mainnet_spec, None);
|
||||
let mut mainnet_spec = ChainSpec::mainnet();
|
||||
// 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");
|
||||
let (k3, v3) = ("SAMPLE_HARDFORK_KEY3", 32);
|
||||
@@ -194,8 +201,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);
|
||||
}
|
||||
}
|
||||
@@ -23,5 +23,5 @@ pub mod bellatrix {
|
||||
pub const INTERVALS_PER_SLOT: u64 = 3;
|
||||
}
|
||||
pub mod deneb {
|
||||
pub use crate::VERSIONED_HASH_VERSION_KZG;
|
||||
pub use kzg::VERSIONED_HASH_VERSION_KZG;
|
||||
}
|
||||
@@ -1,33 +1,27 @@
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::Epoch;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
use crate::{core::Epoch, test_utils::TestRandom};
|
||||
|
||||
/// Specifies a fork which allows nodes to identify each other on the network. This fork is used in
|
||||
/// a nodes local ENR.
|
||||
///
|
||||
/// Spec v0.11
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
#[derive(
|
||||
arbitrary::Arbitrary,
|
||||
Debug,
|
||||
Clone,
|
||||
PartialEq,
|
||||
Default,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
TreeHash,
|
||||
TestRandom,
|
||||
Debug, Clone, PartialEq, Default, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom,
|
||||
)]
|
||||
pub struct EnrForkId {
|
||||
/// Fork digest of the current fork computed from [`ChainSpec::compute_fork_digest`].
|
||||
#[serde(with = "serde_utils::bytes_4_hex")]
|
||||
pub fork_digest: [u8; 4],
|
||||
/// `next_fork_version` is the fork version corresponding to the next planned fork at a future
|
||||
/// epoch. The fork version will only change for regular forks, not BPO forks.
|
||||
#[serde(with = "serde_utils::bytes_4_hex")]
|
||||
pub next_fork_version: [u8; 4],
|
||||
/// `next_fork_epoch` is the epoch at which the next fork (whether a regular fork or a BPO fork) is planned
|
||||
pub next_fork_epoch: Epoch,
|
||||
}
|
||||
|
||||
@@ -1,16 +1,22 @@
|
||||
use crate::*;
|
||||
use std::{
|
||||
fmt::{self, Debug},
|
||||
str::FromStr,
|
||||
};
|
||||
|
||||
use safe_arith::SafeArith;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz_types::typenum::{
|
||||
bit::B0, UInt, U0, U1, U10, U1024, U1048576, U1073741824, U1099511627776, U128, U131072,
|
||||
U134217728, U16, U16777216, U17, U2, U2048, U256, U262144, U32, U33554432, U4, U4096, U512,
|
||||
U625, U64, U65536, U8, U8192,
|
||||
use typenum::{
|
||||
U0, U1, U2, U4, U8, U16, U17, U32, U64, U128, U256, U512, U625, U1024, U2048, U4096, U8192,
|
||||
U65536, U131072, U262144, U1048576, U16777216, U33554432, U134217728, U1073741824,
|
||||
U1099511627776, UInt, Unsigned, bit::B0,
|
||||
};
|
||||
use std::fmt::{self, Debug};
|
||||
use std::str::FromStr;
|
||||
|
||||
pub type U5000 = UInt<UInt<UInt<U625, B0>, B0>, B0>; // 625 * 8 = 5000
|
||||
use crate::{
|
||||
core::{ChainSpec, Epoch},
|
||||
state::BeaconStateError,
|
||||
};
|
||||
|
||||
type U5000 = UInt<UInt<UInt<U625, B0>, B0>, B0>; // 625 * 8 = 5000
|
||||
|
||||
const MAINNET: &str = "mainnet";
|
||||
const MINIMAL: &str = "minimal";
|
||||
@@ -49,9 +55,7 @@ impl fmt::Display for EthSpecId {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait EthSpec:
|
||||
'static + Default + Sync + Send + Clone + Debug + PartialEq + Eq + for<'a> arbitrary::Arbitrary<'a>
|
||||
{
|
||||
pub trait EthSpec: 'static + Default + Sync + Send + Clone + Debug + PartialEq + Eq {
|
||||
/*
|
||||
* Constants
|
||||
*/
|
||||
@@ -113,11 +117,14 @@ pub trait EthSpec:
|
||||
type BytesPerFieldElement: Unsigned + Clone + Sync + Send + Debug + PartialEq;
|
||||
type KzgCommitmentInclusionProofDepth: Unsigned + Clone + Sync + Send + Debug + PartialEq;
|
||||
/*
|
||||
* New in PeerDAS
|
||||
* New in Fulu
|
||||
*/
|
||||
type FieldElementsPerCell: Unsigned + Clone + Sync + Send + Debug + PartialEq;
|
||||
type FieldElementsPerExtBlob: Unsigned + Clone + Sync + Send + Debug + PartialEq;
|
||||
type KzgCommitmentsInclusionProofDepth: Unsigned + Clone + Sync + Send + Debug + PartialEq;
|
||||
type CellsPerExtBlob: Unsigned + Clone + Sync + Send + Debug + PartialEq;
|
||||
type NumberOfColumns: Unsigned + Clone + Sync + Send + Debug + PartialEq;
|
||||
type ProposerLookaheadSlots: Unsigned + Clone + Sync + Send + Debug + PartialEq;
|
||||
/*
|
||||
* Derived values (set these CAREFULLY)
|
||||
*/
|
||||
@@ -165,7 +172,15 @@ pub trait EthSpec:
|
||||
type MaxPendingDepositsPerEpoch: Unsigned + Clone + Sync + Send + Debug + PartialEq;
|
||||
|
||||
/*
|
||||
* FOCIL
|
||||
* New in Gloas
|
||||
*/
|
||||
type PTCSize: Unsigned + Clone + Sync + Send + Debug + PartialEq;
|
||||
type MaxPayloadAttestations: Unsigned + Clone + Sync + Send + Debug + PartialEq;
|
||||
type BuilderPendingPaymentsLimit: Unsigned + Clone + Sync + Send + Debug + PartialEq;
|
||||
type BuilderPendingWithdrawalsLimit: Unsigned + Clone + Sync + Send + Debug + PartialEq;
|
||||
|
||||
/*
|
||||
* New in Eip7805
|
||||
*/
|
||||
type InclusionListCommitteeSize: Unsigned + Clone + Sync + Send + Debug + PartialEq;
|
||||
type MaxTransactionsPerInclusionList: Unsigned + Clone + Sync + Send + Debug + PartialEq;
|
||||
@@ -187,7 +202,7 @@ pub trait EthSpec:
|
||||
fn get_committee_count_per_slot(
|
||||
active_validator_count: usize,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<usize, Error> {
|
||||
) -> Result<usize, BeaconStateError> {
|
||||
Self::get_committee_count_per_slot_with(
|
||||
active_validator_count,
|
||||
spec.max_committees_per_slot,
|
||||
@@ -199,7 +214,7 @@ pub trait EthSpec:
|
||||
active_validator_count: usize,
|
||||
max_committees_per_slot: usize,
|
||||
target_committee_size: usize,
|
||||
) -> Result<usize, Error> {
|
||||
) -> Result<usize, BeaconStateError> {
|
||||
let slots_per_epoch = Self::SlotsPerEpoch::to_usize();
|
||||
|
||||
Ok(std::cmp::max(
|
||||
@@ -315,6 +330,11 @@ pub trait EthSpec:
|
||||
Self::BytesPerBlob::to_usize()
|
||||
}
|
||||
|
||||
/// Returns the `BYTES_PER_CELL` constant for this specification.
|
||||
fn bytes_per_cell() -> usize {
|
||||
Self::BytesPerCell::to_usize()
|
||||
}
|
||||
|
||||
/// Returns the `KZG_COMMITMENT_INCLUSION_PROOF_DEPTH` preset for this specification.
|
||||
fn kzg_proof_inclusion_proof_depth() -> usize {
|
||||
Self::KzgCommitmentInclusionProofDepth::to_usize()
|
||||
@@ -351,6 +371,16 @@ pub trait EthSpec:
|
||||
Self::PendingConsolidationsLimit::to_usize()
|
||||
}
|
||||
|
||||
/// Returns the `BUILDER_PENDING_PAYMENTS_LIMIT` constant for this specification.
|
||||
fn builder_pending_payments_limit() -> usize {
|
||||
Self::BuilderPendingPaymentsLimit::to_usize()
|
||||
}
|
||||
|
||||
/// Returns the `BUILDER_PENDING_WITHDRAWALS_LIMIT` constant for this specification.
|
||||
fn builder_pending_withdrawals_limit() -> usize {
|
||||
Self::BuilderPendingWithdrawalsLimit::to_usize()
|
||||
}
|
||||
|
||||
/// Returns the `MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD` constant for this specification.
|
||||
fn max_consolidation_requests_per_payload() -> usize {
|
||||
Self::MaxConsolidationRequestsPerPayload::to_usize()
|
||||
@@ -394,6 +424,28 @@ pub trait EthSpec:
|
||||
fn max_transactions_per_inclusion_list() -> usize {
|
||||
Self::MaxTransactionsPerInclusionList::to_usize()
|
||||
}
|
||||
|
||||
fn cells_per_ext_blob() -> usize {
|
||||
Self::CellsPerExtBlob::to_usize()
|
||||
}
|
||||
|
||||
fn number_of_columns() -> usize {
|
||||
Self::NumberOfColumns::to_usize()
|
||||
}
|
||||
|
||||
fn proposer_lookahead_slots() -> usize {
|
||||
Self::ProposerLookaheadSlots::to_usize()
|
||||
}
|
||||
|
||||
/// Returns the `PTCSize` constant for this specification.
|
||||
fn ptc_size() -> usize {
|
||||
Self::PTCSize::to_usize()
|
||||
}
|
||||
|
||||
/// Returns the `MaxPayloadAttestations` constant for this specification.
|
||||
fn max_payload_attestations() -> usize {
|
||||
Self::MaxPayloadAttestations::to_usize()
|
||||
}
|
||||
}
|
||||
|
||||
/// Macro to inherit some type values from another EthSpec.
|
||||
@@ -405,7 +457,8 @@ macro_rules! params_from_eth_spec {
|
||||
}
|
||||
|
||||
/// Ethereum Foundation specifications.
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Default, Serialize, Deserialize, arbitrary::Arbitrary)]
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Default, Serialize, Deserialize)]
|
||||
pub struct MainnetEthSpec;
|
||||
|
||||
impl EthSpec for MainnetEthSpec {
|
||||
@@ -422,6 +475,8 @@ impl EthSpec for MainnetEthSpec {
|
||||
type EpochsPerSlashingsVector = U8192;
|
||||
type HistoricalRootsLimit = U16777216;
|
||||
type ValidatorRegistryLimit = U1099511627776;
|
||||
type BuilderPendingPaymentsLimit = U64; // 2 * SLOTS_PER_EPOCH = 2 * 32 = 64
|
||||
type BuilderPendingWithdrawalsLimit = U1048576;
|
||||
type MaxProposerSlashings = U16;
|
||||
type MaxAttesterSlashings = U2;
|
||||
type MaxAttestations = U128;
|
||||
@@ -445,6 +500,9 @@ impl EthSpec for MainnetEthSpec {
|
||||
type MaxCellsPerBlock = U33554432;
|
||||
type KzgCommitmentInclusionProofDepth = U17;
|
||||
type KzgCommitmentsInclusionProofDepth = U4; // inclusion of the whole list of commitments
|
||||
type CellsPerExtBlob = U128;
|
||||
type NumberOfColumns = U128;
|
||||
type ProposerLookaheadSlots = U64; // Derived from (MIN_SEED_LOOKAHEAD + 1) * SLOTS_PER_EPOCH
|
||||
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
|
||||
@@ -460,6 +518,8 @@ impl EthSpec for MainnetEthSpec {
|
||||
type MaxWithdrawalRequestsPerPayload = U16;
|
||||
type MaxTransactionsPerInclusionList = U16;
|
||||
type MaxPendingDepositsPerEpoch = U16;
|
||||
type PTCSize = U512;
|
||||
type MaxPayloadAttestations = U4;
|
||||
type InclusionListCommitteeSize = U16;
|
||||
|
||||
fn default_spec() -> ChainSpec {
|
||||
@@ -472,7 +532,8 @@ impl EthSpec for MainnetEthSpec {
|
||||
}
|
||||
|
||||
/// Ethereum Foundation minimal spec, as defined in the eth2.0-specs repo.
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Default, Serialize, Deserialize, arbitrary::Arbitrary)]
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Default, Serialize, Deserialize)]
|
||||
pub struct MinimalEthSpec;
|
||||
|
||||
impl EthSpec for MinimalEthSpec {
|
||||
@@ -490,17 +551,19 @@ impl EthSpec for MinimalEthSpec {
|
||||
type MaxWithdrawalsPerPayload = U4;
|
||||
type FieldElementsPerBlob = U4096;
|
||||
type BytesPerBlob = U131072;
|
||||
type MaxBlobCommitmentsPerBlock = U32;
|
||||
type KzgCommitmentInclusionProofDepth = U10;
|
||||
type MaxBlobCommitmentsPerBlock = U4096;
|
||||
type KzgCommitmentInclusionProofDepth = U17;
|
||||
type PendingPartialWithdrawalsLimit = U64;
|
||||
type PendingConsolidationsLimit = U64;
|
||||
type MaxDepositRequestsPerPayload = U4;
|
||||
type MaxWithdrawalRequestsPerPayload = U2;
|
||||
type FieldElementsPerCell = U64;
|
||||
type FieldElementsPerExtBlob = U8192;
|
||||
type MaxCellsPerBlock = U33554432;
|
||||
type BytesPerCell = U2048;
|
||||
type KzgCommitmentsInclusionProofDepth = U4;
|
||||
type CellsPerExtBlob = U128;
|
||||
type NumberOfColumns = U128;
|
||||
type ProposerLookaheadSlots = U16; // Derived from (MIN_SEED_LOOKAHEAD + 1) * SLOTS_PER_EPOCH
|
||||
type BuilderPendingPaymentsLimit = U16; // 2 * SLOTS_PER_EPOCH = 2 * 8 = 16
|
||||
|
||||
params_from_eth_spec!(MainnetEthSpec {
|
||||
JustificationBitsLength,
|
||||
@@ -510,6 +573,7 @@ impl EthSpec for MinimalEthSpec {
|
||||
GenesisEpoch,
|
||||
HistoricalRootsLimit,
|
||||
ValidatorRegistryLimit,
|
||||
BuilderPendingWithdrawalsLimit,
|
||||
MaxProposerSlashings,
|
||||
MaxAttesterSlashings,
|
||||
MaxAttestations,
|
||||
@@ -528,6 +592,10 @@ impl EthSpec for MinimalEthSpec {
|
||||
MaxConsolidationRequestsPerPayload,
|
||||
MaxAttesterSlashingsElectra,
|
||||
MaxAttestationsElectra,
|
||||
MaxDepositRequestsPerPayload,
|
||||
MaxWithdrawalRequestsPerPayload,
|
||||
PTCSize,
|
||||
MaxPayloadAttestations,
|
||||
InclusionListCommitteeSize,
|
||||
MaxTransactionsPerInclusionList
|
||||
});
|
||||
@@ -542,7 +610,8 @@ impl EthSpec for MinimalEthSpec {
|
||||
}
|
||||
|
||||
/// Gnosis Beacon Chain specifications.
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Default, Serialize, Deserialize, arbitrary::Arbitrary)]
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Default, Serialize, Deserialize)]
|
||||
pub struct GnosisEthSpec;
|
||||
|
||||
impl EthSpec for GnosisEthSpec {
|
||||
@@ -559,6 +628,8 @@ impl EthSpec for GnosisEthSpec {
|
||||
type EpochsPerSlashingsVector = U8192;
|
||||
type HistoricalRootsLimit = U16777216;
|
||||
type ValidatorRegistryLimit = U1099511627776;
|
||||
type BuilderPendingPaymentsLimit = U32; // 2 * SLOTS_PER_EPOCH = 2 * 16 = 32
|
||||
type BuilderPendingWithdrawalsLimit = U1048576;
|
||||
type MaxProposerSlashings = U16;
|
||||
type MaxAttesterSlashings = U2;
|
||||
type MaxAttestations = U128;
|
||||
@@ -596,6 +667,11 @@ impl EthSpec for GnosisEthSpec {
|
||||
type MaxCellsPerBlock = U33554432;
|
||||
type BytesPerCell = U2048;
|
||||
type KzgCommitmentsInclusionProofDepth = U4;
|
||||
type CellsPerExtBlob = U128;
|
||||
type NumberOfColumns = U128;
|
||||
type ProposerLookaheadSlots = U32; // Derived from (MIN_SEED_LOOKAHEAD + 1) * SLOTS_PER_EPOCH
|
||||
type PTCSize = U512;
|
||||
type MaxPayloadAttestations = U2;
|
||||
type InclusionListCommitteeSize = U16;
|
||||
type MaxTransactionsPerInclusionList = U16;
|
||||
|
||||
@@ -611,12 +687,17 @@ impl EthSpec for GnosisEthSpec {
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::{EthSpec, GnosisEthSpec, MainnetEthSpec, MinimalEthSpec};
|
||||
use ssz_types::typenum::Unsigned;
|
||||
use typenum::Unsigned;
|
||||
|
||||
fn assert_valid_spec<E: EthSpec>() {
|
||||
let spec = E::default_spec();
|
||||
E::kzg_commitments_tree_depth();
|
||||
E::block_body_tree_depth();
|
||||
assert!(E::MaxValidatorsPerSlot::to_i32() >= E::MaxValidatorsPerCommittee::to_i32());
|
||||
assert_eq!(
|
||||
E::proposer_lookahead_slots(),
|
||||
(spec.min_seed_lookahead.as_usize() + 1) * E::slots_per_epoch() as usize
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1,20 +1,19 @@
|
||||
use crate::{
|
||||
test_utils::{RngCore, TestRandom},
|
||||
Hash256,
|
||||
};
|
||||
use std::{fmt, str::FromStr};
|
||||
|
||||
use rand::RngCore;
|
||||
use regex::bytes::Regex;
|
||||
use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer};
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error};
|
||||
use ssz::{Decode, DecodeError, Encode};
|
||||
use std::fmt;
|
||||
use std::str::FromStr;
|
||||
use tree_hash::{PackedEncoding, TreeHash};
|
||||
|
||||
use crate::{core::Hash256, test_utils::TestRandom};
|
||||
|
||||
pub const GRAFFITI_BYTES_LEN: usize = 32;
|
||||
|
||||
/// The 32-byte `graffiti` field on a beacon block.
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
#[derive(Default, Debug, PartialEq, Hash, Clone, Copy, Serialize, Deserialize)]
|
||||
#[serde(transparent)]
|
||||
#[derive(arbitrary::Arbitrary)]
|
||||
pub struct Graffiti(#[serde(with = "serde_graffiti")] pub [u8; GRAFFITI_BYTES_LEN]);
|
||||
|
||||
impl Graffiti {
|
||||
44
consensus/types/src/core/mod.rs
Normal file
44
consensus/types/src/core/mod.rs
Normal file
@@ -0,0 +1,44 @@
|
||||
pub mod consts;
|
||||
|
||||
mod application_domain;
|
||||
mod chain_spec;
|
||||
mod config_and_preset;
|
||||
mod enr_fork_id;
|
||||
mod eth_spec;
|
||||
mod graffiti;
|
||||
mod non_zero_usize;
|
||||
mod preset;
|
||||
mod relative_epoch;
|
||||
mod signing_data;
|
||||
mod slot_data;
|
||||
#[macro_use]
|
||||
mod slot_epoch_macros;
|
||||
mod slot_epoch;
|
||||
#[cfg(feature = "sqlite")]
|
||||
mod sqlite;
|
||||
|
||||
pub use application_domain::{APPLICATION_DOMAIN_BUILDER, ApplicationDomain};
|
||||
pub use chain_spec::{BlobParameters, BlobSchedule, ChainSpec, Config, Domain};
|
||||
pub use config_and_preset::{
|
||||
ConfigAndPreset, ConfigAndPresetDeneb, ConfigAndPresetElectra, ConfigAndPresetFulu,
|
||||
ConfigAndPresetGloas, get_extra_fields,
|
||||
};
|
||||
pub use enr_fork_id::EnrForkId;
|
||||
pub use eth_spec::{EthSpec, EthSpecId, GNOSIS, GnosisEthSpec, MainnetEthSpec, MinimalEthSpec};
|
||||
pub use graffiti::{GRAFFITI_BYTES_LEN, Graffiti, GraffitiString};
|
||||
pub use non_zero_usize::new_non_zero_usize;
|
||||
pub use preset::{
|
||||
AltairPreset, BasePreset, BellatrixPreset, CapellaPreset, DenebPreset, Eip7805Preset,
|
||||
ElectraPreset, FuluPreset, GloasPreset,
|
||||
};
|
||||
pub use relative_epoch::{Error as RelativeEpochError, RelativeEpoch};
|
||||
pub use signing_data::{SignedRoot, SigningData};
|
||||
pub use slot_data::SlotData;
|
||||
pub use slot_epoch::{Epoch, Slot};
|
||||
|
||||
pub type Hash256 = alloy_primitives::B256;
|
||||
pub type Uint256 = alloy_primitives::U256;
|
||||
pub type Hash64 = alloy_primitives::B64;
|
||||
pub type Address = alloy_primitives::Address;
|
||||
pub type VersionedHash = Hash256;
|
||||
pub type MerkleProof = Vec<Hash256>;
|
||||
@@ -1,5 +1,7 @@
|
||||
use crate::{ChainSpec, Epoch, EthSpec, Unsigned};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use typenum::Unsigned;
|
||||
|
||||
use crate::core::{ChainSpec, Epoch, EthSpec};
|
||||
|
||||
/// Value-level representation of an Ethereum consensus "preset".
|
||||
///
|
||||
@@ -208,6 +210,8 @@ pub struct DenebPreset {
|
||||
#[serde(with = "serde_utils::quoted_u64")]
|
||||
pub max_blob_commitments_per_block: u64,
|
||||
#[serde(with = "serde_utils::quoted_u64")]
|
||||
pub kzg_commitment_inclusion_proof_depth: u64,
|
||||
#[serde(with = "serde_utils::quoted_u64")]
|
||||
pub field_elements_per_blob: u64,
|
||||
}
|
||||
|
||||
@@ -215,6 +219,7 @@ impl DenebPreset {
|
||||
pub fn from_chain_spec<E: EthSpec>(_spec: &ChainSpec) -> Self {
|
||||
Self {
|
||||
max_blob_commitments_per_block: E::max_blob_commitments_per_block() as u64,
|
||||
kzg_commitment_inclusion_proof_depth: E::KzgCommitmentInclusionProofDepth::to_u64(),
|
||||
field_elements_per_blob: E::field_elements_per_blob() as u64,
|
||||
}
|
||||
}
|
||||
@@ -298,7 +303,7 @@ pub struct Eip7805Preset {
|
||||
}
|
||||
|
||||
impl Eip7805Preset {
|
||||
pub fn from_chain_spec<E: EthSpec>(spec: &ChainSpec) -> Self {
|
||||
pub fn from_chain_spec(spec: &ChainSpec) -> Self {
|
||||
Self {
|
||||
domain_inclusion_list_committee: spec.domain_inclusion_list_committee,
|
||||
inclusion_list_committee_size: spec.inclusion_list_committee_size,
|
||||
@@ -315,6 +320,10 @@ pub struct FuluPreset {
|
||||
pub field_elements_per_ext_blob: u64,
|
||||
#[serde(with = "serde_utils::quoted_u64")]
|
||||
pub kzg_commitments_inclusion_proof_depth: u64,
|
||||
#[serde(with = "serde_utils::quoted_u64")]
|
||||
pub cells_per_ext_blob: u64,
|
||||
#[serde(with = "serde_utils::quoted_u64")]
|
||||
pub number_of_columns: u64,
|
||||
}
|
||||
|
||||
impl FuluPreset {
|
||||
@@ -324,10 +333,22 @@ impl FuluPreset {
|
||||
field_elements_per_ext_blob: E::field_elements_per_ext_blob() as u64,
|
||||
kzg_commitments_inclusion_proof_depth: E::kzg_commitments_inclusion_proof_depth()
|
||||
as u64,
|
||||
cells_per_ext_blob: E::cells_per_ext_blob() as u64,
|
||||
number_of_columns: E::number_of_columns() as u64,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[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::*;
|
||||
@@ -374,10 +395,13 @@ mod test {
|
||||
assert_eq!(electra, ElectraPreset::from_chain_spec::<E>(&spec));
|
||||
|
||||
let eip7805: Eip7805Preset = preset_from_file(&preset_name, "eip7805.yaml");
|
||||
assert_eq!(eip7805, Eip7805Preset::from_chain_spec::<E>(&spec));
|
||||
assert_eq!(eip7805, Eip7805Preset::from_chain_spec(&spec));
|
||||
|
||||
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]
|
||||
@@ -1,6 +1,7 @@
|
||||
use crate::*;
|
||||
use safe_arith::{ArithError, SafeArith};
|
||||
|
||||
use crate::core::{Epoch, Slot};
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||
pub enum Error {
|
||||
EpochTooLow { base: Epoch, other: Epoch },
|
||||
@@ -18,7 +19,8 @@ impl From<ArithError> for Error {
|
||||
/// to and following some epoch.
|
||||
///
|
||||
/// Spec v0.12.1
|
||||
#[derive(Debug, PartialEq, Clone, Copy, arbitrary::Arbitrary)]
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||
pub enum RelativeEpoch {
|
||||
/// The prior epoch.
|
||||
Previous,
|
||||
@@ -1,25 +1,14 @@
|
||||
use crate::context_deserialize;
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::{ForkName, Hash256};
|
||||
|
||||
use context_deserialize::context_deserialize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash::TreeHash;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
#[derive(
|
||||
arbitrary::Arbitrary,
|
||||
Debug,
|
||||
PartialEq,
|
||||
Clone,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
TreeHash,
|
||||
TestRandom,
|
||||
)]
|
||||
use crate::{core::Hash256, fork::ForkName, test_utils::TestRandom};
|
||||
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)]
|
||||
#[context_deserialize(ForkName)]
|
||||
pub struct SigningData {
|
||||
pub object_root: Hash256,
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::Slot;
|
||||
use crate::core::Slot;
|
||||
|
||||
/// A trait providing a `Slot` getter for messages that are related to a single slot. Useful in
|
||||
/// making parts of attestation and sync committee processing generic.
|
||||
@@ -10,51 +10,38 @@
|
||||
//! implement `Into<u64>`, however this would allow operations between `Slots` and `Epochs` which
|
||||
//! may lead to programming errors which are not detected by the compiler.
|
||||
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::{ChainSpec, SignedRoot};
|
||||
use std::{fmt, hash::Hash};
|
||||
|
||||
use rand::RngCore;
|
||||
use safe_arith::{ArithError, SafeArith};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz::{Decode, DecodeError, Encode};
|
||||
use std::fmt;
|
||||
use std::hash::Hash;
|
||||
|
||||
use crate::{
|
||||
core::{ChainSpec, SignedRoot},
|
||||
test_utils::TestRandom,
|
||||
};
|
||||
|
||||
#[cfg(feature = "legacy-arith")]
|
||||
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Rem, Sub, SubAssign};
|
||||
|
||||
#[derive(
|
||||
arbitrary::Arbitrary,
|
||||
Clone,
|
||||
Copy,
|
||||
Default,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Hash,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
)]
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct Slot(#[serde(with = "serde_utils::quoted_u64")] u64);
|
||||
|
||||
#[derive(
|
||||
arbitrary::Arbitrary,
|
||||
Clone,
|
||||
Copy,
|
||||
Default,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Hash,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
)]
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct Epoch(#[serde(with = "serde_utils::quoted_u64")] u64);
|
||||
|
||||
impl Epoch {
|
||||
/// Returns an iterator `(end..=start)`
|
||||
pub fn range_inclusive_rev(start: Self, end: Self) -> impl Iterator<Item = Self> {
|
||||
(end.0..=start.0).rev().map(Epoch)
|
||||
}
|
||||
}
|
||||
|
||||
impl_common!(Slot);
|
||||
impl_common!(Epoch);
|
||||
|
||||
@@ -118,7 +105,7 @@ impl Epoch {
|
||||
.as_u64())
|
||||
}
|
||||
|
||||
pub fn slot_iter(&self, slots_per_epoch: u64) -> SlotIter {
|
||||
pub fn slot_iter(&self, slots_per_epoch: u64) -> SlotIter<'_> {
|
||||
SlotIter {
|
||||
current_iteration: 0,
|
||||
epoch: self,
|
||||
@@ -1,14 +1,15 @@
|
||||
//! Implementations of SQLite compatibility traits.
|
||||
use crate::{Epoch, Slot};
|
||||
use rusqlite::{
|
||||
types::{FromSql, FromSqlError, ToSql, ToSqlOutput, ValueRef},
|
||||
Error,
|
||||
types::{FromSql, FromSqlError, ToSql, ToSqlOutput, ValueRef},
|
||||
};
|
||||
|
||||
use crate::core::{Epoch, Slot};
|
||||
|
||||
macro_rules! impl_to_from_sql {
|
||||
($type:ty) => {
|
||||
impl ToSql for $type {
|
||||
fn to_sql(&self) -> Result<ToSqlOutput, Error> {
|
||||
fn to_sql(&self) -> Result<ToSqlOutput<'_>, Error> {
|
||||
let val_i64 = i64::try_from(self.as_u64())
|
||||
.map_err(|e| Error::ToSqlConversionFailure(Box::new(e)))?;
|
||||
Ok(ToSqlOutput::from(val_i64))
|
||||
@@ -1,27 +1,33 @@
|
||||
use crate::context_deserialize;
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::{
|
||||
beacon_block_body::BLOB_KZG_COMMITMENTS_INDEX, AbstractExecPayload, BeaconBlockHeader,
|
||||
BeaconStateError, Blob, ChainSpec, Epoch, EthSpec, FixedVector, ForkName, Hash256, KzgProofs,
|
||||
RuntimeFixedVector, RuntimeVariableList, SignedBeaconBlock, SignedBeaconBlockHeader, Slot,
|
||||
VariableList,
|
||||
};
|
||||
use std::{fmt::Debug, hash::Hash, sync::Arc};
|
||||
|
||||
use bls::Signature;
|
||||
use derivative::Derivative;
|
||||
use kzg::{Blob as KzgBlob, Kzg, KzgCommitment, KzgProof, BYTES_PER_BLOB, BYTES_PER_FIELD_ELEMENT};
|
||||
use merkle_proof::{merkle_root_from_branch, verify_merkle_proof, MerkleTreeError};
|
||||
use context_deserialize::context_deserialize;
|
||||
use educe::Educe;
|
||||
use kzg::{BYTES_PER_BLOB, BYTES_PER_FIELD_ELEMENT, Blob as KzgBlob, Kzg, KzgCommitment, KzgProof};
|
||||
use merkle_proof::{MerkleTreeError, merkle_root_from_branch, verify_merkle_proof};
|
||||
use rand::Rng;
|
||||
use safe_arith::ArithError;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz::Encode;
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use std::fmt::Debug;
|
||||
use std::hash::Hash;
|
||||
use std::sync::Arc;
|
||||
use ssz_types::{FixedVector, RuntimeFixedVector, RuntimeVariableList, VariableList};
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash::TreeHash;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
use crate::{
|
||||
block::{
|
||||
BLOB_KZG_COMMITMENTS_INDEX, BeaconBlockHeader, SignedBeaconBlock, SignedBeaconBlockHeader,
|
||||
},
|
||||
core::{ChainSpec, Epoch, EthSpec, Hash256, Slot},
|
||||
data::Blob,
|
||||
execution::AbstractExecPayload,
|
||||
fork::ForkName,
|
||||
kzg_ext::KzgProofs,
|
||||
state::BeaconStateError,
|
||||
test_utils::TestRandom,
|
||||
};
|
||||
|
||||
/// Container of the data that identifies an individual blob.
|
||||
#[derive(
|
||||
Serialize, Deserialize, Encode, Decode, TreeHash, Copy, Clone, Debug, PartialEq, Eq, Hash,
|
||||
@@ -44,22 +50,15 @@ impl Ord for BlobIdentifier {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Clone,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
TreeHash,
|
||||
TestRandom,
|
||||
Derivative,
|
||||
arbitrary::Arbitrary,
|
||||
#[cfg_attr(
|
||||
feature = "arbitrary",
|
||||
derive(arbitrary::Arbitrary),
|
||||
arbitrary(bound = "E: EthSpec")
|
||||
)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom, Educe)]
|
||||
#[context_deserialize(ForkName)]
|
||||
#[serde(bound = "E: EthSpec")]
|
||||
#[arbitrary(bound = "E: EthSpec")]
|
||||
#[derivative(PartialEq, Eq, Hash(bound = "E: EthSpec"))]
|
||||
#[educe(PartialEq, Eq, Hash(bound(E: EthSpec)))]
|
||||
pub struct BlobSidecar<E: EthSpec> {
|
||||
#[serde(with = "serde_utils::quoted_u64")]
|
||||
pub index: u64,
|
||||
@@ -89,6 +88,7 @@ pub enum BlobSidecarError {
|
||||
MissingKzgCommitment,
|
||||
BeaconState(BeaconStateError),
|
||||
MerkleTree(MerkleTreeError),
|
||||
SszTypes(ssz_types::Error),
|
||||
ArithError(ArithError),
|
||||
}
|
||||
|
||||
@@ -288,10 +288,11 @@ impl<E: EthSpec> BlobSidecar<E> {
|
||||
let blob_sidecar = BlobSidecar::new(i, blob, block, *kzg_proof)?;
|
||||
blob_sidecars.push(Arc::new(blob_sidecar));
|
||||
}
|
||||
Ok(RuntimeVariableList::from_vec(
|
||||
RuntimeVariableList::new(
|
||||
blob_sidecars,
|
||||
spec.max_blobs_per_block(block.epoch()) as usize,
|
||||
))
|
||||
)
|
||||
.map_err(BlobSidecarError::SszTypes)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
use crate::{ChainSpec, ColumnIndex, DataColumnSubnetId};
|
||||
use std::collections::HashSet;
|
||||
|
||||
use alloy_primitives::U256;
|
||||
use itertools::Itertools;
|
||||
use maplit::hashset;
|
||||
use safe_arith::{ArithError, SafeArith};
|
||||
use std::collections::HashSet;
|
||||
|
||||
use crate::{
|
||||
EthSpec,
|
||||
core::ChainSpec,
|
||||
data::{ColumnIndex, DataColumnSubnetId},
|
||||
};
|
||||
|
||||
pub type CustodyIndex = u64;
|
||||
|
||||
@@ -25,13 +30,36 @@ pub fn get_custody_groups(
|
||||
custody_group_count: u64,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<HashSet<CustodyIndex>, DataColumnCustodyGroupError> {
|
||||
if custody_group_count == spec.number_of_custody_groups {
|
||||
Ok(HashSet::from_iter(0..spec.number_of_custody_groups))
|
||||
} else {
|
||||
get_custody_groups_ordered(raw_node_id, custody_group_count, spec)
|
||||
.map(|custody_groups| custody_groups.into_iter().collect())
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a deterministically ordered list of custody groups assigned to a node,
|
||||
/// preserving the order in which they were computed during iteration.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `raw_node_id` - 32-byte node identifier
|
||||
/// * `custody_group_count` - Number of custody groups to generate
|
||||
/// * `spec` - Chain specification containing custody group parameters
|
||||
///
|
||||
/// # Returns
|
||||
/// Vector of custody group indices in computation order or error if parameters are invalid
|
||||
fn get_custody_groups_ordered(
|
||||
raw_node_id: [u8; 32],
|
||||
custody_group_count: u64,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<Vec<CustodyIndex>, DataColumnCustodyGroupError> {
|
||||
if custody_group_count > spec.number_of_custody_groups {
|
||||
return Err(DataColumnCustodyGroupError::InvalidCustodyGroupCount(
|
||||
custody_group_count,
|
||||
));
|
||||
}
|
||||
|
||||
let mut custody_groups: HashSet<u64> = hashset![];
|
||||
let mut custody_groups = vec![];
|
||||
let mut current_id = U256::from_be_slice(&raw_node_id);
|
||||
while custody_groups.len() < custody_group_count as usize {
|
||||
let mut node_id_bytes = [0u8; 32];
|
||||
@@ -44,7 +72,9 @@ pub fn get_custody_groups(
|
||||
let custody_group = hash_prefix_u64
|
||||
.safe_rem(spec.number_of_custody_groups)
|
||||
.expect("spec.number_of_custody_groups must not be zero");
|
||||
custody_groups.insert(custody_group);
|
||||
if !custody_groups.contains(&custody_group) {
|
||||
custody_groups.push(custody_group);
|
||||
}
|
||||
|
||||
current_id = current_id.wrapping_add(U256::from(1u64));
|
||||
}
|
||||
@@ -52,10 +82,31 @@ pub fn get_custody_groups(
|
||||
Ok(custody_groups)
|
||||
}
|
||||
|
||||
/// Returns a deterministically ordered list of custody columns assigned to a node,
|
||||
/// preserving the order in which they were computed during iteration.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `raw_node_id` - 32-byte node identifier
|
||||
/// * `spec` - Chain specification containing custody parameters
|
||||
pub fn compute_ordered_custody_column_indices<E: EthSpec>(
|
||||
raw_node_id: [u8; 32],
|
||||
spec: &ChainSpec,
|
||||
) -> Result<Vec<ColumnIndex>, DataColumnCustodyGroupError> {
|
||||
let all_custody_groups_ordered =
|
||||
get_custody_groups_ordered(raw_node_id, spec.number_of_custody_groups, spec)?;
|
||||
|
||||
let mut ordered_custody_columns = vec![];
|
||||
for custody_index in all_custody_groups_ordered {
|
||||
let columns = compute_columns_for_custody_group::<E>(custody_index, spec)?;
|
||||
ordered_custody_columns.extend(columns);
|
||||
}
|
||||
Ok(ordered_custody_columns)
|
||||
}
|
||||
|
||||
/// Returns the columns that are associated with a given custody group.
|
||||
///
|
||||
/// spec: https://github.com/ethereum/consensus-specs/blob/8e0d0d48e81d6c7c5a8253ab61340f5ea5bac66a/specs/fulu/das-core.md#compute_columns_for_custody_group
|
||||
pub fn compute_columns_for_custody_group(
|
||||
pub fn compute_columns_for_custody_group<E: EthSpec>(
|
||||
custody_group: CustodyIndex,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<impl Iterator<Item = ColumnIndex>, DataColumnCustodyGroupError> {
|
||||
@@ -67,7 +118,7 @@ pub fn compute_columns_for_custody_group(
|
||||
}
|
||||
|
||||
let mut columns = Vec::new();
|
||||
for i in 0..spec.data_columns_per_group() {
|
||||
for i in 0..spec.data_columns_per_group::<E>() {
|
||||
let column = number_of_custody_groups
|
||||
.safe_mul(i)
|
||||
.and_then(|v| v.safe_add(custody_group))
|
||||
@@ -78,7 +129,7 @@ pub fn compute_columns_for_custody_group(
|
||||
Ok(columns.into_iter())
|
||||
}
|
||||
|
||||
pub fn compute_subnets_for_node(
|
||||
pub fn compute_subnets_for_node<E: EthSpec>(
|
||||
raw_node_id: [u8; 32],
|
||||
custody_group_count: u64,
|
||||
spec: &ChainSpec,
|
||||
@@ -87,7 +138,7 @@ pub fn compute_subnets_for_node(
|
||||
let mut subnets = HashSet::new();
|
||||
|
||||
for custody_group in custody_groups {
|
||||
let custody_group_subnets = compute_subnets_from_custody_group(custody_group, spec)?;
|
||||
let custody_group_subnets = compute_subnets_from_custody_group::<E>(custody_group, spec)?;
|
||||
subnets.extend(custody_group_subnets);
|
||||
}
|
||||
|
||||
@@ -95,11 +146,11 @@ pub fn compute_subnets_for_node(
|
||||
}
|
||||
|
||||
/// Returns the subnets that are associated with a given custody group.
|
||||
pub fn compute_subnets_from_custody_group(
|
||||
pub fn compute_subnets_from_custody_group<E: EthSpec>(
|
||||
custody_group: CustodyIndex,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<impl Iterator<Item = DataColumnSubnetId> + '_, DataColumnCustodyGroupError> {
|
||||
let result = compute_columns_for_custody_group(custody_group, spec)?
|
||||
let result = compute_columns_for_custody_group::<E>(custody_group, spec)?
|
||||
.map(|column_index| DataColumnSubnetId::from_column_index(column_index, spec))
|
||||
.unique();
|
||||
Ok(result)
|
||||
@@ -108,19 +159,23 @@ pub fn compute_subnets_from_custody_group(
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::MainnetEthSpec;
|
||||
|
||||
type E = MainnetEthSpec;
|
||||
|
||||
#[test]
|
||||
fn test_compute_columns_for_custody_group() {
|
||||
let mut spec = ChainSpec::mainnet();
|
||||
spec.number_of_custody_groups = 64;
|
||||
spec.number_of_columns = 128;
|
||||
let columns_per_custody_group = spec.number_of_columns / spec.number_of_custody_groups;
|
||||
|
||||
let columns_per_custody_group =
|
||||
E::number_of_columns() / (spec.number_of_custody_groups as usize);
|
||||
|
||||
for custody_group in 0..spec.number_of_custody_groups {
|
||||
let columns = compute_columns_for_custody_group(custody_group, &spec)
|
||||
let columns = compute_columns_for_custody_group::<E>(custody_group, &spec)
|
||||
.unwrap()
|
||||
.collect::<Vec<_>>();
|
||||
assert_eq!(columns.len(), columns_per_custody_group as usize);
|
||||
assert_eq!(columns.len(), columns_per_custody_group);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,14 +183,13 @@ mod test {
|
||||
fn test_compute_subnets_from_custody_group() {
|
||||
let mut spec = ChainSpec::mainnet();
|
||||
spec.number_of_custody_groups = 64;
|
||||
spec.number_of_columns = 256;
|
||||
spec.data_column_sidecar_subnet_count = 128;
|
||||
|
||||
let subnets_per_custody_group =
|
||||
spec.data_column_sidecar_subnet_count / spec.number_of_custody_groups;
|
||||
|
||||
for custody_group in 0..spec.number_of_custody_groups {
|
||||
let subnets = compute_subnets_from_custody_group(custody_group, &spec)
|
||||
let subnets = compute_subnets_from_custody_group::<E>(custody_group, &spec)
|
||||
.unwrap()
|
||||
.collect::<Vec<_>>();
|
||||
assert_eq!(subnets.len(), subnets_per_custody_group as usize);
|
||||
@@ -1,90 +1,51 @@
|
||||
use crate::beacon_block_body::{KzgCommitments, BLOB_KZG_COMMITMENTS_INDEX};
|
||||
use crate::context_deserialize;
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::{
|
||||
BeaconBlockHeader, BeaconStateError, Epoch, EthSpec, ForkName, Hash256, RuntimeVariableList,
|
||||
SignedBeaconBlockHeader, Slot,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
|
||||
use bls::Signature;
|
||||
use derivative::Derivative;
|
||||
use kzg::Error as KzgError;
|
||||
use context_deserialize::context_deserialize;
|
||||
use educe::Educe;
|
||||
use kzg::{KzgCommitment, KzgProof};
|
||||
use merkle_proof::verify_merkle_proof;
|
||||
use safe_arith::ArithError;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz::{DecodeError, Encode};
|
||||
use ssz::Encode;
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use ssz_types::Error as SszError;
|
||||
use ssz_types::{FixedVector, VariableList};
|
||||
use std::sync::Arc;
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash::TreeHash;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
use crate::{
|
||||
block::{BLOB_KZG_COMMITMENTS_INDEX, BeaconBlockHeader, SignedBeaconBlockHeader},
|
||||
core::{Epoch, EthSpec, Hash256, Slot},
|
||||
fork::ForkName,
|
||||
kzg_ext::{KzgCommitments, KzgError},
|
||||
state::BeaconStateError,
|
||||
test_utils::TestRandom,
|
||||
};
|
||||
|
||||
pub type ColumnIndex = u64;
|
||||
pub type Cell<E> = FixedVector<u8, <E as EthSpec>::BytesPerCell>;
|
||||
pub type DataColumn<E> = VariableList<Cell<E>, <E as EthSpec>::MaxBlobCommitmentsPerBlock>;
|
||||
|
||||
/// Identifies a set of data columns associated with a specific beacon block.
|
||||
#[derive(Encode, Clone, Debug, PartialEq)]
|
||||
pub struct DataColumnsByRootIdentifier {
|
||||
#[derive(Encode, Decode, Clone, Debug, PartialEq, TreeHash, Deserialize)]
|
||||
#[context_deserialize(ForkName)]
|
||||
pub struct DataColumnsByRootIdentifier<E: EthSpec> {
|
||||
pub block_root: Hash256,
|
||||
pub columns: RuntimeVariableList<ColumnIndex>,
|
||||
}
|
||||
|
||||
impl RuntimeVariableList<DataColumnsByRootIdentifier> {
|
||||
pub fn from_ssz_bytes_with_nested(
|
||||
bytes: &[u8],
|
||||
max_len: usize,
|
||||
num_columns: usize,
|
||||
) -> Result<Self, DecodeError> {
|
||||
if bytes.is_empty() {
|
||||
return Ok(RuntimeVariableList::empty(max_len));
|
||||
}
|
||||
|
||||
let vec = ssz::decode_list_of_variable_length_items::<Vec<u8>, Vec<Vec<u8>>>(
|
||||
bytes,
|
||||
Some(max_len),
|
||||
)?
|
||||
.into_iter()
|
||||
.map(|bytes| {
|
||||
let mut builder = ssz::SszDecoderBuilder::new(&bytes);
|
||||
builder.register_type::<Hash256>()?;
|
||||
builder.register_anonymous_variable_length_item()?;
|
||||
|
||||
let mut decoder = builder.build()?;
|
||||
let block_root = decoder.decode_next()?;
|
||||
let columns = decoder.decode_next_with(|bytes| {
|
||||
RuntimeVariableList::from_ssz_bytes(bytes, num_columns)
|
||||
})?;
|
||||
Ok(DataColumnsByRootIdentifier {
|
||||
block_root,
|
||||
columns,
|
||||
})
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
|
||||
Ok(RuntimeVariableList::from_vec(vec, max_len))
|
||||
}
|
||||
pub columns: VariableList<ColumnIndex, E::NumberOfColumns>,
|
||||
}
|
||||
|
||||
pub type DataColumnSidecarList<E> = Vec<Arc<DataColumnSidecar<E>>>;
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Clone,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
TreeHash,
|
||||
TestRandom,
|
||||
Derivative,
|
||||
arbitrary::Arbitrary,
|
||||
#[cfg_attr(
|
||||
feature = "arbitrary",
|
||||
derive(arbitrary::Arbitrary),
|
||||
arbitrary(bound = "E: EthSpec")
|
||||
)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom, Educe)]
|
||||
#[serde(bound = "E: EthSpec")]
|
||||
#[arbitrary(bound = "E: EthSpec")]
|
||||
#[derivative(PartialEq, Eq, Hash(bound = "E: EthSpec"))]
|
||||
#[educe(PartialEq, Eq, Hash(bound(E: EthSpec)))]
|
||||
#[context_deserialize(ForkName)]
|
||||
pub struct DataColumnSidecar<E: EthSpec> {
|
||||
#[serde(with = "serde_utils::quoted_u64")]
|
||||
@@ -183,6 +144,7 @@ pub enum DataColumnSidecarError {
|
||||
PreDeneb,
|
||||
SszError(SszError),
|
||||
BuildSidecarFailed(String),
|
||||
InvalidCellProofLength { expected: usize, actual: usize },
|
||||
}
|
||||
|
||||
impl From<ArithError> for DataColumnSidecarError {
|
||||
@@ -208,45 +170,3 @@ impl From<SszError> for DataColumnSidecarError {
|
||||
Self::SszError(e)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use bls::FixedBytesExtended;
|
||||
|
||||
#[test]
|
||||
fn round_trip_dcbroot_list() {
|
||||
let max_outer = 5;
|
||||
let max_inner = 10;
|
||||
|
||||
let data = vec![
|
||||
DataColumnsByRootIdentifier {
|
||||
block_root: Hash256::from_low_u64_be(10),
|
||||
columns: RuntimeVariableList::<ColumnIndex>::from_vec(vec![1u64, 2, 3], max_inner),
|
||||
},
|
||||
DataColumnsByRootIdentifier {
|
||||
block_root: Hash256::from_low_u64_be(20),
|
||||
columns: RuntimeVariableList::<ColumnIndex>::from_vec(vec![4u64, 5], max_inner),
|
||||
},
|
||||
];
|
||||
|
||||
let list = RuntimeVariableList::from_vec(data.clone(), max_outer);
|
||||
|
||||
let ssz_bytes = list.as_ssz_bytes();
|
||||
|
||||
let decoded =
|
||||
RuntimeVariableList::<DataColumnsByRootIdentifier>::from_ssz_bytes_with_nested(
|
||||
&ssz_bytes, max_outer, max_inner,
|
||||
)
|
||||
.expect("should decode list of DataColumnsByRootIdentifier");
|
||||
|
||||
assert_eq!(decoded.len(), data.len());
|
||||
for (original, decoded) in data.iter().zip(decoded.iter()) {
|
||||
assert_eq!(decoded.block_root, original.block_root);
|
||||
assert_eq!(
|
||||
decoded.columns.iter().copied().collect::<Vec<_>>(),
|
||||
original.columns.iter().copied().collect::<Vec<_>>()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,25 @@
|
||||
//! Identifies each data column subnet by an integer identifier.
|
||||
use crate::data_column_sidecar::ColumnIndex;
|
||||
use crate::ChainSpec;
|
||||
use safe_arith::{ArithError, SafeArith};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::{self, Display};
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::{
|
||||
fmt::{self, Display},
|
||||
ops::{Deref, DerefMut},
|
||||
};
|
||||
|
||||
#[derive(arbitrary::Arbitrary, Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
use safe_arith::SafeArith;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{core::ChainSpec, data::ColumnIndex};
|
||||
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct DataColumnSubnetId(#[serde(with = "serde_utils::quoted_u64")] u64);
|
||||
|
||||
impl fmt::Debug for DataColumnSubnetId {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
std::fmt::Debug::fmt(&self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl DataColumnSubnetId {
|
||||
pub fn new(id: u64) -> Self {
|
||||
id.into()
|
||||
@@ -62,15 +72,3 @@ impl From<&DataColumnSubnetId> for u64 {
|
||||
val.0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
ArithError(ArithError),
|
||||
InvalidCustodySubnetCount(u64),
|
||||
}
|
||||
|
||||
impl From<ArithError> for Error {
|
||||
fn from(e: ArithError) -> Self {
|
||||
Error::ArithError(e)
|
||||
}
|
||||
}
|
||||
23
consensus/types/src/data/mod.rs
Normal file
23
consensus/types/src/data/mod.rs
Normal file
@@ -0,0 +1,23 @@
|
||||
mod blob_sidecar;
|
||||
mod data_column_custody_group;
|
||||
mod data_column_sidecar;
|
||||
mod data_column_subnet_id;
|
||||
|
||||
pub use blob_sidecar::{
|
||||
BlobIdentifier, BlobSidecar, BlobSidecarError, BlobSidecarList, BlobsList, FixedBlobSidecarList,
|
||||
};
|
||||
pub use data_column_custody_group::{
|
||||
CustodyIndex, DataColumnCustodyGroupError, compute_columns_for_custody_group,
|
||||
compute_ordered_custody_column_indices, compute_subnets_for_node,
|
||||
compute_subnets_from_custody_group, get_custody_groups,
|
||||
};
|
||||
pub use data_column_sidecar::{
|
||||
Cell, ColumnIndex, DataColumn, DataColumnSidecar, DataColumnSidecarError,
|
||||
DataColumnSidecarList, DataColumnsByRootIdentifier,
|
||||
};
|
||||
pub use data_column_subnet_id::DataColumnSubnetId;
|
||||
|
||||
use crate::core::EthSpec;
|
||||
use ssz_types::FixedVector;
|
||||
|
||||
pub type Blob<E> = FixedVector<u8, <E as EthSpec>::BytesPerBlob>;
|
||||
@@ -1,29 +1,21 @@
|
||||
use crate::context_deserialize;
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::*;
|
||||
use context_deserialize::context_deserialize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use ssz_types::typenum::U33;
|
||||
use ssz_types::FixedVector;
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash_derive::TreeHash;
|
||||
use typenum::U33;
|
||||
|
||||
use crate::{core::Hash256, deposit::DepositData, fork::ForkName, test_utils::TestRandom};
|
||||
|
||||
pub const DEPOSIT_TREE_DEPTH: usize = 32;
|
||||
|
||||
/// A deposit to potentially become a beacon chain validator.
|
||||
///
|
||||
/// Spec v0.12.1
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
#[derive(
|
||||
arbitrary::Arbitrary,
|
||||
Debug,
|
||||
PartialEq,
|
||||
Hash,
|
||||
Clone,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
TreeHash,
|
||||
TestRandom,
|
||||
Debug, PartialEq, Hash, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom,
|
||||
)]
|
||||
#[context_deserialize(ForkName)]
|
||||
pub struct Deposit {
|
||||
@@ -1,25 +1,23 @@
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::*;
|
||||
use bls::{PublicKeyBytes, SecretKey, SignatureBytes};
|
||||
use context_deserialize::context_deserialize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
use crate::{
|
||||
core::{ChainSpec, Hash256, SignedRoot},
|
||||
deposit::DepositMessage,
|
||||
fork::ForkName,
|
||||
test_utils::TestRandom,
|
||||
};
|
||||
|
||||
/// The data supplied by the user to the deposit contract.
|
||||
///
|
||||
/// Spec v0.12.1
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
#[derive(
|
||||
arbitrary::Arbitrary,
|
||||
Debug,
|
||||
PartialEq,
|
||||
Hash,
|
||||
Clone,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
TreeHash,
|
||||
TestRandom,
|
||||
Debug, PartialEq, Hash, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom,
|
||||
)]
|
||||
#[context_deserialize(ForkName)]
|
||||
pub struct DepositData {
|
||||
@@ -1,26 +1,21 @@
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::*;
|
||||
|
||||
use bls::PublicKeyBytes;
|
||||
use context_deserialize::context_deserialize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
use crate::{
|
||||
core::{Hash256, SignedRoot},
|
||||
fork::ForkName,
|
||||
test_utils::TestRandom,
|
||||
};
|
||||
|
||||
/// The data supplied by the user to the deposit contract.
|
||||
///
|
||||
/// Spec v0.12.1
|
||||
#[derive(
|
||||
arbitrary::Arbitrary,
|
||||
Debug,
|
||||
PartialEq,
|
||||
Clone,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
TreeHash,
|
||||
TestRandom,
|
||||
)]
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)]
|
||||
#[context_deserialize(ForkName)]
|
||||
pub struct DepositMessage {
|
||||
pub pubkey: PublicKeyBytes,
|
||||
@@ -1,25 +1,16 @@
|
||||
use crate::context_deserialize;
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::{ForkName, Hash256, PublicKeyBytes};
|
||||
use bls::SignatureBytes;
|
||||
use bls::{PublicKeyBytes, SignatureBytes};
|
||||
use context_deserialize::context_deserialize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz::Encode;
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
use crate::{core::Hash256, fork::ForkName, test_utils::TestRandom};
|
||||
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
#[derive(
|
||||
arbitrary::Arbitrary,
|
||||
Debug,
|
||||
PartialEq,
|
||||
Hash,
|
||||
Clone,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
TreeHash,
|
||||
TestRandom,
|
||||
Debug, PartialEq, Hash, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom,
|
||||
)]
|
||||
#[context_deserialize(ForkName)]
|
||||
pub struct DepositRequest {
|
||||
@@ -1,10 +1,11 @@
|
||||
use crate::*;
|
||||
use ethereum_hashing::{hash32_concat, ZERO_HASHES};
|
||||
use ethereum_hashing::{ZERO_HASHES, hash32_concat};
|
||||
use fixed_bytes::FixedBytesExtended;
|
||||
use int_to_bytes::int_to_bytes32;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use test_random_derive::TestRandom;
|
||||
use test_utils::TestRandom;
|
||||
|
||||
use crate::{core::Hash256, deposit::DEPOSIT_TREE_DEPTH, test_utils::TestRandom};
|
||||
|
||||
#[derive(Encode, Decode, Deserialize, Serialize, Clone, Debug, PartialEq, TestRandom)]
|
||||
pub struct FinalizedExecutionBlock {
|
||||
13
consensus/types/src/deposit/mod.rs
Normal file
13
consensus/types/src/deposit/mod.rs
Normal file
@@ -0,0 +1,13 @@
|
||||
mod deposit;
|
||||
mod deposit_data;
|
||||
mod deposit_message;
|
||||
mod deposit_request;
|
||||
mod deposit_tree_snapshot;
|
||||
mod pending_deposit;
|
||||
|
||||
pub use deposit::{DEPOSIT_TREE_DEPTH, Deposit};
|
||||
pub use deposit_data::DepositData;
|
||||
pub use deposit_message::DepositMessage;
|
||||
pub use deposit_request::DepositRequest;
|
||||
pub use deposit_tree_snapshot::{DepositTreeSnapshot, FinalizedExecutionBlock};
|
||||
pub use pending_deposit::PendingDeposit;
|
||||
@@ -1,22 +1,19 @@
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::*;
|
||||
use bls::{PublicKeyBytes, SignatureBytes};
|
||||
use context_deserialize::context_deserialize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
use crate::{
|
||||
core::{Hash256, Slot},
|
||||
fork::ForkName,
|
||||
test_utils::TestRandom,
|
||||
};
|
||||
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
#[derive(
|
||||
arbitrary::Arbitrary,
|
||||
Debug,
|
||||
PartialEq,
|
||||
Hash,
|
||||
Clone,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
TreeHash,
|
||||
TestRandom,
|
||||
Debug, PartialEq, Hash, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom,
|
||||
)]
|
||||
#[context_deserialize(ForkName)]
|
||||
pub struct PendingDeposit {
|
||||
@@ -1,23 +1,20 @@
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::*;
|
||||
use bls::{PublicKeyBytes, SecretKey};
|
||||
use context_deserialize::context_deserialize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
use crate::{
|
||||
core::{Address, ChainSpec, Domain, Hash256, SignedRoot},
|
||||
execution::SignedBlsToExecutionChange,
|
||||
fork::ForkName,
|
||||
test_utils::TestRandom,
|
||||
};
|
||||
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
#[derive(
|
||||
arbitrary::Arbitrary,
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
Hash,
|
||||
Clone,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
TreeHash,
|
||||
TestRandom,
|
||||
Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom,
|
||||
)]
|
||||
#[context_deserialize(ForkName)]
|
||||
pub struct BlsToExecutionChange {
|
||||
123
consensus/types/src/execution/dumb_macros.rs
Normal file
123
consensus/types/src/execution/dumb_macros.rs
Normal file
@@ -0,0 +1,123 @@
|
||||
// These would usually be created by superstuct but now there's no longer a 1:1 mapping between
|
||||
// the variants for ExecutionPayload and the variants for
|
||||
// - ExecutionPayloadHeader
|
||||
// - FullPayload
|
||||
// - BlindedPayload
|
||||
// TODO(EIP-7732): get rid of this whole file and panics once the engine_api is refactored for ePBS
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! map_execution_payload_into_full_payload {
|
||||
($value:expr, $f:expr) => {
|
||||
match $value {
|
||||
ExecutionPayload::Bellatrix(inner) => {
|
||||
let f: fn(ExecutionPayloadBellatrix<_>, fn(_) -> _) -> _ = $f;
|
||||
f(inner, FullPayload::Bellatrix)
|
||||
}
|
||||
ExecutionPayload::Capella(inner) => {
|
||||
let f: fn(ExecutionPayloadCapella<_>, fn(_) -> _) -> _ = $f;
|
||||
f(inner, FullPayload::Capella)
|
||||
}
|
||||
ExecutionPayload::Deneb(inner) => {
|
||||
let f: fn(ExecutionPayloadDeneb<_>, fn(_) -> _) -> _ = $f;
|
||||
f(inner, FullPayload::Deneb)
|
||||
}
|
||||
ExecutionPayload::Electra(inner) => {
|
||||
let f: fn(ExecutionPayloadElectra<_>, fn(_) -> _) -> _ = $f;
|
||||
f(inner, FullPayload::Electra)
|
||||
}
|
||||
ExecutionPayload::Fulu(inner) => {
|
||||
let f: fn(ExecutionPayloadFulu<_>, fn(_) -> _) -> _ = $f;
|
||||
f(inner, FullPayload::Fulu)
|
||||
}
|
||||
ExecutionPayload::Eip7805(inner) => {
|
||||
let f: fn(ExecutionPayloadEip7805<_>, fn(_) -> _) -> _ = $f;
|
||||
f(inner, FullPayload::Eip7805)
|
||||
}
|
||||
ExecutionPayload::Gloas(_) => panic!("FullPayload::Gloas does not exist!"),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! map_execution_payload_into_blinded_payload {
|
||||
($value:expr, $f:expr) => {
|
||||
match $value {
|
||||
ExecutionPayload::Bellatrix(inner) => {
|
||||
let f: fn(ExecutionPayloadBellatrix<_>, fn(_) -> _) -> _ = $f;
|
||||
f(inner, BlindedPayload::Bellatrix)
|
||||
}
|
||||
ExecutionPayload::Capella(inner) => {
|
||||
let f: fn(ExecutionPayloadCapella<_>, fn(_) -> _) -> _ = $f;
|
||||
f(inner, BlindedPayload::Capella)
|
||||
}
|
||||
ExecutionPayload::Deneb(inner) => {
|
||||
let f: fn(ExecutionPayloadDeneb<_>, fn(_) -> _) -> _ = $f;
|
||||
f(inner, BlindedPayload::Deneb)
|
||||
}
|
||||
ExecutionPayload::Electra(inner) => {
|
||||
let f: fn(ExecutionPayloadElectra<_>, fn(_) -> _) -> _ = $f;
|
||||
f(inner, BlindedPayload::Electra)
|
||||
}
|
||||
ExecutionPayload::Fulu(inner) => {
|
||||
let f: fn(ExecutionPayloadFulu<_>, fn(_) -> _) -> _ = $f;
|
||||
f(inner, BlindedPayload::Fulu)
|
||||
}
|
||||
ExecutionPayload::Eip7805(inner) => {
|
||||
let f: fn(ExecutionPayloadEip7805<_>, fn(_) -> _) -> _ = $f;
|
||||
f(inner, BlindedPayload::Eip7805)
|
||||
}
|
||||
ExecutionPayload::Gloas(_) => panic!("BlindedPayload::Gloas does not exist!"),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! map_execution_payload_ref_into_execution_payload_header {
|
||||
(&$lifetime:tt _, $value:expr, $f:expr) => {
|
||||
match $value {
|
||||
ExecutionPayloadRef::Bellatrix(inner) => {
|
||||
let f: fn(
|
||||
&$lifetime ExecutionPayloadBellatrix<_>,
|
||||
fn(_) -> _,
|
||||
) -> _ = $f;
|
||||
f(inner, ExecutionPayloadHeader::Bellatrix)
|
||||
}
|
||||
ExecutionPayloadRef::Capella(inner) => {
|
||||
let f: fn(
|
||||
&$lifetime ExecutionPayloadCapella<_>,
|
||||
fn(_) -> _,
|
||||
) -> _ = $f;
|
||||
f(inner, ExecutionPayloadHeader::Capella)
|
||||
}
|
||||
ExecutionPayloadRef::Deneb(inner) => {
|
||||
let f: fn(
|
||||
&$lifetime ExecutionPayloadDeneb<_>,
|
||||
fn(_) -> _,
|
||||
) -> _ = $f;
|
||||
f(inner, ExecutionPayloadHeader::Deneb)
|
||||
}
|
||||
ExecutionPayloadRef::Electra(inner) => {
|
||||
let f: fn(
|
||||
&$lifetime ExecutionPayloadElectra<_>,
|
||||
fn(_) -> _,
|
||||
) -> _ = $f;
|
||||
f(inner, ExecutionPayloadHeader::Electra)
|
||||
}
|
||||
ExecutionPayloadRef::Fulu(inner) => {
|
||||
let f: fn(
|
||||
&$lifetime ExecutionPayloadFulu<_>,
|
||||
fn(_) -> _,
|
||||
) -> _ = $f;
|
||||
f(inner, ExecutionPayloadHeader::Fulu)
|
||||
}
|
||||
ExecutionPayloadRef::Eip7805(inner) => {
|
||||
let f: fn(
|
||||
&$lifetime ExecutionPayloadEip7805<_>,
|
||||
fn(_) -> _,
|
||||
) -> _ = $f;
|
||||
f(inner, ExecutionPayloadHeader::Eip7805)
|
||||
}
|
||||
ExecutionPayloadRef::Gloas(_) => panic!("ExecutionPayloadHeader::Gloas does not exist!"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,16 @@
|
||||
use super::Hash256;
|
||||
use crate::context_deserialize;
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::ForkName;
|
||||
use context_deserialize::context_deserialize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
use crate::{core::Hash256, fork::ForkName, test_utils::TestRandom};
|
||||
|
||||
/// Contains data obtained from the Eth1 chain.
|
||||
///
|
||||
/// Spec v0.12.1
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
#[derive(
|
||||
arbitrary::Arbitrary,
|
||||
Debug,
|
||||
PartialEq,
|
||||
Clone,
|
||||
@@ -1,28 +1,23 @@
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::FixedBytesExtended;
|
||||
use crate::Hash256;
|
||||
use derivative::Derivative;
|
||||
use std::fmt;
|
||||
|
||||
use fixed_bytes::FixedBytesExtended;
|
||||
use rand::RngCore;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz::{Decode, DecodeError, Encode};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(
|
||||
arbitrary::Arbitrary,
|
||||
Default,
|
||||
Clone,
|
||||
Copy,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Eq,
|
||||
PartialEq,
|
||||
Hash,
|
||||
Derivative,
|
||||
)]
|
||||
#[derivative(Debug = "transparent")]
|
||||
use crate::{core::Hash256, test_utils::TestRandom};
|
||||
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
#[derive(Default, Clone, Copy, Serialize, Deserialize, Eq, PartialEq, Hash)]
|
||||
#[serde(transparent)]
|
||||
pub struct ExecutionBlockHash(#[serde(with = "serde_utils::b256_hex")] pub Hash256);
|
||||
|
||||
impl fmt::Debug for ExecutionBlockHash {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
std::fmt::Debug::fmt(&self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl ExecutionBlockHash {
|
||||
pub fn zero() -> Self {
|
||||
Self(Hash256::zero())
|
||||
@@ -17,10 +17,15 @@
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
use crate::{Address, EthSpec, ExecutionPayloadRef, Hash256, Hash64, Uint256};
|
||||
use alloy_rlp::RlpEncodable;
|
||||
use fixed_bytes::Uint256;
|
||||
use metastruct::metastruct;
|
||||
|
||||
use crate::{
|
||||
core::{Address, EthSpec, Hash64, Hash256},
|
||||
execution::ExecutionPayloadRef,
|
||||
};
|
||||
|
||||
/// Execution block header as used for RLP encoding and Keccak hashing.
|
||||
///
|
||||
/// Credit to Reth for the type definition.
|
||||
@@ -1,21 +1,31 @@
|
||||
use crate::{test_utils::TestRandom, *};
|
||||
use derivative::Derivative;
|
||||
use context_deserialize::{ContextDeserialize, context_deserialize};
|
||||
use educe::Educe;
|
||||
use fixed_bytes::Uint256;
|
||||
use serde::{Deserialize, Deserializer, Serialize};
|
||||
use ssz::{Decode, Encode};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use ssz_types::{FixedVector, VariableList};
|
||||
use superstruct::superstruct;
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
use crate::{
|
||||
core::{Address, EthSpec, Hash256},
|
||||
execution::ExecutionBlockHash,
|
||||
fork::{ForkName, ForkVersionDecode},
|
||||
state::BeaconStateError,
|
||||
test_utils::TestRandom,
|
||||
withdrawal::Withdrawals,
|
||||
};
|
||||
|
||||
pub type Transaction<N> = VariableList<u8, N>;
|
||||
pub type Transactions<E> = VariableList<
|
||||
Transaction<<E as EthSpec>::MaxBytesPerTransaction>,
|
||||
<E as EthSpec>::MaxTransactionsPerPayload,
|
||||
>;
|
||||
|
||||
pub type Withdrawals<E> = VariableList<Withdrawal, <E as EthSpec>::MaxWithdrawalsPerPayload>;
|
||||
|
||||
#[superstruct(
|
||||
variants(Bellatrix, Capella, Deneb, Electra, Eip7805, Fulu),
|
||||
variants(Bellatrix, Capella, Deneb, Electra, Fulu, Eip7805, Gloas),
|
||||
variant_attributes(
|
||||
derive(
|
||||
Default,
|
||||
@@ -27,25 +37,34 @@ pub type Withdrawals<E> = VariableList<Withdrawal, <E as EthSpec>::MaxWithdrawal
|
||||
Decode,
|
||||
TreeHash,
|
||||
TestRandom,
|
||||
Derivative,
|
||||
arbitrary::Arbitrary
|
||||
Educe,
|
||||
),
|
||||
context_deserialize(ForkName),
|
||||
derivative(PartialEq, Hash(bound = "E: EthSpec")),
|
||||
educe(PartialEq, Hash(bound(E: EthSpec))),
|
||||
serde(bound = "E: EthSpec", deny_unknown_fields),
|
||||
arbitrary(bound = "E: EthSpec")
|
||||
cfg_attr(
|
||||
feature = "arbitrary",
|
||||
derive(arbitrary::Arbitrary),
|
||||
arbitrary(bound = "E: EthSpec"),
|
||||
),
|
||||
),
|
||||
cast_error(ty = "Error", expr = "BeaconStateError::IncorrectStateVariant"),
|
||||
partial_getter_error(ty = "Error", expr = "BeaconStateError::IncorrectStateVariant"),
|
||||
map_into(FullPayload, BlindedPayload),
|
||||
map_ref_into(ExecutionPayloadHeader)
|
||||
cast_error(
|
||||
ty = "BeaconStateError",
|
||||
expr = "BeaconStateError::IncorrectStateVariant"
|
||||
),
|
||||
partial_getter_error(
|
||||
ty = "BeaconStateError",
|
||||
expr = "BeaconStateError::IncorrectStateVariant"
|
||||
)
|
||||
)]
|
||||
#[derive(
|
||||
Debug, Clone, Serialize, Deserialize, Encode, TreeHash, Derivative, arbitrary::Arbitrary,
|
||||
#[cfg_attr(
|
||||
feature = "arbitrary",
|
||||
derive(arbitrary::Arbitrary),
|
||||
arbitrary(bound = "E: EthSpec")
|
||||
)]
|
||||
#[derivative(PartialEq, Hash(bound = "E: EthSpec"))]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Encode, TreeHash, Educe)]
|
||||
#[educe(PartialEq, Hash(bound(E: EthSpec)))]
|
||||
#[serde(bound = "E: EthSpec", untagged)]
|
||||
#[arbitrary(bound = "E: EthSpec")]
|
||||
#[ssz(enum_behaviour = "transparent")]
|
||||
#[tree_hash(enum_behaviour = "transparent")]
|
||||
pub struct ExecutionPayload<E: EthSpec> {
|
||||
@@ -83,12 +102,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, Eip7805, Fulu))]
|
||||
#[superstruct(only(Capella, Deneb, Electra, Fulu, Eip7805, Gloas))]
|
||||
pub withdrawals: Withdrawals<E>,
|
||||
#[superstruct(only(Deneb, Electra, Eip7805, Fulu), partial_getter(copy))]
|
||||
#[superstruct(only(Deneb, Electra, Fulu, Eip7805, Gloas), partial_getter(copy))]
|
||||
#[serde(with = "serde_utils::quoted_u64")]
|
||||
pub blob_gas_used: u64,
|
||||
#[superstruct(only(Deneb, Electra, Eip7805, Fulu), partial_getter(copy))]
|
||||
#[superstruct(only(Deneb, Electra, Fulu, Eip7805, Gloas), partial_getter(copy))]
|
||||
#[serde(with = "serde_utils::quoted_u64")]
|
||||
pub excess_blob_gas: u64,
|
||||
}
|
||||
@@ -118,6 +137,7 @@ impl<E: EthSpec> ForkVersionDecode for ExecutionPayload<E> {
|
||||
ForkName::Electra => ExecutionPayloadElectra::from_ssz_bytes(bytes).map(Self::Electra),
|
||||
ForkName::Eip7805 => ExecutionPayloadEip7805::from_ssz_bytes(bytes).map(Self::Eip7805),
|
||||
ForkName::Fulu => ExecutionPayloadFulu::from_ssz_bytes(bytes).map(Self::Fulu),
|
||||
ForkName::Gloas => ExecutionPayloadGloas::from_ssz_bytes(bytes).map(Self::Gloas),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -125,6 +145,7 @@ impl<E: EthSpec> ForkVersionDecode for ExecutionPayload<E> {
|
||||
impl<E: EthSpec> ExecutionPayload<E> {
|
||||
#[allow(clippy::arithmetic_side_effects)]
|
||||
/// Returns the maximum size of an execution payload.
|
||||
/// TODO(EIP-7732): this seems to only exist for the Bellatrix fork, but Mark's branch has it for all the forks, i.e. max_execution_payload_eip7732_size
|
||||
pub fn max_execution_payload_bellatrix_size() -> usize {
|
||||
// Fixed part
|
||||
ExecutionPayloadBellatrix::<E>::default().as_ssz_bytes().len()
|
||||
@@ -148,7 +169,7 @@ impl<'de, E: EthSpec> ContextDeserialize<'de, ForkName> for ExecutionPayload<E>
|
||||
return Err(serde::de::Error::custom(format!(
|
||||
"ExecutionPayload failed to deserialize: unsupported fork '{}'",
|
||||
context
|
||||
)))
|
||||
)));
|
||||
}
|
||||
ForkName::Bellatrix => {
|
||||
Self::Bellatrix(Deserialize::deserialize(deserializer).map_err(convert_err)?)
|
||||
@@ -168,6 +189,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 +205,7 @@ impl<E: EthSpec> ExecutionPayload<E> {
|
||||
ExecutionPayload::Electra(_) => ForkName::Electra,
|
||||
ExecutionPayload::Eip7805(_) => ForkName::Eip7805,
|
||||
ExecutionPayload::Fulu(_) => ForkName::Fulu,
|
||||
ExecutionPayload::Gloas(_) => ForkName::Gloas,
|
||||
}
|
||||
}
|
||||
}
|
||||
40
consensus/types/src/execution/execution_payload_bid.rs
Normal file
40
consensus/types/src/execution/execution_payload_bid.rs
Normal file
@@ -0,0 +1,40 @@
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::{Address, ExecutionBlockHash, ForkName, Hash256, SignedRoot, Slot};
|
||||
use context_deserialize::context_deserialize;
|
||||
use educe::Educe;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
#[derive(
|
||||
Default, Debug, Clone, Serialize, Encode, Decode, Deserialize, TreeHash, Educe, TestRandom,
|
||||
)]
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
#[educe(PartialEq, Hash)]
|
||||
#[context_deserialize(ForkName)]
|
||||
// https://github.com/ethereum/consensus-specs/blob/master/specs/gloas/beacon-chain.md#executionpayloadbid
|
||||
pub struct ExecutionPayloadBid {
|
||||
pub parent_block_hash: ExecutionBlockHash,
|
||||
pub parent_block_root: Hash256,
|
||||
pub block_hash: ExecutionBlockHash,
|
||||
#[serde(with = "serde_utils::address_hex")]
|
||||
pub fee_recipient: Address,
|
||||
#[serde(with = "serde_utils::quoted_u64")]
|
||||
pub gas_limit: u64,
|
||||
#[serde(with = "serde_utils::quoted_u64")]
|
||||
pub builder_index: u64,
|
||||
pub slot: Slot,
|
||||
#[serde(with = "serde_utils::quoted_u64")]
|
||||
pub value: u64,
|
||||
pub blob_kzg_commitments_root: Hash256,
|
||||
}
|
||||
|
||||
impl SignedRoot for ExecutionPayloadBid {}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
ssz_and_tree_hash_tests!(ExecutionPayloadBid);
|
||||
}
|
||||
36
consensus/types/src/execution/execution_payload_envelope.rs
Normal file
36
consensus/types/src/execution/execution_payload_envelope.rs
Normal file
@@ -0,0 +1,36 @@
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::{
|
||||
EthSpec, ExecutionPayloadGloas, ExecutionRequests, ForkName, Hash256, KzgCommitments,
|
||||
SignedRoot, Slot,
|
||||
};
|
||||
use context_deserialize::context_deserialize;
|
||||
use educe::Educe;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Encode, Decode, Deserialize, TestRandom, TreeHash, Educe)]
|
||||
#[educe(PartialEq, Hash(bound(E: EthSpec)))]
|
||||
#[context_deserialize(ForkName)]
|
||||
#[serde(bound = "E: EthSpec")]
|
||||
pub struct ExecutionPayloadEnvelope<E: EthSpec> {
|
||||
pub payload: ExecutionPayloadGloas<E>,
|
||||
pub execution_requests: ExecutionRequests<E>,
|
||||
#[serde(with = "serde_utils::quoted_u64")]
|
||||
pub builder_index: u64,
|
||||
pub beacon_block_root: Hash256,
|
||||
pub slot: Slot,
|
||||
pub blob_kzg_commitments: KzgCommitments<E>,
|
||||
pub state_root: Hash256,
|
||||
}
|
||||
|
||||
impl<E: EthSpec> SignedRoot for ExecutionPayloadEnvelope<E> {}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::MainnetEthSpec;
|
||||
|
||||
ssz_and_tree_hash_tests!(ExecutionPayloadEnvelope<MainnetEthSpec>);
|
||||
}
|
||||
@@ -1,12 +1,28 @@
|
||||
use crate::{test_utils::TestRandom, *};
|
||||
use derivative::Derivative;
|
||||
use context_deserialize::{ContextDeserialize, context_deserialize};
|
||||
use educe::Educe;
|
||||
use fixed_bytes::FixedBytesExtended;
|
||||
use serde::{Deserialize, Deserializer, Serialize};
|
||||
use ssz::{Decode, Encode};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use ssz_types::{FixedVector, VariableList};
|
||||
use superstruct::superstruct;
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash::TreeHash;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
use crate::{
|
||||
core::{Address, EthSpec, Hash256, Uint256},
|
||||
execution::{
|
||||
ExecutionBlockHash, ExecutionPayloadBellatrix, ExecutionPayloadCapella,
|
||||
ExecutionPayloadDeneb, ExecutionPayloadEip7805, ExecutionPayloadElectra,
|
||||
ExecutionPayloadFulu, ExecutionPayloadRef, Transactions,
|
||||
},
|
||||
fork::ForkName,
|
||||
map_execution_payload_ref_into_execution_payload_header,
|
||||
state::BeaconStateError,
|
||||
test_utils::TestRandom,
|
||||
};
|
||||
|
||||
#[superstruct(
|
||||
variants(Bellatrix, Capella, Deneb, Electra, Eip7805, Fulu),
|
||||
variant_attributes(
|
||||
@@ -20,28 +36,39 @@ use tree_hash_derive::TreeHash;
|
||||
Decode,
|
||||
TreeHash,
|
||||
TestRandom,
|
||||
Derivative,
|
||||
arbitrary::Arbitrary
|
||||
Educe,
|
||||
),
|
||||
derivative(PartialEq, Hash(bound = "E: EthSpec")),
|
||||
educe(PartialEq, Hash(bound(E: EthSpec))),
|
||||
serde(bound = "E: EthSpec", deny_unknown_fields),
|
||||
arbitrary(bound = "E: EthSpec"),
|
||||
cfg_attr(
|
||||
feature = "arbitrary",
|
||||
derive(arbitrary::Arbitrary),
|
||||
arbitrary(bound = "E: EthSpec"),
|
||||
),
|
||||
context_deserialize(ForkName),
|
||||
),
|
||||
ref_attributes(
|
||||
derive(PartialEq, TreeHash, Debug),
|
||||
tree_hash(enum_behaviour = "transparent")
|
||||
),
|
||||
cast_error(ty = "Error", expr = "BeaconStateError::IncorrectStateVariant"),
|
||||
partial_getter_error(ty = "Error", expr = "BeaconStateError::IncorrectStateVariant"),
|
||||
cast_error(
|
||||
ty = "BeaconStateError",
|
||||
expr = "BeaconStateError::IncorrectStateVariant"
|
||||
),
|
||||
partial_getter_error(
|
||||
ty = "BeaconStateError",
|
||||
expr = "BeaconStateError::IncorrectStateVariant"
|
||||
),
|
||||
map_ref_into(ExecutionPayloadHeader)
|
||||
)]
|
||||
#[derive(
|
||||
Debug, Clone, Serialize, Deserialize, Encode, TreeHash, Derivative, arbitrary::Arbitrary,
|
||||
#[cfg_attr(
|
||||
feature = "arbitrary",
|
||||
derive(arbitrary::Arbitrary),
|
||||
arbitrary(bound = "E: EthSpec")
|
||||
)]
|
||||
#[derivative(PartialEq, Hash(bound = "E: EthSpec"))]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Encode, TreeHash, Educe)]
|
||||
#[educe(PartialEq, Hash(bound(E: EthSpec)))]
|
||||
#[serde(bound = "E: EthSpec", untagged)]
|
||||
#[arbitrary(bound = "E: EthSpec")]
|
||||
#[tree_hash(enum_behaviour = "transparent")]
|
||||
#[ssz(enum_behaviour = "transparent")]
|
||||
pub struct ExecutionPayloadHeader<E: EthSpec> {
|
||||
@@ -113,13 +140,19 @@ impl<E: EthSpec> ExecutionPayloadHeader<E> {
|
||||
ExecutionPayloadHeaderEip7805::from_ssz_bytes(bytes).map(Self::Eip7805)
|
||||
}
|
||||
ForkName::Fulu => ExecutionPayloadHeaderFulu::from_ssz_bytes(bytes).map(Self::Fulu),
|
||||
ForkName::Gloas => Err(ssz::DecodeError::BytesInvalid(format!(
|
||||
"unsupported fork for ExecutionPayloadHeader: {fork_name}",
|
||||
))),
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::arithmetic_side_effects)]
|
||||
pub fn ssz_max_var_len_for_fork(fork_name: ForkName) -> usize {
|
||||
// TODO(newfork): Add a new case here if there are new variable fields
|
||||
if fork_name.bellatrix_enabled() {
|
||||
if fork_name.gloas_enabled() {
|
||||
// TODO(EIP7732): check this
|
||||
0
|
||||
} else if fork_name.bellatrix_enabled() {
|
||||
// Max size of variable length `extra_data` field
|
||||
E::max_extra_data_bytes() * <u8 as Encode>::ssz_fixed_len()
|
||||
} else {
|
||||
@@ -218,7 +251,7 @@ impl<E: EthSpec> ExecutionPayloadHeaderDeneb<E> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EthSpec> ExecutionPayloadHeaderElectra<E> {
|
||||
impl<E: EthSpec> ExecutionPayloadHeaderFulu<E> {
|
||||
pub fn upgrade_to_eip7805(&self) -> ExecutionPayloadHeaderEip7805<E> {
|
||||
ExecutionPayloadHeaderEip7805 {
|
||||
parent_hash: self.parent_hash,
|
||||
@@ -242,7 +275,7 @@ impl<E: EthSpec> ExecutionPayloadHeaderElectra<E> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EthSpec> ExecutionPayloadHeaderEip7805<E> {
|
||||
impl<E: EthSpec> ExecutionPayloadHeaderElectra<E> {
|
||||
pub fn upgrade_to_fulu(&self) -> ExecutionPayloadHeaderFulu<E> {
|
||||
ExecutionPayloadHeaderFulu {
|
||||
parent_hash: self.parent_hash,
|
||||
@@ -558,12 +591,6 @@ impl<'de, E: EthSpec> ContextDeserialize<'de, ForkName> for ExecutionPayloadHead
|
||||
))
|
||||
};
|
||||
Ok(match context {
|
||||
ForkName::Base | ForkName::Altair => {
|
||||
return Err(serde::de::Error::custom(format!(
|
||||
"ExecutionPayloadHeader failed to deserialize: unsupported fork '{}'",
|
||||
context
|
||||
)))
|
||||
}
|
||||
ForkName::Bellatrix => {
|
||||
Self::Bellatrix(Deserialize::deserialize(deserializer).map_err(convert_err)?)
|
||||
}
|
||||
@@ -582,6 +609,13 @@ impl<'de, E: EthSpec> ContextDeserialize<'de, ForkName> for ExecutionPayloadHead
|
||||
ForkName::Fulu => {
|
||||
Self::Fulu(Deserialize::deserialize(deserializer).map_err(convert_err)?)
|
||||
}
|
||||
|
||||
ForkName::Base | ForkName::Altair | ForkName::Gloas => {
|
||||
return Err(serde::de::Error::custom(format!(
|
||||
"ExecutionPayloadHeader failed to deserialize: unsupported fork '{}'",
|
||||
context
|
||||
)));
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,6 @@
|
||||
use crate::context_deserialize;
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::{ConsolidationRequest, DepositRequest, EthSpec, ForkName, Hash256, WithdrawalRequest};
|
||||
use alloy_primitives::Bytes;
|
||||
use derivative::Derivative;
|
||||
use context_deserialize::context_deserialize;
|
||||
use educe::Educe;
|
||||
use ethereum_hashing::{DynamicContext, Sha256Context};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz::Encode;
|
||||
@@ -11,6 +9,15 @@ use ssz_types::VariableList;
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
use crate::{
|
||||
consolidation::ConsolidationRequest,
|
||||
core::{EthSpec, Hash256},
|
||||
deposit::DepositRequest,
|
||||
fork::ForkName,
|
||||
test_utils::TestRandom,
|
||||
withdrawal::WithdrawalRequest,
|
||||
};
|
||||
|
||||
pub type DepositRequests<E> =
|
||||
VariableList<DepositRequest, <E as EthSpec>::MaxDepositRequestsPerPayload>;
|
||||
pub type WithdrawalRequests<E> =
|
||||
@@ -18,22 +25,16 @@ pub type WithdrawalRequests<E> =
|
||||
pub type ConsolidationRequests<E> =
|
||||
VariableList<ConsolidationRequest, <E as EthSpec>::MaxConsolidationRequestsPerPayload>;
|
||||
|
||||
#[cfg_attr(
|
||||
feature = "arbitrary",
|
||||
derive(arbitrary::Arbitrary),
|
||||
arbitrary(bound = "E: EthSpec")
|
||||
)]
|
||||
#[derive(
|
||||
arbitrary::Arbitrary,
|
||||
Debug,
|
||||
Derivative,
|
||||
Default,
|
||||
Clone,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
TreeHash,
|
||||
TestRandom,
|
||||
Debug, Educe, Default, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom,
|
||||
)]
|
||||
#[serde(bound = "E: EthSpec")]
|
||||
#[arbitrary(bound = "E: EthSpec")]
|
||||
#[derivative(PartialEq, Eq, Hash(bound = "E: EthSpec"))]
|
||||
#[educe(PartialEq, Eq, Hash(bound(E: EthSpec)))]
|
||||
#[context_deserialize(ForkName)]
|
||||
pub struct ExecutionRequests<E: EthSpec> {
|
||||
pub deposits: DepositRequests<E>,
|
||||
54
consensus/types/src/execution/inclusion_list.rs
Normal file
54
consensus/types/src/execution/inclusion_list.rs
Normal file
@@ -0,0 +1,54 @@
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::{EthSpec, Hash256, SignedRoot, Slot, Transactions};
|
||||
use bls::{PublicKeyBytes, Signature};
|
||||
use educe::Educe;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use ssz_types::FixedVector;
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
pub type InclusionListCommittee<E> = FixedVector<u64, <E as EthSpec>::InclusionListCommitteeSize>;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Encode, Educe, Decode, TreeHash, TestRandom)]
|
||||
#[serde(bound = "E: EthSpec")]
|
||||
#[educe(PartialEq, Eq, Hash(bound(E: EthSpec)))]
|
||||
pub struct InclusionList<E: EthSpec> {
|
||||
pub slot: Slot,
|
||||
#[serde(with = "serde_utils::quoted_u64")]
|
||||
pub validator_index: u64,
|
||||
pub inclusion_list_committee_root: Hash256,
|
||||
#[serde(with = "ssz_types::serde_utils::list_of_hex_var_list")]
|
||||
pub transactions: Transactions<E>,
|
||||
}
|
||||
|
||||
impl<E: EthSpec> SignedRoot for InclusionList<E> {}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, Educe)]
|
||||
#[serde(bound = "E: EthSpec")]
|
||||
#[educe(PartialEq, Eq, Hash(bound(E: EthSpec)))]
|
||||
pub struct SignedInclusionList<E: EthSpec> {
|
||||
pub message: InclusionList<E>,
|
||||
pub signature: Signature,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Copy, Serialize, Deserialize)]
|
||||
pub struct InclusionListDuty {
|
||||
/// The slot during which the validator must produce an inclusion list.
|
||||
pub slot: Slot,
|
||||
#[serde(with = "serde_utils::quoted_u64")]
|
||||
/// The index of the validator.
|
||||
pub validator_index: u64,
|
||||
/// The hash tree root of the inclusion list committee.
|
||||
pub committee_root: Hash256,
|
||||
/// The pubkey of the validator.
|
||||
pub pubkey: PublicKeyBytes,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::*;
|
||||
|
||||
ssz_and_tree_hash_tests!(InclusionList<MainnetEthSpec>);
|
||||
}
|
||||
49
consensus/types/src/execution/mod.rs
Normal file
49
consensus/types/src/execution/mod.rs
Normal file
@@ -0,0 +1,49 @@
|
||||
mod eth1_data;
|
||||
mod execution_block_hash;
|
||||
mod execution_block_header;
|
||||
#[macro_use]
|
||||
mod execution_payload;
|
||||
mod bls_to_execution_change;
|
||||
mod dumb_macros;
|
||||
mod execution_payload_bid;
|
||||
mod execution_payload_envelope;
|
||||
mod execution_payload_header;
|
||||
mod execution_requests;
|
||||
mod inclusion_list;
|
||||
mod payload;
|
||||
mod signed_bls_to_execution_change;
|
||||
mod signed_execution_payload_bid;
|
||||
mod signed_execution_payload_envelope;
|
||||
|
||||
pub use bls_to_execution_change::BlsToExecutionChange;
|
||||
pub use eth1_data::Eth1Data;
|
||||
pub use execution_block_hash::ExecutionBlockHash;
|
||||
pub use execution_block_header::{EncodableExecutionBlockHeader, ExecutionBlockHeader};
|
||||
pub use execution_payload::{
|
||||
ExecutionPayload, ExecutionPayloadBellatrix, ExecutionPayloadCapella, ExecutionPayloadDeneb,
|
||||
ExecutionPayloadEip7805, ExecutionPayloadElectra, ExecutionPayloadFulu, ExecutionPayloadGloas,
|
||||
ExecutionPayloadRef, Transaction, Transactions,
|
||||
};
|
||||
pub use execution_payload_bid::ExecutionPayloadBid;
|
||||
pub use execution_payload_envelope::ExecutionPayloadEnvelope;
|
||||
pub use execution_payload_header::{
|
||||
ExecutionPayloadHeader, ExecutionPayloadHeaderBellatrix, ExecutionPayloadHeaderCapella,
|
||||
ExecutionPayloadHeaderDeneb, ExecutionPayloadHeaderEip7805, ExecutionPayloadHeaderElectra,
|
||||
ExecutionPayloadHeaderFulu, ExecutionPayloadHeaderRef, ExecutionPayloadHeaderRefMut,
|
||||
};
|
||||
pub use execution_requests::{
|
||||
ConsolidationRequests, DepositRequests, ExecutionRequests, RequestType, WithdrawalRequests,
|
||||
};
|
||||
pub use inclusion_list::{
|
||||
InclusionList, InclusionListCommittee, InclusionListDuty, SignedInclusionList,
|
||||
};
|
||||
pub use payload::{
|
||||
AbstractExecPayload, BlindedPayload, BlindedPayloadBellatrix, BlindedPayloadCapella,
|
||||
BlindedPayloadDeneb, BlindedPayloadEip7805, BlindedPayloadElectra, BlindedPayloadFulu,
|
||||
BlindedPayloadRef, BlockProductionVersion, BlockType, ExecPayload, FullPayload,
|
||||
FullPayloadBellatrix, FullPayloadCapella, FullPayloadDeneb, FullPayloadEip7805,
|
||||
FullPayloadElectra, FullPayloadFulu, FullPayloadRef, OwnedExecPayload,
|
||||
};
|
||||
pub use signed_bls_to_execution_change::SignedBlsToExecutionChange;
|
||||
pub use signed_execution_payload_bid::SignedExecutionPayloadBid;
|
||||
pub use signed_execution_payload_envelope::SignedExecutionPayloadEnvelope;
|
||||
@@ -1,16 +1,31 @@
|
||||
use crate::{test_utils::TestRandom, *};
|
||||
use derivative::Derivative;
|
||||
use educe::Educe;
|
||||
use serde::de::DeserializeOwned;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz::{Decode, Encode};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use std::borrow::Cow;
|
||||
use std::fmt::Debug;
|
||||
use std::hash::Hash;
|
||||
use ssz_types::VariableList;
|
||||
use std::{borrow::Cow, fmt::Debug, hash::Hash};
|
||||
use superstruct::superstruct;
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash::TreeHash;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
use crate::{
|
||||
core::{Address, EthSpec, Hash256},
|
||||
execution::{
|
||||
ExecutionBlockHash, ExecutionPayload, ExecutionPayloadBellatrix, ExecutionPayloadCapella,
|
||||
ExecutionPayloadDeneb, ExecutionPayloadEip7805, ExecutionPayloadElectra,
|
||||
ExecutionPayloadFulu, ExecutionPayloadHeader, ExecutionPayloadHeaderBellatrix,
|
||||
ExecutionPayloadHeaderCapella, ExecutionPayloadHeaderDeneb, ExecutionPayloadHeaderEip7805,
|
||||
ExecutionPayloadHeaderElectra, ExecutionPayloadHeaderFulu, ExecutionPayloadRef,
|
||||
Transactions,
|
||||
},
|
||||
fork::ForkName,
|
||||
map_execution_payload_into_blinded_payload, map_execution_payload_into_full_payload,
|
||||
state::BeaconStateError,
|
||||
test_utils::TestRandom,
|
||||
};
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum BlockType {
|
||||
Blinded,
|
||||
@@ -38,8 +53,8 @@ pub trait ExecPayload<E: EthSpec>: Debug + Clone + PartialEq + Hash + TreeHash +
|
||||
fn gas_limit(&self) -> u64;
|
||||
fn transactions(&self) -> Option<&Transactions<E>>;
|
||||
/// fork-specific fields
|
||||
fn withdrawals_root(&self) -> Result<Hash256, Error>;
|
||||
fn blob_gas_used(&self) -> Result<u64, Error>;
|
||||
fn withdrawals_root(&self) -> Result<Hash256, BeaconStateError>;
|
||||
fn blob_gas_used(&self) -> Result<u64, BeaconStateError>;
|
||||
|
||||
/// Is this a default payload with 0x0 roots for transactions and withdrawals?
|
||||
fn is_default_with_zero_roots(&self) -> bool;
|
||||
@@ -49,6 +64,7 @@ pub trait ExecPayload<E: EthSpec>: Debug + Clone + PartialEq + Hash + TreeHash +
|
||||
}
|
||||
|
||||
/// `ExecPayload` functionality the requires ownership.
|
||||
#[cfg(feature = "arbitrary")]
|
||||
pub trait OwnedExecPayload<E: EthSpec>:
|
||||
ExecPayload<E>
|
||||
+ Default
|
||||
@@ -61,7 +77,7 @@ pub trait OwnedExecPayload<E: EthSpec>:
|
||||
+ 'static
|
||||
{
|
||||
}
|
||||
|
||||
#[cfg(feature = "arbitrary")]
|
||||
impl<E: EthSpec, P> OwnedExecPayload<E> for P where
|
||||
P: ExecPayload<E>
|
||||
+ Default
|
||||
@@ -75,6 +91,25 @@ impl<E: EthSpec, P> OwnedExecPayload<E> for P where
|
||||
{
|
||||
}
|
||||
|
||||
/// `ExecPayload` functionality the requires ownership.
|
||||
#[cfg(not(feature = "arbitrary"))]
|
||||
pub trait OwnedExecPayload<E: EthSpec>:
|
||||
ExecPayload<E> + Default + Serialize + DeserializeOwned + Encode + Decode + TestRandom + 'static
|
||||
{
|
||||
}
|
||||
#[cfg(not(feature = "arbitrary"))]
|
||||
impl<E: EthSpec, P> OwnedExecPayload<E> for P where
|
||||
P: ExecPayload<E>
|
||||
+ Default
|
||||
+ Serialize
|
||||
+ DeserializeOwned
|
||||
+ Encode
|
||||
+ Decode
|
||||
+ TestRandom
|
||||
+ 'static
|
||||
{
|
||||
}
|
||||
|
||||
pub trait AbstractExecPayload<E: EthSpec>:
|
||||
ExecPayload<E>
|
||||
+ Sized
|
||||
@@ -84,8 +119,8 @@ pub trait AbstractExecPayload<E: EthSpec>:
|
||||
+ TryInto<Self::Capella>
|
||||
+ TryInto<Self::Deneb>
|
||||
+ TryInto<Self::Electra>
|
||||
+ TryInto<Self::Eip7805>
|
||||
+ TryInto<Self::Fulu>
|
||||
+ TryInto<Self::Eip7805>
|
||||
+ Sync
|
||||
{
|
||||
type Ref<'a>: ExecPayload<E>
|
||||
@@ -94,8 +129,8 @@ pub trait AbstractExecPayload<E: EthSpec>:
|
||||
+ From<&'a Self::Capella>
|
||||
+ From<&'a Self::Deneb>
|
||||
+ From<&'a Self::Electra>
|
||||
+ From<&'a Self::Eip7805>
|
||||
+ From<&'a Self::Fulu>;
|
||||
+ From<&'a Self::Fulu>
|
||||
+ From<&'a Self::Eip7805>;
|
||||
|
||||
type Bellatrix: OwnedExecPayload<E>
|
||||
+ Into<Self>
|
||||
@@ -117,16 +152,16 @@ pub trait AbstractExecPayload<E: EthSpec>:
|
||||
+ for<'a> From<Cow<'a, ExecutionPayloadElectra<E>>>
|
||||
+ TryFrom<ExecutionPayloadHeaderElectra<E>>
|
||||
+ Sync;
|
||||
type Eip7805: OwnedExecPayload<E>
|
||||
+ Into<Self>
|
||||
+ for<'a> From<Cow<'a, ExecutionPayloadEip7805<E>>>
|
||||
+ TryFrom<ExecutionPayloadHeaderEip7805<E>>
|
||||
+ Sync;
|
||||
type Fulu: OwnedExecPayload<E>
|
||||
+ Into<Self>
|
||||
+ for<'a> From<Cow<'a, ExecutionPayloadFulu<E>>>
|
||||
+ TryFrom<ExecutionPayloadHeaderFulu<E>>
|
||||
+ Sync;
|
||||
type Eip7805: OwnedExecPayload<E>
|
||||
+ Into<Self>
|
||||
+ for<'a> From<Cow<'a, ExecutionPayloadEip7805<E>>>
|
||||
+ TryFrom<ExecutionPayloadHeaderEip7805<E>>
|
||||
+ Sync;
|
||||
}
|
||||
|
||||
#[superstruct(
|
||||
@@ -141,28 +176,41 @@ pub trait AbstractExecPayload<E: EthSpec>:
|
||||
Decode,
|
||||
TestRandom,
|
||||
TreeHash,
|
||||
Derivative,
|
||||
arbitrary::Arbitrary,
|
||||
Educe,
|
||||
),
|
||||
derivative(PartialEq, Hash(bound = "E: EthSpec")),
|
||||
educe(PartialEq, Hash(bound(E: EthSpec))),
|
||||
serde(bound = "E: EthSpec", deny_unknown_fields),
|
||||
arbitrary(bound = "E: EthSpec"),
|
||||
cfg_attr(
|
||||
feature = "arbitrary",
|
||||
derive(arbitrary::Arbitrary),
|
||||
arbitrary(bound = "E: EthSpec"),
|
||||
),
|
||||
ssz(struct_behaviour = "transparent"),
|
||||
),
|
||||
ref_attributes(
|
||||
derive(Debug, Derivative, TreeHash),
|
||||
derivative(PartialEq, Hash(bound = "E: EthSpec")),
|
||||
derive(Debug, Educe, TreeHash),
|
||||
educe(PartialEq, Hash(bound(E: EthSpec))),
|
||||
tree_hash(enum_behaviour = "transparent"),
|
||||
),
|
||||
map_into(ExecutionPayload),
|
||||
map_ref_into(ExecutionPayloadRef),
|
||||
cast_error(ty = "Error", expr = "BeaconStateError::IncorrectStateVariant"),
|
||||
partial_getter_error(ty = "Error", expr = "BeaconStateError::IncorrectStateVariant")
|
||||
cast_error(
|
||||
ty = "BeaconStateError",
|
||||
expr = "BeaconStateError::IncorrectStateVariant"
|
||||
),
|
||||
partial_getter_error(
|
||||
ty = "BeaconStateError",
|
||||
expr = "BeaconStateError::IncorrectStateVariant"
|
||||
)
|
||||
)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, TreeHash, Derivative, arbitrary::Arbitrary)]
|
||||
#[derivative(PartialEq, Hash(bound = "E: EthSpec"))]
|
||||
#[cfg_attr(
|
||||
feature = "arbitrary",
|
||||
derive(arbitrary::Arbitrary),
|
||||
arbitrary(bound = "E: EthSpec")
|
||||
)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, TreeHash, Educe)]
|
||||
#[educe(PartialEq, Hash(bound(E: EthSpec)))]
|
||||
#[serde(bound = "E: EthSpec")]
|
||||
#[arbitrary(bound = "E: EthSpec")]
|
||||
#[tree_hash(enum_behaviour = "transparent")]
|
||||
pub struct FullPayload<E: EthSpec> {
|
||||
#[superstruct(
|
||||
@@ -284,36 +332,26 @@ impl<E: EthSpec> ExecPayload<E> for FullPayload<E> {
|
||||
})
|
||||
}
|
||||
|
||||
fn withdrawals_root(&self) -> Result<Hash256, Error> {
|
||||
fn withdrawals_root(&self) -> Result<Hash256, BeaconStateError> {
|
||||
match self {
|
||||
FullPayload::Bellatrix(_) => Err(Error::IncorrectStateVariant),
|
||||
FullPayload::Capella(ref inner) => {
|
||||
Ok(inner.execution_payload.withdrawals.tree_hash_root())
|
||||
}
|
||||
FullPayload::Deneb(ref inner) => {
|
||||
Ok(inner.execution_payload.withdrawals.tree_hash_root())
|
||||
}
|
||||
FullPayload::Electra(ref inner) => {
|
||||
Ok(inner.execution_payload.withdrawals.tree_hash_root())
|
||||
}
|
||||
FullPayload::Eip7805(ref inner) => {
|
||||
Ok(inner.execution_payload.withdrawals.tree_hash_root())
|
||||
}
|
||||
FullPayload::Fulu(ref inner) => {
|
||||
Ok(inner.execution_payload.withdrawals.tree_hash_root())
|
||||
}
|
||||
FullPayload::Bellatrix(_) => Err(BeaconStateError::IncorrectStateVariant),
|
||||
FullPayload::Capella(inner) => Ok(inner.execution_payload.withdrawals.tree_hash_root()),
|
||||
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::Eip7805(inner) => Ok(inner.execution_payload.withdrawals.tree_hash_root()),
|
||||
}
|
||||
}
|
||||
|
||||
fn blob_gas_used(&self) -> Result<u64, Error> {
|
||||
fn blob_gas_used(&self) -> Result<u64, BeaconStateError> {
|
||||
match self {
|
||||
FullPayload::Bellatrix(_) | FullPayload::Capella(_) => {
|
||||
Err(Error::IncorrectStateVariant)
|
||||
Err(BeaconStateError::IncorrectStateVariant)
|
||||
}
|
||||
FullPayload::Deneb(ref inner) => Ok(inner.execution_payload.blob_gas_used),
|
||||
FullPayload::Electra(ref inner) => Ok(inner.execution_payload.blob_gas_used),
|
||||
FullPayload::Eip7805(ref inner) => Ok(inner.execution_payload.blob_gas_used),
|
||||
FullPayload::Fulu(ref inner) => Ok(inner.execution_payload.blob_gas_used),
|
||||
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::Eip7805(inner) => Ok(inner.execution_payload.blob_gas_used),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -337,15 +375,16 @@ impl<E: EthSpec> FullPayload<E> {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn default_at_fork(fork_name: ForkName) -> Result<Self, Error> {
|
||||
pub fn default_at_fork(fork_name: ForkName) -> Result<Self, BeaconStateError> {
|
||||
match fork_name {
|
||||
ForkName::Base | ForkName::Altair => Err(Error::IncorrectStateVariant),
|
||||
ForkName::Base | ForkName::Altair => Err(BeaconStateError::IncorrectStateVariant),
|
||||
ForkName::Bellatrix => Ok(FullPayloadBellatrix::default().into()),
|
||||
ForkName::Capella => Ok(FullPayloadCapella::default().into()),
|
||||
ForkName::Deneb => Ok(FullPayloadDeneb::default().into()),
|
||||
ForkName::Electra => Ok(FullPayloadElectra::default().into()),
|
||||
ForkName::Eip7805 => Ok(FullPayloadEip7805::default().into()),
|
||||
ForkName::Fulu => Ok(FullPayloadFulu::default().into()),
|
||||
ForkName::Gloas => Err(BeaconStateError::IncorrectStateVariant),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -433,9 +472,9 @@ impl<E: EthSpec> ExecPayload<E> for FullPayloadRef<'_, E> {
|
||||
})
|
||||
}
|
||||
|
||||
fn withdrawals_root(&self) -> Result<Hash256, Error> {
|
||||
fn withdrawals_root(&self) -> Result<Hash256, BeaconStateError> {
|
||||
match self {
|
||||
FullPayloadRef::Bellatrix(_) => Err(Error::IncorrectStateVariant),
|
||||
FullPayloadRef::Bellatrix(_) => Err(BeaconStateError::IncorrectStateVariant),
|
||||
FullPayloadRef::Capella(inner) => {
|
||||
Ok(inner.execution_payload.withdrawals.tree_hash_root())
|
||||
}
|
||||
@@ -452,10 +491,10 @@ impl<E: EthSpec> ExecPayload<E> for FullPayloadRef<'_, E> {
|
||||
}
|
||||
}
|
||||
|
||||
fn blob_gas_used(&self) -> Result<u64, Error> {
|
||||
fn blob_gas_used(&self) -> Result<u64, BeaconStateError> {
|
||||
match self {
|
||||
FullPayloadRef::Bellatrix(_) | FullPayloadRef::Capella(_) => {
|
||||
Err(Error::IncorrectStateVariant)
|
||||
Err(BeaconStateError::IncorrectStateVariant)
|
||||
}
|
||||
FullPayloadRef::Deneb(inner) => Ok(inner.execution_payload.blob_gas_used),
|
||||
FullPayloadRef::Electra(inner) => Ok(inner.execution_payload.blob_gas_used),
|
||||
@@ -514,27 +553,40 @@ impl<E: EthSpec> TryFrom<ExecutionPayloadHeader<E>> for FullPayload<E> {
|
||||
Decode,
|
||||
TestRandom,
|
||||
TreeHash,
|
||||
Derivative,
|
||||
arbitrary::Arbitrary
|
||||
Educe,
|
||||
),
|
||||
derivative(PartialEq, Hash(bound = "E: EthSpec")),
|
||||
educe(PartialEq, Hash(bound(E: EthSpec))),
|
||||
serde(bound = "E: EthSpec", deny_unknown_fields),
|
||||
arbitrary(bound = "E: EthSpec"),
|
||||
cfg_attr(
|
||||
feature = "arbitrary",
|
||||
derive(arbitrary::Arbitrary),
|
||||
arbitrary(bound = "E: EthSpec"),
|
||||
),
|
||||
ssz(struct_behaviour = "transparent"),
|
||||
),
|
||||
ref_attributes(
|
||||
derive(Debug, Derivative, TreeHash),
|
||||
derivative(PartialEq, Hash(bound = "E: EthSpec")),
|
||||
derive(Debug, Educe, TreeHash),
|
||||
educe(PartialEq, Hash(bound(E: EthSpec))),
|
||||
tree_hash(enum_behaviour = "transparent"),
|
||||
),
|
||||
map_into(ExecutionPayloadHeader),
|
||||
cast_error(ty = "Error", expr = "BeaconStateError::IncorrectStateVariant"),
|
||||
partial_getter_error(ty = "Error", expr = "BeaconStateError::IncorrectStateVariant")
|
||||
cast_error(
|
||||
ty = "BeaconStateError",
|
||||
expr = "BeaconStateError::IncorrectStateVariant"
|
||||
),
|
||||
partial_getter_error(
|
||||
ty = "BeaconStateError",
|
||||
expr = "BeaconStateError::IncorrectStateVariant"
|
||||
)
|
||||
)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, TreeHash, Derivative, arbitrary::Arbitrary)]
|
||||
#[derivative(PartialEq, Hash(bound = "E: EthSpec"))]
|
||||
#[cfg_attr(
|
||||
feature = "arbitrary",
|
||||
derive(arbitrary::Arbitrary),
|
||||
arbitrary(bound = "E: EthSpec")
|
||||
)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, TreeHash, Educe)]
|
||||
#[educe(PartialEq, Hash(bound(E: EthSpec)))]
|
||||
#[serde(bound = "E: EthSpec")]
|
||||
#[arbitrary(bound = "E: EthSpec")]
|
||||
#[tree_hash(enum_behaviour = "transparent")]
|
||||
pub struct BlindedPayload<E: EthSpec> {
|
||||
#[superstruct(
|
||||
@@ -634,32 +686,26 @@ impl<E: EthSpec> ExecPayload<E> for BlindedPayload<E> {
|
||||
None
|
||||
}
|
||||
|
||||
fn withdrawals_root(&self) -> Result<Hash256, Error> {
|
||||
fn withdrawals_root(&self) -> Result<Hash256, BeaconStateError> {
|
||||
match self {
|
||||
BlindedPayload::Bellatrix(_) => Err(Error::IncorrectStateVariant),
|
||||
BlindedPayload::Capella(ref inner) => {
|
||||
Ok(inner.execution_payload_header.withdrawals_root)
|
||||
}
|
||||
BlindedPayload::Deneb(ref inner) => Ok(inner.execution_payload_header.withdrawals_root),
|
||||
BlindedPayload::Electra(ref inner) => {
|
||||
Ok(inner.execution_payload_header.withdrawals_root)
|
||||
}
|
||||
BlindedPayload::Eip7805(ref inner) => {
|
||||
Ok(inner.execution_payload_header.withdrawals_root)
|
||||
}
|
||||
BlindedPayload::Fulu(ref inner) => Ok(inner.execution_payload_header.withdrawals_root),
|
||||
BlindedPayload::Bellatrix(_) => Err(BeaconStateError::IncorrectStateVariant),
|
||||
BlindedPayload::Capella(inner) => Ok(inner.execution_payload_header.withdrawals_root),
|
||||
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::Eip7805(inner) => Ok(inner.execution_payload_header.withdrawals_root),
|
||||
}
|
||||
}
|
||||
|
||||
fn blob_gas_used(&self) -> Result<u64, Error> {
|
||||
fn blob_gas_used(&self) -> Result<u64, BeaconStateError> {
|
||||
match self {
|
||||
BlindedPayload::Bellatrix(_) | BlindedPayload::Capella(_) => {
|
||||
Err(Error::IncorrectStateVariant)
|
||||
Err(BeaconStateError::IncorrectStateVariant)
|
||||
}
|
||||
BlindedPayload::Deneb(ref inner) => Ok(inner.execution_payload_header.blob_gas_used),
|
||||
BlindedPayload::Electra(ref inner) => Ok(inner.execution_payload_header.blob_gas_used),
|
||||
BlindedPayload::Eip7805(ref inner) => Ok(inner.execution_payload_header.blob_gas_used),
|
||||
BlindedPayload::Fulu(ref inner) => Ok(inner.execution_payload_header.blob_gas_used),
|
||||
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::Eip7805(inner) => Ok(inner.execution_payload_header.blob_gas_used),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -748,9 +794,9 @@ impl<'b, E: EthSpec> ExecPayload<E> for BlindedPayloadRef<'b, E> {
|
||||
None
|
||||
}
|
||||
|
||||
fn withdrawals_root(&self) -> Result<Hash256, Error> {
|
||||
fn withdrawals_root(&self) -> Result<Hash256, BeaconStateError> {
|
||||
match self {
|
||||
BlindedPayloadRef::Bellatrix(_) => Err(Error::IncorrectStateVariant),
|
||||
BlindedPayloadRef::Bellatrix(_) => Err(BeaconStateError::IncorrectStateVariant),
|
||||
BlindedPayloadRef::Capella(inner) => {
|
||||
Ok(inner.execution_payload_header.withdrawals_root)
|
||||
}
|
||||
@@ -765,10 +811,10 @@ impl<'b, E: EthSpec> ExecPayload<E> for BlindedPayloadRef<'b, E> {
|
||||
}
|
||||
}
|
||||
|
||||
fn blob_gas_used(&self) -> Result<u64, Error> {
|
||||
fn blob_gas_used(&self) -> Result<u64, BeaconStateError> {
|
||||
match self {
|
||||
BlindedPayloadRef::Bellatrix(_) | BlindedPayloadRef::Capella(_) => {
|
||||
Err(Error::IncorrectStateVariant)
|
||||
Err(BeaconStateError::IncorrectStateVariant)
|
||||
}
|
||||
BlindedPayloadRef::Deneb(inner) => Ok(inner.execution_payload_header.blob_gas_used),
|
||||
BlindedPayloadRef::Electra(inner) => Ok(inner.execution_payload_header.blob_gas_used),
|
||||
@@ -861,12 +907,12 @@ macro_rules! impl_exec_payload_common {
|
||||
f(self)
|
||||
}
|
||||
|
||||
fn withdrawals_root(&self) -> Result<Hash256, Error> {
|
||||
fn withdrawals_root(&self) -> Result<Hash256, BeaconStateError> {
|
||||
let g = $g;
|
||||
g(self)
|
||||
}
|
||||
|
||||
fn blob_gas_used(&self) -> Result<u64, Error> {
|
||||
fn blob_gas_used(&self) -> Result<u64, BeaconStateError> {
|
||||
let h = $h;
|
||||
h(self)
|
||||
}
|
||||
@@ -901,15 +947,16 @@ macro_rules! impl_exec_payload_for_fork {
|
||||
},
|
||||
{ |_| { None } },
|
||||
{
|
||||
let c: for<'a> fn(&'a $wrapper_type_header<E>) -> Result<Hash256, Error> =
|
||||
|payload: &$wrapper_type_header<E>| {
|
||||
let wrapper_ref_type = BlindedPayloadRef::$fork_variant(&payload);
|
||||
wrapper_ref_type.withdrawals_root()
|
||||
};
|
||||
let c: for<'a> fn(
|
||||
&'a $wrapper_type_header<E>,
|
||||
) -> Result<Hash256, BeaconStateError> = |payload: &$wrapper_type_header<E>| {
|
||||
let wrapper_ref_type = BlindedPayloadRef::$fork_variant(&payload);
|
||||
wrapper_ref_type.withdrawals_root()
|
||||
};
|
||||
c
|
||||
},
|
||||
{
|
||||
let c: for<'a> fn(&'a $wrapper_type_header<E>) -> Result<u64, Error> =
|
||||
let c: for<'a> fn(&'a $wrapper_type_header<E>) -> Result<u64, BeaconStateError> =
|
||||
|payload: &$wrapper_type_header<E>| {
|
||||
let wrapper_ref_type = BlindedPayloadRef::$fork_variant(&payload);
|
||||
wrapper_ref_type.blob_gas_used()
|
||||
@@ -919,12 +966,12 @@ macro_rules! impl_exec_payload_for_fork {
|
||||
);
|
||||
|
||||
impl<E: EthSpec> TryInto<$wrapper_type_header<E>> for BlindedPayload<E> {
|
||||
type Error = Error;
|
||||
type Error = BeaconStateError;
|
||||
|
||||
fn try_into(self) -> Result<$wrapper_type_header<E>, Self::Error> {
|
||||
match self {
|
||||
BlindedPayload::$fork_variant(payload) => Ok(payload),
|
||||
_ => Err(Error::IncorrectStateVariant),
|
||||
_ => Err(BeaconStateError::IncorrectStateVariant),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -947,13 +994,13 @@ macro_rules! impl_exec_payload_for_fork {
|
||||
}
|
||||
|
||||
impl<E: EthSpec> TryFrom<ExecutionPayloadHeader<E>> for $wrapper_type_header<E> {
|
||||
type Error = Error;
|
||||
type Error = BeaconStateError;
|
||||
fn try_from(header: ExecutionPayloadHeader<E>) -> Result<Self, Self::Error> {
|
||||
match header {
|
||||
ExecutionPayloadHeader::$fork_variant(execution_payload_header) => {
|
||||
Ok(execution_payload_header.into())
|
||||
}
|
||||
_ => Err(Error::PayloadConversionLogicFlaw),
|
||||
_ => Err(BeaconStateError::PayloadConversionLogicFlaw),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -988,7 +1035,7 @@ macro_rules! impl_exec_payload_for_fork {
|
||||
c
|
||||
},
|
||||
{
|
||||
let c: for<'a> fn(&'a $wrapper_type_full<E>) -> Result<Hash256, Error> =
|
||||
let c: for<'a> fn(&'a $wrapper_type_full<E>) -> Result<Hash256, BeaconStateError> =
|
||||
|payload: &$wrapper_type_full<E>| {
|
||||
let wrapper_ref_type = FullPayloadRef::$fork_variant(&payload);
|
||||
wrapper_ref_type.withdrawals_root()
|
||||
@@ -996,7 +1043,7 @@ macro_rules! impl_exec_payload_for_fork {
|
||||
c
|
||||
},
|
||||
{
|
||||
let c: for<'a> fn(&'a $wrapper_type_full<E>) -> Result<u64, Error> =
|
||||
let c: for<'a> fn(&'a $wrapper_type_full<E>) -> Result<u64, BeaconStateError> =
|
||||
|payload: &$wrapper_type_full<E>| {
|
||||
let wrapper_ref_type = FullPayloadRef::$fork_variant(&payload);
|
||||
wrapper_ref_type.blob_gas_used()
|
||||
@@ -1023,26 +1070,26 @@ macro_rules! impl_exec_payload_for_fork {
|
||||
}
|
||||
|
||||
impl<E: EthSpec> TryFrom<ExecutionPayloadHeader<E>> for $wrapper_type_full<E> {
|
||||
type Error = Error;
|
||||
type Error = BeaconStateError;
|
||||
fn try_from(_: ExecutionPayloadHeader<E>) -> Result<Self, Self::Error> {
|
||||
Err(Error::PayloadConversionLogicFlaw)
|
||||
Err(BeaconStateError::PayloadConversionLogicFlaw)
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EthSpec> TryFrom<$wrapped_type_header<E>> for $wrapper_type_full<E> {
|
||||
type Error = Error;
|
||||
type Error = BeaconStateError;
|
||||
fn try_from(_: $wrapped_type_header<E>) -> Result<Self, Self::Error> {
|
||||
Err(Error::PayloadConversionLogicFlaw)
|
||||
Err(BeaconStateError::PayloadConversionLogicFlaw)
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EthSpec> TryInto<$wrapper_type_full<E>> for FullPayload<E> {
|
||||
type Error = Error;
|
||||
type Error = BeaconStateError;
|
||||
|
||||
fn try_into(self) -> Result<$wrapper_type_full<E>, Self::Error> {
|
||||
match self {
|
||||
FullPayload::$fork_variant(payload) => Ok(payload),
|
||||
_ => Err(Error::PayloadConversionLogicFlaw),
|
||||
_ => Err(BeaconStateError::PayloadConversionLogicFlaw),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,23 +1,15 @@
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::*;
|
||||
use bls::Signature;
|
||||
use context_deserialize::context_deserialize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
use crate::{execution::BlsToExecutionChange, fork::ForkName, test_utils::TestRandom};
|
||||
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
#[derive(
|
||||
arbitrary::Arbitrary,
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
Hash,
|
||||
Clone,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
TreeHash,
|
||||
TestRandom,
|
||||
Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom,
|
||||
)]
|
||||
#[context_deserialize(ForkName)]
|
||||
pub struct SignedBlsToExecutionChange {
|
||||
@@ -0,0 +1,35 @@
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::{ExecutionPayloadBid, ForkName};
|
||||
use bls::Signature;
|
||||
use context_deserialize::context_deserialize;
|
||||
use educe::Educe;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
#[derive(TestRandom, TreeHash, Debug, Clone, Encode, Decode, Serialize, Deserialize, Educe)]
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
#[educe(PartialEq, Hash)]
|
||||
#[context_deserialize(ForkName)]
|
||||
// https://github.com/ethereum/consensus-specs/blob/master/specs/gloas/beacon-chain.md#signedexecutionpayloadbid
|
||||
pub struct SignedExecutionPayloadBid {
|
||||
pub message: ExecutionPayloadBid,
|
||||
pub signature: Signature,
|
||||
}
|
||||
|
||||
impl SignedExecutionPayloadBid {
|
||||
pub fn empty() -> Self {
|
||||
Self {
|
||||
message: ExecutionPayloadBid::default(),
|
||||
signature: Signature::empty(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
ssz_and_tree_hash_tests!(SignedExecutionPayloadBid);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::{EthSpec, ExecutionPayloadEnvelope};
|
||||
use bls::Signature;
|
||||
use educe::Educe;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Encode, Decode, Deserialize, TestRandom, TreeHash, Educe)]
|
||||
#[educe(PartialEq, Hash(bound(E: EthSpec)))]
|
||||
#[serde(bound = "E: EthSpec")]
|
||||
pub struct SignedExecutionPayloadEnvelope<E: EthSpec> {
|
||||
pub message: ExecutionPayloadEnvelope<E>,
|
||||
pub signature: Signature,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::MainnetEthSpec;
|
||||
|
||||
ssz_and_tree_hash_tests!(SignedExecutionPayloadEnvelope<MainnetEthSpec>);
|
||||
}
|
||||
5
consensus/types/src/exit/mod.rs
Normal file
5
consensus/types/src/exit/mod.rs
Normal file
@@ -0,0 +1,5 @@
|
||||
mod signed_voluntary_exit;
|
||||
mod voluntary_exit;
|
||||
|
||||
pub use signed_voluntary_exit::SignedVoluntaryExit;
|
||||
pub use voluntary_exit::VoluntaryExit;
|
||||
@@ -1,27 +1,18 @@
|
||||
use crate::context_deserialize;
|
||||
use crate::{test_utils::TestRandom, ForkName, VoluntaryExit};
|
||||
use bls::Signature;
|
||||
|
||||
use context_deserialize::context_deserialize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
use crate::{exit::VoluntaryExit, fork::ForkName, test_utils::TestRandom};
|
||||
|
||||
/// An exit voluntarily submitted a validator who wishes to withdraw.
|
||||
///
|
||||
/// Spec v0.12.1
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
#[derive(
|
||||
arbitrary::Arbitrary,
|
||||
Debug,
|
||||
PartialEq,
|
||||
Hash,
|
||||
Clone,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
TreeHash,
|
||||
TestRandom,
|
||||
Debug, PartialEq, Hash, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom,
|
||||
)]
|
||||
#[context_deserialize(ForkName)]
|
||||
pub struct SignedVoluntaryExit {
|
||||
@@ -1,29 +1,23 @@
|
||||
use crate::context_deserialize;
|
||||
use crate::{
|
||||
test_utils::TestRandom, ChainSpec, Domain, Epoch, ForkName, Hash256, SecretKey, SignedRoot,
|
||||
SignedVoluntaryExit,
|
||||
};
|
||||
|
||||
use bls::SecretKey;
|
||||
use context_deserialize::context_deserialize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
use crate::{
|
||||
core::{ChainSpec, Domain, Epoch, Hash256, SignedRoot},
|
||||
exit::SignedVoluntaryExit,
|
||||
fork::ForkName,
|
||||
test_utils::TestRandom,
|
||||
};
|
||||
|
||||
/// An exit voluntarily submitted a validator who wishes to withdraw.
|
||||
///
|
||||
/// Spec v0.12.1
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
#[derive(
|
||||
arbitrary::Arbitrary,
|
||||
Debug,
|
||||
PartialEq,
|
||||
Hash,
|
||||
Clone,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
TreeHash,
|
||||
TestRandom,
|
||||
Debug, PartialEq, Hash, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom,
|
||||
)]
|
||||
#[context_deserialize(ForkName)]
|
||||
pub struct VoluntaryExit {
|
||||
@@ -1,17 +1,16 @@
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::{Epoch, ForkName};
|
||||
use context_deserialize_derive::context_deserialize;
|
||||
|
||||
use context_deserialize::context_deserialize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
use crate::{core::Epoch, fork::ForkName, test_utils::TestRandom};
|
||||
|
||||
/// Specifies a fork of the `BeaconChain`, to prevent replay attacks.
|
||||
///
|
||||
/// Spec v0.12.1
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
#[derive(
|
||||
arbitrary::Arbitrary,
|
||||
Debug,
|
||||
Clone,
|
||||
Copy,
|
||||
285
consensus/types/src/fork/fork_context.rs
Normal file
285
consensus/types/src/fork/fork_context.rs
Normal file
@@ -0,0 +1,285 @@
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use parking_lot::RwLock;
|
||||
|
||||
use crate::{
|
||||
core::{ChainSpec, Epoch, EthSpec, Hash256, Slot},
|
||||
fork::ForkName,
|
||||
};
|
||||
|
||||
/// Represents a hard fork in the consensus protocol.
|
||||
///
|
||||
/// A hard fork can be one of two types:
|
||||
/// * A named fork (represented by `ForkName`) which introduces protocol changes.
|
||||
/// * A blob-parameter-only (BPO) fork which only modifies blob parameters.
|
||||
///
|
||||
/// For BPO forks, the `fork_name` remains unchanged from the previous fork,
|
||||
/// but the `fork_epoch` and `fork_digest` will be different to reflect the
|
||||
/// new blob parameter changes.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct HardFork {
|
||||
fork_name: ForkName,
|
||||
fork_epoch: Epoch,
|
||||
fork_digest: [u8; 4],
|
||||
}
|
||||
|
||||
impl HardFork {
|
||||
pub fn new(fork_name: ForkName, fork_digest: [u8; 4], fork_epoch: Epoch) -> HardFork {
|
||||
HardFork {
|
||||
fork_name,
|
||||
fork_epoch,
|
||||
fork_digest,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Provides fork specific info like the current fork name and the fork digests corresponding to every valid fork.
|
||||
#[derive(Debug)]
|
||||
pub struct ForkContext {
|
||||
current_fork: RwLock<HardFork>,
|
||||
epoch_to_forks: BTreeMap<Epoch, HardFork>,
|
||||
pub spec: ChainSpec,
|
||||
}
|
||||
|
||||
impl ForkContext {
|
||||
/// Creates a new `ForkContext` object by enumerating all enabled forks and computing their
|
||||
/// fork digest.
|
||||
///
|
||||
/// A fork is disabled in the `ChainSpec` if the activation slot corresponding to that fork is `None`.
|
||||
pub fn new<E: EthSpec>(
|
||||
current_slot: Slot,
|
||||
genesis_validators_root: Hash256,
|
||||
spec: &ChainSpec,
|
||||
) -> Self {
|
||||
let epoch_to_forks: BTreeMap<_, _> = spec
|
||||
.all_digest_epochs()
|
||||
.map(|epoch| {
|
||||
let fork_name = spec.fork_name_at_epoch(epoch);
|
||||
let fork_digest = spec.compute_fork_digest(genesis_validators_root, epoch);
|
||||
(epoch, HardFork::new(fork_name, fork_digest, epoch))
|
||||
})
|
||||
.collect();
|
||||
|
||||
let current_epoch = current_slot.epoch(E::slots_per_epoch());
|
||||
let current_fork = epoch_to_forks
|
||||
.values()
|
||||
.rfind(|&fork| fork.fork_epoch <= current_epoch)
|
||||
.cloned()
|
||||
.expect("should match at least genesis epoch");
|
||||
|
||||
Self {
|
||||
current_fork: RwLock::new(current_fork),
|
||||
epoch_to_forks,
|
||||
spec: spec.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the provided `fork_name` exists in the `ForkContext` object.
|
||||
pub fn fork_exists(&self, fork_name: ForkName) -> bool {
|
||||
self.spec.fork_epoch(fork_name).is_some()
|
||||
}
|
||||
|
||||
/// Returns the current fork name.
|
||||
pub fn current_fork_name(&self) -> ForkName {
|
||||
self.current_fork.read().fork_name
|
||||
}
|
||||
|
||||
/// Returns the current fork epoch.
|
||||
pub fn current_fork_epoch(&self) -> Epoch {
|
||||
self.current_fork.read().fork_epoch
|
||||
}
|
||||
|
||||
/// Returns the current fork digest.
|
||||
pub fn current_fork_digest(&self) -> [u8; 4] {
|
||||
self.current_fork.read().fork_digest
|
||||
}
|
||||
|
||||
/// Returns the next fork digest. If there's no future fork, returns the current fork digest.
|
||||
pub fn next_fork_digest(&self) -> Option<[u8; 4]> {
|
||||
let current_fork_epoch = self.current_fork_epoch();
|
||||
self.epoch_to_forks
|
||||
.range(current_fork_epoch..)
|
||||
.nth(1)
|
||||
.map(|(_, fork)| fork.fork_digest)
|
||||
}
|
||||
|
||||
/// Updates the `digest_epoch` field to a new digest epoch.
|
||||
pub fn update_current_fork(
|
||||
&self,
|
||||
new_fork_name: ForkName,
|
||||
new_fork_digest: [u8; 4],
|
||||
new_fork_epoch: Epoch,
|
||||
) {
|
||||
debug_assert!(self.epoch_to_forks.contains_key(&new_fork_epoch));
|
||||
*self.current_fork.write() = HardFork::new(new_fork_name, new_fork_digest, new_fork_epoch);
|
||||
}
|
||||
|
||||
/// Returns the context bytes/fork_digest corresponding to the genesis fork version.
|
||||
pub fn genesis_context_bytes(&self) -> [u8; 4] {
|
||||
self.epoch_to_forks
|
||||
.first_key_value()
|
||||
.expect("must contain genesis epoch")
|
||||
.1
|
||||
.fork_digest
|
||||
}
|
||||
|
||||
/// Returns the fork type given the context bytes/fork_digest.
|
||||
/// Returns `None` if context bytes doesn't correspond to any valid `ForkName`.
|
||||
pub fn get_fork_from_context_bytes(&self, context: [u8; 4]) -> Option<&ForkName> {
|
||||
self.epoch_to_forks
|
||||
.values()
|
||||
.find(|fork| fork.fork_digest == context)
|
||||
.map(|fork| &fork.fork_name)
|
||||
}
|
||||
|
||||
/// Returns the context bytes/fork_digest corresponding to an epoch.
|
||||
/// See [`ChainSpec::compute_fork_digest`]
|
||||
pub fn context_bytes(&self, epoch: Epoch) -> [u8; 4] {
|
||||
self.epoch_to_forks
|
||||
.range(..=epoch)
|
||||
.next_back()
|
||||
.expect("should match at least genesis epoch")
|
||||
.1
|
||||
.fork_digest
|
||||
}
|
||||
|
||||
/// Returns all `fork_digest`s that are currently in the `ForkContext` object.
|
||||
pub fn all_fork_digests(&self) -> Vec<[u8; 4]> {
|
||||
self.epoch_to_forks
|
||||
.values()
|
||||
.map(|fork| fork.fork_digest)
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::core::{BlobParameters, BlobSchedule, MainnetEthSpec};
|
||||
|
||||
type E = MainnetEthSpec;
|
||||
|
||||
fn make_chain_spec() -> ChainSpec {
|
||||
let blob_parameters = vec![
|
||||
BlobParameters {
|
||||
epoch: Epoch::new(6),
|
||||
max_blobs_per_block: 12,
|
||||
},
|
||||
BlobParameters {
|
||||
epoch: Epoch::new(50),
|
||||
max_blobs_per_block: 24,
|
||||
},
|
||||
BlobParameters {
|
||||
epoch: Epoch::new(100),
|
||||
max_blobs_per_block: 48,
|
||||
},
|
||||
];
|
||||
|
||||
let mut spec = E::default_spec();
|
||||
spec.altair_fork_epoch = Some(Epoch::new(1));
|
||||
spec.bellatrix_fork_epoch = Some(Epoch::new(2));
|
||||
spec.capella_fork_epoch = Some(Epoch::new(3));
|
||||
spec.deneb_fork_epoch = Some(Epoch::new(4));
|
||||
spec.electra_fork_epoch = Some(Epoch::new(5));
|
||||
spec.fulu_fork_epoch = Some(Epoch::new(6));
|
||||
spec.gloas_fork_epoch = Some(Epoch::new(7));
|
||||
spec.blob_schedule = BlobSchedule::new(blob_parameters);
|
||||
spec
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fork_exists() {
|
||||
let spec = make_chain_spec();
|
||||
let genesis_root = Hash256::ZERO;
|
||||
let current_slot = Slot::new(7);
|
||||
|
||||
let context = ForkContext::new::<E>(current_slot, genesis_root, &spec);
|
||||
|
||||
assert!(context.fork_exists(ForkName::Electra));
|
||||
assert!(context.fork_exists(ForkName::Fulu));
|
||||
assert!(context.fork_exists(ForkName::Gloas));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_current_fork_name_and_epoch() {
|
||||
let spec = make_chain_spec();
|
||||
let electra_epoch = spec.electra_fork_epoch.unwrap();
|
||||
let electra_slot = electra_epoch.end_slot(E::slots_per_epoch());
|
||||
let genesis_root = Hash256::ZERO;
|
||||
|
||||
let context = ForkContext::new::<E>(electra_slot, genesis_root, &spec);
|
||||
|
||||
assert_eq!(context.current_fork_name(), ForkName::Electra);
|
||||
assert_eq!(context.current_fork_epoch(), electra_epoch);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_next_fork_digest() {
|
||||
let spec = make_chain_spec();
|
||||
let electra_epoch = spec.electra_fork_epoch.unwrap();
|
||||
let electra_slot = electra_epoch.end_slot(E::slots_per_epoch());
|
||||
let genesis_root = Hash256::ZERO;
|
||||
|
||||
let context = ForkContext::new::<E>(electra_slot, genesis_root, &spec);
|
||||
|
||||
let next_digest = context.next_fork_digest().unwrap();
|
||||
let expected_digest = spec.compute_fork_digest(genesis_root, spec.fulu_fork_epoch.unwrap());
|
||||
assert_eq!(next_digest, expected_digest);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_fork_from_context_bytes() {
|
||||
let spec = make_chain_spec();
|
||||
let genesis_root = Hash256::ZERO;
|
||||
let current_slot = Slot::new(0);
|
||||
|
||||
let context = ForkContext::new::<E>(current_slot, genesis_root, &spec);
|
||||
|
||||
let electra_digest = spec.compute_fork_digest(genesis_root, Epoch::new(5));
|
||||
assert_eq!(
|
||||
context.get_fork_from_context_bytes(electra_digest),
|
||||
Some(&ForkName::Electra)
|
||||
);
|
||||
|
||||
let invalid_digest = [9, 9, 9, 9];
|
||||
assert!(
|
||||
context
|
||||
.get_fork_from_context_bytes(invalid_digest)
|
||||
.is_none()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_context_bytes() {
|
||||
let spec = make_chain_spec();
|
||||
let genesis_root = Hash256::ZERO;
|
||||
let current_slot = Slot::new(0);
|
||||
|
||||
let context = ForkContext::new::<E>(current_slot, genesis_root, &spec);
|
||||
|
||||
assert_eq!(
|
||||
context.context_bytes(Epoch::new(0)),
|
||||
spec.compute_fork_digest(genesis_root, Epoch::new(0))
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
context.context_bytes(Epoch::new(12)),
|
||||
spec.compute_fork_digest(genesis_root, Epoch::new(10))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_all_fork_digests() {
|
||||
let spec = make_chain_spec();
|
||||
let genesis_root = Hash256::ZERO;
|
||||
let current_slot = Slot::new(20);
|
||||
|
||||
let context = ForkContext::new::<MainnetEthSpec>(current_slot, genesis_root, &spec);
|
||||
|
||||
// Get all enabled fork digests
|
||||
let fork_digests = context.all_fork_digests();
|
||||
let expected_digest_count = spec.all_digest_epochs().count();
|
||||
|
||||
assert_eq!(fork_digests.len(), expected_digest_count);
|
||||
}
|
||||
}
|
||||
@@ -1,27 +1,21 @@
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::{ForkName, Hash256, SignedRoot};
|
||||
use context_deserialize_derive::context_deserialize;
|
||||
|
||||
use context_deserialize::context_deserialize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
use crate::{
|
||||
core::{Hash256, SignedRoot},
|
||||
fork::ForkName,
|
||||
test_utils::TestRandom,
|
||||
};
|
||||
|
||||
/// Specifies a fork of the `BeaconChain`, to prevent replay attacks.
|
||||
///
|
||||
/// Spec v0.12.1
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
#[derive(
|
||||
arbitrary::Arbitrary,
|
||||
Debug,
|
||||
Clone,
|
||||
PartialEq,
|
||||
Default,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
TreeHash,
|
||||
TestRandom,
|
||||
Debug, Clone, PartialEq, Default, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom,
|
||||
)]
|
||||
#[context_deserialize(ForkName)]
|
||||
pub struct ForkData {
|
||||
64
consensus/types/src/fork/fork_macros.rs
Normal file
64
consensus/types/src/fork/fork_macros.rs
Normal file
@@ -0,0 +1,64 @@
|
||||
/// Map a fork name into a fork-versioned superstruct type like `BeaconBlock`.
|
||||
///
|
||||
/// The `$body` expression is where the magic happens. The macro allows us to achieve polymorphism
|
||||
/// in the return type, which is not usually possible in Rust without trait objects.
|
||||
///
|
||||
/// E.g. you could call `map_fork_name!(fork, BeaconBlock, serde_json::from_str(s))` to decode
|
||||
/// different `BeaconBlock` variants depending on the value of `fork`. Note how the type of the body
|
||||
/// will change between `BeaconBlockBase` and `BeaconBlockAltair` depending on which branch is
|
||||
/// taken, the important thing is that they are re-unified by injecting them back into the
|
||||
/// `BeaconBlock` parent enum.
|
||||
///
|
||||
/// If you would also like to extract additional data alongside the superstruct type, use
|
||||
/// the more flexible `map_fork_name_with` macro.
|
||||
#[macro_export]
|
||||
macro_rules! map_fork_name {
|
||||
($fork_name:expr, $t:tt, $body:expr) => {
|
||||
$crate::map_fork_name_with!($fork_name, $t, { ($body, ()) }).0
|
||||
};
|
||||
}
|
||||
|
||||
/// Map a fork name into a tuple of `(t, extra)` where `t` is a superstruct type.
|
||||
#[macro_export]
|
||||
macro_rules! map_fork_name_with {
|
||||
($fork_name:expr, $t:tt, $body:block) => {
|
||||
match $fork_name {
|
||||
$crate::fork::ForkName::Base => {
|
||||
let (value, extra_data) = $body;
|
||||
($t::Base(value), extra_data)
|
||||
}
|
||||
$crate::fork::ForkName::Altair => {
|
||||
let (value, extra_data) = $body;
|
||||
($t::Altair(value), extra_data)
|
||||
}
|
||||
$crate::fork::ForkName::Bellatrix => {
|
||||
let (value, extra_data) = $body;
|
||||
($t::Bellatrix(value), extra_data)
|
||||
}
|
||||
$crate::fork::ForkName::Capella => {
|
||||
let (value, extra_data) = $body;
|
||||
($t::Capella(value), extra_data)
|
||||
}
|
||||
$crate::fork::ForkName::Deneb => {
|
||||
let (value, extra_data) = $body;
|
||||
($t::Deneb(value), extra_data)
|
||||
}
|
||||
$crate::fork::ForkName::Electra => {
|
||||
let (value, extra_data) = $body;
|
||||
($t::Electra(value), extra_data)
|
||||
}
|
||||
$crate::fork::ForkName::Fulu => {
|
||||
let (value, extra_data) = $body;
|
||||
($t::Fulu(value), extra_data)
|
||||
}
|
||||
$crate::fork::ForkName::Eip7805 => {
|
||||
let (value, extra_data) = $body;
|
||||
($t::Eip7805(value), extra_data)
|
||||
}
|
||||
$crate::fork::ForkName::Gloas => {
|
||||
let (value, extra_data) = $body;
|
||||
($t::Gloas(value), extra_data)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -1,8 +1,12 @@
|
||||
use crate::{ChainSpec, Epoch};
|
||||
use std::{
|
||||
fmt::{self, Display, Formatter},
|
||||
str::FromStr,
|
||||
};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
use std::str::FromStr;
|
||||
|
||||
use crate::core::{ChainSpec, Epoch};
|
||||
|
||||
#[derive(
|
||||
Debug, Clone, Copy, Decode, Encode, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize,
|
||||
@@ -17,8 +21,9 @@ pub enum ForkName {
|
||||
Capella,
|
||||
Deneb,
|
||||
Electra,
|
||||
Eip7805,
|
||||
Fulu,
|
||||
Eip7805,
|
||||
Gloas,
|
||||
}
|
||||
|
||||
impl ForkName {
|
||||
@@ -30,16 +35,15 @@ impl ForkName {
|
||||
ForkName::Capella,
|
||||
ForkName::Deneb,
|
||||
ForkName::Electra,
|
||||
ForkName::Eip7805,
|
||||
ForkName::Fulu,
|
||||
ForkName::Eip7805,
|
||||
ForkName::Gloas,
|
||||
]
|
||||
}
|
||||
|
||||
pub fn list_all_fork_epochs(spec: &ChainSpec) -> Vec<(ForkName, Option<Epoch>)> {
|
||||
ForkName::list_all()
|
||||
.into_iter()
|
||||
// Skip Base
|
||||
.skip(1)
|
||||
.map(|fork| (fork, spec.fork_epoch(fork)))
|
||||
.collect()
|
||||
}
|
||||
@@ -53,7 +57,7 @@ impl ForkName {
|
||||
/// This fork serves as the baseline for many tests, and the goal
|
||||
/// is to ensure features are passing on this fork.
|
||||
pub fn latest_stable() -> ForkName {
|
||||
ForkName::Electra
|
||||
ForkName::Fulu
|
||||
}
|
||||
|
||||
/// Set the activation slots in the given `ChainSpec` so that the fork named by `self`
|
||||
@@ -67,8 +71,9 @@ impl ForkName {
|
||||
spec.capella_fork_epoch = None;
|
||||
spec.deneb_fork_epoch = None;
|
||||
spec.electra_fork_epoch = None;
|
||||
spec.eip7805_fork_epoch = None;
|
||||
spec.fulu_fork_epoch = None;
|
||||
spec.eip7805_fork_epoch = None;
|
||||
spec.gloas_fork_epoch = None;
|
||||
spec
|
||||
}
|
||||
ForkName::Altair => {
|
||||
@@ -77,8 +82,9 @@ impl ForkName {
|
||||
spec.capella_fork_epoch = None;
|
||||
spec.deneb_fork_epoch = None;
|
||||
spec.electra_fork_epoch = None;
|
||||
spec.eip7805_fork_epoch = None;
|
||||
spec.fulu_fork_epoch = None;
|
||||
spec.eip7805_fork_epoch = None;
|
||||
spec.gloas_fork_epoch = None;
|
||||
spec
|
||||
}
|
||||
ForkName::Bellatrix => {
|
||||
@@ -87,8 +93,9 @@ impl ForkName {
|
||||
spec.capella_fork_epoch = None;
|
||||
spec.deneb_fork_epoch = None;
|
||||
spec.electra_fork_epoch = None;
|
||||
spec.eip7805_fork_epoch = None;
|
||||
spec.fulu_fork_epoch = None;
|
||||
spec.eip7805_fork_epoch = None;
|
||||
spec.gloas_fork_epoch = None;
|
||||
spec
|
||||
}
|
||||
ForkName::Capella => {
|
||||
@@ -97,8 +104,9 @@ impl ForkName {
|
||||
spec.capella_fork_epoch = Some(Epoch::new(0));
|
||||
spec.deneb_fork_epoch = None;
|
||||
spec.electra_fork_epoch = None;
|
||||
spec.eip7805_fork_epoch = None;
|
||||
spec.fulu_fork_epoch = None;
|
||||
spec.eip7805_fork_epoch = None;
|
||||
spec.gloas_fork_epoch = None;
|
||||
spec
|
||||
}
|
||||
ForkName::Deneb => {
|
||||
@@ -107,8 +115,9 @@ impl ForkName {
|
||||
spec.capella_fork_epoch = Some(Epoch::new(0));
|
||||
spec.deneb_fork_epoch = Some(Epoch::new(0));
|
||||
spec.electra_fork_epoch = None;
|
||||
spec.eip7805_fork_epoch = None;
|
||||
spec.fulu_fork_epoch = None;
|
||||
spec.eip7805_fork_epoch = None;
|
||||
spec.gloas_fork_epoch = None;
|
||||
spec
|
||||
}
|
||||
ForkName::Electra => {
|
||||
@@ -117,18 +126,8 @@ impl ForkName {
|
||||
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 = None;
|
||||
spec.eip7805_fork_epoch = None;
|
||||
spec.fulu_fork_epoch = None;
|
||||
spec
|
||||
}
|
||||
ForkName::Eip7805 => {
|
||||
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.eip7805_fork_epoch = Some(Epoch::new(0));
|
||||
spec.fulu_fork_epoch = None;
|
||||
spec
|
||||
}
|
||||
ForkName::Fulu => {
|
||||
@@ -137,8 +136,30 @@ impl ForkName {
|
||||
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.eip7805_fork_epoch = Some(Epoch::new(0));
|
||||
spec.fulu_fork_epoch = Some(Epoch::new(0));
|
||||
spec.eip7805_fork_epoch = None;
|
||||
spec.gloas_fork_epoch = None;
|
||||
spec
|
||||
}
|
||||
ForkName::Eip7805 => {
|
||||
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 = 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.eip7805_fork_epoch = Some(Epoch::new(0));
|
||||
spec.gloas_fork_epoch = Some(Epoch::new(0));
|
||||
spec
|
||||
}
|
||||
}
|
||||
@@ -146,7 +167,7 @@ impl ForkName {
|
||||
|
||||
/// Return the name of the fork immediately prior to the current one.
|
||||
///
|
||||
/// If `self` is `ForkName::Base` then `Base` is returned.
|
||||
/// If `self` is `ForkName::Base` then `None` is returned.
|
||||
pub fn previous_fork(self) -> Option<ForkName> {
|
||||
match self {
|
||||
ForkName::Base => None,
|
||||
@@ -155,8 +176,9 @@ impl ForkName {
|
||||
ForkName::Capella => Some(ForkName::Bellatrix),
|
||||
ForkName::Deneb => Some(ForkName::Capella),
|
||||
ForkName::Electra => Some(ForkName::Deneb),
|
||||
ForkName::Eip7805 => Some(ForkName::Electra),
|
||||
ForkName::Fulu => Some(ForkName::Eip7805),
|
||||
ForkName::Fulu => Some(ForkName::Electra),
|
||||
ForkName::Eip7805 => Some(ForkName::Fulu),
|
||||
ForkName::Gloas => Some(ForkName::Eip7805),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,9 +192,10 @@ impl ForkName {
|
||||
ForkName::Bellatrix => Some(ForkName::Capella),
|
||||
ForkName::Capella => Some(ForkName::Deneb),
|
||||
ForkName::Deneb => Some(ForkName::Electra),
|
||||
ForkName::Electra => Some(ForkName::Eip7805),
|
||||
ForkName::Eip7805 => Some(ForkName::Fulu),
|
||||
ForkName::Fulu => None,
|
||||
ForkName::Electra => Some(ForkName::Fulu),
|
||||
ForkName::Fulu => Some(ForkName::Eip7805),
|
||||
ForkName::Eip7805 => Some(ForkName::Gloas),
|
||||
ForkName::Gloas => None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,74 +219,57 @@ impl ForkName {
|
||||
self >= ForkName::Electra
|
||||
}
|
||||
|
||||
pub fn fulu_enabled(self) -> bool {
|
||||
self >= ForkName::Fulu
|
||||
}
|
||||
|
||||
pub fn eip7805_enabled(self) -> bool {
|
||||
self >= ForkName::Eip7805
|
||||
}
|
||||
|
||||
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`.
|
||||
///
|
||||
/// The `$body` expression is where the magic happens. The macro allows us to achieve polymorphism
|
||||
/// in the return type, which is not usually possible in Rust without trait objects.
|
||||
///
|
||||
/// E.g. you could call `map_fork_name!(fork, BeaconBlock, serde_json::from_str(s))` to decode
|
||||
/// different `BeaconBlock` variants depending on the value of `fork`. Note how the type of the body
|
||||
/// will change between `BeaconBlockBase` and `BeaconBlockAltair` depending on which branch is
|
||||
/// taken, the important thing is that they are re-unified by injecting them back into the
|
||||
/// `BeaconBlock` parent enum.
|
||||
///
|
||||
/// If you would also like to extract additional data alongside the superstruct type, use
|
||||
/// the more flexible `map_fork_name_with` macro.
|
||||
#[macro_export]
|
||||
macro_rules! map_fork_name {
|
||||
($fork_name:expr, $t:tt, $body:expr) => {
|
||||
map_fork_name_with!($fork_name, $t, { ($body, ()) }).0
|
||||
};
|
||||
}
|
||||
|
||||
/// Map a fork name into a tuple of `(t, extra)` where `t` is a superstruct type.
|
||||
#[macro_export]
|
||||
macro_rules! map_fork_name_with {
|
||||
($fork_name:expr, $t:tt, $body:block) => {
|
||||
match $fork_name {
|
||||
ForkName::Base => {
|
||||
let (value, extra_data) = $body;
|
||||
($t::Base(value), extra_data)
|
||||
}
|
||||
ForkName::Altair => {
|
||||
let (value, extra_data) = $body;
|
||||
($t::Altair(value), extra_data)
|
||||
}
|
||||
ForkName::Bellatrix => {
|
||||
let (value, extra_data) = $body;
|
||||
($t::Bellatrix(value), extra_data)
|
||||
}
|
||||
ForkName::Capella => {
|
||||
let (value, extra_data) = $body;
|
||||
($t::Capella(value), extra_data)
|
||||
}
|
||||
ForkName::Deneb => {
|
||||
let (value, extra_data) = $body;
|
||||
($t::Deneb(value), extra_data)
|
||||
}
|
||||
ForkName::Electra => {
|
||||
let (value, extra_data) = $body;
|
||||
($t::Electra(value), extra_data)
|
||||
}
|
||||
ForkName::Eip7805 => {
|
||||
let (value, extra_data) = $body;
|
||||
($t::Eip7805(value), extra_data)
|
||||
}
|
||||
ForkName::Fulu => {
|
||||
let (value, extra_data) = $body;
|
||||
($t::Fulu(value), extra_data)
|
||||
}
|
||||
pub fn fork_ascii(self) {
|
||||
if self == ForkName::Fulu {
|
||||
println!(
|
||||
r#"
|
||||
╔═══════════════════════════════════════╗
|
||||
║ ║
|
||||
║ TO FULU, MOAR BLOBS TO ETHEREUM ║
|
||||
║ ║
|
||||
║ III DECEMBER MMXXV ║
|
||||
║ ║
|
||||
╚═══════════════════════════════════════╝
|
||||
|
||||
=============================================================================
|
||||
|||| ||||
|
||||
|---------------------------------------------------------------------------|
|
||||
|___-----___-----___-----___-----___-----___-----___-----___-----___-----___|
|
||||
/ _ \===/ _ \ / _ \===/ _ \ / _ \===/ _ \ / _ \===/ _ \
|
||||
( (.\ oOo /.) ) ( (.\ oOo /.) ) ( (.\ oOo /.) ) ( (.\ oOo /.) )
|
||||
\__/=====\__/ \__/=====\__/ \__/=====\__/ \__/=====\__/
|
||||
||||||| ||||||| ||||||| |||||||
|
||||
||||||| ||||||| \\/), ||||||| |||||||
|
||||
||||||| ||||||| ,'.' /, ||||||| |||||||
|
||||
||||||| ||||||| (_)- / /, ||||||| |||||||
|
||||
||||||| ||||||| /\_/ |__..--, * ||||||| |||||||
|
||||
||||||| ||||||| (\___/\ \ \ / ).' ||||||| |||||||
|
||||
||||||| ||||||| \____/ / (_ // ||||||| |||||||
|
||||
||||||| ||||||| \\_ ,'--'\_( ||||||| |||||||
|
||||
(oOoOo) (oOoOo) )_)_/ )_/ )_) (oOoOo) (oOoOo)
|
||||
J%%%%%L J%%%%%L (_(_.'(_.'(_.' J%%%%%L J%%%%%L
|
||||
ZZZZZZZZZ ZZZZZZZZZ ZZZZZZZZZ ZZZZZZZZZ
|
||||
===========================================================================
|
||||
|_________________________________________________________________________|
|
||||
|___________________________________________________________________________|
|
||||
|_____________________________________________________________________________|
|
||||
|_______________________________________________________________________________|
|
||||
"#
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for ForkName {
|
||||
@@ -279,6 +285,7 @@ impl FromStr for ForkName {
|
||||
"electra" => ForkName::Electra,
|
||||
"eip7805" => ForkName::Eip7805,
|
||||
"fulu" => ForkName::Fulu,
|
||||
"gloas" => ForkName::Gloas,
|
||||
_ => return Err(format!("unknown fork name: {}", fork_name)),
|
||||
})
|
||||
}
|
||||
@@ -295,6 +302,7 @@ impl Display for ForkName {
|
||||
ForkName::Electra => "electra".fmt(f),
|
||||
ForkName::Eip7805 => "eip7805".fmt(f),
|
||||
ForkName::Fulu => "fulu".fmt(f),
|
||||
ForkName::Gloas => "gloas".fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
6
consensus/types/src/fork/fork_version_decode.rs
Normal file
6
consensus/types/src/fork/fork_version_decode.rs
Normal file
@@ -0,0 +1,6 @@
|
||||
use crate::fork::ForkName;
|
||||
|
||||
pub trait ForkVersionDecode: Sized {
|
||||
/// SSZ decode with explicit fork variant.
|
||||
fn from_ssz_bytes_by_fork(bytes: &[u8], fork_name: ForkName) -> Result<Self, ssz::DecodeError>;
|
||||
}
|
||||
15
consensus/types/src/fork/mod.rs
Normal file
15
consensus/types/src/fork/mod.rs
Normal file
@@ -0,0 +1,15 @@
|
||||
mod fork;
|
||||
mod fork_context;
|
||||
mod fork_data;
|
||||
mod fork_macros;
|
||||
mod fork_name;
|
||||
mod fork_version_decode;
|
||||
|
||||
pub use crate::{map_fork_name, map_fork_name_with};
|
||||
pub use fork::Fork;
|
||||
pub use fork_context::{ForkContext, HardFork};
|
||||
pub use fork_data::ForkData;
|
||||
pub use fork_name::{ForkName, InconsistentFork};
|
||||
pub use fork_version_decode::ForkVersionDecode;
|
||||
|
||||
pub type ForkVersion = [u8; 4];
|
||||
@@ -1,95 +0,0 @@
|
||||
use parking_lot::RwLock;
|
||||
|
||||
use crate::{ChainSpec, EthSpec, ForkName, Hash256, Slot};
|
||||
use std::collections::HashMap;
|
||||
|
||||
/// Provides fork specific info like the current fork name and the fork digests corresponding to every valid fork.
|
||||
#[derive(Debug)]
|
||||
pub struct ForkContext {
|
||||
current_fork: RwLock<ForkName>,
|
||||
fork_to_digest: HashMap<ForkName, [u8; 4]>,
|
||||
digest_to_fork: HashMap<[u8; 4], ForkName>,
|
||||
pub spec: ChainSpec,
|
||||
}
|
||||
|
||||
impl ForkContext {
|
||||
/// Creates a new `ForkContext` object by enumerating all enabled forks and computing their
|
||||
/// fork digest.
|
||||
///
|
||||
/// A fork is disabled in the `ChainSpec` if the activation slot corresponding to that fork is `None`.
|
||||
pub fn new<E: EthSpec>(
|
||||
current_slot: Slot,
|
||||
genesis_validators_root: Hash256,
|
||||
spec: &ChainSpec,
|
||||
) -> Self {
|
||||
let fork_to_digest: HashMap<ForkName, [u8; 4]> = ForkName::list_all()
|
||||
.into_iter()
|
||||
.filter_map(|fork| {
|
||||
if spec.fork_epoch(fork).is_some() {
|
||||
Some((
|
||||
fork,
|
||||
ChainSpec::compute_fork_digest(
|
||||
spec.fork_version_for_name(fork),
|
||||
genesis_validators_root,
|
||||
),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
let digest_to_fork = fork_to_digest
|
||||
.clone()
|
||||
.into_iter()
|
||||
.map(|(k, v)| (v, k))
|
||||
.collect();
|
||||
|
||||
Self {
|
||||
current_fork: RwLock::new(spec.fork_name_at_slot::<E>(current_slot)),
|
||||
fork_to_digest,
|
||||
digest_to_fork,
|
||||
spec: spec.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the provided `fork_name` exists in the `ForkContext` object.
|
||||
pub fn fork_exists(&self, fork_name: ForkName) -> bool {
|
||||
self.fork_to_digest.contains_key(&fork_name)
|
||||
}
|
||||
|
||||
/// Returns the `current_fork`.
|
||||
pub fn current_fork(&self) -> ForkName {
|
||||
*self.current_fork.read()
|
||||
}
|
||||
|
||||
/// Updates the `current_fork` field to a new fork.
|
||||
pub fn update_current_fork(&self, new_fork: ForkName) {
|
||||
*self.current_fork.write() = new_fork;
|
||||
}
|
||||
|
||||
/// Returns the context bytes/fork_digest corresponding to the genesis fork version.
|
||||
pub fn genesis_context_bytes(&self) -> [u8; 4] {
|
||||
*self
|
||||
.fork_to_digest
|
||||
.get(&ForkName::Base)
|
||||
.expect("ForkContext must contain genesis context bytes")
|
||||
}
|
||||
|
||||
/// Returns the fork type given the context bytes/fork_digest.
|
||||
/// Returns `None` if context bytes doesn't correspond to any valid `ForkName`.
|
||||
pub fn from_context_bytes(&self, context: [u8; 4]) -> Option<&ForkName> {
|
||||
self.digest_to_fork.get(&context)
|
||||
}
|
||||
|
||||
/// Returns the context bytes/fork_digest corresponding to a fork name.
|
||||
/// Returns `None` if the `ForkName` has not been initialized.
|
||||
pub fn to_context_bytes(&self, fork_name: ForkName) -> Option<[u8; 4]> {
|
||||
self.fork_to_digest.get(&fork_name).cloned()
|
||||
}
|
||||
|
||||
/// Returns all `fork_digest`s that are currently in the `ForkContext` object.
|
||||
pub fn all_fork_digests(&self) -> Vec<[u8; 4]> {
|
||||
self.digest_to_fork.keys().cloned().collect()
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::{EthSpec, Hash256, Signature, SignedRoot, Slot, Transactions};
|
||||
|
||||
use derivative::Derivative;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Clone,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
TreeHash,
|
||||
TestRandom,
|
||||
Derivative,
|
||||
arbitrary::Arbitrary,
|
||||
)]
|
||||
#[serde(bound = "E: EthSpec")]
|
||||
#[arbitrary(bound = "E: EthSpec")]
|
||||
#[derivative(PartialEq, Eq, Hash(bound = "E: EthSpec"))]
|
||||
pub struct InclusionList<E: EthSpec> {
|
||||
pub slot: Slot,
|
||||
#[serde(with = "serde_utils::quoted_u64")]
|
||||
pub validator_index: u64,
|
||||
pub inclusion_list_committee_root: Hash256,
|
||||
#[serde(with = "ssz_types::serde_utils::list_of_hex_var_list")]
|
||||
pub transactions: Transactions<E>,
|
||||
}
|
||||
|
||||
impl<E: EthSpec> SignedRoot for InclusionList<E> {}
|
||||
|
||||
#[derive(
|
||||
Debug, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, Derivative, arbitrary::Arbitrary,
|
||||
)]
|
||||
#[serde(bound = "E: EthSpec")]
|
||||
#[arbitrary(bound = "E: EthSpec")]
|
||||
#[derivative(PartialEq, Eq, Hash(bound = "E: EthSpec"))]
|
||||
pub struct SignedInclusionList<E: EthSpec> {
|
||||
pub message: InclusionList<E>,
|
||||
pub signature: Signature,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::*;
|
||||
|
||||
ssz_and_tree_hash_tests!(InclusionList<MainnetEthSpec>);
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
use crate::*;
|
||||
|
||||
pub type InclusionListCommittee<E> = FixedVector<u64, <E as EthSpec>::InclusionListCommitteeSize>;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user