Verify KZG in Bulk During Block Sync (#4903)
This commit is contained in:
parent
a380f6ef1f
commit
7818100777
@ -583,29 +583,33 @@ pub fn signature_verify_chain_segment<T: BeaconChainTypes>(
|
||||
&chain.spec,
|
||||
)?;
|
||||
|
||||
// unzip chain segment and verify kzg in bulk
|
||||
let (roots, blocks): (Vec<_>, Vec<_>) = chain_segment.into_iter().unzip();
|
||||
let maybe_available_blocks = chain
|
||||
.data_availability_checker
|
||||
.verify_kzg_for_rpc_blocks(blocks)?;
|
||||
// zip it back up
|
||||
let mut signature_verified_blocks = roots
|
||||
.into_iter()
|
||||
.zip(maybe_available_blocks)
|
||||
.map(|(block_root, maybe_available_block)| {
|
||||
let consensus_context = ConsensusContext::new(maybe_available_block.slot())
|
||||
.set_current_block_root(block_root);
|
||||
SignatureVerifiedBlock {
|
||||
block: maybe_available_block,
|
||||
block_root,
|
||||
parent: None,
|
||||
consensus_context,
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// verify signatures
|
||||
let pubkey_cache = get_validator_pubkey_cache(chain)?;
|
||||
let mut signature_verifier = get_signature_verifier(&state, &pubkey_cache, &chain.spec);
|
||||
|
||||
let mut signature_verified_blocks = Vec::with_capacity(chain_segment.len());
|
||||
|
||||
for (block_root, block) in &chain_segment {
|
||||
let mut consensus_context =
|
||||
ConsensusContext::new(block.slot()).set_current_block_root(*block_root);
|
||||
|
||||
signature_verifier.include_all_signatures(block.as_block(), &mut consensus_context)?;
|
||||
|
||||
let maybe_available_block = chain
|
||||
.data_availability_checker
|
||||
.check_rpc_block_availability(block.clone())?;
|
||||
|
||||
// Save the block and its consensus context. The context will have had its proposer index
|
||||
// and attesting indices filled in, which can be used to accelerate later block processing.
|
||||
signature_verified_blocks.push(SignatureVerifiedBlock {
|
||||
block: maybe_available_block,
|
||||
block_root: *block_root,
|
||||
parent: None,
|
||||
consensus_context,
|
||||
});
|
||||
for svb in &mut signature_verified_blocks {
|
||||
signature_verifier
|
||||
.include_all_signatures(svb.block.as_block(), &mut svb.consensus_context)?;
|
||||
}
|
||||
|
||||
if signature_verifier.verify().is_err() {
|
||||
@ -1159,10 +1163,7 @@ impl<T: BeaconChainTypes> IntoExecutionPendingBlock<T> for Arc<SignedBeaconBlock
|
||||
.map_err(|e| BlockSlashInfo::SignatureNotChecked(self.signed_block_header(), e))?;
|
||||
let maybe_available = chain
|
||||
.data_availability_checker
|
||||
.check_rpc_block_availability(RpcBlock::new_without_blobs(
|
||||
Some(block_root),
|
||||
self.clone(),
|
||||
))
|
||||
.verify_kzg_for_rpc_block(RpcBlock::new_without_blobs(Some(block_root), self.clone()))
|
||||
.map_err(|e| {
|
||||
BlockSlashInfo::SignatureNotChecked(
|
||||
self.signed_block_header(),
|
||||
@ -1192,7 +1193,7 @@ impl<T: BeaconChainTypes> IntoExecutionPendingBlock<T> for RpcBlock<T::EthSpec>
|
||||
.map_err(|e| BlockSlashInfo::SignatureNotChecked(self.signed_block_header(), e))?;
|
||||
let maybe_available = chain
|
||||
.data_availability_checker
|
||||
.check_rpc_block_availability(self.clone())
|
||||
.verify_kzg_for_rpc_block(self.clone())
|
||||
.map_err(|e| {
|
||||
BlockSlashInfo::SignatureNotChecked(
|
||||
self.signed_block_header(),
|
||||
|
@ -45,6 +45,13 @@ impl<E: EthSpec> RpcBlock<E> {
|
||||
RpcBlockInner::BlockAndBlobs(block, _) => block,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn blobs(&self) -> Option<&BlobSidecarList<E>> {
|
||||
match &self.block {
|
||||
RpcBlockInner::Block(_) => None,
|
||||
RpcBlockInner::BlockAndBlobs(_, blobs) => Some(blobs),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Note: This variant is intentionally private because we want to safely construct the
|
||||
|
@ -240,9 +240,12 @@ impl<T: BeaconChainTypes> DataAvailabilityChecker<T> {
|
||||
.put_pending_executed_block(executed_block)
|
||||
}
|
||||
|
||||
/// Checks if a block is available, returns a `MaybeAvailableBlock` that may include the fully
|
||||
/// available block.
|
||||
pub fn check_rpc_block_availability(
|
||||
/// Verifies kzg commitments for an RpcBlock, returns a `MaybeAvailableBlock` that may
|
||||
/// include the fully available block.
|
||||
///
|
||||
/// WARNING: This function assumes all required blobs are already present, it does NOT
|
||||
/// check if there are any missing blobs.
|
||||
pub fn verify_kzg_for_rpc_block(
|
||||
&self,
|
||||
block: RpcBlock<T::EthSpec>,
|
||||
) -> Result<MaybeAvailableBlock<T::EthSpec>, AvailabilityCheckError> {
|
||||
@ -279,6 +282,68 @@ impl<T: BeaconChainTypes> DataAvailabilityChecker<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks if a vector of blocks are available. Returns a vector of `MaybeAvailableBlock`
|
||||
/// This is more efficient than calling `verify_kzg_for_rpc_block` in a loop as it does
|
||||
/// all kzg verification at once
|
||||
///
|
||||
/// WARNING: This function assumes all required blobs are already present, it does NOT
|
||||
/// check if there are any missing blobs.
|
||||
pub fn verify_kzg_for_rpc_blocks(
|
||||
&self,
|
||||
blocks: Vec<RpcBlock<T::EthSpec>>,
|
||||
) -> Result<Vec<MaybeAvailableBlock<T::EthSpec>>, AvailabilityCheckError> {
|
||||
let mut results = Vec::with_capacity(blocks.len());
|
||||
let all_blobs: BlobSidecarList<T::EthSpec> = blocks
|
||||
.iter()
|
||||
.filter(|block| self.blobs_required_for_block(block.as_block()))
|
||||
// this clone is cheap as it's cloning an Arc
|
||||
.filter_map(|block| block.blobs().cloned())
|
||||
.flatten()
|
||||
.collect::<Vec<_>>()
|
||||
.into();
|
||||
|
||||
// verify kzg for all blobs at once
|
||||
if !all_blobs.is_empty() {
|
||||
let kzg = self
|
||||
.kzg
|
||||
.as_ref()
|
||||
.ok_or(AvailabilityCheckError::KzgNotInitialized)?;
|
||||
verify_kzg_for_blob_list(&all_blobs, kzg)?;
|
||||
}
|
||||
|
||||
for block in blocks {
|
||||
let (block_root, block, blobs) = block.deconstruct();
|
||||
match blobs {
|
||||
None => {
|
||||
if self.blobs_required_for_block(&block) {
|
||||
results.push(MaybeAvailableBlock::AvailabilityPending { block_root, block })
|
||||
} else {
|
||||
results.push(MaybeAvailableBlock::Available(AvailableBlock {
|
||||
block_root,
|
||||
block,
|
||||
blobs: None,
|
||||
}))
|
||||
}
|
||||
}
|
||||
Some(blob_list) => {
|
||||
let verified_blobs = if self.blobs_required_for_block(&block) {
|
||||
Some(blob_list)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
// already verified kzg for all blobs
|
||||
results.push(MaybeAvailableBlock::Available(AvailableBlock {
|
||||
block_root,
|
||||
block,
|
||||
blobs: verified_blobs,
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(results)
|
||||
}
|
||||
|
||||
/// Determines the blob requirements for a block. If the block is pre-deneb, no blobs are required.
|
||||
/// If the block's epoch is from prior to the data availability boundary, no blobs are required.
|
||||
fn blobs_required_for_block(&self, block: &SignedBeaconBlock<T::EthSpec>) -> bool {
|
||||
|
@ -140,7 +140,7 @@ async fn produces_attestations() {
|
||||
available_block,
|
||||
) = chain
|
||||
.data_availability_checker
|
||||
.check_rpc_block_availability(rpc_block)
|
||||
.verify_kzg_for_rpc_block(rpc_block)
|
||||
.unwrap()
|
||||
else {
|
||||
panic!("block should be available")
|
||||
@ -218,7 +218,7 @@ async fn early_attester_cache_old_request() {
|
||||
harness
|
||||
.chain
|
||||
.data_availability_checker
|
||||
.check_rpc_block_availability(rpc_block)
|
||||
.verify_kzg_for_rpc_block(rpc_block)
|
||||
.unwrap()
|
||||
else {
|
||||
panic!("block should be available")
|
||||
|
@ -2464,10 +2464,10 @@ async fn weak_subjectivity_sync_test(slots: Vec<Slot>, checkpoint_slot: Slot) {
|
||||
if let MaybeAvailableBlock::Available(block) = harness
|
||||
.chain
|
||||
.data_availability_checker
|
||||
.check_rpc_block_availability(
|
||||
.verify_kzg_for_rpc_block(
|
||||
RpcBlock::new(Some(block_root), Arc::new(full_block), Some(blobs)).unwrap(),
|
||||
)
|
||||
.expect("should check availability")
|
||||
.expect("should verify kzg")
|
||||
{
|
||||
available_blocks.push(block);
|
||||
}
|
||||
|
@ -560,14 +560,10 @@ impl<T: BeaconChainTypes> NetworkBeaconProcessor<T> {
|
||||
downloaded_blocks: Vec<RpcBlock<T::EthSpec>>,
|
||||
) -> (usize, Result<(), ChainSegmentFailed>) {
|
||||
let total_blocks = downloaded_blocks.len();
|
||||
let available_blocks = match downloaded_blocks
|
||||
.into_iter()
|
||||
.map(|block| {
|
||||
self.chain
|
||||
.data_availability_checker
|
||||
.check_rpc_block_availability(block)
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
let available_blocks = match self
|
||||
.chain
|
||||
.data_availability_checker
|
||||
.verify_kzg_for_rpc_blocks(downloaded_blocks)
|
||||
{
|
||||
Ok(blocks) => blocks
|
||||
.into_iter()
|
||||
|
Loading…
Reference in New Issue
Block a user