Add KZG proof and blob validation
This commit is contained in:
parent
62627d984c
commit
02a88f0704
@ -73,6 +73,7 @@ use fork_choice::{
|
|||||||
use futures::channel::mpsc::Sender;
|
use futures::channel::mpsc::Sender;
|
||||||
use itertools::process_results;
|
use itertools::process_results;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
use kzg::Kzg;
|
||||||
use operation_pool::{AttestationRef, OperationPool, PersistedOperationPool, ReceivedPreCapella};
|
use operation_pool::{AttestationRef, OperationPool, PersistedOperationPool, ReceivedPreCapella};
|
||||||
use parking_lot::{Mutex, RwLock};
|
use parking_lot::{Mutex, RwLock};
|
||||||
use proto_array::{CountUnrealizedFull, DoNotReOrg, ProposerHeadError};
|
use proto_array::{CountUnrealizedFull, DoNotReOrg, ProposerHeadError};
|
||||||
@ -107,6 +108,7 @@ use store::{
|
|||||||
use task_executor::{ShutdownReason, TaskExecutor};
|
use task_executor::{ShutdownReason, TaskExecutor};
|
||||||
use tree_hash::TreeHash;
|
use tree_hash::TreeHash;
|
||||||
use types::beacon_state::CloneConfig;
|
use types::beacon_state::CloneConfig;
|
||||||
|
use types::blobs_sidecar::KzgCommitments;
|
||||||
use types::consts::eip4844::MIN_EPOCHS_FOR_BLOBS_SIDECARS_REQUESTS;
|
use types::consts::eip4844::MIN_EPOCHS_FOR_BLOBS_SIDECARS_REQUESTS;
|
||||||
use types::consts::merge::INTERVALS_PER_SLOT;
|
use types::consts::merge::INTERVALS_PER_SLOT;
|
||||||
use types::*;
|
use types::*;
|
||||||
@ -4760,39 +4762,60 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
|||||||
.as_ref()
|
.as_ref()
|
||||||
.ok_or(BlockProductionError::TrustedSetupNotInitialized)?;
|
.ok_or(BlockProductionError::TrustedSetupNotInitialized)?;
|
||||||
let beacon_block_root = block.canonical_root();
|
let beacon_block_root = block.canonical_root();
|
||||||
let expected_kzg_commitments = block.body().blob_kzg_commitments().map_err(|_| {
|
let expected_kzg_commitments: &KzgCommitments<T::EthSpec> =
|
||||||
BlockProductionError::InvalidBlockVariant(
|
block.body().blob_kzg_commitments().map_err(|_| {
|
||||||
"EIP4844 block does not contain kzg commitments".to_string(),
|
BlockProductionError::InvalidBlockVariant(
|
||||||
)
|
"EIP4844 block does not contain kzg commitments".to_string(),
|
||||||
})?;
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
if expected_kzg_commitments.len() != blobs.len() {
|
||||||
|
return Err(BlockProductionError::MissingKzgCommitment(format!(
|
||||||
|
"Missing KZG commitment for slot {}. Expected {}, got: {}",
|
||||||
|
slot,
|
||||||
|
blobs.len(),
|
||||||
|
expected_kzg_commitments.len()
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
let kzg_proofs =
|
||||||
|
Self::compute_blob_kzg_proofs(kzg, &blobs, expected_kzg_commitments, slot)?;
|
||||||
|
|
||||||
|
kzg_utils::validate_blobs::<T::EthSpec>(
|
||||||
|
kzg,
|
||||||
|
expected_kzg_commitments,
|
||||||
|
&blobs,
|
||||||
|
&kzg_proofs,
|
||||||
|
)
|
||||||
|
.map_err(BlockProductionError::KzgError)?;
|
||||||
|
|
||||||
let blob_sidecars = VariableList::from(
|
let blob_sidecars = VariableList::from(
|
||||||
blobs
|
blobs
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(blob_index, blob)| {
|
.map(|(blob_index, blob)| {
|
||||||
BlobSidecar {
|
let kzg_commitment = expected_kzg_commitments
|
||||||
|
.get(blob_index)
|
||||||
|
.expect("KZG commitment should exist for blob");
|
||||||
|
|
||||||
|
let kzg_proof = kzg_proofs
|
||||||
|
.get(blob_index)
|
||||||
|
.expect("KZG proof should exist for blob");
|
||||||
|
|
||||||
|
Ok(BlobSidecar {
|
||||||
block_root: beacon_block_root,
|
block_root: beacon_block_root,
|
||||||
index: blob_index as u64,
|
index: blob_index as u64,
|
||||||
slot,
|
slot,
|
||||||
block_parent_root: block.parent_root(),
|
block_parent_root: block.parent_root(),
|
||||||
proposer_index,
|
proposer_index,
|
||||||
blob,
|
blob,
|
||||||
kzg_commitment: expected_kzg_commitments[blob_index].clone(),
|
kzg_commitment: *kzg_commitment,
|
||||||
kzg_proof: Default::default(), // TODO: compute KZG proof
|
kzg_proof: *kzg_proof,
|
||||||
}
|
})
|
||||||
})
|
})
|
||||||
.collect::<Vec<BlobSidecar<T::EthSpec>>>(),
|
.collect::<Result<Vec<BlobSidecar<T::EthSpec>>, BlockProductionError>>()?,
|
||||||
);
|
);
|
||||||
|
|
||||||
// TODO: validate blobs
|
|
||||||
// kzg_utils::validate_blobs_sidecar(
|
|
||||||
// kzg,
|
|
||||||
// slot,
|
|
||||||
// beacon_block_root,
|
|
||||||
// expected_kzg_commitments,
|
|
||||||
// &blobs_sidecar,
|
|
||||||
// ).map_err(BlockProductionError::KzgError)?;
|
|
||||||
self.blob_cache.put(beacon_block_root, blob_sidecars);
|
self.blob_cache.put(beacon_block_root, blob_sidecars);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4809,6 +4832,29 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
|||||||
Ok((block, state))
|
Ok((block, state))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn compute_blob_kzg_proofs(
|
||||||
|
kzg: &Arc<Kzg>,
|
||||||
|
blobs: &Blobs<<T as BeaconChainTypes>::EthSpec>,
|
||||||
|
expected_kzg_commitments: &KzgCommitments<<T as BeaconChainTypes>::EthSpec>,
|
||||||
|
slot: Slot,
|
||||||
|
) -> Result<Vec<KzgProof>, BlockProductionError> {
|
||||||
|
blobs
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(blob_index, blob)| {
|
||||||
|
let kzg_commitment = expected_kzg_commitments.get(blob_index).ok_or(
|
||||||
|
BlockProductionError::MissingKzgCommitment(format!(
|
||||||
|
"Missing KZG commitment for slot {} blob index {}",
|
||||||
|
slot, blob_index
|
||||||
|
)),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
kzg_utils::compute_blob_kzg_proof::<T::EthSpec>(kzg, blob, kzg_commitment.clone())
|
||||||
|
.map_err(BlockProductionError::KzgError)
|
||||||
|
})
|
||||||
|
.collect::<Result<Vec<KzgProof>, BlockProductionError>>()
|
||||||
|
}
|
||||||
|
|
||||||
/// This method must be called whenever an execution engine indicates that a payload is
|
/// This method must be called whenever an execution engine indicates that a payload is
|
||||||
/// invalid.
|
/// invalid.
|
||||||
///
|
///
|
||||||
|
@ -273,6 +273,7 @@ pub enum BlockProductionError {
|
|||||||
ShuttingDown,
|
ShuttingDown,
|
||||||
MissingSyncAggregate,
|
MissingSyncAggregate,
|
||||||
MissingExecutionPayload,
|
MissingExecutionPayload,
|
||||||
|
MissingKzgCommitment(String),
|
||||||
TokioJoin(tokio::task::JoinError),
|
TokioJoin(tokio::task::JoinError),
|
||||||
BeaconChain(BeaconChainError),
|
BeaconChain(BeaconChainError),
|
||||||
InvalidPayloadFork,
|
InvalidPayloadFork,
|
||||||
|
@ -42,10 +42,11 @@ pub fn validate_blobs<T: EthSpec>(
|
|||||||
/// Compute the kzg proof given an ssz blob and its kzg commitment.
|
/// Compute the kzg proof given an ssz blob and its kzg commitment.
|
||||||
pub fn compute_blob_kzg_proof<T: EthSpec>(
|
pub fn compute_blob_kzg_proof<T: EthSpec>(
|
||||||
kzg: &Kzg,
|
kzg: &Kzg,
|
||||||
blob: Blob<T>,
|
blob: &Blob<T>,
|
||||||
kzg_commitment: KzgCommitment,
|
kzg_commitment: KzgCommitment,
|
||||||
) -> Result<KzgProof, KzgError> {
|
) -> Result<KzgProof, KzgError> {
|
||||||
kzg.compute_blob_kzg_proof(ssz_blob_to_crypto_blob::<T>(blob), kzg_commitment)
|
// Avoid this blob clone
|
||||||
|
kzg.compute_blob_kzg_proof(ssz_blob_to_crypto_blob::<T>(blob.clone()), kzg_commitment)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compute the kzg commitment for a given blob.
|
/// Compute the kzg commitment for a given blob.
|
||||||
|
@ -314,7 +314,6 @@ mod tests {
|
|||||||
VoluntaryExit,
|
VoluntaryExit,
|
||||||
ProposerSlashing,
|
ProposerSlashing,
|
||||||
AttesterSlashing,
|
AttesterSlashing,
|
||||||
BeaconBlocksAndBlobsSidecar,
|
|
||||||
]
|
]
|
||||||
.iter()
|
.iter()
|
||||||
{
|
{
|
||||||
|
@ -259,7 +259,7 @@ impl<E: EthSpec> HotColdDB<E, LevelDB<E>, LevelDB<E>> {
|
|||||||
db.blobs_db = Some(LevelDB::open(path.as_path())?);
|
db.blobs_db = Some(LevelDB::open(path.as_path())?);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let blob_info = blob_info.unwrap_or(db.get_blob_info());
|
let blob_info = blob_info.unwrap_or_else(|| db.get_blob_info());
|
||||||
db.compare_and_set_blob_info_with_write(blob_info, new_blob_info)?;
|
db.compare_and_set_blob_info_with_write(blob_info, new_blob_info)?;
|
||||||
info!(
|
info!(
|
||||||
db.log,
|
db.log,
|
||||||
@ -1899,7 +1899,7 @@ impl<E: EthSpec, Hot: ItemStore<E>, Cold: ItemStore<E>> HotColdDB<E, Hot, Cold>
|
|||||||
let blob_info = self.get_blob_info();
|
let blob_info = self.get_blob_info();
|
||||||
let oldest_blob_slot = blob_info
|
let oldest_blob_slot = blob_info
|
||||||
.oldest_blob_slot
|
.oldest_blob_slot
|
||||||
.unwrap_or(eip4844_fork.start_slot(E::slots_per_epoch()));
|
.unwrap_or_else(|| eip4844_fork.start_slot(E::slots_per_epoch()));
|
||||||
|
|
||||||
// The last entirely pruned epoch, blobs sidecar pruning may have stopped early in the
|
// The last entirely pruned epoch, blobs sidecar pruning may have stopped early in the
|
||||||
// middle of an epoch otherwise the oldest blob slot is a start slot.
|
// middle of an epoch otherwise the oldest blob slot is a start slot.
|
||||||
|
@ -8,7 +8,7 @@ use std::fmt::{Debug, Display, Formatter};
|
|||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use tree_hash::{PackedEncoding, TreeHash};
|
use tree_hash::{PackedEncoding, TreeHash};
|
||||||
|
|
||||||
#[derive(Derivative, Clone, Encode, Decode)]
|
#[derive(Derivative, Clone, Copy, Encode, Decode)]
|
||||||
#[derivative(PartialEq, Eq, Hash)]
|
#[derivative(PartialEq, Eq, Hash)]
|
||||||
#[ssz(struct_behaviour = "transparent")]
|
#[ssz(struct_behaviour = "transparent")]
|
||||||
pub struct KzgCommitment(pub [u8; BYTES_PER_COMMITMENT]);
|
pub struct KzgCommitment(pub [u8; BYTES_PER_COMMITMENT]);
|
||||||
|
Loading…
Reference in New Issue
Block a user