mirror of
https://github.com/sigp/lighthouse.git
synced 2026-04-17 21:08:32 +00:00
Merge branch 'unstable' into electra-alpha7
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
*/
|
||||
|
||||
@@ -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> {
|
||||
|
||||
@@ -155,7 +155,6 @@ pub enum Error {
|
||||
current_fork: ForkName,
|
||||
},
|
||||
TotalActiveBalanceDiffUninitialized,
|
||||
MissingImmutableValidator(usize),
|
||||
IndexNotSupported(usize),
|
||||
InvalidFlagIndex(usize),
|
||||
MerkleTreeError(merkle_proof::MerkleTreeError),
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -15,6 +15,7 @@ use tree_hash_derive::TreeHash;
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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) =
|
||||
|
||||
@@ -15,6 +15,7 @@ use tree_hash_derive::TreeHash;
|
||||
Debug,
|
||||
Clone,
|
||||
PartialEq,
|
||||
Eq,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
|
||||
Reference in New Issue
Block a user