Merge branch 'unstable' into electra-alpha7

This commit is contained in:
Pawan Dhananjay
2024-11-20 15:59:06 -08:00
162 changed files with 6474 additions and 3188 deletions

View File

@@ -1,6 +1,6 @@
/// A collection of all functions that mutates the `ProgressiveBalancesCache`.
use crate::metrics::{
PARTICIPATION_CURR_EPOCH_TARGET_ATTESTING_GWEI_PROGRESSIVE_TOTAL,
self, PARTICIPATION_CURR_EPOCH_TARGET_ATTESTING_GWEI_PROGRESSIVE_TOTAL,
PARTICIPATION_PREV_EPOCH_TARGET_ATTESTING_GWEI_PROGRESSIVE_TOTAL,
};
use crate::{BlockProcessingError, EpochProcessingError};
@@ -21,6 +21,8 @@ pub fn initialize_progressive_balances_cache<E: EthSpec>(
return Ok(());
}
let _timer = metrics::start_timer(&metrics::BUILD_PROGRESSIVE_BALANCES_CACHE_TIME);
// Calculate the total flag balances for previous & current epoch in a single iteration.
// This calculates `get_total_balance(unslashed_participating_indices(..))` for each flag in
// the current and previous epoch.

View File

@@ -1,6 +1,7 @@
use crate::common::altair::BaseRewardPerIncrement;
use crate::common::base::SqrtTotalActiveBalance;
use crate::common::{altair, base};
use crate::metrics;
use safe_arith::SafeArith;
use types::epoch_cache::{EpochCache, EpochCacheError, EpochCacheKey};
use types::{
@@ -138,6 +139,8 @@ pub fn initialize_epoch_cache<E: EthSpec>(
return Ok(());
}
let _timer = metrics::start_timer(&metrics::BUILD_EPOCH_CACHE_TIME);
let current_epoch = state.current_epoch();
let next_epoch = state.next_epoch().map_err(EpochCacheError::BeaconState)?;
let decision_block_root = state

View File

@@ -41,6 +41,20 @@ pub static PROCESS_EPOCH_TIME: LazyLock<Result<Histogram>> = LazyLock::new(|| {
"Time required for process_epoch",
)
});
pub static BUILD_EPOCH_CACHE_TIME: LazyLock<Result<Histogram>> = LazyLock::new(|| {
try_create_histogram(
"beacon_state_processing_epoch_cache",
"Time required to build the epoch cache",
)
});
pub static BUILD_PROGRESSIVE_BALANCES_CACHE_TIME: LazyLock<Result<Histogram>> =
LazyLock::new(|| {
try_create_histogram(
"beacon_state_processing_progressive_balances_cache",
"Time required to build the progressive balances cache",
)
});
/*
* Participation Metrics (progressive balances)
*/

View File

@@ -147,7 +147,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) => {
@@ -178,57 +178,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`.
@@ -241,7 +255,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> {

View File

@@ -155,7 +155,6 @@ pub enum Error {
current_fork: ForkName,
},
TotalActiveBalanceDiffUninitialized,
MissingImmutableValidator(usize),
IndexNotSupported(usize),
InvalidFlagIndex(usize),
MerkleTreeError(merkle_proof::MerkleTreeError),

View File

@@ -150,6 +150,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(),

View File

@@ -15,6 +15,7 @@ use tree_hash_derive::TreeHash;
#[derive(
Debug,
PartialEq,
Eq,
Serialize,
Deserialize,
Encode,

View File

@@ -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()

View File

@@ -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) =

View File

@@ -15,6 +15,7 @@ use tree_hash_derive::TreeHash;
Debug,
Clone,
PartialEq,
Eq,
Serialize,
Deserialize,
Encode,