Merge branch 'unstable' of https://github.com/sigp/lighthouse into electra_attestation_changes

This commit is contained in:
realbigsean
2024-06-17 15:08:36 -04:00
47 changed files with 258 additions and 144 deletions

View File

@@ -2,6 +2,7 @@
use crate::test_utils::*;
use beacon_chain::test_utils::{BeaconChainHarness, EphemeralHarnessType};
use beacon_chain::types::*;
use lazy_static::lazy_static;
use swap_or_not_shuffle::shuffle_list;
pub const VALIDATOR_COUNT: usize = 16;

View File

@@ -6,6 +6,7 @@ use beacon_chain::types::{
ChainSpec, Domain, Epoch, EthSpec, Hash256, Keypair, MainnetEthSpec, MinimalEthSpec,
RelativeEpoch, Slot, Vector,
};
use lazy_static::lazy_static;
use ssz::Encode;
use std::ops::Mul;
use swap_or_not_shuffle::compute_shuffled_index;

View File

@@ -12,7 +12,7 @@ use kzg::{
};
use merkle_proof::{merkle_root_from_branch, verify_merkle_proof, MerkleTreeError};
use rand::Rng;
use safe_arith::{ArithError, SafeArith};
use safe_arith::ArithError;
use serde::{Deserialize, Serialize};
use ssz::Encode;
use ssz_derive::{Decode, Encode};
@@ -190,33 +190,30 @@ impl<E: EthSpec> BlobSidecar<E> {
}
/// Verifies the kzg commitment inclusion merkle proof.
pub fn verify_blob_sidecar_inclusion_proof(&self) -> Result<bool, MerkleTreeError> {
// Depth of the subtree rooted at `blob_kzg_commitments` in the `BeaconBlockBody`
// is equal to depth of the ssz List max size + 1 for the length mixin
let kzg_commitments_tree_depth = (E::max_blob_commitments_per_block()
.next_power_of_two()
.ilog2()
.safe_add(1))? as usize;
pub fn verify_blob_sidecar_inclusion_proof(&self) -> bool {
let kzg_commitments_tree_depth = E::kzg_commitments_tree_depth();
// EthSpec asserts that kzg_commitments_tree_depth is less than KzgCommitmentInclusionProofDepth
let (kzg_commitment_subtree_proof, kzg_commitments_proof) = self
.kzg_commitment_inclusion_proof
.split_at(kzg_commitments_tree_depth);
// Compute the `tree_hash_root` of the `blob_kzg_commitments` subtree using the
// inclusion proof branches
let blob_kzg_commitments_root = merkle_root_from_branch(
self.kzg_commitment.tree_hash_root(),
self.kzg_commitment_inclusion_proof
.get(0..kzg_commitments_tree_depth)
.ok_or(MerkleTreeError::PleaseNotifyTheDevs)?,
kzg_commitment_subtree_proof,
kzg_commitments_tree_depth,
self.index as usize,
);
// The remaining inclusion proof branches are for the top level `BeaconBlockBody` tree
Ok(verify_merkle_proof(
verify_merkle_proof(
blob_kzg_commitments_root,
self.kzg_commitment_inclusion_proof
.get(kzg_commitments_tree_depth..E::kzg_proof_inclusion_proof_depth())
.ok_or(MerkleTreeError::PleaseNotifyTheDevs)?,
E::kzg_proof_inclusion_proof_depth().safe_sub(kzg_commitments_tree_depth)?,
kzg_commitments_proof,
E::block_body_tree_depth(),
BLOB_KZG_COMMITMENTS_INDEX,
self.signed_block_header.message.body_root,
))
)
}
pub fn random_valid<R: Rng>(rng: &mut R, kzg: &Kzg) -> Result<Self, String> {

View File

@@ -294,6 +294,22 @@ pub trait EthSpec:
Self::KzgCommitmentInclusionProofDepth::to_usize()
}
fn kzg_commitments_tree_depth() -> usize {
// Depth of the subtree rooted at `blob_kzg_commitments` in the `BeaconBlockBody`
// is equal to depth of the ssz List max size + 1 for the length mixin
Self::max_blob_commitments_per_block()
.next_power_of_two()
.ilog2()
.safe_add(1)
.expect("The log of max_blob_commitments_per_block can not overflow") as usize
}
fn block_body_tree_depth() -> usize {
Self::kzg_proof_inclusion_proof_depth()
.safe_sub(Self::kzg_commitments_tree_depth())
.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()
@@ -525,3 +541,26 @@ impl EthSpec for GnosisEthSpec {
EthSpecId::Gnosis
}
}
#[cfg(test)]
mod test {
use crate::{EthSpec, GnosisEthSpec, MainnetEthSpec, MinimalEthSpec};
fn assert_valid_spec<E: EthSpec>() {
E::kzg_commitments_tree_depth();
E::block_body_tree_depth();
}
#[test]
fn mainnet_spec() {
assert_valid_spec::<MainnetEthSpec>();
}
#[test]
fn minimal_spec() {
assert_valid_spec::<MinimalEthSpec>();
}
#[test]
fn gnosis_spec() {
assert_valid_spec::<GnosisEthSpec>();
}
}

View File

@@ -117,7 +117,6 @@ impl<E: EthSpec> ExecutionPayloadHeader<E> {
#[allow(clippy::arithmetic_side_effects)]
pub fn ssz_max_var_len_for_fork(fork_name: ForkName) -> usize {
// Matching here in case variable fields are added in future forks.
// TODO(electra): review electra changes
match fork_name {
ForkName::Base
| ForkName::Altair

View File

@@ -9,8 +9,6 @@
)
)]
#[macro_use]
extern crate lazy_static;
#[macro_use]
pub mod test_utils;

View File

@@ -1,5 +1,6 @@
//! Identifies each shard by an integer identifier.
use crate::{AttestationRef, ChainSpec, CommitteeIndex, Epoch, EthSpec, Slot};
use lazy_static::lazy_static;
use safe_arith::{ArithError, SafeArith};
use serde::{Deserialize, Serialize};
use std::ops::{Deref, DerefMut};

View File

@@ -1,6 +1,7 @@
//! Identifies each sync committee subnet by an integer identifier.
use crate::consts::altair::SYNC_COMMITTEE_SUBNET_COUNT;
use crate::EthSpec;
use lazy_static::lazy_static;
use safe_arith::{ArithError, SafeArith};
use serde::{Deserialize, Serialize};
use ssz_types::typenum::Unsigned;

View File

@@ -0,0 +1,96 @@
use rand::Rng;
use kzg::{KzgCommitment, KzgProof};
use crate::beacon_block_body::KzgCommitments;
use crate::*;
use super::*;
type BlobsBundle<E> = (KzgCommitments<E>, KzgProofs<E>, BlobsList<E>);
pub fn generate_rand_block_and_blobs<E: EthSpec>(
fork_name: ForkName,
num_blobs: usize,
rng: &mut impl Rng,
) -> (SignedBeaconBlock<E, FullPayload<E>>, Vec<BlobSidecar<E>>) {
let inner = map_fork_name!(fork_name, BeaconBlock, <_>::random_for_test(rng));
let mut block = SignedBeaconBlock::from_block(inner, Signature::random_for_test(rng));
let mut blob_sidecars = vec![];
if block.fork_name_unchecked() < ForkName::Deneb {
return (block, blob_sidecars);
}
let (commitments, proofs, blobs) = generate_blobs::<E>(num_blobs).unwrap();
*block
.message_mut()
.body_mut()
.blob_kzg_commitments_mut()
.expect("kzg commitment expected from Deneb") = commitments.clone();
for (index, ((blob, kzg_commitment), kzg_proof)) in blobs
.into_iter()
.zip(commitments.into_iter())
.zip(proofs.into_iter())
.enumerate()
{
blob_sidecars.push(BlobSidecar {
index: index as u64,
blob: blob.clone(),
kzg_commitment,
kzg_proof,
signed_block_header: block.signed_block_header(),
kzg_commitment_inclusion_proof: block
.message()
.body()
.kzg_commitment_merkle_proof(index)
.unwrap(),
});
}
(block, blob_sidecars)
}
pub fn generate_blobs<E: EthSpec>(n_blobs: usize) -> Result<BlobsBundle<E>, String> {
let (mut commitments, mut proofs, mut blobs) = BlobsBundle::<E>::default();
for blob_index in 0..n_blobs {
blobs
.push(Blob::<E>::default())
.map_err(|_| format!("blobs are full, blob index: {:?}", blob_index))?;
commitments
.push(KzgCommitment::empty_for_testing())
.map_err(|_| format!("blobs are full, blob index: {:?}", blob_index))?;
proofs
.push(KzgProof::empty())
.map_err(|_| format!("blobs are full, blob index: {:?}", blob_index))?;
}
Ok((commitments, proofs, blobs))
}
#[cfg(test)]
mod test {
use super::*;
use rand::thread_rng;
#[test]
fn test_verify_blob_inclusion_proof() {
let (_block, blobs) =
generate_rand_block_and_blobs::<MainnetEthSpec>(ForkName::Deneb, 6, &mut thread_rng());
for blob in blobs {
assert!(blob.verify_blob_sidecar_inclusion_proof());
}
}
#[test]
fn test_verify_blob_inclusion_proof_invalid() {
let (_block, blobs) =
generate_rand_block_and_blobs::<MainnetEthSpec>(ForkName::Deneb, 6, &mut thread_rng());
for mut blob in blobs {
blob.kzg_commitment_inclusion_proof = FixedVector::random_for_test(&mut thread_rng());
assert!(!blob.verify_blob_sidecar_inclusion_proof());
}
}
}

View File

@@ -15,6 +15,8 @@ use tree_hash::TreeHash;
#[macro_use]
mod macros;
mod generate_deterministic_keypairs;
#[cfg(test)]
mod generate_random_block_and_blobs;
mod test_random;
pub fn test_ssz_tree_hash_pair<T, U>(v1: &T, v2: &U)