everything, everywhere, all at once

This commit is contained in:
realbigsean
2023-03-17 16:12:40 -04:00
parent 98babb2e67
commit 05db0d2ba3
17 changed files with 453 additions and 253 deletions

View File

@@ -25,7 +25,7 @@ use crate::eth1_finalization_cache::{Eth1FinalizationCache, Eth1FinalizationData
use crate::events::ServerSentEventHandler;
use crate::execution_payload::{get_execution_payload, NotifyExecutionLayer, PreparePayloadHandle};
use crate::fork_choice_signal::{ForkChoiceSignalRx, ForkChoiceSignalTx, ForkChoiceWaitResult};
use crate::gossip_blob_cache::DataAvailabilityChecker;
use crate::gossip_blob_cache::{Availability, AvailabilityCheckError, DataAvailabilityChecker};
use crate::head_tracker::HeadTracker;
use crate::historical_blocks::HistoricalBlockError;
use crate::kzg_utils;
@@ -116,7 +116,7 @@ use tokio::task::JoinHandle;
use tree_hash::TreeHash;
use types::beacon_block_body::KzgCommitments;
use types::beacon_state::CloneConfig;
use types::blob_sidecar::Blobs;
use types::blob_sidecar::{BlobIdentifier, BlobSidecarArcList, Blobs};
use types::consts::eip4844::MIN_EPOCHS_FOR_BLOBS_SIDECARS_REQUESTS;
use types::consts::merge::INTERVALS_PER_SLOT;
use types::*;
@@ -189,6 +189,25 @@ pub enum WhenSlotSkipped {
Prev,
}
#[derive(Debug)]
pub enum AvailabilityProcessingStatus {
PendingBlobs(Vec<BlobIdentifier>),
PendingBlock(Hash256),
Imported(Hash256),
}
//TODO(sean) using this in tests for now
impl TryInto<SignedBeaconBlockHash> for AvailabilityProcessingStatus {
type Error = ();
fn try_into(self) -> Result<SignedBeaconBlockHash, Self::Error> {
match self {
AvailabilityProcessingStatus::Imported(hash) => Ok(hash.into()),
_ => Err(()),
}
}
}
/// The result of a chain segment processing.
pub enum ChainSegmentResult<T: EthSpec> {
/// Processing this chain segment finished successfully.
@@ -445,7 +464,7 @@ pub struct BeaconChain<T: BeaconChainTypes> {
/// Provides monitoring of a set of explicitly defined validators.
pub validator_monitor: RwLock<ValidatorMonitor<T::EthSpec>>,
pub proposal_blob_cache: BlobCache<T::EthSpec>,
pub data_availability_checker: Option<DataAvailabilityChecker<T::EthSpec>>,
pub data_availability_checker: DataAvailabilityChecker<T::EthSpec>,
pub kzg: Option<Arc<Kzg>>,
}
@@ -1061,7 +1080,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
pub fn get_blobs(
&self,
block_root: &Hash256,
) -> Result<Option<BlobSidecarList<T::EthSpec>>, Error> {
) -> Result<Option<BlobSidecarArcList<T::EthSpec>>, Error> {
Ok(self.store.get_blobs(block_root)?)
}
@@ -2635,6 +2654,18 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
.map_err(BeaconChainError::TokioJoin)?
}
pub async fn process_blob(
self: &Arc<Self>,
blob: BlobSidecar<T::EthSpec>,
count_unrealized: CountUnrealized,
) -> Result<AvailabilityProcessingStatus, BlockError<T::EthSpec>> {
self.check_availability_and_maybe_import(
|chain| chain.data_availability_checker.put_blob(Arc::new(blob)),
count_unrealized,
)
.await
}
/// Returns `Ok(block_root)` if the given `unverified_block` was successfully verified and
/// imported into the chain.
///
@@ -2653,7 +2684,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
unverified_block: B,
count_unrealized: CountUnrealized,
notify_execution_layer: NotifyExecutionLayer,
) -> Result<Hash256, BlockError<T::EthSpec>> {
) -> Result<AvailabilityProcessingStatus, BlockError<T::EthSpec>> {
// Start the Prometheus timer.
let _full_timer = metrics::start_timer(&metrics::BLOCK_PROCESSING_TIMES);
@@ -2673,65 +2704,18 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
let executed_block = self
.clone()
.into_executed_block(execution_pending, count_unrealized)
.await?;
.await
.map_err(|e| self.handle_block_error(e))?;
// Check if the executed block has all it's blobs available to qualify as a fully
// available block
let import_block = if let Some(da_checker) = self.data_availability_checker.as_ref() {
da_checker.put_block(executed_block); //TODO(sean) errors
return Err(BlockError::AvailabilityPending(block_root));
} else {
self.clone().import_available_block(
executed_block,
VerifiedBlobs::PreEip4844,
count_unrealized,
)
};
// Verify and import the block.
match import_block.await {
// The block was successfully verified and imported. Yay.
Ok(block_root) => {
trace!(
self.log,
"Beacon block imported";
"block_root" => ?block_root,
"block_slot" => slot,
);
// Increment the Prometheus counter for block processing successes.
metrics::inc_counter(&metrics::BLOCK_PROCESSING_SUCCESSES);
Ok(block_root)
}
Err(e @ BlockError::BeaconChainError(BeaconChainError::TokioJoin(_))) => {
debug!(
self.log,
"Beacon block processing cancelled";
"error" => ?e,
);
Err(e)
}
// There was an error whilst attempting to verify and import the block. The block might
// be partially verified or partially imported.
Err(BlockError::BeaconChainError(e)) => {
crit!(
self.log,
"Beacon block processing error";
"error" => ?e,
);
Err(BlockError::BeaconChainError(e))
}
// The block failed verification.
Err(other) => {
trace!(
self.log,
"Beacon block rejected";
"reason" => other.to_string(),
);
Err(other)
}
}
self.check_availability_and_maybe_import(
|chain| {
chain
.data_availability_checker
.check_block_availability(executed_block)
},
count_unrealized,
)
.await
}
/// Accepts a fully-verified block and awaits on it's payload verification handle to
@@ -2800,55 +2784,118 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
})
}
fn handle_block_error(&self, e: BlockError<T::EthSpec>) -> BlockError<T::EthSpec> {
match e {
e @ BlockError::BeaconChainError(BeaconChainError::TokioJoin(_)) => {
debug!(
self.log,
"Beacon block processing cancelled";
"error" => ?e,
);
e
}
BlockError::BeaconChainError(e) => {
crit!(
self.log,
"Beacon block processing error";
"error" => ?e,
);
BlockError::BeaconChainError(e)
}
other => {
trace!(
self.log,
"Beacon block rejected";
"reason" => other.to_string(),
);
other
}
}
}
/// Accepts a fully-verified, available block and imports it into the chain without performing any
/// additional verification.
///
/// An error is returned if the block was unable to be imported. It may be partially imported
/// (i.e., this function is not atomic).
async fn import_available_block(
self: Arc<Self>,
executed_block: ExecutedBlock<T::EthSpec>,
blobs: VerifiedBlobs<T::EthSpec>,
async fn check_availability_and_maybe_import(
self: &Arc<Self>,
cache_fn: impl FnOnce(Arc<Self>) -> Result<Availability<T::EthSpec>, AvailabilityCheckError>,
count_unrealized: CountUnrealized,
) -> Result<Hash256, BlockError<T::EthSpec>> {
let ExecutedBlock {
block,
block_root,
state,
parent_block,
confirmed_state_roots,
payload_verification_outcome,
parent_eth1_finalization_data,
consensus_context,
} = executed_block;
) -> Result<AvailabilityProcessingStatus, BlockError<T::EthSpec>> {
let availability = cache_fn(self.clone())?;
match availability {
Availability::Available(block) => {
let ExecutedBlock {
block,
block_root,
state,
parent_block,
parent_eth1_finalization_data,
confirmed_state_roots,
consensus_context,
payload_verification_outcome,
} = block;
let chain = self.clone();
let available_block = match block {
BlockWrapper::Available(block) => block,
BlockWrapper::AvailabilityPending(_) => {
todo!() // logic error
}
};
let available_block = AvailableBlock {
block: block.block_cloned(),
blobs: blobs,
};
let slot = available_block.block.slot();
let block_hash = self
.spawn_blocking_handle(
move || {
chain.import_block(
available_block,
block_root,
state,
confirmed_state_roots,
payload_verification_outcome.payload_verification_status,
count_unrealized,
parent_block,
parent_eth1_finalization_data,
consensus_context,
// import
let chain = self.clone();
let result = self
.spawn_blocking_handle(
move || {
chain.import_block(
available_block,
block_root,
state,
confirmed_state_roots,
payload_verification_outcome.payload_verification_status,
count_unrealized,
parent_block,
parent_eth1_finalization_data,
consensus_context,
)
},
"payload_verification_handle",
)
},
"payload_verification_handle",
)
.await??;
.await
.map_err(|e| {
let b = BlockError::from(e);
self.handle_block_error(b)
})?;
Ok(block_hash)
match result {
// The block was successfully verified and imported. Yay.
Ok(block_root) => {
trace!(
self.log,
"Beacon block imported";
"block_root" => ?block_root,
"block_slot" => slot,
);
// Increment the Prometheus counter for block processing successes.
metrics::inc_counter(&metrics::BLOCK_PROCESSING_SUCCESSES);
Ok(AvailabilityProcessingStatus::Imported(block_root))
}
Err(e) => Err(self.handle_block_error(e)),
}
}
Availability::PendingBlock(block_root) => {
Ok(AvailabilityProcessingStatus::PendingBlock(block_root))
}
Availability::PendingBlobs(blob_ids) => {
Ok(AvailabilityProcessingStatus::PendingBlobs(blob_ids))
}
}
}
/// Accepts a fully-verified and available block and imports it into the chain without performing any
@@ -6154,52 +6201,6 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
.map(|fork_epoch| fork_epoch <= current_epoch)
.unwrap_or(false))
}
pub fn start_block_importer(
self: &Arc<Self>,
mut rx: tokio::sync::mpsc::Receiver<ExecutedBlock<T::EthSpec>>,
) {
let chain = self.clone();
self.task_executor.spawn(
async move {
while let Some(block) = rx.recv().await {
let ExecutedBlock {
block,
block_root,
state,
parent_block,
parent_eth1_finalization_data,
confirmed_state_roots,
consensus_context,
payload_verification_outcome,
} = block;
let available_block = block.into_available_block().unwrap(); //TODO(sean) remove unwrap
let chain_inner = chain.clone();
let block_hash = chain
.spawn_blocking_handle(
move || {
chain_inner.import_block(
available_block,
block_root,
state,
confirmed_state_roots,
payload_verification_outcome.payload_verification_status,
CountUnrealized::True, //TODO(sean)
parent_block,
parent_eth1_finalization_data,
consensus_context,
)
},
"block_importer",
)
.await;
}
},
"block_importer_listener",
);
}
}
impl<T: BeaconChainTypes> Drop for BeaconChain<T> {

View File

@@ -1,16 +1,20 @@
use derivative::Derivative;
use slot_clock::SlotClock;
use state_processing::ConsensusContext;
use std::sync::Arc;
use crate::beacon_chain::{
BeaconChain, BeaconChainTypes, MAXIMUM_GOSSIP_CLOCK_DISPARITY,
VALIDATOR_PUBKEY_CACHE_LOCK_TIMEOUT,
};
use crate::snapshot_cache::PreProcessingSnapshot;
use crate::BeaconChainError;
use state_processing::per_block_processing::eip4844::eip4844::verify_kzg_commitments_against_transactions;
use types::blob_sidecar::BlobSidecarArcList;
use types::{
BeaconBlockRef, BeaconStateError, BlobSidecarList, Epoch, EthSpec, Hash256, KzgCommitment,
SignedBeaconBlock, SignedBeaconBlockHeader, SignedBlobSidecar, Slot, Transactions,
BeaconBlockRef, BeaconStateError, BlobSidecar, BlobSidecarList, Epoch, EthSpec, Hash256,
KzgCommitment, SignedBeaconBlock, SignedBeaconBlockHeader, SignedBlobSidecar, Slot,
Transactions,
};
#[derive(Debug)]
@@ -122,11 +126,24 @@ impl From<BeaconStateError> for BlobError {
}
}
/// A wrapper around a `BlobSidecar` that indicates it has been approved for re-gossiping on
/// the p2p network.
#[derive(Debug)]
pub struct GossipVerifiedBlob<T: EthSpec> {
blob: BlobSidecar<T>,
}
impl<T: EthSpec> GossipVerifiedBlob<T> {
pub fn to_blob(self) -> BlobSidecar<T> {
self.blob
}
}
pub fn validate_blob_sidecar_for_gossip<T: BeaconChainTypes>(
blob_sidecar: SignedBlobSidecar<T::EthSpec>,
subnet: u64,
chain: &BeaconChain<T>,
) -> Result<(), BlobError> {
) -> Result<GossipVerifiedBlob<T::EthSpec>, BlobError> {
let blob_slot = blob_sidecar.message.slot;
let blob_index = blob_sidecar.message.index;
let block_root = blob_sidecar.message.block_root;
@@ -240,7 +257,9 @@ pub fn validate_blob_sidecar_for_gossip<T: BeaconChainTypes>(
});
}
Ok(())
Ok(GossipVerifiedBlob {
blob: blob_sidecar.message,
})
}
pub fn verify_data_availability<T: BeaconChainTypes>(
@@ -310,7 +329,7 @@ pub struct AvailableBlock<T: EthSpec> {
}
impl<T: EthSpec> AvailableBlock<T> {
pub fn blobs(&self) -> Option<Arc<BlobSidecarList<T>>> {
pub fn blobs(&self) -> Option<BlobSidecarArcList<T>> {
match &self.blobs {
VerifiedBlobs::EmptyBlobs | VerifiedBlobs::NotRequired | VerifiedBlobs::PreEip4844 => {
None
@@ -319,7 +338,7 @@ impl<T: EthSpec> AvailableBlock<T> {
}
}
pub fn deconstruct(self) -> (Arc<SignedBeaconBlock<T>>, Option<Arc<BlobSidecarList<T>>>) {
pub fn deconstruct(self) -> (Arc<SignedBeaconBlock<T>>, Option<BlobSidecarArcList<T>>) {
match self.blobs {
VerifiedBlobs::EmptyBlobs | VerifiedBlobs::NotRequired | VerifiedBlobs::PreEip4844 => {
(self.block, None)
@@ -333,7 +352,7 @@ impl<T: EthSpec> AvailableBlock<T> {
#[derivative(Hash(bound = "E: EthSpec"))]
pub enum VerifiedBlobs<E: EthSpec> {
/// These blobs are available.
Available(Arc<BlobSidecarList<E>>),
Available(BlobSidecarArcList<E>),
/// This block is from outside the data availability boundary so doesn't require
/// a data availability check.
NotRequired,

View File

@@ -54,6 +54,7 @@ use crate::execution_payload::{
is_optimistic_candidate_block, validate_execution_payload_for_gossip, validate_merge_block,
AllowOptimisticImport, NotifyExecutionLayer, PayloadNotifier,
};
use crate::gossip_blob_cache::AvailabilityCheckError;
use crate::snapshot_cache::PreProcessingSnapshot;
use crate::validator_monitor::HISTORIC_EPOCHS as VALIDATOR_MONITOR_HISTORIC_EPOCHS;
use crate::validator_pubkey_cache::ValidatorPubkeyCache;
@@ -307,7 +308,7 @@ pub enum BlockError<T: EthSpec> {
parent_root: Hash256,
},
BlobValidation(BlobError),
AvailabilityPending(Hash256),
AvailabilityCheck(AvailabilityCheckError),
}
impl<T: EthSpec> From<BlobError> for BlockError<T> {
@@ -316,6 +317,12 @@ impl<T: EthSpec> From<BlobError> for BlockError<T> {
}
}
impl<T: EthSpec> From<AvailabilityCheckError> for BlockError<T> {
fn from(e: AvailabilityCheckError) -> Self {
Self::AvailabilityCheck(e)
}
}
/// Returned when block validation failed due to some issue verifying
/// the execution payload.
#[derive(Debug)]

View File

@@ -87,7 +87,6 @@ pub struct BeaconChainBuilder<T: BeaconChainTypes> {
event_handler: Option<ServerSentEventHandler<T::EthSpec>>,
slot_clock: Option<T::SlotClock>,
shutdown_sender: Option<Sender<ShutdownReason>>,
block_importer_sender: Option<tokio::sync::mpsc::Sender<ExecutedBlock<T::EthSpec>>>,
head_tracker: Option<HeadTracker>,
validator_pubkey_cache: Option<ValidatorPubkeyCache<T>>,
spec: ChainSpec,
@@ -130,7 +129,6 @@ where
event_handler: None,
slot_clock: None,
shutdown_sender: None,
block_importer_sender: None,
head_tracker: None,
validator_pubkey_cache: None,
spec: TEthSpec::default_spec(),
@@ -562,14 +560,6 @@ where
self
}
pub fn block_importer_sender(
mut self,
sender: tokio::sync::mpsc::Sender<ExecutedBlock<TEthSpec>>,
) -> Self {
self.block_importer_sender = Some(sender);
self
}
/// Creates a new, empty operation pool.
fn empty_op_pool(mut self) -> Self {
self.op_pool = Some(OperationPool::new());
@@ -653,18 +643,13 @@ where
slot_clock.now().ok_or("Unable to read slot")?
};
let (kzg, data_availability_checker) = if let (Some(tx), Some(trusted_setup)) =
(self.block_importer_sender, self.trusted_setup)
{
let kzg = if let Some(trusted_setup) = self.trusted_setup {
let kzg = Kzg::new_from_trusted_setup(trusted_setup)
.map_err(|e| format!("Failed to load trusted setup: {:?}", e))?;
let kzg_arc = Arc::new(kzg);
(
Some(kzg_arc.clone()),
Some(DataAvailabilityChecker::new(kzg_arc, tx)),
)
Some(kzg_arc)
} else {
(None, None)
None
};
let initial_head_block_root = fork_choice
@@ -869,7 +854,7 @@ where
slasher: self.slasher.clone(),
validator_monitor: RwLock::new(validator_monitor),
//TODO(sean) should we move kzg solely to the da checker?
data_availability_checker,
data_availability_checker: DataAvailabilityChecker::new(kzg.clone()),
proposal_blob_cache: BlobCache::default(),
kzg,
};

View File

@@ -6,6 +6,7 @@ use crate::{
use parking_lot::RwLock;
use proto_array::Block as ProtoBlock;
use std::sync::Arc;
use types::blob_sidecar::BlobSidecarArcList;
use types::*;
pub struct CacheItem<E: EthSpec> {
@@ -21,7 +22,8 @@ pub struct CacheItem<E: EthSpec> {
* Values used to make the block available.
*/
block: Arc<SignedBeaconBlock<E>>,
blobs: Option<Arc<BlobSidecarList<E>>>,
//TODO(sean) remove this and just use the da checker?'
blobs: Option<BlobSidecarArcList<E>>,
proto_block: ProtoBlock,
}
@@ -160,7 +162,7 @@ impl<E: EthSpec> EarlyAttesterCache<E> {
}
/// Returns the blobs, if `block_root` matches the cached item.
pub fn get_blobs(&self, block_root: Hash256) -> Option<Arc<BlobSidecarList<E>>> {
pub fn get_blobs(&self, block_root: Hash256) -> Option<BlobSidecarArcList<E>> {
self.item
.read()
.as_ref()

View File

@@ -1,12 +1,14 @@
use crate::blob_verification::{verify_data_availability, AsBlock};
use crate::blob_verification::{
verify_data_availability, AsBlock, AvailableBlock, BlockWrapper, VerifiedBlobs,
};
use crate::block_verification::{ExecutedBlock, IntoExecutionPendingBlock};
use crate::kzg_utils::validate_blob;
use crate::{BeaconChain, BeaconChainError, BeaconChainTypes, BlockError};
use eth2::reqwest::header::Entry;
use kzg::Error as KzgError;
use kzg::{Kzg, KzgCommitment};
use parking_lot::{Mutex, RwLock};
use ssz_types::VariableList;
use ssz_types::{Error, VariableList};
use std::collections::hash_map::Entry;
use std::collections::{BTreeMap, HashMap, HashSet};
use std::future::Future;
use std::sync::{mpsc, Arc};
@@ -14,10 +16,19 @@ use tokio::sync::mpsc::Sender;
use types::blob_sidecar::{BlobIdentifier, BlobSidecar};
use types::{EthSpec, Hash256, SignedBeaconBlock};
pub enum BlobCacheError {
#[derive(Debug)]
pub enum AvailabilityCheckError {
DuplicateBlob(Hash256),
Kzg(KzgError),
SszTypes(ssz_types::Error),
}
impl From<ssz_types::Error> for AvailabilityCheckError {
fn from(value: Error) -> Self {
Self::SszTypes(value)
}
}
/// This cache contains
/// - blobs that have been gossip verified
/// - commitments for blocks that have been gossip verified, but the commitments themselves
@@ -26,8 +37,13 @@ pub enum BlobCacheError {
pub struct DataAvailabilityChecker<T: EthSpec> {
rpc_blob_cache: RwLock<HashMap<BlobIdentifier, Arc<BlobSidecar<T>>>>,
gossip_blob_cache: Mutex<HashMap<Hash256, GossipBlobCache<T>>>,
kzg: Arc<Kzg>,
tx: Sender<ExecutedBlock<T>>,
kzg: Option<Arc<Kzg>>,
}
pub enum Availability<T: EthSpec> {
PendingBlobs(Vec<BlobIdentifier>),
PendingBlock(Hash256),
Available(ExecutedBlock<T>),
}
struct GossipBlobCache<T: EthSpec> {
@@ -36,12 +52,11 @@ struct GossipBlobCache<T: EthSpec> {
}
impl<T: EthSpec> DataAvailabilityChecker<T> {
pub fn new(kzg: Arc<Kzg>, tx: Sender<ExecutedBlock<T>>) -> Self {
pub fn new(kzg: Option<Arc<Kzg>>) -> Self {
Self {
rpc_blob_cache: <_>::default(),
gossip_blob_cache: <_>::default(),
kzg,
tx,
}
}
@@ -50,15 +65,25 @@ impl<T: EthSpec> DataAvailabilityChecker<T> {
/// cached, verify the block and import it.
///
/// This should only accept gossip verified blobs, so we should not have to worry about dupes.
pub fn put_blob(&self, blob: Arc<BlobSidecar<T>>) -> Result<(), BlobCacheError> {
// return an enum here that may include the full block
pub fn put_blob(
&self,
blob: Arc<BlobSidecar<T>>,
) -> Result<Availability<T>, AvailabilityCheckError> {
let verified = if let Some(kzg) = self.kzg.as_ref() {
validate_blob::<T>(
kzg,
blob.blob.clone(),
blob.kzg_commitment.clone(),
blob.kzg_proof,
)
.map_err(|e| AvailabilityCheckError::Kzg(e))?
} else {
false
// error wrong fork
};
// TODO(remove clones)
let verified = validate_blob::<T>(
&self.kzg,
blob.blob.clone(),
blob.kzg_commitment.clone(),
blob.kzg_proof,
)
.map_err(|e| BlobCacheError::Kzg(e))?;
if verified {
let mut blob_cache = self.gossip_blob_cache.lock();
@@ -93,7 +118,6 @@ impl<T: EthSpec> DataAvailabilityChecker<T> {
// send to reprocessing queue ?
//TODO(sean) try_send?
//TODO(sean) errors
self.tx.try_send(executed_block);
} else {
let _ = inner.executed_block.insert(executed_block);
}
@@ -110,38 +134,106 @@ impl<T: EthSpec> DataAvailabilityChecker<T> {
self.rpc_blob_cache.write().insert(blob.id(), blob.clone());
}
Ok(())
Ok(Availability::PendingBlobs(vec![]))
}
pub fn put_block(&self, executed_block: ExecutedBlock<T>) -> Result<(), BlobCacheError> {
let mut guard = self.gossip_blob_cache.lock();
guard
.entry(executed_block.block_root)
.and_modify(|cache| {
let block: &SignedBeaconBlock<T> = executed_block.block.as_block();
if let Ok(block) = block.message_eip4844() {
let verified_commitments: Vec<_> = cache
.verified_blobs
.iter()
.map(|blob| blob.kzg_commitment)
.collect();
if verified_commitments == block.body.blob_kzg_commitments.clone().to_vec() {
// send to reprocessing queue ?
//TODO(sean) errors
self.tx.try_send(executed_block.clone());
} else {
let _ = cache.executed_block.insert(executed_block.clone());
// log that we cached
// return an enum here that may include the full block
pub fn check_block_availability(
&self,
executed_block: ExecutedBlock<T>,
) -> Result<Availability<T>, AvailabilityCheckError> {
let block_clone = executed_block.block.clone();
let availability = match block_clone {
BlockWrapper::Available(available_block) => Availability::Available(executed_block),
BlockWrapper::AvailabilityPending(block) => {
if let Ok(kzg_commitments) = block.message().body().blob_kzg_commitments() {
// first check if the blockwrapper contains blobs, if so, use those
let mut guard = self.gossip_blob_cache.lock();
let entry = guard.entry(executed_block.block_root);
match entry {
Entry::Occupied(mut occupied_entry) => {
let cache: &mut GossipBlobCache<T> = occupied_entry.get_mut();
let verified_commitments: Vec<_> = cache
.verified_blobs
.iter()
.map(|blob| blob.kzg_commitment)
.collect();
if verified_commitments == kzg_commitments.clone().to_vec() {
let removed: GossipBlobCache<T> = occupied_entry.remove();
let ExecutedBlock {
block: _,
block_root,
state,
parent_block,
parent_eth1_finalization_data,
confirmed_state_roots,
consensus_context,
payload_verification_outcome,
} = executed_block;
let available_block = BlockWrapper::Available(AvailableBlock {
block,
blobs: VerifiedBlobs::Available(VariableList::new(
removed.verified_blobs,
)?),
});
let available_executed = ExecutedBlock {
block: available_block,
block_root,
state,
parent_block,
parent_eth1_finalization_data,
confirmed_state_roots,
consensus_context,
payload_verification_outcome,
};
Availability::Available(available_executed)
} else {
let mut missing_blobs = Vec::with_capacity(kzg_commitments.len());
for i in 0..kzg_commitments.len() {
if cache.verified_blobs.get(i).is_none() {
missing_blobs.push(BlobIdentifier {
block_root: executed_block.block_root,
index: i as u64,
})
}
}
//TODO(sean) add a check that missing blobs > 0
let _ = cache.executed_block.insert(executed_block.clone());
// log that we cached the block?
Availability::PendingBlobs(missing_blobs)
}
}
Entry::Vacant(vacant_entry) => {
let mut blob_ids = Vec::with_capacity(kzg_commitments.len());
for i in 0..kzg_commitments.len() {
blob_ids.push(BlobIdentifier {
block_root: executed_block.block_root,
index: i as u64,
});
}
vacant_entry.insert(GossipBlobCache {
verified_blobs: vec![],
executed_block: Some(executed_block),
});
Availability::PendingBlobs(blob_ids)
}
}
} else {
// log error
Availability::Available(executed_block)
}
})
.or_insert(GossipBlobCache {
verified_blobs: vec![],
executed_block: Some(executed_block),
});
Ok(())
}
};
Ok(availability)
}
}

View File

@@ -54,9 +54,10 @@ pub mod validator_monitor;
pub mod validator_pubkey_cache;
pub use self::beacon_chain::{
AttestationProcessingOutcome, BeaconChain, BeaconChainTypes, BeaconStore, ChainSegmentResult,
CountUnrealized, ForkChoiceError, OverrideForkchoiceUpdate, ProduceBlockVerification,
StateSkipConfig, WhenSlotSkipped, INVALID_FINALIZED_MERGE_TRANSITION_BLOCK_SHUTDOWN_REASON,
AttestationProcessingOutcome, AvailabilityProcessingStatus, BeaconChain, BeaconChainTypes,
BeaconStore, ChainSegmentResult, CountUnrealized, ForkChoiceError, OverrideForkchoiceUpdate,
ProduceBlockVerification, StateSkipConfig, WhenSlotSkipped,
INVALID_FINALIZED_MERGE_TRANSITION_BLOCK_SHUTDOWN_REASON,
INVALID_JUSTIFIED_PAYLOAD_SHUTDOWN_REASON, MAXIMUM_GOSSIP_CLOCK_DISPARITY,
};
pub use self::beacon_snapshot::BeaconSnapshot;

View File

@@ -1680,7 +1680,8 @@ where
NotifyExecutionLayer::Yes,
)
.await?
.into();
.try_into()
.unwrap();
self.chain.recompute_head_at_current_slot().await;
Ok(block_hash)
}
@@ -1698,7 +1699,8 @@ where
NotifyExecutionLayer::Yes,
)
.await?
.into();
.try_into()
.unwrap();
self.chain.recompute_head_at_current_slot().await;
Ok(block_hash)
}