Skip to content

Commit

Permalink
Save blob verification work in gossip verified block
Browse files Browse the repository at this point in the history
  • Loading branch information
emhane committed Feb 17, 2023
1 parent dd31621 commit 3fc5b36
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 106 deletions.
4 changes: 3 additions & 1 deletion beacon_node/beacon_chain/src/beacon_chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ use crate::attester_cache::{AttesterCache, AttesterCacheKey};
use crate::beacon_proposer_cache::compute_proposer_duties_from_head;
use crate::beacon_proposer_cache::BeaconProposerCache;
use crate::blob_cache::BlobCache;
use crate::blob_verification::{AsBlock, AvailabilityPendingBlock, AvailableBlock, BlockWrapper, IntoAvailableBlock};
use crate::blob_verification::{
AsBlock, AvailabilityPendingBlock, AvailableBlock, BlockWrapper, IntoAvailableBlock,
};
use crate::block_times_cache::BlockTimesCache;
use crate::block_verification::{
check_block_is_finalized_descendant, check_block_relevancy, get_block_root,
Expand Down
174 changes: 75 additions & 99 deletions beacon_node/beacon_chain/src/blob_verification.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ fn verify_data_availability<T: BeaconChainTypes>(
transactions: &Transactions<T::EthSpec>,
block_slot: Slot,
block_root: Hash256,
chain: &BeaconChain<T>,
kzg: Option<Arc<Kzg>>,
) -> Result<(), BlobError> {
if verify_kzg_commitments_against_transactions::<T::EthSpec>(transactions, kzg_commitments)
.is_err()
Expand All @@ -132,10 +132,7 @@ fn verify_data_availability<T: BeaconChainTypes>(
}

// Validatate that the kzg proof is valid against the commitments and blobs
let kzg = chain
.kzg
.as_ref()
.ok_or(BlobError::TrustedSetupNotInitialized)?;
let kzg = kzg.as_ref().ok_or(BlobError::TrustedSetupNotInitialized)?;

if !kzg_utils::validate_blobs_sidecar(
kzg,
Expand Down Expand Up @@ -206,10 +203,11 @@ pub enum DataAvailabilityCheckRequired {
impl<T: BeaconChainTypes> BlockWrapper<T::EthSpec> {
fn into_availablilty_pending_block(
self,
block_root: Hash256,
chain: &BeaconChain<T>,
) -> Result<AvailabilityPendingBlock<T::EthSpec>, BlobError> {
) -> AvailabilityPendingBlock<T::EthSpec> {
let data_availability_boundary = chain.data_availability_boundary();
let kzg = chain.kzg;
drop(chain);
let da_check_required =
data_availability_boundary.map_or(DataAvailabilityCheckRequired::No, |boundary| {
if self.slot().epoch(T::EthSpec::slots_per_epoch()) >= boundary {
Expand All @@ -218,46 +216,84 @@ impl<T: BeaconChainTypes> BlockWrapper<T::EthSpec> {
DataAvailabilityCheckRequired::No
}
});
match self {
BlockWrapper::Block(block) => {
AvailabilityPendingBlock::new(block, block_root, da_check_required)
}
BlockWrapper::BlockAndBlobs(block, blobs_sidecar) => {
if matches!(da_check_required, DataAvailabilityCheckRequired::Yes) {
let (block, data_availability_handle) = match self {
BlockWrapper::Block(block) => match da_check_required {
DataAvailabilityCheckRequired::Yes => {
let kzg_commitments = block
.message()
.body()
.blob_kzg_commitments()
.map_err(|_| BlobError::KzgCommitmentMissing)?;
let transactions = block
.message()
.body()
.execution_payload_eip4844()
.map(|payload| payload.transactions())
.map_err(|_| BlobError::TransactionsMissing)?
.ok_or(BlobError::TransactionsMissing)?;
verify_data_availability(
(block, move || -> Result<AvailableBlock<T>, BlobError> {
let kzg_commitments = kzg_commitments?;
if kzg_commitments.is_emoty() {
Ok(AvailableBlock(AvailableBlockInner::Block(block)))
} else {
Err(BlobError::UnavailableBlobs)
}
})
}
DataAvailabilityCheckRequired::No => {
(block, move || -> Result<AvailableBlock<T>, BlobError> {
Ok(AvailableBlock(AvailableBlockInner::Block(block)))
})
}
},
BlockWrapper::BlockAndBlobs(block, blobs_sidecar) => {
//if matches!(da_check_required, DataAvailabilityCheckRequired::No) {
// return Err("network level is passing us too old blobs and should be fixed
// not to gossip too old blobs")
//}
let kzg_commitments = block
.message()
.body()
.blob_kzg_commitments()
.map_err(|_| BlobError::KzgCommitmentMissing);
let transactions = block
.message()
.body()
.execution_payload_eip4844()
.map(|payload| payload.transactions())
.map_err(|_| BlobError::TransactionsMissing);
let block_slot = block.slot();
(block, move || -> Result<AvailableBlock<T>, BlobError> {
let kzg_commitments = kzg_commitments?;
let transactions = transactions?.ok_or(BlobError::TransactionsMissing)?;
if verify_data_availability(
&blobs_sidecar,
kzg_commitments,
transactions,
block.slot(),
block_slot,
block_root,
chain,
)?;
}

AvailabilityPendingBlock::new_with_blobs(block, blobs_sidecar, da_check_required)
kzg,
)? {
Ok(AvailableBlock(AvailableBlockInner::BlockAndBlob(
SignedBeaconBlockAndBlobsSidecar {
beacon_block,
blobs_sidecar,
},
)))
} else {
Err(BlobError::UnavailableBlobs)
}
})
}
// todo(emhane): didn't figure out if we really need this yet
BlockWrapper::BlockAndBlobsFuture(block, _) => {
(block, || -> Result<AvailableBlock<T>, BlobError> {
Err(BlobError::UnavailableBlobs)
})
}
};
AvailabilityPendingBlock {
block,
data_availability_handle,
}
}
}

pub trait IntoAvailableBlock<T: BeaconChainTypes> {
fn into_available_block(
self,
block_root: Hash256,
chain: &BeaconChain<T>,
) -> Result<AvailableBlock<T::EthSpec>, BlobError>;
fn into_available_block(self) -> Result<AvailableBlock<T::EthSpec>, BlobError>;
}

/// A wrapper over a [`SignedBeaconBlock`] or a [`SignedBeaconBlockAndBlobsSidecar`]. An
Expand All @@ -272,7 +308,7 @@ pub struct AvailabilityPendingBlock<E: EthSpec> {
}

/// Used to await the result of data availability check.
type DataAvailabilityHandle<E> = JoinHandle<Result<Option<Arc<BlobsSidecar<E>>>, BlobError>>;
type DataAvailabilityHandle<E> = FnOnce() -> Result<AvailableBlock<T>, BlobError>;

#[derive(Clone, Debug, Derivative)]
#[derivative(PartialEq, Hash(bound = "E: EthSpec"))]
Expand Down Expand Up @@ -300,72 +336,6 @@ enum AvailableBlockInner<E: EthSpec> {
}

impl<E: EthSpec> AvailabilityPendingBlock<E> {
pub fn new(
beacon_block: Arc<SignedBeaconBlock<E>>,
block_root: Hash256,
da_check_required: DataAvailabilityCheckRequired,
) -> Result<Self, BlobError> {
match beacon_block.as_ref() {
// No data availability check required prior to Eip4844.
SignedBeaconBlock::Base(_)
| SignedBeaconBlock::Altair(_)
| SignedBeaconBlock::Capella(_)
| SignedBeaconBlock::Merge(_) => {
Ok(AvailableBlock(AvailableBlockInner::Block(beacon_block)))
}
SignedBeaconBlock::Eip4844(_) => {
match da_check_required {
DataAvailabilityCheckRequired::Yes => {
// Attempt to reconstruct empty blobs here.
let blobs_sidecar = beacon_block
.reconstruct_empty_blobs(Some(block_root))
.map(Arc::new)?;
return Ok(AvailableBlock(AvailableBlockInner::BlockAndBlob(
SignedBeaconBlockAndBlobsSidecar {
beacon_block,
blobs_sidecar,
},
)));
}
DataAvailabilityCheckRequired::No => {
Ok(AvailableBlock(AvailableBlockInner::Block(beacon_block)))
}
}
}
}
}

/// This function is private because an `AvailableBlock` should be
/// constructed via the `into_available_block` method.
fn new_with_blobs(
beacon_block: Arc<SignedBeaconBlock<E>>,
blobs_sidecar: Arc<BlobsSidecar<E>>,
da_check_required: DataAvailabilityCheckRequired,
) -> Result<Self, BlobError> {
match beacon_block.as_ref() {
// This method shouldn't be called with a pre-Eip4844 block.
SignedBeaconBlock::Base(_)
| SignedBeaconBlock::Altair(_)
| SignedBeaconBlock::Capella(_)
| SignedBeaconBlock::Merge(_) => Err(BlobError::InconsistentFork),
SignedBeaconBlock::Eip4844(_) => {
match da_check_required {
DataAvailabilityCheckRequired::Yes => Ok(AvailableBlock(
AvailableBlockInner::BlockAndBlob(SignedBeaconBlockAndBlobsSidecar {
beacon_block,
blobs_sidecar,
}),
)),
DataAvailabilityCheckRequired::No => {
// Blobs were not verified so we drop them, we'll instead just pass around
// an available `Eip4844` block without blobs.
Ok(AvailableBlock(AvailableBlockInner::Block(beacon_block)))
}
}
}
}
}

pub fn blobs(&self) -> Option<Arc<BlobsSidecar<E>>> {
match &self.0 {
AvailableBlockInner::Block(_) => None,
Expand All @@ -389,6 +359,12 @@ impl<E: EthSpec> AvailabilityPendingBlock<E> {
}
}

impl IntoAvailableBlock<T: BeaconChainTypes> for AvailabilityPendingBlock<T> {
fn into_available_block(self) -> Result<AvailableBlock<T::EthSpec>, BlobError> {
self.data_availability_handle()?
}
}

pub trait IntoBlockWrapper<E: EthSpec>: AsBlock<E> {
fn into_block_wrapper(self) -> BlockWrapper<E>;
}
Expand Down
8 changes: 4 additions & 4 deletions beacon_node/beacon_chain/src/block_verification.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@
//!
//! ```
use crate::blob_verification::{
validate_blob_for_gossip, AsBlock, AvailabilityPendingBlock, AvailableBlock, BlobError,
BlockWrapper, IntoAvailableBlock, IntoBlockWrapper,
validate_blob_for_gossip, AsBlock, AvailabilityPendingBlock, BlobError, BlockWrapper,
IntoAvailableBlock, IntoBlockWrapper,
};
use crate::eth1_finalization_cache::Eth1FinalizationData;
use crate::execution_payload::{
Expand Down Expand Up @@ -662,7 +662,7 @@ type PayloadVerificationHandle<E> =
/// `BeaconChain` immediately after it is instantiated.
pub struct ExecutionPendingBlock<
T: BeaconChainTypes,
B: IntoAvailablBlockk = AvailableBlock<T::EthSpec>,
B: IntoAvailablBlockk = AvailabilityPendingBlock<T::EthSpec>,
> {
pub block: B,
pub block_root: Hash256,
Expand All @@ -679,7 +679,7 @@ pub struct ExecutionPendingBlock<
/// Used to allow functions to accept blocks at various stages of verification.
pub trait IntoExecutionPendingBlock<
T: BeaconChainTypes,
B: IntoAvailableBlock = AvailableBlock<T::EthSpec>,
B: IntoAvailableBlock = AvailabilityPendingBlock<T::EthSpec>,
>: Sized
{
fn into_execution_pending_block(
Expand Down
4 changes: 2 additions & 2 deletions beacon_node/beacon_chain/src/early_attester_cache.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::blob_verification::{AvailabilityPendingBlock, AvailableBlock};
use crate::blob_verification::{AvailabilityPendingBlock, AvailabilityPendingBlock};
use crate::{
attester_cache::{CommitteeLengths, Error},
metrics,
Expand Down Expand Up @@ -51,7 +51,7 @@ impl<E: EthSpec> EarlyAttesterCache<E> {
pub fn add_head_block(
&self,
beacon_block_root: Hash256,
block: AvailableBlock<E>,
block: AvailabilityPendingBlock<E>,
proto_block: ProtoBlock,
state: &BeaconState<E>,
spec: &ChainSpec,
Expand Down

0 comments on commit 3fc5b36

Please sign in to comment.