mirror of
https://github.com/sigp/lighthouse.git
synced 2026-04-27 01:33:33 +00:00
Merge remote-tracking branch 'origin/unstable' into max-blobs-preset
This commit is contained in:
@@ -146,4 +146,4 @@ impl<E: EthSpec> AggregateAndProof<E> {
|
||||
}
|
||||
|
||||
impl<E: EthSpec> SignedRoot for AggregateAndProof<E> {}
|
||||
impl<'a, E: EthSpec> SignedRoot for AggregateAndProofRef<'a, E> {}
|
||||
impl<E: EthSpec> SignedRoot for AggregateAndProofRef<'_, E> {}
|
||||
|
||||
@@ -233,7 +233,7 @@ impl<E: EthSpec> Attestation<E> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, E: EthSpec> AttestationRef<'a, E> {
|
||||
impl<E: EthSpec> AttestationRef<'_, E> {
|
||||
pub fn clone_as_attestation(self) -> Attestation<E> {
|
||||
match self {
|
||||
Self::Base(att) => Attestation::Base(att.clone()),
|
||||
@@ -422,7 +422,7 @@ impl<E: EthSpec> SlotData for Attestation<E> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, E: EthSpec> SlotData for AttestationRef<'a, E> {
|
||||
impl<E: EthSpec> SlotData for AttestationRef<'_, E> {
|
||||
fn get_slot(&self) -> Slot {
|
||||
self.data().slot
|
||||
}
|
||||
|
||||
@@ -80,10 +80,7 @@ pub struct BeaconBlock<E: EthSpec, Payload: AbstractExecPayload<E> = FullPayload
|
||||
pub type BlindedBeaconBlock<E> = BeaconBlock<E, BlindedPayload<E>>;
|
||||
|
||||
impl<E: EthSpec, Payload: AbstractExecPayload<E>> SignedRoot for BeaconBlock<E, Payload> {}
|
||||
impl<'a, E: EthSpec, Payload: AbstractExecPayload<E>> SignedRoot
|
||||
for BeaconBlockRef<'a, E, Payload>
|
||||
{
|
||||
}
|
||||
impl<E: EthSpec, Payload: AbstractExecPayload<E>> SignedRoot for BeaconBlockRef<'_, E, Payload> {}
|
||||
|
||||
/// Empty block trait for each block variant to implement.
|
||||
pub trait EmptyBlock {
|
||||
|
||||
@@ -145,7 +145,7 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload<E>> BeaconBlockBodyRef<'a, E,
|
||||
}
|
||||
}
|
||||
|
||||
fn body_merkle_leaves(&self) -> Vec<Hash256> {
|
||||
pub(crate) fn body_merkle_leaves(&self) -> Vec<Hash256> {
|
||||
let mut leaves = vec![];
|
||||
match self {
|
||||
Self::Base(body) => {
|
||||
@@ -176,57 +176,71 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload<E>> BeaconBlockBodyRef<'a, E,
|
||||
leaves
|
||||
}
|
||||
|
||||
/// Produces the proof of inclusion for a `KzgCommitment` in `self.blob_kzg_commitments`
|
||||
/// at `index`.
|
||||
/// Calculate a KZG commitment merkle proof.
|
||||
///
|
||||
/// Prefer to use `complete_kzg_commitment_merkle_proof` with a reused proof for the
|
||||
/// `blob_kzg_commitments` field.
|
||||
pub fn kzg_commitment_merkle_proof(
|
||||
&self,
|
||||
index: usize,
|
||||
) -> Result<FixedVector<Hash256, E::KzgCommitmentInclusionProofDepth>, Error> {
|
||||
// We compute the branches by generating 2 merkle trees:
|
||||
// 1. Merkle tree for the `blob_kzg_commitments` List object
|
||||
// 2. Merkle tree for the `BeaconBlockBody` container
|
||||
// We then merge the branches for both the trees all the way up to the root.
|
||||
let kzg_commitments_proof = self.kzg_commitments_merkle_proof()?;
|
||||
let proof = self.complete_kzg_commitment_merkle_proof(index, &kzg_commitments_proof)?;
|
||||
Ok(proof)
|
||||
}
|
||||
|
||||
// Part1 (Branches for the subtree rooted at `blob_kzg_commitments`)
|
||||
//
|
||||
// Branches for `blob_kzg_commitments` without length mix-in
|
||||
let blob_leaves = self
|
||||
.blob_kzg_commitments()?
|
||||
.iter()
|
||||
.map(|commitment| commitment.tree_hash_root())
|
||||
.collect::<Vec<_>>();
|
||||
let depth = E::max_blob_commitments_per_block()
|
||||
.next_power_of_two()
|
||||
.ilog2();
|
||||
let tree = MerkleTree::create(&blob_leaves, depth as usize);
|
||||
let (_, mut proof) = tree
|
||||
.generate_proof(index, depth as usize)
|
||||
.map_err(Error::MerkleTreeError)?;
|
||||
/// 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.
|
||||
pub fn complete_kzg_commitment_merkle_proof(
|
||||
&self,
|
||||
index: usize,
|
||||
kzg_commitments_proof: &[Hash256],
|
||||
) -> Result<FixedVector<Hash256, E::KzgCommitmentInclusionProofDepth>, Error> {
|
||||
match self {
|
||||
Self::Base(_) | Self::Altair(_) | Self::Bellatrix(_) | Self::Capella(_) => {
|
||||
Err(Error::IncorrectStateVariant)
|
||||
}
|
||||
Self::Deneb(_) | Self::Electra(_) => {
|
||||
// We compute the branches by generating 2 merkle trees:
|
||||
// 1. Merkle tree for the `blob_kzg_commitments` List object
|
||||
// 2. Merkle tree for the `BeaconBlockBody` container
|
||||
// We then merge the branches for both the trees all the way up to the root.
|
||||
|
||||
// Add the branch corresponding to the length mix-in.
|
||||
let length = blob_leaves.len();
|
||||
let usize_len = std::mem::size_of::<usize>();
|
||||
let mut length_bytes = [0; BYTES_PER_CHUNK];
|
||||
length_bytes
|
||||
.get_mut(0..usize_len)
|
||||
.ok_or(Error::MerkleTreeError(MerkleTreeError::PleaseNotifyTheDevs))?
|
||||
.copy_from_slice(&length.to_le_bytes());
|
||||
let length_root = Hash256::from_slice(length_bytes.as_slice());
|
||||
proof.push(length_root);
|
||||
// Part1 (Branches for the subtree rooted at `blob_kzg_commitments`)
|
||||
//
|
||||
// Branches for `blob_kzg_commitments` without length mix-in
|
||||
let blob_leaves = self
|
||||
.blob_kzg_commitments()?
|
||||
.iter()
|
||||
.map(|commitment| commitment.tree_hash_root())
|
||||
.collect::<Vec<_>>();
|
||||
let depth = E::max_blob_commitments_per_block()
|
||||
.next_power_of_two()
|
||||
.ilog2();
|
||||
let tree = MerkleTree::create(&blob_leaves, depth as usize);
|
||||
let (_, mut proof) = tree
|
||||
.generate_proof(index, depth as usize)
|
||||
.map_err(Error::MerkleTreeError)?;
|
||||
|
||||
// Part 2
|
||||
// Branches for `BeaconBlockBody` container
|
||||
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 (_, mut proof_body) = tree
|
||||
.generate_proof(BLOB_KZG_COMMITMENTS_INDEX, beacon_block_body_depth)
|
||||
.map_err(Error::MerkleTreeError)?;
|
||||
// Join the proofs for the subtree and the main tree
|
||||
proof.append(&mut proof_body);
|
||||
debug_assert_eq!(proof.len(), E::kzg_proof_inclusion_proof_depth());
|
||||
// Add the branch corresponding to the length mix-in.
|
||||
let length = blob_leaves.len();
|
||||
let usize_len = std::mem::size_of::<usize>();
|
||||
let mut length_bytes = [0; BYTES_PER_CHUNK];
|
||||
length_bytes
|
||||
.get_mut(0..usize_len)
|
||||
.ok_or(Error::MerkleTreeError(MerkleTreeError::PleaseNotifyTheDevs))?
|
||||
.copy_from_slice(&length.to_le_bytes());
|
||||
let length_root = Hash256::from_slice(length_bytes.as_slice());
|
||||
proof.push(length_root);
|
||||
|
||||
Ok(proof.into())
|
||||
// Part 2
|
||||
// Branches for `BeaconBlockBody` container
|
||||
// Join the proofs for the subtree and the main tree
|
||||
proof.extend_from_slice(kzg_commitments_proof);
|
||||
|
||||
Ok(FixedVector::new(proof)?)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Produces the proof of inclusion for `self.blob_kzg_commitments`.
|
||||
@@ -239,7 +253,7 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload<E>> BeaconBlockBodyRef<'a, E,
|
||||
let (_, proof) = tree
|
||||
.generate_proof(BLOB_KZG_COMMITMENTS_INDEX, beacon_block_body_depth)
|
||||
.map_err(Error::MerkleTreeError)?;
|
||||
Ok(proof.into())
|
||||
Ok(FixedVector::new(proof)?)
|
||||
}
|
||||
|
||||
pub fn block_body_merkle_proof(&self, generalized_index: usize) -> Result<Vec<Hash256>, Error> {
|
||||
@@ -364,7 +378,7 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload<E>> BeaconBlockBodyRefMut<'a,
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, E: EthSpec, Payload: AbstractExecPayload<E>> BeaconBlockBodyRef<'a, E, Payload> {
|
||||
impl<E: EthSpec, Payload: AbstractExecPayload<E>> BeaconBlockBodyRef<'_, E, Payload> {
|
||||
/// Get the fork_name of this object
|
||||
pub fn fork_name(self) -> ForkName {
|
||||
match self {
|
||||
|
||||
@@ -7,7 +7,7 @@ pub struct BeaconCommittee<'a> {
|
||||
pub committee: &'a [usize],
|
||||
}
|
||||
|
||||
impl<'a> BeaconCommittee<'a> {
|
||||
impl BeaconCommittee<'_> {
|
||||
pub fn into_owned(self) -> OwnedBeaconCommittee {
|
||||
OwnedBeaconCommittee {
|
||||
slot: self.slot,
|
||||
|
||||
@@ -59,6 +59,7 @@ pub enum Error {
|
||||
UnknownValidator(usize),
|
||||
UnableToDetermineProducer,
|
||||
InvalidBitfield,
|
||||
EmptyCommittee,
|
||||
ValidatorIsWithdrawable,
|
||||
ValidatorIsInactive {
|
||||
val_index: usize,
|
||||
@@ -155,7 +156,6 @@ pub enum Error {
|
||||
current_fork: ForkName,
|
||||
},
|
||||
TotalActiveBalanceDiffUninitialized,
|
||||
MissingImmutableValidator(usize),
|
||||
IndexNotSupported(usize),
|
||||
InvalidFlagIndex(usize),
|
||||
MerkleTreeError(merkle_proof::MerkleTreeError),
|
||||
@@ -510,7 +510,7 @@ where
|
||||
#[compare_fields(as_iter)]
|
||||
#[test_random(default)]
|
||||
#[superstruct(only(Electra))]
|
||||
pub pending_balance_deposits: List<PendingBalanceDeposit, E::PendingBalanceDepositsLimit>,
|
||||
pub pending_deposits: List<PendingDeposit, E::PendingDepositsLimit>,
|
||||
#[compare_fields(as_iter)]
|
||||
#[test_random(default)]
|
||||
#[superstruct(only(Electra))]
|
||||
@@ -1548,19 +1548,23 @@ impl<E: EthSpec> BeaconState<E> {
|
||||
.ok_or(Error::UnknownValidator(validator_index))
|
||||
}
|
||||
|
||||
/// Add a validator to the registry and return the validator index that was allocated for it.
|
||||
pub fn add_validator_to_registry(
|
||||
&mut self,
|
||||
deposit_data: &DepositData,
|
||||
pubkey: PublicKeyBytes,
|
||||
withdrawal_credentials: Hash256,
|
||||
amount: u64,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<(), Error> {
|
||||
let fork = self.fork_name_unchecked();
|
||||
let amount = if fork.electra_enabled() {
|
||||
0
|
||||
} else {
|
||||
deposit_data.amount
|
||||
};
|
||||
self.validators_mut()
|
||||
.push(Validator::from_deposit(deposit_data, amount, fork, spec))?;
|
||||
) -> Result<usize, Error> {
|
||||
let index = self.validators().len();
|
||||
let fork_name = self.fork_name_unchecked();
|
||||
self.validators_mut().push(Validator::from_deposit(
|
||||
pubkey,
|
||||
withdrawal_credentials,
|
||||
amount,
|
||||
fork_name,
|
||||
spec,
|
||||
))?;
|
||||
self.balances_mut().push(amount)?;
|
||||
|
||||
// Altair or later initializations.
|
||||
@@ -1574,7 +1578,20 @@ impl<E: EthSpec> BeaconState<E> {
|
||||
inactivity_scores.push(0)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
// Keep the pubkey cache up to date if it was up to date prior to this call.
|
||||
//
|
||||
// Doing this here while we know the pubkey and index is marginally quicker than doing it in
|
||||
// a call to `update_pubkey_cache` later because we don't need to index into the validators
|
||||
// tree again.
|
||||
let pubkey_cache = self.pubkey_cache_mut();
|
||||
if pubkey_cache.len() == index {
|
||||
let success = pubkey_cache.insert(pubkey, index);
|
||||
if !success {
|
||||
return Err(Error::PubkeyCacheInconsistent);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(index)
|
||||
}
|
||||
|
||||
/// Safe copy-on-write accessor for the `validators` list.
|
||||
@@ -1781,19 +1798,6 @@ impl<E: EthSpec> BeaconState<E> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the number of outstanding deposits.
|
||||
///
|
||||
/// Returns `Err` if the state is invalid.
|
||||
pub fn get_outstanding_deposit_len(&self) -> Result<u64, Error> {
|
||||
self.eth1_data()
|
||||
.deposit_count
|
||||
.checked_sub(self.eth1_deposit_index())
|
||||
.ok_or(Error::InvalidDepositState {
|
||||
deposit_count: self.eth1_data().deposit_count,
|
||||
deposit_index: self.eth1_deposit_index(),
|
||||
})
|
||||
}
|
||||
|
||||
/// Build all caches (except the tree hash cache), if they need to be built.
|
||||
pub fn build_caches(&mut self, spec: &ChainSpec) -> Result<(), Error> {
|
||||
self.build_all_committee_caches(spec)?;
|
||||
@@ -2150,27 +2154,6 @@ impl<E: EthSpec> BeaconState<E> {
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
/// Get active balance for the given `validator_index`.
|
||||
pub fn get_active_balance(
|
||||
&self,
|
||||
validator_index: usize,
|
||||
spec: &ChainSpec,
|
||||
current_fork: ForkName,
|
||||
) -> Result<u64, Error> {
|
||||
let max_effective_balance = self
|
||||
.validators()
|
||||
.get(validator_index)
|
||||
.map(|validator| validator.get_max_effective_balance(spec, current_fork))
|
||||
.ok_or(Error::UnknownValidator(validator_index))?;
|
||||
Ok(std::cmp::min(
|
||||
*self
|
||||
.balances()
|
||||
.get(validator_index)
|
||||
.ok_or(Error::UnknownValidator(validator_index))?,
|
||||
max_effective_balance,
|
||||
))
|
||||
}
|
||||
|
||||
pub fn get_pending_balance_to_withdraw(&self, validator_index: usize) -> Result<u64, Error> {
|
||||
let mut pending_balance = 0;
|
||||
for withdrawal in self
|
||||
@@ -2197,42 +2180,18 @@ impl<E: EthSpec> BeaconState<E> {
|
||||
if *balance > spec.min_activation_balance {
|
||||
let excess_balance = balance.safe_sub(spec.min_activation_balance)?;
|
||||
*balance = spec.min_activation_balance;
|
||||
self.pending_balance_deposits_mut()?
|
||||
.push(PendingBalanceDeposit {
|
||||
index: validator_index as u64,
|
||||
amount: excess_balance,
|
||||
})?;
|
||||
let validator = self.get_validator(validator_index)?.clone();
|
||||
self.pending_deposits_mut()?.push(PendingDeposit {
|
||||
pubkey: validator.pubkey,
|
||||
withdrawal_credentials: validator.withdrawal_credentials,
|
||||
amount: excess_balance,
|
||||
signature: Signature::infinity()?.into(),
|
||||
slot: spec.genesis_slot,
|
||||
})?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn queue_entire_balance_and_reset_validator(
|
||||
&mut self,
|
||||
validator_index: usize,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<(), Error> {
|
||||
let balance = self
|
||||
.balances_mut()
|
||||
.get_mut(validator_index)
|
||||
.ok_or(Error::UnknownValidator(validator_index))?;
|
||||
let balance_copy = *balance;
|
||||
*balance = 0_u64;
|
||||
|
||||
let validator = self
|
||||
.validators_mut()
|
||||
.get_mut(validator_index)
|
||||
.ok_or(Error::UnknownValidator(validator_index))?;
|
||||
validator.effective_balance = 0;
|
||||
validator.activation_eligibility_epoch = spec.far_future_epoch;
|
||||
|
||||
self.pending_balance_deposits_mut()?
|
||||
.push(PendingBalanceDeposit {
|
||||
index: validator_index as u64,
|
||||
amount: balance_copy,
|
||||
})
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
/// Change the withdrawal prefix of the given `validator_index` to the compounding withdrawal validator prefix.
|
||||
pub fn switch_to_compounding_validator(
|
||||
&mut self,
|
||||
@@ -2243,12 +2202,10 @@ impl<E: EthSpec> BeaconState<E> {
|
||||
.validators_mut()
|
||||
.get_mut(validator_index)
|
||||
.ok_or(Error::UnknownValidator(validator_index))?;
|
||||
if validator.has_eth1_withdrawal_credential(spec) {
|
||||
AsMut::<[u8; 32]>::as_mut(&mut validator.withdrawal_credentials)[0] =
|
||||
spec.compounding_withdrawal_prefix_byte;
|
||||
AsMut::<[u8; 32]>::as_mut(&mut validator.withdrawal_credentials)[0] =
|
||||
spec.compounding_withdrawal_prefix_byte;
|
||||
|
||||
self.queue_excess_active_balance(validator_index, spec)?;
|
||||
}
|
||||
self.queue_excess_active_balance(validator_index, spec)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -2506,33 +2463,64 @@ impl<E: EthSpec> BeaconState<E> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn compute_merkle_proof(&self, generalized_index: usize) -> Result<Vec<Hash256>, Error> {
|
||||
// 1. Convert generalized index to field index.
|
||||
let field_index = match generalized_index {
|
||||
pub fn compute_current_sync_committee_proof(&self) -> Result<Vec<Hash256>, Error> {
|
||||
// Sync committees are top-level fields, subtract off the generalized indices
|
||||
// for the internal nodes. Result should be 22 or 23, the field offset of the committee
|
||||
// in the `BeaconState`:
|
||||
// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/beacon-chain.md#beaconstate
|
||||
let field_index = if self.fork_name_unchecked().electra_enabled() {
|
||||
light_client_update::CURRENT_SYNC_COMMITTEE_INDEX_ELECTRA
|
||||
} else {
|
||||
light_client_update::CURRENT_SYNC_COMMITTEE_INDEX
|
||||
| light_client_update::NEXT_SYNC_COMMITTEE_INDEX => {
|
||||
// Sync committees are top-level fields, subtract off the generalized indices
|
||||
// for the internal nodes. Result should be 22 or 23, the field offset of the committee
|
||||
// in the `BeaconState`:
|
||||
// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/beacon-chain.md#beaconstate
|
||||
generalized_index
|
||||
.checked_sub(self.num_fields_pow2())
|
||||
.ok_or(Error::IndexNotSupported(generalized_index))?
|
||||
}
|
||||
light_client_update::FINALIZED_ROOT_INDEX => {
|
||||
// Finalized root is the right child of `finalized_checkpoint`, divide by two to get
|
||||
// the generalized index of `state.finalized_checkpoint`.
|
||||
let finalized_checkpoint_generalized_index = generalized_index / 2;
|
||||
// Subtract off the internal nodes. Result should be 105/2 - 32 = 20 which matches
|
||||
// position of `finalized_checkpoint` in `BeaconState`.
|
||||
finalized_checkpoint_generalized_index
|
||||
.checked_sub(self.num_fields_pow2())
|
||||
.ok_or(Error::IndexNotSupported(generalized_index))?
|
||||
}
|
||||
_ => return Err(Error::IndexNotSupported(generalized_index)),
|
||||
};
|
||||
let leaves = self.get_beacon_state_leaves();
|
||||
self.generate_proof(field_index, &leaves)
|
||||
}
|
||||
|
||||
// 2. Get all `BeaconState` leaves.
|
||||
pub fn compute_next_sync_committee_proof(&self) -> Result<Vec<Hash256>, Error> {
|
||||
// Sync committees are top-level fields, subtract off the generalized indices
|
||||
// for the internal nodes. Result should be 22 or 23, the field offset of the committee
|
||||
// in the `BeaconState`:
|
||||
// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/beacon-chain.md#beaconstate
|
||||
let field_index = if self.fork_name_unchecked().electra_enabled() {
|
||||
light_client_update::NEXT_SYNC_COMMITTEE_INDEX_ELECTRA
|
||||
} else {
|
||||
light_client_update::NEXT_SYNC_COMMITTEE_INDEX
|
||||
};
|
||||
let leaves = self.get_beacon_state_leaves();
|
||||
self.generate_proof(field_index, &leaves)
|
||||
}
|
||||
|
||||
pub fn compute_finalized_root_proof(&self) -> Result<Vec<Hash256>, Error> {
|
||||
// Finalized root is the right child of `finalized_checkpoint`, divide by two to get
|
||||
// the generalized index of `state.finalized_checkpoint`.
|
||||
let field_index = if self.fork_name_unchecked().electra_enabled() {
|
||||
// Index should be 169/2 - 64 = 20 which matches the position
|
||||
// of `finalized_checkpoint` in `BeaconState`
|
||||
light_client_update::FINALIZED_ROOT_INDEX_ELECTRA
|
||||
} else {
|
||||
// Index should be 105/2 - 32 = 20 which matches the position
|
||||
// of `finalized_checkpoint` in `BeaconState`
|
||||
light_client_update::FINALIZED_ROOT_INDEX
|
||||
};
|
||||
let leaves = self.get_beacon_state_leaves();
|
||||
let mut proof = self.generate_proof(field_index, &leaves)?;
|
||||
proof.insert(0, self.finalized_checkpoint().epoch.tree_hash_root());
|
||||
Ok(proof)
|
||||
}
|
||||
|
||||
fn generate_proof(
|
||||
&self,
|
||||
field_index: usize,
|
||||
leaves: &[Hash256],
|
||||
) -> Result<Vec<Hash256>, Error> {
|
||||
let depth = self.num_fields_pow2().ilog2() as usize;
|
||||
let tree = merkle_proof::MerkleTree::create(leaves, depth);
|
||||
let (_, proof) = tree.generate_proof(field_index, depth)?;
|
||||
Ok(proof)
|
||||
}
|
||||
|
||||
fn get_beacon_state_leaves(&self) -> Vec<Hash256> {
|
||||
let mut leaves = vec![];
|
||||
#[allow(clippy::arithmetic_side_effects)]
|
||||
match self {
|
||||
@@ -2568,18 +2556,7 @@ impl<E: EthSpec> BeaconState<E> {
|
||||
}
|
||||
};
|
||||
|
||||
// 3. Make deposit tree.
|
||||
// Use the depth of the `BeaconState` fields (i.e. `log2(32) = 5`).
|
||||
let depth = light_client_update::CURRENT_SYNC_COMMITTEE_PROOF_LEN;
|
||||
let tree = merkle_proof::MerkleTree::create(&leaves, depth);
|
||||
let (_, mut proof) = tree.generate_proof(field_index, depth)?;
|
||||
|
||||
// 4. If we're proving the finalized root, patch in the finalized epoch to complete the proof.
|
||||
if generalized_index == light_client_update::FINALIZED_ROOT_INDEX {
|
||||
proof.insert(0, self.finalized_checkpoint().epoch.tree_hash_root());
|
||||
}
|
||||
|
||||
Ok(proof)
|
||||
leaves
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ impl<'a, E: EthSpec> BlockRootsIter<'a, E> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, E: EthSpec> Iterator for BlockRootsIter<'a, E> {
|
||||
impl<E: EthSpec> Iterator for BlockRootsIter<'_, E> {
|
||||
type Item = Result<(Slot, Hash256), Error>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
|
||||
@@ -307,43 +307,6 @@ mod committees {
|
||||
}
|
||||
}
|
||||
|
||||
mod get_outstanding_deposit_len {
|
||||
use super::*;
|
||||
|
||||
async fn state() -> BeaconState<MinimalEthSpec> {
|
||||
get_harness(16, Slot::new(0))
|
||||
.await
|
||||
.chain
|
||||
.head_beacon_state_cloned()
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn returns_ok() {
|
||||
let mut state = state().await;
|
||||
assert_eq!(state.get_outstanding_deposit_len(), Ok(0));
|
||||
|
||||
state.eth1_data_mut().deposit_count = 17;
|
||||
*state.eth1_deposit_index_mut() = 16;
|
||||
assert_eq!(state.get_outstanding_deposit_len(), Ok(1));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn returns_err_if_the_state_is_invalid() {
|
||||
let mut state = state().await;
|
||||
// The state is invalid, deposit count is lower than deposit index.
|
||||
state.eth1_data_mut().deposit_count = 16;
|
||||
*state.eth1_deposit_index_mut() = 17;
|
||||
|
||||
assert_eq!(
|
||||
state.get_outstanding_deposit_len(),
|
||||
Err(BeaconStateError::InvalidDepositState {
|
||||
deposit_count: 16,
|
||||
deposit_index: 17,
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_base_and_altair() {
|
||||
type E = MainnetEthSpec;
|
||||
|
||||
@@ -140,6 +140,37 @@ impl<E: EthSpec> BlobSidecar<E> {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn new_with_existing_proof(
|
||||
index: usize,
|
||||
blob: Blob<E>,
|
||||
signed_block: &SignedBeaconBlock<E>,
|
||||
signed_block_header: SignedBeaconBlockHeader,
|
||||
kzg_commitments_inclusion_proof: &[Hash256],
|
||||
kzg_proof: KzgProof,
|
||||
) -> Result<Self, BlobSidecarError> {
|
||||
let expected_kzg_commitments = signed_block
|
||||
.message()
|
||||
.body()
|
||||
.blob_kzg_commitments()
|
||||
.map_err(|_e| BlobSidecarError::PreDeneb)?;
|
||||
let kzg_commitment = *expected_kzg_commitments
|
||||
.get(index)
|
||||
.ok_or(BlobSidecarError::MissingKzgCommitment)?;
|
||||
let kzg_commitment_inclusion_proof = signed_block
|
||||
.message()
|
||||
.body()
|
||||
.complete_kzg_commitment_merkle_proof(index, kzg_commitments_inclusion_proof)?;
|
||||
|
||||
Ok(Self {
|
||||
index: index as u64,
|
||||
blob,
|
||||
kzg_commitment,
|
||||
kzg_proof,
|
||||
signed_block_header,
|
||||
kzg_commitment_inclusion_proof,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn id(&self) -> BlobIdentifier {
|
||||
BlobIdentifier {
|
||||
block_root: self.block_root(),
|
||||
|
||||
@@ -127,6 +127,11 @@ pub struct ChainSpec {
|
||||
pub deposit_network_id: u64,
|
||||
pub deposit_contract_address: Address,
|
||||
|
||||
/*
|
||||
* Execution Specs
|
||||
*/
|
||||
pub gas_limit_adjustment_factor: u64,
|
||||
|
||||
/*
|
||||
* Altair hard fork params
|
||||
*/
|
||||
@@ -204,7 +209,6 @@ pub struct ChainSpec {
|
||||
pub target_aggregators_per_committee: u64,
|
||||
pub gossip_max_size: u64,
|
||||
pub max_request_blocks: u64,
|
||||
pub epochs_per_subnet_subscription: u64,
|
||||
pub min_epochs_for_block_requests: u64,
|
||||
pub max_chunk_size: u64,
|
||||
pub ttfb_timeout: u64,
|
||||
@@ -215,9 +219,7 @@ pub struct ChainSpec {
|
||||
pub message_domain_valid_snappy: [u8; 4],
|
||||
pub subnets_per_node: u8,
|
||||
pub attestation_subnet_count: u64,
|
||||
pub attestation_subnet_extra_bits: u8,
|
||||
pub attestation_subnet_prefix_bits: u8,
|
||||
pub attestation_subnet_shuffling_prefix_bits: u8,
|
||||
|
||||
/*
|
||||
* Networking Deneb
|
||||
@@ -729,6 +731,11 @@ impl ChainSpec {
|
||||
.parse()
|
||||
.expect("chain spec deposit contract address"),
|
||||
|
||||
/*
|
||||
* Execution Specs
|
||||
*/
|
||||
gas_limit_adjustment_factor: 1024,
|
||||
|
||||
/*
|
||||
* Altair hard fork params
|
||||
*/
|
||||
@@ -827,7 +834,6 @@ impl ChainSpec {
|
||||
subnets_per_node: 2,
|
||||
maximum_gossip_clock_disparity_millis: default_maximum_gossip_clock_disparity_millis(),
|
||||
target_aggregators_per_committee: 16,
|
||||
epochs_per_subnet_subscription: default_epochs_per_subnet_subscription(),
|
||||
gossip_max_size: default_gossip_max_size(),
|
||||
min_epochs_for_block_requests: default_min_epochs_for_block_requests(),
|
||||
max_chunk_size: default_max_chunk_size(),
|
||||
@@ -835,10 +841,7 @@ impl ChainSpec {
|
||||
resp_timeout: default_resp_timeout(),
|
||||
message_domain_invalid_snappy: default_message_domain_invalid_snappy(),
|
||||
message_domain_valid_snappy: default_message_domain_valid_snappy(),
|
||||
attestation_subnet_extra_bits: default_attestation_subnet_extra_bits(),
|
||||
attestation_subnet_prefix_bits: default_attestation_subnet_prefix_bits(),
|
||||
attestation_subnet_shuffling_prefix_bits:
|
||||
default_attestation_subnet_shuffling_prefix_bits(),
|
||||
max_request_blocks: default_max_request_blocks(),
|
||||
|
||||
/*
|
||||
@@ -1048,6 +1051,11 @@ impl ChainSpec {
|
||||
.parse()
|
||||
.expect("chain spec deposit contract address"),
|
||||
|
||||
/*
|
||||
* Execution Specs
|
||||
*/
|
||||
gas_limit_adjustment_factor: 1024,
|
||||
|
||||
/*
|
||||
* Altair hard fork params
|
||||
*/
|
||||
@@ -1145,7 +1153,6 @@ impl ChainSpec {
|
||||
subnets_per_node: 4, // Make this larger than usual to avoid network damage
|
||||
maximum_gossip_clock_disparity_millis: default_maximum_gossip_clock_disparity_millis(),
|
||||
target_aggregators_per_committee: 16,
|
||||
epochs_per_subnet_subscription: default_epochs_per_subnet_subscription(),
|
||||
gossip_max_size: default_gossip_max_size(),
|
||||
min_epochs_for_block_requests: 33024,
|
||||
max_chunk_size: default_max_chunk_size(),
|
||||
@@ -1153,11 +1160,8 @@ impl ChainSpec {
|
||||
resp_timeout: default_resp_timeout(),
|
||||
message_domain_invalid_snappy: default_message_domain_invalid_snappy(),
|
||||
message_domain_valid_snappy: default_message_domain_valid_snappy(),
|
||||
attestation_subnet_extra_bits: default_attestation_subnet_extra_bits(),
|
||||
attestation_subnet_prefix_bits: default_attestation_subnet_prefix_bits(),
|
||||
attestation_subnet_shuffling_prefix_bits:
|
||||
default_attestation_subnet_shuffling_prefix_bits(),
|
||||
max_request_blocks: default_max_request_blocks(),
|
||||
attestation_subnet_prefix_bits: default_attestation_subnet_prefix_bits(),
|
||||
|
||||
/*
|
||||
* Networking Deneb Specific
|
||||
@@ -1309,15 +1313,16 @@ pub struct Config {
|
||||
#[serde(with = "serde_utils::address_hex")]
|
||||
deposit_contract_address: Address,
|
||||
|
||||
#[serde(default = "default_gas_limit_adjustment_factor")]
|
||||
#[serde(with = "serde_utils::quoted_u64")]
|
||||
gas_limit_adjustment_factor: u64,
|
||||
|
||||
#[serde(default = "default_gossip_max_size")]
|
||||
#[serde(with = "serde_utils::quoted_u64")]
|
||||
gossip_max_size: u64,
|
||||
#[serde(default = "default_max_request_blocks")]
|
||||
#[serde(with = "serde_utils::quoted_u64")]
|
||||
max_request_blocks: u64,
|
||||
#[serde(default = "default_epochs_per_subnet_subscription")]
|
||||
#[serde(with = "serde_utils::quoted_u64")]
|
||||
epochs_per_subnet_subscription: u64,
|
||||
#[serde(default = "default_min_epochs_for_block_requests")]
|
||||
#[serde(with = "serde_utils::quoted_u64")]
|
||||
min_epochs_for_block_requests: u64,
|
||||
@@ -1342,15 +1347,9 @@ pub struct Config {
|
||||
#[serde(default = "default_message_domain_valid_snappy")]
|
||||
#[serde(with = "serde_utils::bytes_4_hex")]
|
||||
message_domain_valid_snappy: [u8; 4],
|
||||
#[serde(default = "default_attestation_subnet_extra_bits")]
|
||||
#[serde(with = "serde_utils::quoted_u8")]
|
||||
attestation_subnet_extra_bits: u8,
|
||||
#[serde(default = "default_attestation_subnet_prefix_bits")]
|
||||
#[serde(with = "serde_utils::quoted_u8")]
|
||||
attestation_subnet_prefix_bits: u8,
|
||||
#[serde(default = "default_attestation_subnet_shuffling_prefix_bits")]
|
||||
#[serde(with = "serde_utils::quoted_u8")]
|
||||
attestation_subnet_shuffling_prefix_bits: u8,
|
||||
#[serde(default = "default_max_request_blocks_deneb")]
|
||||
#[serde(with = "serde_utils::quoted_u64")]
|
||||
max_request_blocks_deneb: u64,
|
||||
@@ -1435,10 +1434,18 @@ fn default_subnets_per_node() -> u8 {
|
||||
2u8
|
||||
}
|
||||
|
||||
fn default_attestation_subnet_prefix_bits() -> u8 {
|
||||
6
|
||||
}
|
||||
|
||||
const fn default_max_per_epoch_activation_churn_limit() -> u64 {
|
||||
8
|
||||
}
|
||||
|
||||
const fn default_gas_limit_adjustment_factor() -> u64 {
|
||||
1024
|
||||
}
|
||||
|
||||
const fn default_gossip_max_size() -> u64 {
|
||||
10485760
|
||||
}
|
||||
@@ -1467,18 +1474,6 @@ const fn default_message_domain_valid_snappy() -> [u8; 4] {
|
||||
[1, 0, 0, 0]
|
||||
}
|
||||
|
||||
const fn default_attestation_subnet_extra_bits() -> u8 {
|
||||
0
|
||||
}
|
||||
|
||||
const fn default_attestation_subnet_prefix_bits() -> u8 {
|
||||
6
|
||||
}
|
||||
|
||||
const fn default_attestation_subnet_shuffling_prefix_bits() -> u8 {
|
||||
3
|
||||
}
|
||||
|
||||
const fn default_max_request_blocks() -> u64 {
|
||||
1024
|
||||
}
|
||||
@@ -1517,10 +1512,6 @@ const fn default_max_per_epoch_activation_exit_churn_limit() -> u64 {
|
||||
256_000_000_000
|
||||
}
|
||||
|
||||
const fn default_epochs_per_subnet_subscription() -> u64 {
|
||||
256
|
||||
}
|
||||
|
||||
const fn default_attestation_propagation_slot_range() -> u64 {
|
||||
32
|
||||
}
|
||||
@@ -1698,6 +1689,7 @@ impl Config {
|
||||
shard_committee_period: spec.shard_committee_period,
|
||||
eth1_follow_distance: spec.eth1_follow_distance,
|
||||
subnets_per_node: spec.subnets_per_node,
|
||||
attestation_subnet_prefix_bits: spec.attestation_subnet_prefix_bits,
|
||||
|
||||
inactivity_score_bias: spec.inactivity_score_bias,
|
||||
inactivity_score_recovery_rate: spec.inactivity_score_recovery_rate,
|
||||
@@ -1712,9 +1704,10 @@ impl Config {
|
||||
deposit_network_id: spec.deposit_network_id,
|
||||
deposit_contract_address: spec.deposit_contract_address,
|
||||
|
||||
gas_limit_adjustment_factor: spec.gas_limit_adjustment_factor,
|
||||
|
||||
gossip_max_size: spec.gossip_max_size,
|
||||
max_request_blocks: spec.max_request_blocks,
|
||||
epochs_per_subnet_subscription: spec.epochs_per_subnet_subscription,
|
||||
min_epochs_for_block_requests: spec.min_epochs_for_block_requests,
|
||||
max_chunk_size: spec.max_chunk_size,
|
||||
ttfb_timeout: spec.ttfb_timeout,
|
||||
@@ -1723,9 +1716,6 @@ impl Config {
|
||||
maximum_gossip_clock_disparity_millis: spec.maximum_gossip_clock_disparity_millis,
|
||||
message_domain_invalid_snappy: spec.message_domain_invalid_snappy,
|
||||
message_domain_valid_snappy: spec.message_domain_valid_snappy,
|
||||
attestation_subnet_extra_bits: spec.attestation_subnet_extra_bits,
|
||||
attestation_subnet_prefix_bits: spec.attestation_subnet_prefix_bits,
|
||||
attestation_subnet_shuffling_prefix_bits: spec.attestation_subnet_shuffling_prefix_bits,
|
||||
max_request_blocks_deneb: spec.max_request_blocks_deneb,
|
||||
max_request_blob_sidecars: spec.max_request_blob_sidecars,
|
||||
max_request_data_column_sidecars: spec.max_request_data_column_sidecars,
|
||||
@@ -1780,6 +1770,7 @@ impl Config {
|
||||
shard_committee_period,
|
||||
eth1_follow_distance,
|
||||
subnets_per_node,
|
||||
attestation_subnet_prefix_bits,
|
||||
inactivity_score_bias,
|
||||
inactivity_score_recovery_rate,
|
||||
ejection_balance,
|
||||
@@ -1790,6 +1781,7 @@ impl Config {
|
||||
deposit_chain_id,
|
||||
deposit_network_id,
|
||||
deposit_contract_address,
|
||||
gas_limit_adjustment_factor,
|
||||
gossip_max_size,
|
||||
min_epochs_for_block_requests,
|
||||
max_chunk_size,
|
||||
@@ -1797,11 +1789,7 @@ impl Config {
|
||||
resp_timeout,
|
||||
message_domain_invalid_snappy,
|
||||
message_domain_valid_snappy,
|
||||
attestation_subnet_extra_bits,
|
||||
attestation_subnet_prefix_bits,
|
||||
attestation_subnet_shuffling_prefix_bits,
|
||||
max_request_blocks,
|
||||
epochs_per_subnet_subscription,
|
||||
attestation_propagation_slot_range,
|
||||
maximum_gossip_clock_disparity_millis,
|
||||
max_request_blocks_deneb,
|
||||
@@ -1856,6 +1844,7 @@ impl Config {
|
||||
deposit_chain_id,
|
||||
deposit_network_id,
|
||||
deposit_contract_address,
|
||||
gas_limit_adjustment_factor,
|
||||
terminal_total_difficulty,
|
||||
terminal_block_hash,
|
||||
terminal_block_hash_activation_epoch,
|
||||
@@ -1866,11 +1855,8 @@ impl Config {
|
||||
resp_timeout,
|
||||
message_domain_invalid_snappy,
|
||||
message_domain_valid_snappy,
|
||||
attestation_subnet_extra_bits,
|
||||
attestation_subnet_prefix_bits,
|
||||
attestation_subnet_shuffling_prefix_bits,
|
||||
max_request_blocks,
|
||||
epochs_per_subnet_subscription,
|
||||
attestation_propagation_slot_range,
|
||||
maximum_gossip_clock_disparity_millis,
|
||||
max_request_blocks_deneb,
|
||||
@@ -2167,9 +2153,7 @@ mod yaml_tests {
|
||||
check_default!(resp_timeout);
|
||||
check_default!(message_domain_invalid_snappy);
|
||||
check_default!(message_domain_valid_snappy);
|
||||
check_default!(attestation_subnet_extra_bits);
|
||||
check_default!(attestation_subnet_prefix_bits);
|
||||
check_default!(attestation_subnet_shuffling_prefix_bits);
|
||||
|
||||
assert_eq!(chain_spec.bellatrix_fork_epoch, None);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::beacon_block_body::{KzgCommitments, BLOB_KZG_COMMITMENTS_INDEX};
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::BeaconStateError;
|
||||
use crate::{BeaconBlockHeader, EthSpec, Hash256, KzgProofs, SignedBeaconBlockHeader, Slot};
|
||||
use crate::{BeaconBlockHeader, Epoch, EthSpec, Hash256, KzgProofs, SignedBeaconBlockHeader, Slot};
|
||||
use bls::Signature;
|
||||
use derivative::Derivative;
|
||||
use kzg::Error as KzgError;
|
||||
@@ -67,6 +67,10 @@ impl<E: EthSpec> DataColumnSidecar<E> {
|
||||
self.signed_block_header.message.slot
|
||||
}
|
||||
|
||||
pub fn epoch(&self) -> Epoch {
|
||||
self.slot().epoch(E::slots_per_epoch())
|
||||
}
|
||||
|
||||
pub fn block_root(&self) -> Hash256 {
|
||||
self.signed_block_header.message.tree_hash_root()
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::{Hash256, PublicKeyBytes, Signature};
|
||||
use crate::{Hash256, PublicKeyBytes};
|
||||
use bls::SignatureBytes;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz::Encode;
|
||||
use ssz_derive::{Decode, Encode};
|
||||
@@ -10,7 +11,6 @@ use tree_hash_derive::TreeHash;
|
||||
arbitrary::Arbitrary,
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
Hash,
|
||||
Clone,
|
||||
Serialize,
|
||||
@@ -25,7 +25,7 @@ pub struct DepositRequest {
|
||||
pub withdrawal_credentials: Hash256,
|
||||
#[serde(with = "serde_utils::quoted_u64")]
|
||||
pub amount: u64,
|
||||
pub signature: Signature,
|
||||
pub signature: SignatureBytes,
|
||||
#[serde(with = "serde_utils::quoted_u64")]
|
||||
pub index: u64,
|
||||
}
|
||||
@@ -36,7 +36,7 @@ impl DepositRequest {
|
||||
pubkey: PublicKeyBytes::empty(),
|
||||
withdrawal_credentials: Hash256::ZERO,
|
||||
amount: 0,
|
||||
signature: Signature::empty(),
|
||||
signature: SignatureBytes::empty(),
|
||||
index: 0,
|
||||
}
|
||||
.as_ssz_bytes()
|
||||
|
||||
@@ -149,7 +149,7 @@ pub trait EthSpec:
|
||||
/*
|
||||
* New in Electra
|
||||
*/
|
||||
type PendingBalanceDepositsLimit: Unsigned + Clone + Sync + Send + Debug + PartialEq;
|
||||
type PendingDepositsLimit: Unsigned + Clone + Sync + Send + Debug + PartialEq;
|
||||
type PendingPartialWithdrawalsLimit: Unsigned + Clone + Sync + Send + Debug + PartialEq;
|
||||
type PendingConsolidationsLimit: Unsigned + Clone + Sync + Send + Debug + PartialEq;
|
||||
type MaxConsolidationRequestsPerPayload: Unsigned + Clone + Sync + Send + Debug + PartialEq;
|
||||
@@ -157,6 +157,7 @@ pub trait EthSpec:
|
||||
type MaxAttesterSlashingsElectra: Unsigned + Clone + Sync + Send + Debug + PartialEq;
|
||||
type MaxAttestationsElectra: Unsigned + Clone + Sync + Send + Debug + PartialEq;
|
||||
type MaxWithdrawalRequestsPerPayload: Unsigned + Clone + Sync + Send + Debug + PartialEq;
|
||||
type MaxPendingDepositsPerEpoch: Unsigned + Clone + Sync + Send + Debug + PartialEq;
|
||||
|
||||
fn default_spec() -> ChainSpec;
|
||||
|
||||
@@ -324,9 +325,9 @@ pub trait EthSpec:
|
||||
.expect("Preset values are not configurable and never result in non-positive block body depth")
|
||||
}
|
||||
|
||||
/// Returns the `PENDING_BALANCE_DEPOSITS_LIMIT` constant for this specification.
|
||||
fn pending_balance_deposits_limit() -> usize {
|
||||
Self::PendingBalanceDepositsLimit::to_usize()
|
||||
/// Returns the `PENDING_DEPOSITS_LIMIT` constant for this specification.
|
||||
fn pending_deposits_limit() -> usize {
|
||||
Self::PendingDepositsLimit::to_usize()
|
||||
}
|
||||
|
||||
/// Returns the `PENDING_PARTIAL_WITHDRAWALS_LIMIT` constant for this specification.
|
||||
@@ -364,6 +365,11 @@ pub trait EthSpec:
|
||||
Self::MaxWithdrawalRequestsPerPayload::to_usize()
|
||||
}
|
||||
|
||||
/// Returns the `MAX_PENDING_DEPOSITS_PER_EPOCH` constant for this specification.
|
||||
fn max_pending_deposits_per_epoch() -> usize {
|
||||
Self::MaxPendingDepositsPerEpoch::to_usize()
|
||||
}
|
||||
|
||||
fn kzg_commitments_inclusion_proof_depth() -> usize {
|
||||
Self::KzgCommitmentsInclusionProofDepth::to_usize()
|
||||
}
|
||||
@@ -422,7 +428,7 @@ impl EthSpec for MainnetEthSpec {
|
||||
type SlotsPerEth1VotingPeriod = U2048; // 64 epochs * 32 slots per epoch
|
||||
type MaxBlsToExecutionChanges = U16;
|
||||
type MaxWithdrawalsPerPayload = U16;
|
||||
type PendingBalanceDepositsLimit = U134217728;
|
||||
type PendingDepositsLimit = U134217728;
|
||||
type PendingPartialWithdrawalsLimit = U134217728;
|
||||
type PendingConsolidationsLimit = U262144;
|
||||
type MaxConsolidationRequestsPerPayload = U1;
|
||||
@@ -430,6 +436,7 @@ impl EthSpec for MainnetEthSpec {
|
||||
type MaxAttesterSlashingsElectra = U1;
|
||||
type MaxAttestationsElectra = U8;
|
||||
type MaxWithdrawalRequestsPerPayload = U16;
|
||||
type MaxPendingDepositsPerEpoch = U16;
|
||||
|
||||
fn default_spec() -> ChainSpec {
|
||||
ChainSpec::mainnet()
|
||||
@@ -491,7 +498,8 @@ impl EthSpec for MinimalEthSpec {
|
||||
MaxExtraDataBytes,
|
||||
MaxBlsToExecutionChanges,
|
||||
BytesPerFieldElement,
|
||||
PendingBalanceDepositsLimit,
|
||||
PendingDepositsLimit,
|
||||
MaxPendingDepositsPerEpoch,
|
||||
MaxConsolidationRequestsPerPayload,
|
||||
MaxAttesterSlashingsElectra,
|
||||
MaxAttestationsElectra
|
||||
@@ -547,7 +555,7 @@ impl EthSpec for GnosisEthSpec {
|
||||
type BytesPerFieldElement = U32;
|
||||
type BytesPerBlob = U131072;
|
||||
type KzgCommitmentInclusionProofDepth = U17;
|
||||
type PendingBalanceDepositsLimit = U134217728;
|
||||
type PendingDepositsLimit = U134217728;
|
||||
type PendingPartialWithdrawalsLimit = U134217728;
|
||||
type PendingConsolidationsLimit = U262144;
|
||||
type MaxConsolidationRequestsPerPayload = U1;
|
||||
@@ -555,6 +563,7 @@ impl EthSpec for GnosisEthSpec {
|
||||
type MaxAttesterSlashingsElectra = U1;
|
||||
type MaxAttestationsElectra = U8;
|
||||
type MaxWithdrawalRequestsPerPayload = U16;
|
||||
type MaxPendingDepositsPerEpoch = U16;
|
||||
type FieldElementsPerCell = U64;
|
||||
type FieldElementsPerExtBlob = U8192;
|
||||
type BytesPerCell = U2048;
|
||||
|
||||
@@ -52,9 +52,11 @@ pub struct ExecutionBlockHeader {
|
||||
pub blob_gas_used: Option<u64>,
|
||||
pub excess_blob_gas: Option<u64>,
|
||||
pub parent_beacon_block_root: Option<Hash256>,
|
||||
pub requests_root: Option<Hash256>,
|
||||
}
|
||||
|
||||
impl ExecutionBlockHeader {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn from_payload<E: EthSpec>(
|
||||
payload: ExecutionPayloadRef<E>,
|
||||
rlp_empty_list_root: Hash256,
|
||||
@@ -63,6 +65,7 @@ impl ExecutionBlockHeader {
|
||||
rlp_blob_gas_used: Option<u64>,
|
||||
rlp_excess_blob_gas: Option<u64>,
|
||||
rlp_parent_beacon_block_root: Option<Hash256>,
|
||||
rlp_requests_root: Option<Hash256>,
|
||||
) -> Self {
|
||||
// Most of these field mappings are defined in EIP-3675 except for `mixHash`, which is
|
||||
// defined in EIP-4399.
|
||||
@@ -87,6 +90,7 @@ impl ExecutionBlockHeader {
|
||||
blob_gas_used: rlp_blob_gas_used,
|
||||
excess_blob_gas: rlp_excess_blob_gas,
|
||||
parent_beacon_block_root: rlp_parent_beacon_block_root,
|
||||
requests_root: rlp_requests_root,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -114,6 +118,7 @@ pub struct EncodableExecutionBlockHeader<'a> {
|
||||
pub blob_gas_used: Option<u64>,
|
||||
pub excess_blob_gas: Option<u64>,
|
||||
pub parent_beacon_block_root: Option<&'a [u8]>,
|
||||
pub requests_root: Option<&'a [u8]>,
|
||||
}
|
||||
|
||||
impl<'a> From<&'a ExecutionBlockHeader> for EncodableExecutionBlockHeader<'a> {
|
||||
@@ -139,6 +144,7 @@ impl<'a> From<&'a ExecutionBlockHeader> for EncodableExecutionBlockHeader<'a> {
|
||||
blob_gas_used: header.blob_gas_used,
|
||||
excess_blob_gas: header.excess_blob_gas,
|
||||
parent_beacon_block_root: None,
|
||||
requests_root: None,
|
||||
};
|
||||
if let Some(withdrawals_root) = &header.withdrawals_root {
|
||||
encodable.withdrawals_root = Some(withdrawals_root.as_slice());
|
||||
@@ -146,6 +152,9 @@ impl<'a> From<&'a ExecutionBlockHeader> for EncodableExecutionBlockHeader<'a> {
|
||||
if let Some(parent_beacon_block_root) = &header.parent_beacon_block_root {
|
||||
encodable.parent_beacon_block_root = Some(parent_beacon_block_root.as_slice())
|
||||
}
|
||||
if let Some(requests_root) = &header.requests_root {
|
||||
encodable.requests_root = Some(requests_root.as_slice())
|
||||
}
|
||||
encodable
|
||||
}
|
||||
}
|
||||
|
||||
@@ -371,7 +371,7 @@ impl<E: EthSpec> TryFrom<ExecutionPayloadHeader<E>> for ExecutionPayloadHeaderDe
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, E: EthSpec> ExecutionPayloadHeaderRefMut<'a, E> {
|
||||
impl<E: EthSpec> ExecutionPayloadHeaderRefMut<'_, E> {
|
||||
/// Mutate through
|
||||
pub fn replace(self, header: ExecutionPayloadHeader<E>) -> Result<(), BeaconStateError> {
|
||||
match self {
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::{ConsolidationRequest, DepositRequest, EthSpec, WithdrawalRequest};
|
||||
use crate::{ConsolidationRequest, DepositRequest, EthSpec, Hash256, WithdrawalRequest};
|
||||
use alloy_primitives::Bytes;
|
||||
use derivative::Derivative;
|
||||
use ethereum_hashing::{DynamicContext, Sha256Context};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz::Encode;
|
||||
use ssz_derive::{Decode, Encode};
|
||||
@@ -47,6 +48,43 @@ impl<E: EthSpec> ExecutionRequests<E> {
|
||||
let consolidation_bytes = Bytes::from(self.consolidations.as_ssz_bytes());
|
||||
vec![deposit_bytes, withdrawal_bytes, consolidation_bytes]
|
||||
}
|
||||
|
||||
/// Generate the execution layer `requests_hash` based on EIP-7685.
|
||||
///
|
||||
/// `sha256(sha256(requests_0) ++ sha256(requests_1) ++ ...)`
|
||||
pub fn requests_hash(&self) -> Hash256 {
|
||||
let mut hasher = DynamicContext::new();
|
||||
|
||||
for (i, request) in self.get_execution_requests_list().iter().enumerate() {
|
||||
let mut request_hasher = DynamicContext::new();
|
||||
request_hasher.update(&[i as u8]);
|
||||
request_hasher.update(request);
|
||||
let request_hash = request_hasher.finalize();
|
||||
|
||||
hasher.update(&request_hash);
|
||||
}
|
||||
|
||||
hasher.finalize().into()
|
||||
}
|
||||
}
|
||||
|
||||
/// This is used to index into the `execution_requests` array.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum RequestPrefix {
|
||||
Deposit,
|
||||
Withdrawal,
|
||||
Consolidation,
|
||||
}
|
||||
|
||||
impl RequestPrefix {
|
||||
pub fn from_prefix(prefix: u8) -> Option<Self> {
|
||||
match prefix {
|
||||
0 => Some(Self::Deposit),
|
||||
1 => Some(Self::Withdrawal),
|
||||
2 => Some(Self::Consolidation),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -15,6 +15,7 @@ use tree_hash_derive::TreeHash;
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
|
||||
@@ -134,7 +134,7 @@ impl<E: EthSpec> IndexedAttestation<E> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, E: EthSpec> IndexedAttestationRef<'a, E> {
|
||||
impl<E: EthSpec> IndexedAttestationRef<'_, E> {
|
||||
pub fn is_double_vote(&self, other: Self) -> bool {
|
||||
self.data().target.epoch == other.data().target.epoch && self.data() != other.data()
|
||||
}
|
||||
|
||||
@@ -54,8 +54,8 @@ pub mod light_client_finality_update;
|
||||
pub mod light_client_optimistic_update;
|
||||
pub mod light_client_update;
|
||||
pub mod pending_attestation;
|
||||
pub mod pending_balance_deposit;
|
||||
pub mod pending_consolidation;
|
||||
pub mod pending_deposit;
|
||||
pub mod pending_partial_withdrawal;
|
||||
pub mod proposer_preparation_data;
|
||||
pub mod proposer_slashing;
|
||||
@@ -170,7 +170,7 @@ pub use crate::execution_payload_header::{
|
||||
ExecutionPayloadHeaderDeneb, ExecutionPayloadHeaderElectra, ExecutionPayloadHeaderRef,
|
||||
ExecutionPayloadHeaderRefMut,
|
||||
};
|
||||
pub use crate::execution_requests::ExecutionRequests;
|
||||
pub use crate::execution_requests::{ExecutionRequests, RequestPrefix};
|
||||
pub use crate::fork::Fork;
|
||||
pub use crate::fork_context::ForkContext;
|
||||
pub use crate::fork_data::ForkData;
|
||||
@@ -200,7 +200,7 @@ pub use crate::light_client_optimistic_update::{
|
||||
};
|
||||
pub use crate::light_client_update::{
|
||||
Error as LightClientUpdateError, LightClientUpdate, LightClientUpdateAltair,
|
||||
LightClientUpdateCapella, LightClientUpdateDeneb, LightClientUpdateElectra,
|
||||
LightClientUpdateCapella, LightClientUpdateDeneb, LightClientUpdateElectra, MerkleProof,
|
||||
};
|
||||
pub use crate::participation_flags::ParticipationFlags;
|
||||
pub use crate::payload::{
|
||||
@@ -210,8 +210,8 @@ pub use crate::payload::{
|
||||
FullPayloadRef, OwnedExecPayload,
|
||||
};
|
||||
pub use crate::pending_attestation::PendingAttestation;
|
||||
pub use crate::pending_balance_deposit::PendingBalanceDeposit;
|
||||
pub use crate::pending_consolidation::PendingConsolidation;
|
||||
pub use crate::pending_deposit::PendingDeposit;
|
||||
pub use crate::pending_partial_withdrawal::PendingPartialWithdrawal;
|
||||
pub use crate::preset::{
|
||||
AltairPreset, BasePreset, BellatrixPreset, CapellaPreset, DenebPreset, ElectraPreset,
|
||||
|
||||
@@ -57,7 +57,16 @@ pub struct LightClientBootstrap<E: EthSpec> {
|
||||
/// The `SyncCommittee` used in the requested period.
|
||||
pub current_sync_committee: Arc<SyncCommittee<E>>,
|
||||
/// Merkle proof for sync committee
|
||||
#[superstruct(
|
||||
only(Altair, Capella, Deneb),
|
||||
partial_getter(rename = "current_sync_committee_branch_altair")
|
||||
)]
|
||||
pub current_sync_committee_branch: FixedVector<Hash256, CurrentSyncCommitteeProofLen>,
|
||||
#[superstruct(
|
||||
only(Electra),
|
||||
partial_getter(rename = "current_sync_committee_branch_electra")
|
||||
)]
|
||||
pub current_sync_committee_branch: FixedVector<Hash256, CurrentSyncCommitteeProofLenElectra>,
|
||||
}
|
||||
|
||||
impl<E: EthSpec> LightClientBootstrap<E> {
|
||||
@@ -115,7 +124,7 @@ impl<E: EthSpec> LightClientBootstrap<E> {
|
||||
pub fn new(
|
||||
block: &SignedBlindedBeaconBlock<E>,
|
||||
current_sync_committee: Arc<SyncCommittee<E>>,
|
||||
current_sync_committee_branch: FixedVector<Hash256, CurrentSyncCommitteeProofLen>,
|
||||
current_sync_committee_branch: Vec<Hash256>,
|
||||
chain_spec: &ChainSpec,
|
||||
) -> Result<Self, Error> {
|
||||
let light_client_bootstrap = match block
|
||||
@@ -126,22 +135,22 @@ impl<E: EthSpec> LightClientBootstrap<E> {
|
||||
ForkName::Altair | ForkName::Bellatrix => Self::Altair(LightClientBootstrapAltair {
|
||||
header: LightClientHeaderAltair::block_to_light_client_header(block)?,
|
||||
current_sync_committee,
|
||||
current_sync_committee_branch,
|
||||
current_sync_committee_branch: current_sync_committee_branch.into(),
|
||||
}),
|
||||
ForkName::Capella => Self::Capella(LightClientBootstrapCapella {
|
||||
header: LightClientHeaderCapella::block_to_light_client_header(block)?,
|
||||
current_sync_committee,
|
||||
current_sync_committee_branch,
|
||||
current_sync_committee_branch: current_sync_committee_branch.into(),
|
||||
}),
|
||||
ForkName::Deneb => Self::Deneb(LightClientBootstrapDeneb {
|
||||
header: LightClientHeaderDeneb::block_to_light_client_header(block)?,
|
||||
current_sync_committee,
|
||||
current_sync_committee_branch,
|
||||
current_sync_committee_branch: current_sync_committee_branch.into(),
|
||||
}),
|
||||
ForkName::Electra => Self::Electra(LightClientBootstrapElectra {
|
||||
header: LightClientHeaderElectra::block_to_light_client_header(block)?,
|
||||
current_sync_committee,
|
||||
current_sync_committee_branch,
|
||||
current_sync_committee_branch: current_sync_committee_branch.into(),
|
||||
}),
|
||||
};
|
||||
|
||||
@@ -155,9 +164,7 @@ impl<E: EthSpec> LightClientBootstrap<E> {
|
||||
) -> Result<Self, Error> {
|
||||
let mut header = beacon_state.latest_block_header().clone();
|
||||
header.state_root = beacon_state.update_tree_hash_cache()?;
|
||||
let current_sync_committee_branch =
|
||||
FixedVector::new(beacon_state.compute_merkle_proof(CURRENT_SYNC_COMMITTEE_INDEX)?)?;
|
||||
|
||||
let current_sync_committee_branch = beacon_state.compute_current_sync_committee_proof()?;
|
||||
let current_sync_committee = beacon_state.current_sync_committee()?.clone();
|
||||
|
||||
let light_client_bootstrap = match block
|
||||
@@ -168,22 +175,22 @@ impl<E: EthSpec> LightClientBootstrap<E> {
|
||||
ForkName::Altair | ForkName::Bellatrix => Self::Altair(LightClientBootstrapAltair {
|
||||
header: LightClientHeaderAltair::block_to_light_client_header(block)?,
|
||||
current_sync_committee,
|
||||
current_sync_committee_branch,
|
||||
current_sync_committee_branch: current_sync_committee_branch.into(),
|
||||
}),
|
||||
ForkName::Capella => Self::Capella(LightClientBootstrapCapella {
|
||||
header: LightClientHeaderCapella::block_to_light_client_header(block)?,
|
||||
current_sync_committee,
|
||||
current_sync_committee_branch,
|
||||
current_sync_committee_branch: current_sync_committee_branch.into(),
|
||||
}),
|
||||
ForkName::Deneb => Self::Deneb(LightClientBootstrapDeneb {
|
||||
header: LightClientHeaderDeneb::block_to_light_client_header(block)?,
|
||||
current_sync_committee,
|
||||
current_sync_committee_branch,
|
||||
current_sync_committee_branch: current_sync_committee_branch.into(),
|
||||
}),
|
||||
ForkName::Electra => Self::Electra(LightClientBootstrapElectra {
|
||||
header: LightClientHeaderElectra::block_to_light_client_header(block)?,
|
||||
current_sync_committee,
|
||||
current_sync_committee_branch,
|
||||
current_sync_committee_branch: current_sync_committee_branch.into(),
|
||||
}),
|
||||
};
|
||||
|
||||
@@ -210,8 +217,28 @@ impl<E: EthSpec> ForkVersionDeserialize for LightClientBootstrap<E> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::MainnetEthSpec;
|
||||
// `ssz_tests!` can only be defined once per namespace
|
||||
#[cfg(test)]
|
||||
mod altair {
|
||||
use crate::{LightClientBootstrapAltair, MainnetEthSpec};
|
||||
ssz_tests!(LightClientBootstrapAltair<MainnetEthSpec>);
|
||||
}
|
||||
|
||||
ssz_tests!(LightClientBootstrapDeneb<MainnetEthSpec>);
|
||||
#[cfg(test)]
|
||||
mod capella {
|
||||
use crate::{LightClientBootstrapCapella, MainnetEthSpec};
|
||||
ssz_tests!(LightClientBootstrapCapella<MainnetEthSpec>);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod deneb {
|
||||
use crate::{LightClientBootstrapDeneb, MainnetEthSpec};
|
||||
ssz_tests!(LightClientBootstrapDeneb<MainnetEthSpec>);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod electra {
|
||||
use crate::{LightClientBootstrapElectra, MainnetEthSpec};
|
||||
ssz_tests!(LightClientBootstrapElectra<MainnetEthSpec>);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,8 +63,13 @@ pub struct LightClientFinalityUpdate<E: EthSpec> {
|
||||
#[superstruct(only(Electra), partial_getter(rename = "finalized_header_electra"))]
|
||||
pub finalized_header: LightClientHeaderElectra<E>,
|
||||
/// Merkle proof attesting finalized header.
|
||||
#[test_random(default)]
|
||||
#[superstruct(
|
||||
only(Altair, Capella, Deneb),
|
||||
partial_getter(rename = "finality_branch_altair")
|
||||
)]
|
||||
pub finality_branch: FixedVector<Hash256, FinalizedRootProofLen>,
|
||||
#[superstruct(only(Electra), partial_getter(rename = "finality_branch_electra"))]
|
||||
pub finality_branch: FixedVector<Hash256, FinalizedRootProofLenElectra>,
|
||||
/// current sync aggregate
|
||||
pub sync_aggregate: SyncAggregate<E>,
|
||||
/// Slot of the sync aggregated signature
|
||||
@@ -75,7 +80,7 @@ impl<E: EthSpec> LightClientFinalityUpdate<E> {
|
||||
pub fn new(
|
||||
attested_block: &SignedBlindedBeaconBlock<E>,
|
||||
finalized_block: &SignedBlindedBeaconBlock<E>,
|
||||
finality_branch: FixedVector<Hash256, FinalizedRootProofLen>,
|
||||
finality_branch: Vec<Hash256>,
|
||||
sync_aggregate: SyncAggregate<E>,
|
||||
signature_slot: Slot,
|
||||
chain_spec: &ChainSpec,
|
||||
@@ -92,7 +97,7 @@ impl<E: EthSpec> LightClientFinalityUpdate<E> {
|
||||
finalized_header: LightClientHeaderAltair::block_to_light_client_header(
|
||||
finalized_block,
|
||||
)?,
|
||||
finality_branch,
|
||||
finality_branch: finality_branch.into(),
|
||||
sync_aggregate,
|
||||
signature_slot,
|
||||
})
|
||||
@@ -104,7 +109,7 @@ impl<E: EthSpec> LightClientFinalityUpdate<E> {
|
||||
finalized_header: LightClientHeaderCapella::block_to_light_client_header(
|
||||
finalized_block,
|
||||
)?,
|
||||
finality_branch,
|
||||
finality_branch: finality_branch.into(),
|
||||
sync_aggregate,
|
||||
signature_slot,
|
||||
}),
|
||||
@@ -115,7 +120,7 @@ impl<E: EthSpec> LightClientFinalityUpdate<E> {
|
||||
finalized_header: LightClientHeaderDeneb::block_to_light_client_header(
|
||||
finalized_block,
|
||||
)?,
|
||||
finality_branch,
|
||||
finality_branch: finality_branch.into(),
|
||||
sync_aggregate,
|
||||
signature_slot,
|
||||
}),
|
||||
@@ -126,7 +131,7 @@ impl<E: EthSpec> LightClientFinalityUpdate<E> {
|
||||
finalized_header: LightClientHeaderElectra::block_to_light_client_header(
|
||||
finalized_block,
|
||||
)?,
|
||||
finality_branch,
|
||||
finality_branch: finality_branch.into(),
|
||||
sync_aggregate,
|
||||
signature_slot,
|
||||
}),
|
||||
@@ -226,8 +231,28 @@ impl<E: EthSpec> ForkVersionDeserialize for LightClientFinalityUpdate<E> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::MainnetEthSpec;
|
||||
// `ssz_tests!` can only be defined once per namespace
|
||||
#[cfg(test)]
|
||||
mod altair {
|
||||
use crate::{LightClientFinalityUpdateAltair, MainnetEthSpec};
|
||||
ssz_tests!(LightClientFinalityUpdateAltair<MainnetEthSpec>);
|
||||
}
|
||||
|
||||
ssz_tests!(LightClientFinalityUpdateDeneb<MainnetEthSpec>);
|
||||
#[cfg(test)]
|
||||
mod capella {
|
||||
use crate::{LightClientFinalityUpdateCapella, MainnetEthSpec};
|
||||
ssz_tests!(LightClientFinalityUpdateCapella<MainnetEthSpec>);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod deneb {
|
||||
use crate::{LightClientFinalityUpdateDeneb, MainnetEthSpec};
|
||||
ssz_tests!(LightClientFinalityUpdateDeneb<MainnetEthSpec>);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod electra {
|
||||
use crate::{LightClientFinalityUpdateElectra, MainnetEthSpec};
|
||||
ssz_tests!(LightClientFinalityUpdateElectra<MainnetEthSpec>);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,12 +179,12 @@ impl<E: EthSpec> LightClientHeaderCapella<E> {
|
||||
.to_ref()
|
||||
.block_body_merkle_proof(EXECUTION_PAYLOAD_INDEX)?;
|
||||
|
||||
return Ok(LightClientHeaderCapella {
|
||||
Ok(LightClientHeaderCapella {
|
||||
beacon: block.message().block_header(),
|
||||
execution: header,
|
||||
execution_branch: FixedVector::new(execution_branch)?,
|
||||
_phantom_data: PhantomData,
|
||||
});
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -307,3 +307,31 @@ impl<E: EthSpec> ForkVersionDeserialize for LightClientHeader<E> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
// `ssz_tests!` can only be defined once per namespace
|
||||
#[cfg(test)]
|
||||
mod altair {
|
||||
use crate::{LightClientHeaderAltair, MainnetEthSpec};
|
||||
ssz_tests!(LightClientHeaderAltair<MainnetEthSpec>);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod capella {
|
||||
use crate::{LightClientHeaderCapella, MainnetEthSpec};
|
||||
ssz_tests!(LightClientHeaderCapella<MainnetEthSpec>);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod deneb {
|
||||
use crate::{LightClientHeaderDeneb, MainnetEthSpec};
|
||||
ssz_tests!(LightClientHeaderDeneb<MainnetEthSpec>);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod electra {
|
||||
use crate::{LightClientHeaderElectra, MainnetEthSpec};
|
||||
ssz_tests!(LightClientHeaderElectra<MainnetEthSpec>);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -214,8 +214,28 @@ impl<E: EthSpec> ForkVersionDeserialize for LightClientOptimisticUpdate<E> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::MainnetEthSpec;
|
||||
// `ssz_tests!` can only be defined once per namespace
|
||||
#[cfg(test)]
|
||||
mod altair {
|
||||
use crate::{LightClientOptimisticUpdateAltair, MainnetEthSpec};
|
||||
ssz_tests!(LightClientOptimisticUpdateAltair<MainnetEthSpec>);
|
||||
}
|
||||
|
||||
ssz_tests!(LightClientOptimisticUpdateDeneb<MainnetEthSpec>);
|
||||
#[cfg(test)]
|
||||
mod capella {
|
||||
use crate::{LightClientOptimisticUpdateCapella, MainnetEthSpec};
|
||||
ssz_tests!(LightClientOptimisticUpdateCapella<MainnetEthSpec>);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod deneb {
|
||||
use crate::{LightClientOptimisticUpdateDeneb, MainnetEthSpec};
|
||||
ssz_tests!(LightClientOptimisticUpdateDeneb<MainnetEthSpec>);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod electra {
|
||||
use crate::{LightClientOptimisticUpdateElectra, MainnetEthSpec};
|
||||
ssz_tests!(LightClientOptimisticUpdateElectra<MainnetEthSpec>);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ use serde_json::Value;
|
||||
use ssz::{Decode, Encode};
|
||||
use ssz_derive::Decode;
|
||||
use ssz_derive::Encode;
|
||||
use ssz_types::typenum::{U4, U5, U6};
|
||||
use ssz_types::typenum::{U4, U5, U6, U7};
|
||||
use std::sync::Arc;
|
||||
use superstruct::superstruct;
|
||||
use test_random_derive::TestRandom;
|
||||
@@ -25,24 +25,39 @@ pub const CURRENT_SYNC_COMMITTEE_INDEX: usize = 54;
|
||||
pub const NEXT_SYNC_COMMITTEE_INDEX: usize = 55;
|
||||
pub const EXECUTION_PAYLOAD_INDEX: usize = 25;
|
||||
|
||||
pub const FINALIZED_ROOT_INDEX_ELECTRA: usize = 169;
|
||||
pub const CURRENT_SYNC_COMMITTEE_INDEX_ELECTRA: usize = 86;
|
||||
pub const NEXT_SYNC_COMMITTEE_INDEX_ELECTRA: usize = 87;
|
||||
|
||||
pub type FinalizedRootProofLen = U6;
|
||||
pub type CurrentSyncCommitteeProofLen = U5;
|
||||
pub type ExecutionPayloadProofLen = U4;
|
||||
|
||||
pub type NextSyncCommitteeProofLen = U5;
|
||||
|
||||
pub type FinalizedRootProofLenElectra = U7;
|
||||
pub type CurrentSyncCommitteeProofLenElectra = U6;
|
||||
pub type NextSyncCommitteeProofLenElectra = U6;
|
||||
|
||||
pub const FINALIZED_ROOT_PROOF_LEN: usize = 6;
|
||||
pub const CURRENT_SYNC_COMMITTEE_PROOF_LEN: usize = 5;
|
||||
pub const NEXT_SYNC_COMMITTEE_PROOF_LEN: usize = 5;
|
||||
pub const EXECUTION_PAYLOAD_PROOF_LEN: usize = 4;
|
||||
|
||||
pub const FINALIZED_ROOT_PROOF_LEN_ELECTRA: usize = 7;
|
||||
pub const NEXT_SYNC_COMMITTEE_PROOF_LEN_ELECTRA: usize = 6;
|
||||
pub const CURRENT_SYNC_COMMITTEE_PROOF_LEN_ELECTRA: usize = 6;
|
||||
|
||||
pub type MerkleProof = Vec<Hash256>;
|
||||
// Max light client updates by range request limits
|
||||
// spec: https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/p2p-interface.md#configuration
|
||||
pub const MAX_REQUEST_LIGHT_CLIENT_UPDATES: u64 = 128;
|
||||
|
||||
type FinalityBranch = FixedVector<Hash256, FinalizedRootProofLen>;
|
||||
type FinalityBranchElectra = FixedVector<Hash256, FinalizedRootProofLenElectra>;
|
||||
type NextSyncCommitteeBranch = FixedVector<Hash256, NextSyncCommitteeProofLen>;
|
||||
|
||||
type NextSyncCommitteeBranchElectra = FixedVector<Hash256, NextSyncCommitteeProofLenElectra>;
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub enum Error {
|
||||
SszTypesError(ssz_types::Error),
|
||||
@@ -124,8 +139,17 @@ pub struct LightClientUpdate<E: EthSpec> {
|
||||
pub attested_header: LightClientHeaderElectra<E>,
|
||||
/// The `SyncCommittee` used in the next period.
|
||||
pub next_sync_committee: Arc<SyncCommittee<E>>,
|
||||
/// Merkle proof for next sync committee
|
||||
// Merkle proof for next sync committee
|
||||
#[superstruct(
|
||||
only(Altair, Capella, Deneb),
|
||||
partial_getter(rename = "next_sync_committee_branch_altair")
|
||||
)]
|
||||
pub next_sync_committee_branch: NextSyncCommitteeBranch,
|
||||
#[superstruct(
|
||||
only(Electra),
|
||||
partial_getter(rename = "next_sync_committee_branch_electra")
|
||||
)]
|
||||
pub next_sync_committee_branch: NextSyncCommitteeBranchElectra,
|
||||
/// The last `BeaconBlockHeader` from the last attested finalized block (end of epoch).
|
||||
#[superstruct(only(Altair), partial_getter(rename = "finalized_header_altair"))]
|
||||
pub finalized_header: LightClientHeaderAltair<E>,
|
||||
@@ -136,7 +160,13 @@ pub struct LightClientUpdate<E: EthSpec> {
|
||||
#[superstruct(only(Electra), partial_getter(rename = "finalized_header_electra"))]
|
||||
pub finalized_header: LightClientHeaderElectra<E>,
|
||||
/// Merkle proof attesting finalized header.
|
||||
#[superstruct(
|
||||
only(Altair, Capella, Deneb),
|
||||
partial_getter(rename = "finality_branch_altair")
|
||||
)]
|
||||
pub finality_branch: FinalityBranch,
|
||||
#[superstruct(only(Electra), partial_getter(rename = "finality_branch_electra"))]
|
||||
pub finality_branch: FinalityBranchElectra,
|
||||
/// current sync aggreggate
|
||||
pub sync_aggregate: SyncAggregate<E>,
|
||||
/// Slot of the sync aggregated signature
|
||||
@@ -165,8 +195,8 @@ impl<E: EthSpec> LightClientUpdate<E> {
|
||||
sync_aggregate: &SyncAggregate<E>,
|
||||
block_slot: Slot,
|
||||
next_sync_committee: Arc<SyncCommittee<E>>,
|
||||
next_sync_committee_branch: FixedVector<Hash256, NextSyncCommitteeProofLen>,
|
||||
finality_branch: FixedVector<Hash256, FinalizedRootProofLen>,
|
||||
next_sync_committee_branch: Vec<Hash256>,
|
||||
finality_branch: Vec<Hash256>,
|
||||
attested_block: &SignedBlindedBeaconBlock<E>,
|
||||
finalized_block: Option<&SignedBlindedBeaconBlock<E>>,
|
||||
chain_spec: &ChainSpec,
|
||||
@@ -189,9 +219,9 @@ impl<E: EthSpec> LightClientUpdate<E> {
|
||||
Self::Altair(LightClientUpdateAltair {
|
||||
attested_header,
|
||||
next_sync_committee,
|
||||
next_sync_committee_branch,
|
||||
next_sync_committee_branch: next_sync_committee_branch.into(),
|
||||
finalized_header,
|
||||
finality_branch,
|
||||
finality_branch: finality_branch.into(),
|
||||
sync_aggregate: sync_aggregate.clone(),
|
||||
signature_slot: block_slot,
|
||||
})
|
||||
@@ -209,9 +239,9 @@ impl<E: EthSpec> LightClientUpdate<E> {
|
||||
Self::Capella(LightClientUpdateCapella {
|
||||
attested_header,
|
||||
next_sync_committee,
|
||||
next_sync_committee_branch,
|
||||
next_sync_committee_branch: next_sync_committee_branch.into(),
|
||||
finalized_header,
|
||||
finality_branch,
|
||||
finality_branch: finality_branch.into(),
|
||||
sync_aggregate: sync_aggregate.clone(),
|
||||
signature_slot: block_slot,
|
||||
})
|
||||
@@ -229,9 +259,9 @@ impl<E: EthSpec> LightClientUpdate<E> {
|
||||
Self::Deneb(LightClientUpdateDeneb {
|
||||
attested_header,
|
||||
next_sync_committee,
|
||||
next_sync_committee_branch,
|
||||
next_sync_committee_branch: next_sync_committee_branch.into(),
|
||||
finalized_header,
|
||||
finality_branch,
|
||||
finality_branch: finality_branch.into(),
|
||||
sync_aggregate: sync_aggregate.clone(),
|
||||
signature_slot: block_slot,
|
||||
})
|
||||
@@ -249,9 +279,9 @@ impl<E: EthSpec> LightClientUpdate<E> {
|
||||
Self::Electra(LightClientUpdateElectra {
|
||||
attested_header,
|
||||
next_sync_committee,
|
||||
next_sync_committee_branch,
|
||||
next_sync_committee_branch: next_sync_committee_branch.into(),
|
||||
finalized_header,
|
||||
finality_branch,
|
||||
finality_branch: finality_branch.into(),
|
||||
sync_aggregate: sync_aggregate.clone(),
|
||||
signature_slot: block_slot,
|
||||
})
|
||||
@@ -388,25 +418,21 @@ impl<E: EthSpec> LightClientUpdate<E> {
|
||||
return Ok(new_attested_header_slot < prev_attested_header_slot);
|
||||
}
|
||||
|
||||
return Ok(new.signature_slot() < self.signature_slot());
|
||||
Ok(new.signature_slot() < self.signature_slot())
|
||||
}
|
||||
|
||||
fn is_next_sync_committee_branch_empty(&self) -> bool {
|
||||
for index in self.next_sync_committee_branch().iter() {
|
||||
if *index != Hash256::default() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
fn is_next_sync_committee_branch_empty<'a>(&'a self) -> bool {
|
||||
map_light_client_update_ref!(&'a _, self.to_ref(), |update, cons| {
|
||||
cons(update);
|
||||
is_empty_branch(update.next_sync_committee_branch.as_ref())
|
||||
})
|
||||
}
|
||||
|
||||
pub fn is_finality_branch_empty(&self) -> bool {
|
||||
for index in self.finality_branch().iter() {
|
||||
if *index != Hash256::default() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
pub fn is_finality_branch_empty<'a>(&'a self) -> bool {
|
||||
map_light_client_update_ref!(&'a _, self.to_ref(), |update, cons| {
|
||||
cons(update);
|
||||
is_empty_branch(update.finality_branch.as_ref())
|
||||
})
|
||||
}
|
||||
|
||||
// A `LightClientUpdate` has two `LightClientHeader`s
|
||||
@@ -436,6 +462,15 @@ impl<E: EthSpec> LightClientUpdate<E> {
|
||||
}
|
||||
}
|
||||
|
||||
fn is_empty_branch(branch: &[Hash256]) -> bool {
|
||||
for index in branch.iter() {
|
||||
if *index != Hash256::default() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn compute_sync_committee_period_at_slot<E: EthSpec>(
|
||||
slot: Slot,
|
||||
chain_spec: &ChainSpec,
|
||||
@@ -447,16 +482,53 @@ fn compute_sync_committee_period_at_slot<E: EthSpec>(
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::MainnetEthSpec;
|
||||
use ssz_types::typenum::Unsigned;
|
||||
|
||||
ssz_tests!(LightClientUpdateDeneb<MainnetEthSpec>);
|
||||
// `ssz_tests!` can only be defined once per namespace
|
||||
#[cfg(test)]
|
||||
mod altair {
|
||||
use super::*;
|
||||
use crate::MainnetEthSpec;
|
||||
ssz_tests!(LightClientUpdateAltair<MainnetEthSpec>);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod capella {
|
||||
use super::*;
|
||||
use crate::MainnetEthSpec;
|
||||
ssz_tests!(LightClientUpdateCapella<MainnetEthSpec>);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod deneb {
|
||||
use super::*;
|
||||
use crate::MainnetEthSpec;
|
||||
ssz_tests!(LightClientUpdateDeneb<MainnetEthSpec>);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod electra {
|
||||
use super::*;
|
||||
use crate::MainnetEthSpec;
|
||||
ssz_tests!(LightClientUpdateElectra<MainnetEthSpec>);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn finalized_root_params() {
|
||||
assert!(2usize.pow(FINALIZED_ROOT_PROOF_LEN as u32) <= FINALIZED_ROOT_INDEX);
|
||||
assert!(2usize.pow(FINALIZED_ROOT_PROOF_LEN as u32 + 1) > FINALIZED_ROOT_INDEX);
|
||||
assert_eq!(FinalizedRootProofLen::to_usize(), FINALIZED_ROOT_PROOF_LEN);
|
||||
|
||||
assert!(
|
||||
2usize.pow(FINALIZED_ROOT_PROOF_LEN_ELECTRA as u32) <= FINALIZED_ROOT_INDEX_ELECTRA
|
||||
);
|
||||
assert!(
|
||||
2usize.pow(FINALIZED_ROOT_PROOF_LEN_ELECTRA as u32 + 1) > FINALIZED_ROOT_INDEX_ELECTRA
|
||||
);
|
||||
assert_eq!(
|
||||
FinalizedRootProofLenElectra::to_usize(),
|
||||
FINALIZED_ROOT_PROOF_LEN_ELECTRA
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -471,6 +543,19 @@ mod tests {
|
||||
CurrentSyncCommitteeProofLen::to_usize(),
|
||||
CURRENT_SYNC_COMMITTEE_PROOF_LEN
|
||||
);
|
||||
|
||||
assert!(
|
||||
2usize.pow(CURRENT_SYNC_COMMITTEE_PROOF_LEN_ELECTRA as u32)
|
||||
<= CURRENT_SYNC_COMMITTEE_INDEX_ELECTRA
|
||||
);
|
||||
assert!(
|
||||
2usize.pow(CURRENT_SYNC_COMMITTEE_PROOF_LEN_ELECTRA as u32 + 1)
|
||||
> CURRENT_SYNC_COMMITTEE_INDEX_ELECTRA
|
||||
);
|
||||
assert_eq!(
|
||||
CurrentSyncCommitteeProofLenElectra::to_usize(),
|
||||
CURRENT_SYNC_COMMITTEE_PROOF_LEN_ELECTRA
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -481,5 +566,18 @@ mod tests {
|
||||
NextSyncCommitteeProofLen::to_usize(),
|
||||
NEXT_SYNC_COMMITTEE_PROOF_LEN
|
||||
);
|
||||
|
||||
assert!(
|
||||
2usize.pow(NEXT_SYNC_COMMITTEE_PROOF_LEN_ELECTRA as u32)
|
||||
<= NEXT_SYNC_COMMITTEE_INDEX_ELECTRA
|
||||
);
|
||||
assert!(
|
||||
2usize.pow(NEXT_SYNC_COMMITTEE_PROOF_LEN_ELECTRA as u32 + 1)
|
||||
> NEXT_SYNC_COMMITTEE_INDEX_ELECTRA
|
||||
);
|
||||
assert_eq!(
|
||||
NextSyncCommitteeProofLenElectra::to_usize(),
|
||||
NEXT_SYNC_COMMITTEE_PROOF_LEN_ELECTRA
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ pub trait ExecPayload<E: EthSpec>: Debug + Clone + PartialEq + Hash + TreeHash +
|
||||
fn prev_randao(&self) -> Hash256;
|
||||
fn block_number(&self) -> u64;
|
||||
fn timestamp(&self) -> u64;
|
||||
fn extra_data(&self) -> VariableList<u8, E::MaxExtraDataBytes>;
|
||||
fn block_hash(&self) -> ExecutionBlockHash;
|
||||
fn fee_recipient(&self) -> Address;
|
||||
fn gas_limit(&self) -> u64;
|
||||
@@ -225,6 +226,13 @@ impl<E: EthSpec> ExecPayload<E> for FullPayload<E> {
|
||||
})
|
||||
}
|
||||
|
||||
fn extra_data<'a>(&'a self) -> VariableList<u8, E::MaxExtraDataBytes> {
|
||||
map_full_payload_ref!(&'a _, self.to_ref(), move |payload, cons| {
|
||||
cons(payload);
|
||||
payload.execution_payload.extra_data.clone()
|
||||
})
|
||||
}
|
||||
|
||||
fn block_hash<'a>(&'a self) -> ExecutionBlockHash {
|
||||
map_full_payload_ref!(&'a _, self.to_ref(), move |payload, cons| {
|
||||
cons(payload);
|
||||
@@ -317,7 +325,7 @@ impl<'a, E: EthSpec> FullPayloadRef<'a, E> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'b, E: EthSpec> ExecPayload<E> for FullPayloadRef<'b, E> {
|
||||
impl<E: EthSpec> ExecPayload<E> for FullPayloadRef<'_, E> {
|
||||
fn block_type() -> BlockType {
|
||||
BlockType::Full
|
||||
}
|
||||
@@ -357,6 +365,13 @@ impl<'b, E: EthSpec> ExecPayload<E> for FullPayloadRef<'b, E> {
|
||||
})
|
||||
}
|
||||
|
||||
fn extra_data<'a>(&'a self) -> VariableList<u8, E::MaxExtraDataBytes> {
|
||||
map_full_payload_ref!(&'a _, self, move |payload, cons| {
|
||||
cons(payload);
|
||||
payload.execution_payload.extra_data.clone()
|
||||
})
|
||||
}
|
||||
|
||||
fn block_hash<'a>(&'a self) -> ExecutionBlockHash {
|
||||
map_full_payload_ref!(&'a _, self, move |payload, cons| {
|
||||
cons(payload);
|
||||
@@ -542,6 +557,13 @@ impl<E: EthSpec> ExecPayload<E> for BlindedPayload<E> {
|
||||
})
|
||||
}
|
||||
|
||||
fn extra_data<'a>(&'a self) -> VariableList<u8, <E as EthSpec>::MaxExtraDataBytes> {
|
||||
map_blinded_payload_ref!(&'a _, self.to_ref(), move |payload, cons| {
|
||||
cons(payload);
|
||||
payload.execution_payload_header.extra_data.clone()
|
||||
})
|
||||
}
|
||||
|
||||
fn block_hash<'a>(&'a self) -> ExecutionBlockHash {
|
||||
map_blinded_payload_ref!(&'a _, self.to_ref(), move |payload, cons| {
|
||||
cons(payload);
|
||||
@@ -643,6 +665,13 @@ impl<'b, E: EthSpec> ExecPayload<E> for BlindedPayloadRef<'b, E> {
|
||||
})
|
||||
}
|
||||
|
||||
fn extra_data<'a>(&'a self) -> VariableList<u8, <E as EthSpec>::MaxExtraDataBytes> {
|
||||
map_blinded_payload_ref!(&'a _, self, move |payload, cons| {
|
||||
cons(payload);
|
||||
payload.execution_payload_header.extra_data.clone()
|
||||
})
|
||||
}
|
||||
|
||||
fn block_hash<'a>(&'a self) -> ExecutionBlockHash {
|
||||
map_blinded_payload_ref!(&'a _, self, move |payload, cons| {
|
||||
cons(payload);
|
||||
@@ -745,6 +774,10 @@ macro_rules! impl_exec_payload_common {
|
||||
self.$wrapped_field.timestamp
|
||||
}
|
||||
|
||||
fn extra_data(&self) -> VariableList<u8, E::MaxExtraDataBytes> {
|
||||
self.$wrapped_field.extra_data.clone()
|
||||
}
|
||||
|
||||
fn block_hash(&self) -> ExecutionBlockHash {
|
||||
self.$wrapped_field.block_hash
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use test_random_derive::TestRandom;
|
||||
@@ -8,7 +9,6 @@ use tree_hash_derive::TreeHash;
|
||||
arbitrary::Arbitrary,
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
Hash,
|
||||
Clone,
|
||||
Serialize,
|
||||
@@ -18,16 +18,18 @@ use tree_hash_derive::TreeHash;
|
||||
TreeHash,
|
||||
TestRandom,
|
||||
)]
|
||||
pub struct PendingBalanceDeposit {
|
||||
#[serde(with = "serde_utils::quoted_u64")]
|
||||
pub index: u64,
|
||||
pub struct PendingDeposit {
|
||||
pub pubkey: PublicKeyBytes,
|
||||
pub withdrawal_credentials: Hash256,
|
||||
#[serde(with = "serde_utils::quoted_u64")]
|
||||
pub amount: u64,
|
||||
pub signature: SignatureBytes,
|
||||
pub slot: Slot,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
ssz_and_tree_hash_tests!(PendingBalanceDeposit);
|
||||
ssz_and_tree_hash_tests!(PendingDeposit);
|
||||
}
|
||||
@@ -260,7 +260,7 @@ impl ElectraPreset {
|
||||
whistleblower_reward_quotient_electra: spec.whistleblower_reward_quotient_electra,
|
||||
max_pending_partials_per_withdrawals_sweep: spec
|
||||
.max_pending_partials_per_withdrawals_sweep,
|
||||
pending_balance_deposits_limit: E::pending_balance_deposits_limit() as u64,
|
||||
pending_balance_deposits_limit: E::pending_deposits_limit() as u64,
|
||||
pending_partial_withdrawals_limit: E::pending_partial_withdrawals_limit() as u64,
|
||||
pending_consolidations_limit: E::pending_consolidations_limit() as u64,
|
||||
max_consolidation_requests_per_payload: E::max_consolidation_requests_per_payload()
|
||||
|
||||
@@ -18,7 +18,7 @@ use std::slice::SliceIndex;
|
||||
/// ## Example
|
||||
///
|
||||
/// ```
|
||||
/// use ssz_types::{RuntimeVariableList};
|
||||
/// use types::{RuntimeVariableList};
|
||||
///
|
||||
/// let base: Vec<u64> = vec![1, 2, 3, 4];
|
||||
///
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use crate::beacon_block_body::format_kzg_commitments;
|
||||
use crate::beacon_block_body::{format_kzg_commitments, BLOB_KZG_COMMITMENTS_INDEX};
|
||||
use crate::*;
|
||||
use derivative::Derivative;
|
||||
use merkle_proof::MerkleTree;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use std::fmt;
|
||||
@@ -239,6 +240,45 @@ impl<E: EthSpec, Payload: AbstractExecPayload<E>> SignedBeaconBlock<E, Payload>
|
||||
}
|
||||
}
|
||||
|
||||
/// Produce a signed beacon block header AND a merkle proof for the KZG commitments.
|
||||
///
|
||||
/// This method is more efficient than generating each part separately as it reuses hashing.
|
||||
pub fn signed_block_header_and_kzg_commitments_proof(
|
||||
&self,
|
||||
) -> Result<
|
||||
(
|
||||
SignedBeaconBlockHeader,
|
||||
FixedVector<Hash256, E::KzgCommitmentsInclusionProofDepth>,
|
||||
),
|
||||
Error,
|
||||
> {
|
||||
// Create the block body merkle tree
|
||||
let body_leaves = self.message().body().body_merkle_leaves();
|
||||
let beacon_block_body_depth = body_leaves.len().next_power_of_two().ilog2() as usize;
|
||||
let body_merkle_tree = MerkleTree::create(&body_leaves, beacon_block_body_depth);
|
||||
|
||||
// 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)?;
|
||||
let kzg_commitments_inclusion_proof = FixedVector::new(proof)?;
|
||||
|
||||
let block_header = BeaconBlockHeader {
|
||||
slot: self.slot(),
|
||||
proposer_index: self.message().proposer_index(),
|
||||
parent_root: self.parent_root(),
|
||||
state_root: self.state_root(),
|
||||
body_root: body_merkle_tree.hash(),
|
||||
};
|
||||
|
||||
let signed_header = SignedBeaconBlockHeader {
|
||||
message: block_header,
|
||||
signature: self.signature().clone(),
|
||||
};
|
||||
|
||||
Ok((signed_header, kzg_commitments_inclusion_proof))
|
||||
}
|
||||
|
||||
/// Convenience accessor for the block's slot.
|
||||
pub fn slot(&self) -> Slot {
|
||||
self.message().slot()
|
||||
|
||||
@@ -133,7 +133,7 @@ pub struct SlotIter<'a> {
|
||||
slots_per_epoch: u64,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for SlotIter<'a> {
|
||||
impl Iterator for SlotIter<'_> {
|
||||
type Item = Slot;
|
||||
|
||||
fn next(&mut self) -> Option<Slot> {
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
//! Identifies each shard by an integer identifier.
|
||||
use crate::{AttestationRef, ChainSpec, CommitteeIndex, Epoch, EthSpec, Slot};
|
||||
use crate::{AttestationRef, ChainSpec, CommitteeIndex, EthSpec, Slot};
|
||||
use alloy_primitives::{bytes::Buf, U256};
|
||||
use safe_arith::{ArithError, SafeArith};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::sync::LazyLock;
|
||||
use swap_or_not_shuffle::compute_shuffled_index;
|
||||
|
||||
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;
|
||||
|
||||
static SUBNET_ID_TO_STRING: LazyLock<Vec<String>> = LazyLock::new(|| {
|
||||
let mut v = Vec::with_capacity(MAX_SUBNET_ID);
|
||||
|
||||
@@ -74,52 +77,22 @@ impl SubnetId {
|
||||
.into())
|
||||
}
|
||||
|
||||
/// Computes the set of subnets the node should be subscribed to during the current epoch,
|
||||
/// along with the first epoch in which these subscriptions are no longer valid.
|
||||
/// Computes the set of subnets the node should be subscribed to. We subscribe to these subnets
|
||||
/// for the duration of the node's runtime.
|
||||
#[allow(clippy::arithmetic_side_effects)]
|
||||
pub fn compute_subnets_for_epoch<E: EthSpec>(
|
||||
pub fn compute_attestation_subnets(
|
||||
raw_node_id: [u8; 32],
|
||||
epoch: Epoch,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<(impl Iterator<Item = SubnetId>, Epoch), &'static str> {
|
||||
// simplify variable naming
|
||||
let subscription_duration = spec.epochs_per_subnet_subscription;
|
||||
) -> 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 shuffling_prefix_bits = spec.attestation_subnet_shuffling_prefix_bits as u64;
|
||||
let node_id = U256::from_be_slice(&raw_node_id);
|
||||
|
||||
let node_id = U256::from_be_slice(&raw_node_id);
|
||||
// calculate the prefixes used to compute the subnet and shuffling
|
||||
let node_id_prefix = (node_id >> (256 - prefix_bits)).as_le_slice().get_u64_le();
|
||||
let shuffling_prefix = (node_id >> (256 - (prefix_bits + shuffling_prefix_bits)))
|
||||
let node_id_prefix = (node_id >> (NODE_ID_BITS - prefix_bits))
|
||||
.as_le_slice()
|
||||
.get_u64_le();
|
||||
|
||||
// number of groups the shuffling creates
|
||||
let shuffling_groups = 1 << shuffling_prefix_bits;
|
||||
// shuffling group for this node
|
||||
let shuffling_bits = shuffling_prefix % shuffling_groups;
|
||||
let epoch_transition = (node_id_prefix
|
||||
+ (shuffling_bits * (subscription_duration >> shuffling_prefix_bits)))
|
||||
% subscription_duration;
|
||||
|
||||
// Calculate at which epoch this node needs to re-evaluate
|
||||
let valid_until_epoch = epoch.as_u64()
|
||||
+ subscription_duration
|
||||
.saturating_sub((epoch.as_u64() + epoch_transition) % subscription_duration);
|
||||
|
||||
let subscription_event_idx = (epoch.as_u64() + epoch_transition) / subscription_duration;
|
||||
let permutation_seed =
|
||||
ethereum_hashing::hash(&int_to_bytes::int_to_bytes8(subscription_event_idx));
|
||||
|
||||
let num_subnets = 1 << spec.attestation_subnet_prefix_bits;
|
||||
let permutated_prefix = compute_shuffled_index(
|
||||
node_id_prefix as usize,
|
||||
num_subnets,
|
||||
&permutation_seed,
|
||||
spec.shuffle_round_count,
|
||||
)
|
||||
.ok_or("Unable to shuffle")? as u64;
|
||||
|
||||
// Get the constants we need to avoid holding a reference to the spec
|
||||
let &ChainSpec {
|
||||
subnets_per_node,
|
||||
@@ -127,10 +100,8 @@ impl SubnetId {
|
||||
..
|
||||
} = spec;
|
||||
|
||||
let subnet_set_generator = (0..subnets_per_node).map(move |idx| {
|
||||
SubnetId::new((permutated_prefix + idx as u64) % attestation_subnet_count)
|
||||
});
|
||||
Ok((subnet_set_generator, valid_until_epoch.into()))
|
||||
(0..subnets_per_node)
|
||||
.map(move |idx| SubnetId::new((node_id_prefix + idx as u64) % attestation_subnet_count))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,7 +151,7 @@ mod tests {
|
||||
|
||||
/// A set of tests compared to the python specification
|
||||
#[test]
|
||||
fn compute_subnets_for_epoch_unit_test() {
|
||||
fn compute_attestation_subnets_test() {
|
||||
// Randomized variables used generated with the python specification
|
||||
let node_ids = [
|
||||
"0",
|
||||
@@ -189,59 +160,34 @@ mod tests {
|
||||
"27726842142488109545414954493849224833670205008410190955613662332153332462900",
|
||||
"39755236029158558527862903296867805548949739810920318269566095185775868999998",
|
||||
"31899136003441886988955119620035330314647133604576220223892254902004850516297",
|
||||
"58579998103852084482416614330746509727562027284701078483890722833654510444626",
|
||||
"28248042035542126088870192155378394518950310811868093527036637864276176517397",
|
||||
"60930578857433095740782970114409273483106482059893286066493409689627770333527",
|
||||
"103822458477361691467064888613019442068586830412598673713899771287914656699997",
|
||||
]
|
||||
.map(|v| Uint256::from_str_radix(v, 10).unwrap().to_be_bytes::<32>());
|
||||
|
||||
let epochs = [
|
||||
54321u64, 1017090249, 1827566880, 846255942, 766597383, 1204990115, 1616209495,
|
||||
1774367616, 1484598751, 3525502229,
|
||||
]
|
||||
.map(Epoch::from);
|
||||
let expected_subnets = [
|
||||
vec![0, 1],
|
||||
vec![49u64, 50u64],
|
||||
vec![10, 11],
|
||||
vec![15, 16],
|
||||
vec![21, 22],
|
||||
vec![17, 18],
|
||||
];
|
||||
|
||||
// Test mainnet
|
||||
let spec = ChainSpec::mainnet();
|
||||
|
||||
// Calculated by hand
|
||||
let expected_valid_time = [
|
||||
54528u64, 1017090255, 1827567030, 846256049, 766597387, 1204990287, 1616209536,
|
||||
1774367857, 1484598847, 3525502311,
|
||||
];
|
||||
|
||||
// Calculated from pyspec
|
||||
let expected_subnets = [
|
||||
vec![4u64, 5u64],
|
||||
vec![31, 32],
|
||||
vec![39, 40],
|
||||
vec![38, 39],
|
||||
vec![53, 54],
|
||||
vec![57, 58],
|
||||
vec![48, 49],
|
||||
vec![1, 2],
|
||||
vec![34, 35],
|
||||
vec![37, 38],
|
||||
];
|
||||
|
||||
for x in 0..node_ids.len() {
|
||||
println!("Test: {}", x);
|
||||
println!(
|
||||
"NodeId: {:?}\n Epoch: {}\n, expected_update_time: {}\n, expected_subnets: {:?}",
|
||||
node_ids[x], epochs[x], expected_valid_time[x], expected_subnets[x]
|
||||
"NodeId: {:?}\nExpected_subnets: {:?}",
|
||||
node_ids[x], expected_subnets[x]
|
||||
);
|
||||
|
||||
let (computed_subnets, valid_time) = SubnetId::compute_subnets_for_epoch::<
|
||||
crate::MainnetEthSpec,
|
||||
>(node_ids[x], epochs[x], &spec)
|
||||
.unwrap();
|
||||
let computed_subnets = SubnetId::compute_attestation_subnets(node_ids[x], &spec);
|
||||
|
||||
assert_eq!(
|
||||
expected_subnets[x],
|
||||
computed_subnets.map(SubnetId::into).collect::<Vec<u64>>()
|
||||
);
|
||||
assert_eq!(Epoch::from(expected_valid_time[x]), valid_time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,6 +83,35 @@ mod test {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_verify_blob_inclusion_proof_from_existing_proof() {
|
||||
let (block, mut blob_sidecars) =
|
||||
generate_rand_block_and_blobs::<MainnetEthSpec>(ForkName::Deneb, 1, &mut thread_rng());
|
||||
let BlobSidecar {
|
||||
index,
|
||||
blob,
|
||||
kzg_proof,
|
||||
..
|
||||
} = blob_sidecars.pop().unwrap();
|
||||
|
||||
// Compute the commitments inclusion proof and use it for building blob sidecar.
|
||||
let (signed_block_header, kzg_commitments_inclusion_proof) = block
|
||||
.signed_block_header_and_kzg_commitments_proof()
|
||||
.unwrap();
|
||||
|
||||
let blob_sidecar = BlobSidecar::new_with_existing_proof(
|
||||
index as usize,
|
||||
blob,
|
||||
&block,
|
||||
signed_block_header,
|
||||
&kzg_commitments_inclusion_proof,
|
||||
kzg_proof,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert!(blob_sidecar.verify_blob_sidecar_inclusion_proof());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_verify_blob_inclusion_proof_invalid() {
|
||||
let (_block, blobs) =
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
test_utils::TestRandom, Address, BeaconState, ChainSpec, Checkpoint, DepositData, Epoch,
|
||||
EthSpec, FixedBytesExtended, ForkName, Hash256, PublicKeyBytes,
|
||||
test_utils::TestRandom, Address, BeaconState, ChainSpec, Checkpoint, Epoch, EthSpec,
|
||||
FixedBytesExtended, ForkName, Hash256, PublicKeyBytes,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
@@ -15,6 +15,7 @@ use tree_hash_derive::TreeHash;
|
||||
Debug,
|
||||
Clone,
|
||||
PartialEq,
|
||||
Eq,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
@@ -37,14 +38,15 @@ pub struct Validator {
|
||||
impl Validator {
|
||||
#[allow(clippy::arithmetic_side_effects)]
|
||||
pub fn from_deposit(
|
||||
deposit_data: &DepositData,
|
||||
pubkey: PublicKeyBytes,
|
||||
withdrawal_credentials: Hash256,
|
||||
amount: u64,
|
||||
fork_name: ForkName,
|
||||
spec: &ChainSpec,
|
||||
) -> Self {
|
||||
let mut validator = Validator {
|
||||
pubkey: deposit_data.pubkey,
|
||||
withdrawal_credentials: deposit_data.withdrawal_credentials,
|
||||
pubkey,
|
||||
withdrawal_credentials,
|
||||
activation_eligibility_epoch: spec.far_future_epoch,
|
||||
activation_epoch: spec.far_future_epoch,
|
||||
exit_epoch: spec.far_future_epoch,
|
||||
@@ -290,16 +292,6 @@ impl Validator {
|
||||
spec.max_effective_balance
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_active_balance(
|
||||
&self,
|
||||
validator_balance: u64,
|
||||
spec: &ChainSpec,
|
||||
current_fork: ForkName,
|
||||
) -> u64 {
|
||||
let max_effective_balance = self.get_max_effective_balance(spec, current_fork);
|
||||
std::cmp::min(validator_balance, max_effective_balance)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Validator {
|
||||
|
||||
Reference in New Issue
Block a user