mirror of
https://github.com/sigp/lighthouse.git
synced 2026-05-08 09:16:00 +00:00
add 'gossip blob cache' and start to clean up processing and transition types
This commit is contained in:
committed by
Pawan Dhananjay
parent
956ac7cbe9
commit
736a24e35a
@@ -7,7 +7,7 @@ use crate::attester_cache::{AttesterCache, AttesterCacheKey};
|
|||||||
use crate::beacon_proposer_cache::compute_proposer_duties_from_head;
|
use crate::beacon_proposer_cache::compute_proposer_duties_from_head;
|
||||||
use crate::beacon_proposer_cache::BeaconProposerCache;
|
use crate::beacon_proposer_cache::BeaconProposerCache;
|
||||||
use crate::blob_cache::BlobCache;
|
use crate::blob_cache::BlobCache;
|
||||||
use crate::blob_verification::{AsBlock, AvailabilityPendingBlock, AvailableBlock, BlockWrapper, IntoAvailableBlock};
|
use crate::blob_verification::{AsBlock, AvailabilityPendingBlock, AvailableBlock, BlobError, BlockWrapper, IntoAvailableBlock};
|
||||||
use crate::block_times_cache::BlockTimesCache;
|
use crate::block_times_cache::BlockTimesCache;
|
||||||
use crate::block_verification::{
|
use crate::block_verification::{
|
||||||
check_block_is_finalized_checkpoint_or_descendant, check_block_relevancy, get_block_root,
|
check_block_is_finalized_checkpoint_or_descendant, check_block_relevancy, get_block_root,
|
||||||
@@ -97,10 +97,13 @@ use std::borrow::Cow;
|
|||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
use std::future::Future;
|
||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
use tokio::task::JoinHandle;
|
||||||
|
use state_processing::per_block_processing::eip4844::eip4844::verify_kzg_commitments_against_transactions;
|
||||||
use store::iter::{BlockRootsIterator, ParentRootBlockIterator, StateRootsIterator};
|
use store::iter::{BlockRootsIterator, ParentRootBlockIterator, StateRootsIterator};
|
||||||
use store::{
|
use store::{
|
||||||
DatabaseBlock, Error as DBError, HotColdDB, KeyValueStore, KeyValueStoreOp, StoreItem, StoreOp,
|
DatabaseBlock, Error as DBError, HotColdDB, KeyValueStore, KeyValueStoreOp, StoreItem, StoreOp,
|
||||||
@@ -432,6 +435,7 @@ pub struct BeaconChain<T: BeaconChainTypes> {
|
|||||||
/// Provides monitoring of a set of explicitly defined validators.
|
/// Provides monitoring of a set of explicitly defined validators.
|
||||||
pub validator_monitor: RwLock<ValidatorMonitor<T::EthSpec>>,
|
pub validator_monitor: RwLock<ValidatorMonitor<T::EthSpec>>,
|
||||||
pub blob_cache: BlobCache<T::EthSpec>,
|
pub blob_cache: BlobCache<T::EthSpec>,
|
||||||
|
pub blob_cache: BlobCache<T::EthSpec>,
|
||||||
pub kzg: Option<Arc<kzg::Kzg>>,
|
pub kzg: Option<Arc<kzg::Kzg>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6143,6 +6147,48 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
|||||||
.map(|fork_epoch| fork_epoch <= current_epoch)
|
.map(|fork_epoch| fork_epoch <= current_epoch)
|
||||||
.unwrap_or(false))
|
.unwrap_or(false))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn check_data_availability(&self, block: Arc<SignedBeaconBlock<T::EthSpec>>) -> Result<AvailableBlock<T>, Error> {
|
||||||
|
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)?;
|
||||||
|
|
||||||
|
if verify_kzg_commitments_against_transactions::<T::EthSpec>(transactions, kzg_commitments)
|
||||||
|
.is_err()
|
||||||
|
{
|
||||||
|
return Err(BlobError::TransactionCommitmentMismatch);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.blob_cache
|
||||||
|
|
||||||
|
// Validatate that the kzg proof is valid against the commitments and blobs
|
||||||
|
let kzg = self
|
||||||
|
.kzg
|
||||||
|
.as_ref()
|
||||||
|
.ok_or(BlobError::TrustedSetupNotInitialized)?;
|
||||||
|
|
||||||
|
if !kzg_utils::validate_blobs_sidecar(
|
||||||
|
kzg,
|
||||||
|
block_slot,
|
||||||
|
block_root,
|
||||||
|
kzg_commitments,
|
||||||
|
blob_sidecar,
|
||||||
|
)
|
||||||
|
.map_err(BlobError::KzgError)?
|
||||||
|
{
|
||||||
|
return Err(BlobError::InvalidKzgProof);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: BeaconChainTypes> Drop for BeaconChain<T> {
|
impl<T: BeaconChainTypes> Drop for BeaconChain<T> {
|
||||||
|
|||||||
@@ -2,18 +2,19 @@ use derivative::Derivative;
|
|||||||
use slot_clock::SlotClock;
|
use slot_clock::SlotClock;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::task::JoinHandle;
|
use tokio::task::JoinHandle;
|
||||||
|
use ssz_types::VariableList;
|
||||||
|
|
||||||
use crate::beacon_chain::{BeaconChain, BeaconChainTypes, MAXIMUM_GOSSIP_CLOCK_DISPARITY};
|
use crate::beacon_chain::{BeaconChain, BeaconChainTypes, MAXIMUM_GOSSIP_CLOCK_DISPARITY};
|
||||||
use crate::block_verification::PayloadVerificationOutcome;
|
use crate::block_verification::PayloadVerificationOutcome;
|
||||||
use crate::{kzg_utils, BeaconChainError, BlockError};
|
use crate::{kzg_utils, BeaconChainError, BlockError};
|
||||||
use state_processing::per_block_processing::eip4844::eip4844::verify_kzg_commitments_against_transactions;
|
use state_processing::per_block_processing::eip4844::eip4844::verify_kzg_commitments_against_transactions;
|
||||||
use types::signed_beacon_block::BlobReconstructionError;
|
|
||||||
use types::{
|
use types::{
|
||||||
BeaconBlockRef, BeaconStateError, BlobsSidecar, EthSpec, Hash256, KzgCommitment,
|
BeaconBlockRef, BeaconStateError, BlobsSidecar, EthSpec, Hash256, KzgCommitment,
|
||||||
SignedBeaconBlock, SignedBeaconBlockAndBlobsSidecar, SignedBeaconBlockHeader, Slot,
|
SignedBeaconBlock, SignedBeaconBlockHeader, Slot,
|
||||||
Transactions,
|
Transactions,
|
||||||
};
|
};
|
||||||
use types::{Epoch, ExecPayload};
|
use types::{Epoch, ExecPayload};
|
||||||
|
use types::blob_sidecar::BlobSidecar;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum BlobError {
|
pub enum BlobError {
|
||||||
@@ -66,15 +67,6 @@ pub enum BlobError {
|
|||||||
InconsistentFork,
|
InconsistentFork,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<BlobReconstructionError> for BlobError {
|
|
||||||
fn from(e: BlobReconstructionError) -> Self {
|
|
||||||
match e {
|
|
||||||
BlobReconstructionError::UnavailableBlobs => BlobError::UnavailableBlobs,
|
|
||||||
BlobReconstructionError::InconsistentFork => BlobError::InconsistentFork,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<BeaconChainError> for BlobError {
|
impl From<BeaconChainError> for BlobError {
|
||||||
fn from(e: BeaconChainError) -> Self {
|
fn from(e: BeaconChainError) -> Self {
|
||||||
BlobError::BeaconChainError(e)
|
BlobError::BeaconChainError(e)
|
||||||
@@ -117,7 +109,7 @@ pub fn validate_blob_for_gossip<T: BeaconChainTypes>(
|
|||||||
block_wrapper.into_availablilty_pending_block(block_root, chain)
|
block_wrapper.into_availablilty_pending_block(block_root, chain)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verify_data_availability<T: BeaconChainTypes>(
|
pub fn verify_data_availability<T: BeaconChainTypes>(
|
||||||
blob_sidecar: &BlobsSidecar<T::EthSpec>,
|
blob_sidecar: &BlobsSidecar<T::EthSpec>,
|
||||||
kzg_commitments: &[KzgCommitment],
|
kzg_commitments: &[KzgCommitment],
|
||||||
transactions: &Transactions<T::EthSpec>,
|
transactions: &Transactions<T::EthSpec>,
|
||||||
@@ -152,51 +144,6 @@ fn verify_data_availability<T: BeaconChainTypes>(
|
|||||||
// Ok(())
|
// Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A wrapper over a [`SignedBeaconBlock`] or a [`SignedBeaconBlockAndBlobsSidecar`]. This makes no
|
|
||||||
/// claims about data availability and should not be used in consensus. This struct is useful in
|
|
||||||
/// networking when we want to send blocks around without consensus checks.
|
|
||||||
#[derive(Clone, Debug, Derivative)]
|
|
||||||
#[derivative(PartialEq, Hash(bound = "E: EthSpec"))]
|
|
||||||
pub enum BlockWrapper<E: EthSpec> {
|
|
||||||
Block(Arc<SignedBeaconBlock<E>>),
|
|
||||||
BlockAndBlobs(Arc<SignedBeaconBlock<E>>, Arc<BlobsSidecar<E>>),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<E: EthSpec> BlockWrapper<E> {
|
|
||||||
pub fn new(
|
|
||||||
block: Arc<SignedBeaconBlock<E>>,
|
|
||||||
blobs_sidecar: Option<Arc<BlobsSidecar<E>>>,
|
|
||||||
) -> Self {
|
|
||||||
if let Some(blobs_sidecar) = blobs_sidecar {
|
|
||||||
BlockWrapper::BlockAndBlobs(block, blobs_sidecar)
|
|
||||||
} else {
|
|
||||||
BlockWrapper::Block(block)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<E: EthSpec> From<SignedBeaconBlock<E>> for BlockWrapper<E> {
|
|
||||||
fn from(block: SignedBeaconBlock<E>) -> Self {
|
|
||||||
BlockWrapper::Block(Arc::new(block))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<E: EthSpec> From<SignedBeaconBlockAndBlobsSidecar<E>> for BlockWrapper<E> {
|
|
||||||
fn from(block: SignedBeaconBlockAndBlobsSidecar<E>) -> Self {
|
|
||||||
let SignedBeaconBlockAndBlobsSidecar {
|
|
||||||
beacon_block,
|
|
||||||
blobs_sidecar,
|
|
||||||
} = block;
|
|
||||||
BlockWrapper::BlockAndBlobs(beacon_block, blobs_sidecar)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<E: EthSpec> From<Arc<SignedBeaconBlock<E>>> for BlockWrapper<E> {
|
|
||||||
fn from(block: Arc<SignedBeaconBlock<E>>) -> Self {
|
|
||||||
BlockWrapper::Block(block)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub enum DataAvailabilityCheckRequired {
|
pub enum DataAvailabilityCheckRequired {
|
||||||
Yes,
|
Yes,
|
||||||
@@ -209,42 +156,12 @@ impl<T: BeaconChainTypes> BlockWrapper<T::EthSpec> {
|
|||||||
block_root: Hash256,
|
block_root: Hash256,
|
||||||
chain: &BeaconChain<T>,
|
chain: &BeaconChain<T>,
|
||||||
) -> Result<AvailabilityPendingBlock<T::EthSpec>, BlobError> {
|
) -> Result<AvailabilityPendingBlock<T::EthSpec>, BlobError> {
|
||||||
let data_availability_boundary = chain.data_availability_boundary();
|
|
||||||
let da_check_required =
|
|
||||||
data_availability_boundary.map_or(DataAvailabilityCheckRequired::No, |boundary| {
|
|
||||||
if self.slot().epoch(T::EthSpec::slots_per_epoch()) >= boundary {
|
|
||||||
DataAvailabilityCheckRequired::Yes
|
|
||||||
} else {
|
|
||||||
DataAvailabilityCheckRequired::No
|
|
||||||
}
|
|
||||||
});
|
|
||||||
match self {
|
match self {
|
||||||
BlockWrapper::Block(block) => {
|
BlockWrapper::Block(block) => {
|
||||||
AvailabilityPendingBlock::new(block, block_root, da_check_required)
|
AvailabilityPendingBlock::new(block, block_root, da_check_required)
|
||||||
}
|
}
|
||||||
BlockWrapper::BlockAndBlobs(block, blobs_sidecar) => {
|
BlockWrapper::BlockAndBlobs(block, blobs_sidecar) => {
|
||||||
if matches!(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(
|
|
||||||
&blobs_sidecar,
|
|
||||||
kzg_commitments,
|
|
||||||
transactions,
|
|
||||||
block.slot(),
|
|
||||||
block_root,
|
|
||||||
chain,
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
AvailabilityPendingBlock::new_with_blobs(block, blobs_sidecar, da_check_required)
|
AvailabilityPendingBlock::new_with_blobs(block, blobs_sidecar, da_check_required)
|
||||||
}
|
}
|
||||||
@@ -264,24 +181,24 @@ pub trait IntoAvailableBlock<T: BeaconChainTypes> {
|
|||||||
/// `AvailableBlock` has passed any required data availability checks and should be used in
|
/// `AvailableBlock` has passed any required data availability checks and should be used in
|
||||||
/// consensus.
|
/// consensus.
|
||||||
#[derive(Clone, Debug, Derivative)]
|
#[derive(Clone, Debug, Derivative)]
|
||||||
#[derivative(PartialEq, Hash(bound = "E: EthSpec"))]
|
#[derivative(PartialEq, Hash(bound = "T: BeaconChainTypes"))]
|
||||||
pub struct AvailabilityPendingBlock<E: EthSpec> {
|
pub struct AvailabilityPendingBlock<T: BeaconChainTypes> {
|
||||||
block: Arc<SignedBeaconBlock<E>>,
|
block: Arc<SignedBeaconBlock<T::EthSpec>>,
|
||||||
data_availability_handle: DataAvailabilityHandle<E>,
|
data_availability_handle: DataAvailabilityHandle<T::EthSpec>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Used to await the result of data availability check.
|
/// Used to await the result of data availability check.
|
||||||
type DataAvailabilityHandle<E> = JoinHandle<Result<Option<Arc<BlobsSidecar<E>>>, BlobError>>;
|
type DataAvailabilityHandle<E> = JoinHandle<Result<Option<Blobs<E>>, BlobError>>;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Derivative)]
|
#[derive(Clone, Debug, Derivative)]
|
||||||
#[derivative(PartialEq, Hash(bound = "E: EthSpec"))]
|
#[derivative(PartialEq, Hash(bound = "T: BeaconChainTypes"))]
|
||||||
pub struct AvailableBlock<E: EthSpec> {
|
pub struct AvailableBlock<T: BeaconChainTypes> {
|
||||||
block: Arc<SignedBeaconBlock<E>>,
|
block: Arc<SignedBeaconBlock<T::EthSpec>>,
|
||||||
blobs: Blobs<E>,
|
blobs: Blobs<T::EthSpec>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <E: EthSpec> AvailableBlock<E> {
|
impl <T: BeaconChainTypes> AvailableBlock<T> {
|
||||||
pub fn blobs(&self) -> Option<Arc<BlobsSidecar<E>>> {
|
pub fn blobs(&self) -> Option<Arc<BlobsSidecar<T>>> {
|
||||||
match &self.blobs {
|
match &self.blobs {
|
||||||
Blobs::NotRequired | Blobs::None => None,
|
Blobs::NotRequired | Blobs::None => None,
|
||||||
Blobs::Available(block_sidecar) => {
|
Blobs::Available(block_sidecar) => {
|
||||||
@@ -290,7 +207,7 @@ impl <E: EthSpec> AvailableBlock<E> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deconstruct(self) -> (Arc<SignedBeaconBlock<E>>, Option<Arc<BlobsSidecar<E>>>) {
|
pub fn deconstruct(self) -> (Arc<SignedBeaconBlock<T::EthSpec>>, Option<Arc<BlobsSidecar<T::EthSpec>>>) {
|
||||||
match self.blobs {
|
match self.blobs {
|
||||||
Blobs::NotRequired | Blobs::None => (self.block, None),
|
Blobs::NotRequired | Blobs::None => (self.block, None),
|
||||||
Blobs::Available(blob_sidecars) => {
|
Blobs::Available(blob_sidecars) => {
|
||||||
@@ -302,7 +219,7 @@ impl <E: EthSpec> AvailableBlock<E> {
|
|||||||
|
|
||||||
pub enum Blobs<E: EthSpec> {
|
pub enum Blobs<E: EthSpec> {
|
||||||
/// These blobs are available.
|
/// These blobs are available.
|
||||||
Available(Arc<BlobsSidecar<E>>),
|
Available(VariableList<Arc<BlobSidecar<E>>, E::MaxBlobsPerBlock>),
|
||||||
/// This block is from outside the data availability boundary or the block is from prior
|
/// This block is from outside the data availability boundary or the block is from prior
|
||||||
/// to the eip4844 fork.
|
/// to the eip4844 fork.
|
||||||
NotRequired,
|
NotRequired,
|
||||||
@@ -310,19 +227,33 @@ pub enum Blobs<E: EthSpec> {
|
|||||||
None,
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E: EthSpec> AvailabilityPendingBlock<E> {
|
//TODO(sean) add block root to the availability pending block?
|
||||||
|
impl<T: BeaconChainTypes> AvailabilityPendingBlock<T> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
beacon_block: Arc<SignedBeaconBlock<E>>,
|
beacon_block: Arc<SignedBeaconBlock<T::EthSpec>>,
|
||||||
block_root: Hash256,
|
block_root: Hash256,
|
||||||
da_check_required: DataAvailabilityCheckRequired,
|
chain: &BeaconChain<T>,
|
||||||
) -> Result<Self, BlobError> {
|
) -> Result<Self, BlobError> {
|
||||||
|
let data_availability_boundary = chain.data_availability_boundary();
|
||||||
|
let da_check_required =
|
||||||
|
data_availability_boundary.map_or(DataAvailabilityCheckRequired::No, |boundary| {
|
||||||
|
if chain.epoch()? >= boundary {
|
||||||
|
DataAvailabilityCheckRequired::Yes
|
||||||
|
} else {
|
||||||
|
DataAvailabilityCheckRequired::No
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
match beacon_block.as_ref() {
|
match beacon_block.as_ref() {
|
||||||
// No data availability check required prior to Eip4844.
|
// No data availability check required prior to Eip4844.
|
||||||
SignedBeaconBlock::Base(_)
|
SignedBeaconBlock::Base(_)
|
||||||
| SignedBeaconBlock::Altair(_)
|
| SignedBeaconBlock::Altair(_)
|
||||||
| SignedBeaconBlock::Capella(_)
|
| SignedBeaconBlock::Capella(_)
|
||||||
| SignedBeaconBlock::Merge(_) => {
|
| SignedBeaconBlock::Merge(_) => {
|
||||||
Ok(AvailableBlock(AvailableBlockInner::Block(beacon_block)))
|
Ok(AvailabilityPendingBlock {
|
||||||
|
block: beacon_block ,
|
||||||
|
data_availability_handle: async{ Ok(Some(Blobs::NotRequired))}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
SignedBeaconBlock::Eip4844(_) => {
|
SignedBeaconBlock::Eip4844(_) => {
|
||||||
match da_check_required {
|
match da_check_required {
|
||||||
@@ -339,7 +270,10 @@ impl<E: EthSpec> AvailabilityPendingBlock<E> {
|
|||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
DataAvailabilityCheckRequired::No => {
|
DataAvailabilityCheckRequired::No => {
|
||||||
Ok(AvailableBlock(AvailableBlockInner::Block(beacon_block)))
|
AvailabilityPendingBlock {
|
||||||
|
block: beacon_block,
|
||||||
|
data_availability_handle: async{ Ok(Some(Blobs::NotRequired))}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -348,11 +282,21 @@ impl<E: EthSpec> AvailabilityPendingBlock<E> {
|
|||||||
|
|
||||||
/// This function is private because an `AvailableBlock` should be
|
/// This function is private because an `AvailableBlock` should be
|
||||||
/// constructed via the `into_available_block` method.
|
/// constructed via the `into_available_block` method.
|
||||||
|
//TODO(sean) do we want this to optionally cricumvent the beacon cache?
|
||||||
fn new_with_blobs(
|
fn new_with_blobs(
|
||||||
beacon_block: Arc<SignedBeaconBlock<E>>,
|
beacon_block: Arc<SignedBeaconBlock<T::EthSpec>>,
|
||||||
blobs_sidecar: Arc<BlobsSidecar<E>>,
|
blobs_sidecar: Arc<BlobsSidecar<T::EthSpec>>,
|
||||||
da_check_required: DataAvailabilityCheckRequired,
|
chain: &BeaconChain<T>,
|
||||||
) -> Result<Self, BlobError> {
|
) -> Result<Self, BlobError> {
|
||||||
|
let data_availability_boundary = chain.data_availability_boundary();
|
||||||
|
let da_check_required =
|
||||||
|
data_availability_boundary.map_or(DataAvailabilityCheckRequired::No, |boundary| {
|
||||||
|
if chain.epoch()? >= boundary {
|
||||||
|
DataAvailabilityCheckRequired::Yes
|
||||||
|
} else {
|
||||||
|
DataAvailabilityCheckRequired::No
|
||||||
|
}
|
||||||
|
});
|
||||||
match beacon_block.as_ref() {
|
match beacon_block.as_ref() {
|
||||||
// This method shouldn't be called with a pre-Eip4844 block.
|
// This method shouldn't be called with a pre-Eip4844 block.
|
||||||
SignedBeaconBlock::Base(_)
|
SignedBeaconBlock::Base(_)
|
||||||
@@ -369,7 +313,10 @@ impl<E: EthSpec> AvailabilityPendingBlock<E> {
|
|||||||
DataAvailabilityCheckRequired::No => {
|
DataAvailabilityCheckRequired::No => {
|
||||||
// Blobs were not verified so we drop them, we'll instead just pass around
|
// Blobs were not verified so we drop them, we'll instead just pass around
|
||||||
// an available `Eip4844` block without blobs.
|
// an available `Eip4844` block without blobs.
|
||||||
Ok(AvailableBlock(AvailableBlockInner::Block(beacon_block)))
|
Ok(AvailableBlock{
|
||||||
|
block: beacon_block,
|
||||||
|
blobs: Blobs::NotRequired
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -93,7 +93,6 @@ use std::time::Duration;
|
|||||||
use store::{Error as DBError, HotStateSummary, KeyValueStore, StoreOp};
|
use store::{Error as DBError, HotStateSummary, KeyValueStore, StoreOp};
|
||||||
use task_executor::JoinHandle;
|
use task_executor::JoinHandle;
|
||||||
use tree_hash::TreeHash;
|
use tree_hash::TreeHash;
|
||||||
use types::signed_beacon_block::BlobReconstructionError;
|
|
||||||
use types::ExecPayload;
|
use types::ExecPayload;
|
||||||
use types::{
|
use types::{
|
||||||
BeaconBlockRef, BeaconState, BeaconStateError, BlindedPayload, ChainSpec, CloneConfig, Epoch,
|
BeaconBlockRef, BeaconState, BeaconStateError, BlindedPayload, ChainSpec, CloneConfig, Epoch,
|
||||||
@@ -491,12 +490,6 @@ impl<T: EthSpec> From<ArithError> for BlockError<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: EthSpec> From<BlobReconstructionError> for BlockError<T> {
|
|
||||||
fn from(e: BlobReconstructionError) -> Self {
|
|
||||||
BlockError::BlobValidation(BlobError::from(e))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Stores information about verifying a payload against an execution engine.
|
/// Stores information about verifying a payload against an execution engine.
|
||||||
pub struct PayloadVerificationOutcome {
|
pub struct PayloadVerificationOutcome {
|
||||||
pub payload_verification_status: PayloadVerificationStatus,
|
pub payload_verification_status: PayloadVerificationStatus,
|
||||||
@@ -634,7 +627,7 @@ pub fn signature_verify_chain_segment<T: BeaconChainTypes>(
|
|||||||
#[derive(Derivative)]
|
#[derive(Derivative)]
|
||||||
#[derivative(Debug(bound = "T: BeaconChainTypes"))]
|
#[derivative(Debug(bound = "T: BeaconChainTypes"))]
|
||||||
pub struct GossipVerifiedBlock<T: BeaconChainTypes> {
|
pub struct GossipVerifiedBlock<T: BeaconChainTypes> {
|
||||||
pub block: AvailabilityPendingBlock<T::EthSpec>,
|
pub block: AvailabilityPendingBlock<T>,
|
||||||
pub block_root: Hash256,
|
pub block_root: Hash256,
|
||||||
parent: Option<PreProcessingSnapshot<T::EthSpec>>,
|
parent: Option<PreProcessingSnapshot<T::EthSpec>>,
|
||||||
consensus_context: ConsensusContext<T::EthSpec>,
|
consensus_context: ConsensusContext<T::EthSpec>,
|
||||||
|
|||||||
111
beacon_node/beacon_chain/src/gossip_blob_cache.rs
Normal file
111
beacon_node/beacon_chain/src/gossip_blob_cache.rs
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
use std::collections::{BTreeMap, HashMap};
|
||||||
|
use kzg::KzgCommitment;
|
||||||
|
use ssz_types::VariableList;
|
||||||
|
use types::blob_sidecar::{BlobIdentifier, BlobSidecar};
|
||||||
|
use types::{EthSpec, Hash256};
|
||||||
|
use crate::blob_verification::verify_data_availability;
|
||||||
|
|
||||||
|
/// Only need to put when we get a blob
|
||||||
|
/// Only need to get when we have a block we want to verify
|
||||||
|
pub struct GossipBlobCache<T: EthSpec> {
|
||||||
|
sender: tokio::sync::mpsc::Sender<Operation<T>>,
|
||||||
|
thread: tokio::task::JoinHandle<()>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Operation<T: EthSpec> {
|
||||||
|
DataAvailabilityCheck(DataAvailabilityRequest<T>),
|
||||||
|
Put(BlobSidecar<T>),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DataAvailabilityRequest<T: EthSpec> {
|
||||||
|
block_root: Hash256,
|
||||||
|
kzg_commitments: VariableList<KzgCommitment, T::MaxBlobsPerBlock>,
|
||||||
|
sender: oneshot_broadcast::Sender<VariableList<BlobSidecar<T>, T::MaxBlobsPerBlock>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl <T: EthSpec> GossipBlobCache<T> {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
//TODO(sean) figure out capacity
|
||||||
|
|
||||||
|
let (tx, mut rx) = tokio::sync::mpsc::channel::<Operation<T>>(1000);
|
||||||
|
|
||||||
|
|
||||||
|
let thread = tokio::task::spawn(async move || {
|
||||||
|
let mut unverified_blobs: BTreeMap<BlobIdentifier, BlobSidecar<T>> = BTreeMap::new();
|
||||||
|
let mut verified_blobs: HashMap<Hash256, VariableList<BlobSidecar<T>, T::MaxBlobsPerBlock>>= HashMap::new();
|
||||||
|
let mut requests: HashMap<Hash256, DataAvailabilityRequest<T>> = HashMap::new();
|
||||||
|
while let Some(op) = rx.recv().await {
|
||||||
|
// check if we already have a verified set of blobs for this, if so ignore
|
||||||
|
// check if we can complete a set of blobs and verify
|
||||||
|
// -- if yes, do it, then check if there are outstanding requests we can resolve, and resolve them
|
||||||
|
// -- -- spawn a thread that does verification
|
||||||
|
// -- if no, add to unverified blobs
|
||||||
|
|
||||||
|
match op {
|
||||||
|
Operation::Put(blob) => {
|
||||||
|
let blob_id = blob.id();
|
||||||
|
if !unverified_blobs.contains_key(&blob_id) {
|
||||||
|
unverified_blobs.insert(blob_id, blob)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !verified_blobs.contains_key(&blob.block_root) {
|
||||||
|
// ignore
|
||||||
|
if let Some(request) = requests.get(&blob.block_root) {
|
||||||
|
let expected_blob_count = request.kzg_commitments.len();
|
||||||
|
|
||||||
|
let mut blobs = unverified_blobs.range(BlobIdentifier::new(blob.block_root, 0)..BlobIdentifier::new(blob.block_root, expected_blob_count as u64));
|
||||||
|
|
||||||
|
for (index, (_, blob)) in blobs.enumerate() {
|
||||||
|
// find missing blobs and trigger a request
|
||||||
|
}
|
||||||
|
|
||||||
|
verify_data_availability(blob, request.kzg_commitments);
|
||||||
|
verified_blobs.put(blob.block_root, blob);
|
||||||
|
|
||||||
|
request.sender.send(result)
|
||||||
|
}
|
||||||
|
// check if the request can be completed, and if so complete it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Operation::DataAvailabilityCheck(request) => {
|
||||||
|
if let Some(verified_blobs) = verified_blobs.get(&blob.block_root) {
|
||||||
|
request.sender.send(result)
|
||||||
|
} else {
|
||||||
|
requests.insert(request.block_root, request)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Operation::GetBlobById(id) => {
|
||||||
|
unverified_blobs.get(id)
|
||||||
|
}
|
||||||
|
Operation::GetBlobsByBlockRoot((root, count)) => {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Self {
|
||||||
|
sender: tx,
|
||||||
|
thread,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn put(&self, blob: BlobSidecar<T>) {
|
||||||
|
self.sender.send(Operation::Put(blob));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_verified(&self, block_root: Hash256, kzg_commitments: VariableList<KzgCommitment, T::MaxBlobsPerBlock>) -> Receiever<VariableList<BlobSidecar<T>, T::MaxBlobsPerBlock>> {
|
||||||
|
// check if there are verified blobs
|
||||||
|
// if not, check if not check if there's a request for this block already.
|
||||||
|
// -- if yes, await the join handle return
|
||||||
|
// -- if no, create new request entry (spawn a new thread?)
|
||||||
|
let (tx, rx) = tokio::sync::oneshot::channel();
|
||||||
|
let req = DataAvailabilityRequest {
|
||||||
|
block_root,
|
||||||
|
kzg_commitments,
|
||||||
|
sender: tx,
|
||||||
|
};
|
||||||
|
self.sender.send(Operation::DataAvailabilityCheck(req));
|
||||||
|
rx
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -51,6 +51,7 @@ pub mod test_utils;
|
|||||||
mod timeout_rw_lock;
|
mod timeout_rw_lock;
|
||||||
pub mod validator_monitor;
|
pub mod validator_monitor;
|
||||||
pub mod validator_pubkey_cache;
|
pub mod validator_pubkey_cache;
|
||||||
|
pub mod gossip_blob_cache;
|
||||||
|
|
||||||
pub use self::beacon_chain::{
|
pub use self::beacon_chain::{
|
||||||
AttestationProcessingOutcome, BeaconChain, BeaconChainTypes, BeaconStore, ChainSegmentResult,
|
AttestationProcessingOutcome, BeaconChain, BeaconChainTypes, BeaconStore, ChainSegmentResult,
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ use crate::{Blob, EthSpec, Hash256, SignedRoot, Slot};
|
|||||||
use derivative::Derivative;
|
use derivative::Derivative;
|
||||||
use kzg::{KzgCommitment, KzgProof};
|
use kzg::{KzgCommitment, KzgProof};
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
use bls::Signature;
|
||||||
use ssz::Encode;
|
use ssz::Encode;
|
||||||
use ssz_derive::{Decode, Encode};
|
use ssz_derive::{Decode, Encode};
|
||||||
use ssz_types::VariableList;
|
|
||||||
use test_random_derive::TestRandom;
|
use test_random_derive::TestRandom;
|
||||||
use tree_hash_derive::TreeHash;
|
use tree_hash_derive::TreeHash;
|
||||||
|
|
||||||
@@ -52,6 +52,10 @@ pub type BlobSidecarList<T> = VariableList<BlobSidecar<T>, <T as EthSpec>::MaxBl
|
|||||||
impl<T: EthSpec> SignedRoot for BlobSidecar<T> {}
|
impl<T: EthSpec> SignedRoot for BlobSidecar<T> {}
|
||||||
|
|
||||||
impl<T: EthSpec> BlobSidecar<T> {
|
impl<T: EthSpec> BlobSidecar<T> {
|
||||||
|
pub fn id(&self) -> BlobIdentifier {
|
||||||
|
BlobIdentifier::new(self.block_root, self.index)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn empty() -> Self {
|
pub fn empty() -> Self {
|
||||||
Self::default()
|
Self::default()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ pub mod beacon_block_body;
|
|||||||
pub mod beacon_block_header;
|
pub mod beacon_block_header;
|
||||||
pub mod beacon_committee;
|
pub mod beacon_committee;
|
||||||
pub mod beacon_state;
|
pub mod beacon_state;
|
||||||
|
pub mod blob_sidecar;
|
||||||
pub mod bls_to_execution_change;
|
pub mod bls_to_execution_change;
|
||||||
pub mod builder_bid;
|
pub mod builder_bid;
|
||||||
pub mod chain_spec;
|
pub mod chain_spec;
|
||||||
@@ -219,6 +220,7 @@ pub type BLSFieldElement = Uint256;
|
|||||||
pub type Blob<T> = FixedVector<u8, <T as EthSpec>::BytesPerBlob>;
|
pub type Blob<T> = FixedVector<u8, <T as EthSpec>::BytesPerBlob>;
|
||||||
pub type VersionedHash = Hash256;
|
pub type VersionedHash = Hash256;
|
||||||
pub type Hash64 = ethereum_types::H64;
|
pub type Hash64 = ethereum_types::H64;
|
||||||
|
pub type BlobsSidecar<T> = VariableList<BlobSidecar<T>, <T as EthSpec>::MaxBlobsPerBlock>;
|
||||||
|
|
||||||
pub use bls::{
|
pub use bls::{
|
||||||
AggregatePublicKey, AggregateSignature, Keypair, PublicKey, PublicKeyBytes, SecretKey,
|
AggregatePublicKey, AggregateSignature, Keypair, PublicKey, PublicKeyBytes, SecretKey,
|
||||||
@@ -229,3 +231,4 @@ pub use kzg::{KzgCommitment, KzgProof};
|
|||||||
|
|
||||||
pub use ssz_types::{typenum, typenum::Unsigned, BitList, BitVector, FixedVector, VariableList};
|
pub use ssz_types::{typenum, typenum::Unsigned, BitList, BitVector, FixedVector, VariableList};
|
||||||
pub use superstruct::superstruct;
|
pub use superstruct::superstruct;
|
||||||
|
use crate::blob_sidecar::BlobSidecar;
|
||||||
|
|||||||
@@ -35,14 +35,6 @@ impl From<SignedBeaconBlockHash> for Hash256 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum BlobReconstructionError {
|
|
||||||
/// No blobs for the specified block where we would expect blobs.
|
|
||||||
UnavailableBlobs,
|
|
||||||
/// Blobs provided for a pre-Eip4844 fork.
|
|
||||||
InconsistentFork,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A `BeaconBlock` and a signature from its proposer.
|
/// A `BeaconBlock` and a signature from its proposer.
|
||||||
#[superstruct(
|
#[superstruct(
|
||||||
variants(Base, Altair, Merge, Capella, Eip4844),
|
variants(Base, Altair, Merge, Capella, Eip4844),
|
||||||
|
|||||||
Reference in New Issue
Block a user