Merge pull request #3833 from realbigsean/empty-blobs
Empty blobs validation
This commit is contained in:
commit
019467840f
@ -42,6 +42,7 @@ pub enum Error {
|
|||||||
// Boxed to avoid an infinite-size recursion issue.
|
// Boxed to avoid an infinite-size recursion issue.
|
||||||
BeaconChain(Box<BeaconChainError>),
|
BeaconChain(Box<BeaconChainError>),
|
||||||
MissingBeaconState(Hash256),
|
MissingBeaconState(Hash256),
|
||||||
|
MissingBlobs,
|
||||||
FailedToTransitionState(StateAdvanceError),
|
FailedToTransitionState(StateAdvanceError),
|
||||||
CannotAttestToFutureState {
|
CannotAttestToFutureState {
|
||||||
state_slot: Slot,
|
state_slot: Slot,
|
||||||
|
@ -2935,7 +2935,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
|||||||
// If the write fails, revert fork choice to the version from disk, else we can
|
// If the write fails, revert fork choice to the version from disk, else we can
|
||||||
// end up with blocks in fork choice that are missing from disk.
|
// end up with blocks in fork choice that are missing from disk.
|
||||||
// See https://github.com/sigp/lighthouse/issues/2028
|
// See https://github.com/sigp/lighthouse/issues/2028
|
||||||
let (signed_block, blobs) = signed_block.deconstruct();
|
let (signed_block, blobs) = signed_block.deconstruct(Some(block_root));
|
||||||
let block = signed_block.message();
|
let block = signed_block.message();
|
||||||
let mut ops: Vec<_> = confirmed_state_roots
|
let mut ops: Vec<_> = confirmed_state_roots
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@ -2944,7 +2944,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
|||||||
ops.push(StoreOp::PutBlock(block_root, signed_block.clone()));
|
ops.push(StoreOp::PutBlock(block_root, signed_block.clone()));
|
||||||
ops.push(StoreOp::PutState(block.state_root(), &state));
|
ops.push(StoreOp::PutState(block.state_root(), &state));
|
||||||
|
|
||||||
if let Some(blobs) = blobs {
|
if let Some(blobs) = blobs? {
|
||||||
//FIXME(sean) using this for debugging for now
|
//FIXME(sean) using this for debugging for now
|
||||||
info!(self.log, "Writing blobs to store"; "block_root" => ?block_root);
|
info!(self.log, "Writing blobs to store"; "block_root" => ?block_root);
|
||||||
ops.push(StoreOp::PutBlobs(block_root, blobs));
|
ops.push(StoreOp::PutBlobs(block_root, blobs));
|
||||||
|
@ -3,6 +3,7 @@ use slot_clock::SlotClock;
|
|||||||
use crate::beacon_chain::{BeaconChain, BeaconChainTypes, MAXIMUM_GOSSIP_CLOCK_DISPARITY};
|
use crate::beacon_chain::{BeaconChain, BeaconChainTypes, MAXIMUM_GOSSIP_CLOCK_DISPARITY};
|
||||||
use crate::{kzg_utils, BeaconChainError};
|
use crate::{kzg_utils, BeaconChainError};
|
||||||
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::{BeaconStateError, BlobsSidecar, Hash256, KzgCommitment, Slot, Transactions};
|
use types::{BeaconStateError, BlobsSidecar, Hash256, KzgCommitment, Slot, Transactions};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -89,6 +90,12 @@ pub enum BlobError {
|
|||||||
MissingBlobs,
|
MissingBlobs,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<BlobReconstructionError> for BlobError {
|
||||||
|
fn from(_: BlobReconstructionError) -> Self {
|
||||||
|
BlobError::MissingBlobs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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)
|
||||||
|
@ -87,6 +87,7 @@ 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::signed_block_and_blobs::BlockWrapper;
|
use types::signed_block_and_blobs::BlockWrapper;
|
||||||
use types::ExecPayload;
|
use types::ExecPayload;
|
||||||
use types::{
|
use types::{
|
||||||
@ -479,6 +480,12 @@ 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,
|
||||||
@ -905,7 +912,7 @@ impl<T: BeaconChainTypes> GossipVerifiedBlock<T> {
|
|||||||
// Validate the block's execution_payload (if any).
|
// Validate the block's execution_payload (if any).
|
||||||
validate_execution_payload_for_gossip(&parent_block, block.message(), chain)?;
|
validate_execution_payload_for_gossip(&parent_block, block.message(), chain)?;
|
||||||
|
|
||||||
if let Some(blobs_sidecar) = block.blobs() {
|
if let Some(blobs_sidecar) = block.blobs(Some(block_root))? {
|
||||||
let kzg_commitments = block
|
let kzg_commitments = block
|
||||||
.message()
|
.message()
|
||||||
.body()
|
.body()
|
||||||
@ -919,7 +926,7 @@ impl<T: BeaconChainTypes> GossipVerifiedBlock<T> {
|
|||||||
.map_err(|_| BlockError::BlobValidation(BlobError::TransactionsMissing))?
|
.map_err(|_| BlockError::BlobValidation(BlobError::TransactionsMissing))?
|
||||||
.ok_or(BlockError::BlobValidation(BlobError::TransactionsMissing))?;
|
.ok_or(BlockError::BlobValidation(BlobError::TransactionsMissing))?;
|
||||||
validate_blob_for_gossip(
|
validate_blob_for_gossip(
|
||||||
blobs_sidecar,
|
&blobs_sidecar,
|
||||||
kzg_commitments,
|
kzg_commitments,
|
||||||
transactions,
|
transactions,
|
||||||
block.slot(),
|
block.slot(),
|
||||||
@ -1134,11 +1141,7 @@ impl<T: BeaconChainTypes> IntoExecutionPendingBlock<T> for Arc<SignedBeaconBlock
|
|||||||
let block_root = check_block_relevancy(&self, block_root, chain)
|
let block_root = check_block_relevancy(&self, block_root, chain)
|
||||||
.map_err(|e| BlockSlashInfo::SignatureNotChecked(self.signed_block_header(), e))?;
|
.map_err(|e| BlockSlashInfo::SignatureNotChecked(self.signed_block_header(), e))?;
|
||||||
|
|
||||||
SignatureVerifiedBlock::check_slashable(
|
SignatureVerifiedBlock::check_slashable(BlockWrapper::Block(self), block_root, chain)?
|
||||||
BlockWrapper::Block { block: self },
|
|
||||||
block_root,
|
|
||||||
chain,
|
|
||||||
)?
|
|
||||||
.into_execution_pending_block_slashable(block_root, chain, notify_execution_layer)
|
.into_execution_pending_block_slashable(block_root, chain, notify_execution_layer)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1563,7 +1566,7 @@ impl<T: BeaconChainTypes> ExecutionPendingBlock<T> {
|
|||||||
if let Some(data_availability_boundary) = chain.data_availability_boundary() {
|
if let Some(data_availability_boundary) = chain.data_availability_boundary() {
|
||||||
if block_slot.epoch(T::EthSpec::slots_per_epoch()) >= data_availability_boundary {
|
if block_slot.epoch(T::EthSpec::slots_per_epoch()) >= data_availability_boundary {
|
||||||
let sidecar = block
|
let sidecar = block
|
||||||
.blobs()
|
.blobs(Some(block_root))?
|
||||||
.ok_or(BlockError::BlobValidation(BlobError::MissingBlobs))?;
|
.ok_or(BlockError::BlobValidation(BlobError::MissingBlobs))?;
|
||||||
let kzg = chain.kzg.as_ref().ok_or(BlockError::BlobValidation(
|
let kzg = chain.kzg.as_ref().ok_or(BlockError::BlobValidation(
|
||||||
BlobError::TrustedSetupNotInitialized,
|
BlobError::TrustedSetupNotInitialized,
|
||||||
@ -1586,7 +1589,7 @@ impl<T: BeaconChainTypes> ExecutionPendingBlock<T> {
|
|||||||
block.slot(),
|
block.slot(),
|
||||||
block_root,
|
block_root,
|
||||||
kzg_commitments,
|
kzg_commitments,
|
||||||
sidecar,
|
&sidecar,
|
||||||
)
|
)
|
||||||
.map_err(|e| BlockError::BlobValidation(BlobError::KzgError(e)))?
|
.map_err(|e| BlockError::BlobValidation(BlobError::KzgError(e)))?
|
||||||
{
|
{
|
||||||
|
@ -69,7 +69,7 @@ impl<E: EthSpec> EarlyAttesterCache<E> {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
let (block, blobs) = block.deconstruct();
|
let (block, blobs) = block.deconstruct(Some(beacon_block_root));
|
||||||
let item = CacheItem {
|
let item = CacheItem {
|
||||||
epoch,
|
epoch,
|
||||||
committee_lengths,
|
committee_lengths,
|
||||||
@ -77,7 +77,7 @@ impl<E: EthSpec> EarlyAttesterCache<E> {
|
|||||||
source,
|
source,
|
||||||
target,
|
target,
|
||||||
block,
|
block,
|
||||||
blobs,
|
blobs: blobs.map_err(|_| Error::MissingBlobs)?,
|
||||||
proto_block,
|
proto_block,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -42,9 +42,7 @@ pub async fn publish_block<T: BeaconChainTypes>(
|
|||||||
network_tx,
|
network_tx,
|
||||||
PubsubMessage::BeaconBlockAndBlobsSidecars(block_and_blobs.clone()),
|
PubsubMessage::BeaconBlockAndBlobsSidecars(block_and_blobs.clone()),
|
||||||
)?;
|
)?;
|
||||||
BlockWrapper::BlockAndBlob {
|
BlockWrapper::BlockAndBlob(block_and_blobs)
|
||||||
block_sidecar_pair: block_and_blobs,
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
//FIXME(sean): This should probably return a specific no-blob-cached error code, beacon API coordination required
|
//FIXME(sean): This should probably return a specific no-blob-cached error code, beacon API coordination required
|
||||||
return Err(warp_utils::reject::broadcast_without_import(format!(
|
return Err(warp_utils::reject::broadcast_without_import(format!(
|
||||||
@ -53,7 +51,7 @@ pub async fn publish_block<T: BeaconChainTypes>(
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
crate::publish_pubsub_message(network_tx, PubsubMessage::BeaconBlock(block.clone()))?;
|
crate::publish_pubsub_message(network_tx, PubsubMessage::BeaconBlock(block.clone()))?;
|
||||||
BlockWrapper::Block { block }
|
BlockWrapper::Block(block)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Determine the delay after the start of the slot, register it with metrics.
|
// Determine the delay after the start of the slot, register it with metrics.
|
||||||
|
@ -1699,7 +1699,7 @@ impl<T: BeaconChainTypes> BeaconProcessor<T> {
|
|||||||
message_id,
|
message_id,
|
||||||
peer_id,
|
peer_id,
|
||||||
peer_client,
|
peer_client,
|
||||||
BlockWrapper::Block { block },
|
BlockWrapper::Block(block),
|
||||||
work_reprocessing_tx,
|
work_reprocessing_tx,
|
||||||
duplicate_cache,
|
duplicate_cache,
|
||||||
seen_timestamp,
|
seen_timestamp,
|
||||||
@ -1721,7 +1721,7 @@ impl<T: BeaconChainTypes> BeaconProcessor<T> {
|
|||||||
message_id,
|
message_id,
|
||||||
peer_id,
|
peer_id,
|
||||||
peer_client,
|
peer_client,
|
||||||
BlockWrapper::BlockAndBlob { block_sidecar_pair },
|
BlockWrapper::BlockAndBlob(block_sidecar_pair),
|
||||||
work_reprocessing_tx,
|
work_reprocessing_tx,
|
||||||
duplicate_cache,
|
duplicate_cache,
|
||||||
seen_timestamp,
|
seen_timestamp,
|
||||||
|
@ -191,11 +191,9 @@ impl<T: BeaconChainTypes> Worker<T> {
|
|||||||
let unwrapped = downloaded_blocks
|
let unwrapped = downloaded_blocks
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|block| match block {
|
.map(|block| match block {
|
||||||
BlockWrapper::Block { block } => block,
|
BlockWrapper::Block(block) => block,
|
||||||
//FIXME(sean) handle blobs in backfill
|
//FIXME(sean) handle blobs in backfill
|
||||||
BlockWrapper::BlockAndBlob {
|
BlockWrapper::BlockAndBlob(_) => todo!(),
|
||||||
block_sidecar_pair: _,
|
|
||||||
} => todo!(),
|
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
@ -51,16 +51,14 @@ impl<T: EthSpec> BlockBlobRequestInfo<T> {
|
|||||||
{
|
{
|
||||||
let blobs_sidecar =
|
let blobs_sidecar =
|
||||||
accumulated_sidecars.pop_front().ok_or("missing sidecar")?;
|
accumulated_sidecars.pop_front().ok_or("missing sidecar")?;
|
||||||
Ok(BlockWrapper::BlockAndBlob {
|
Ok(BlockWrapper::BlockAndBlob(
|
||||||
block_sidecar_pair: SignedBeaconBlockAndBlobsSidecar {
|
SignedBeaconBlockAndBlobsSidecar {
|
||||||
beacon_block,
|
beacon_block,
|
||||||
blobs_sidecar,
|
blobs_sidecar,
|
||||||
},
|
},
|
||||||
})
|
))
|
||||||
} else {
|
} else {
|
||||||
Ok(BlockWrapper::Block {
|
Ok(BlockWrapper::Block(beacon_block))
|
||||||
block: beacon_block,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<_>, _>>();
|
.collect::<Result<Vec<_>, _>>();
|
||||||
|
@ -734,14 +734,14 @@ impl<T: BeaconChainTypes> SyncManager<T> {
|
|||||||
RequestId::SingleBlock { id } => self.block_lookups.single_block_lookup_response(
|
RequestId::SingleBlock { id } => self.block_lookups.single_block_lookup_response(
|
||||||
id,
|
id,
|
||||||
peer_id,
|
peer_id,
|
||||||
beacon_block.map(|block| BlockWrapper::Block { block }),
|
beacon_block.map(|block| BlockWrapper::Block(block)),
|
||||||
seen_timestamp,
|
seen_timestamp,
|
||||||
&mut self.network,
|
&mut self.network,
|
||||||
),
|
),
|
||||||
RequestId::ParentLookup { id } => self.block_lookups.parent_lookup_response(
|
RequestId::ParentLookup { id } => self.block_lookups.parent_lookup_response(
|
||||||
id,
|
id,
|
||||||
peer_id,
|
peer_id,
|
||||||
beacon_block.map(|block| BlockWrapper::Block { block }),
|
beacon_block.map(|block| BlockWrapper::Block(block)),
|
||||||
seen_timestamp,
|
seen_timestamp,
|
||||||
&mut self.network,
|
&mut self.network,
|
||||||
),
|
),
|
||||||
@ -756,7 +756,7 @@ impl<T: BeaconChainTypes> SyncManager<T> {
|
|||||||
batch_id,
|
batch_id,
|
||||||
&peer_id,
|
&peer_id,
|
||||||
id,
|
id,
|
||||||
beacon_block.map(|block| BlockWrapper::Block { block }),
|
beacon_block.map(|block| BlockWrapper::Block(block)),
|
||||||
) {
|
) {
|
||||||
Ok(ProcessResult::SyncCompleted) => self.update_sync_state(),
|
Ok(ProcessResult::SyncCompleted) => self.update_sync_state(),
|
||||||
Ok(ProcessResult::Successful) => {}
|
Ok(ProcessResult::Successful) => {}
|
||||||
@ -780,7 +780,7 @@ impl<T: BeaconChainTypes> SyncManager<T> {
|
|||||||
chain_id,
|
chain_id,
|
||||||
batch_id,
|
batch_id,
|
||||||
id,
|
id,
|
||||||
beacon_block.map(|block| BlockWrapper::Block { block }),
|
beacon_block.map(|block| BlockWrapper::Block(block)),
|
||||||
);
|
);
|
||||||
self.update_sync_state();
|
self.update_sync_state();
|
||||||
}
|
}
|
||||||
@ -930,9 +930,11 @@ impl<T: BeaconChainTypes> SyncManager<T> {
|
|||||||
RequestId::SingleBlock { id } => self.block_lookups.single_block_lookup_response(
|
RequestId::SingleBlock { id } => self.block_lookups.single_block_lookup_response(
|
||||||
id,
|
id,
|
||||||
peer_id,
|
peer_id,
|
||||||
block_sidecar_pair.map(|block_sidecar_pair| BlockWrapper::BlockAndBlob {
|
block_sidecar_pair.map(|block_sidecar_pair| {
|
||||||
|
BlockWrapper::BlockAndBlob(
|
||||||
// TODO: why is this in an arc
|
// TODO: why is this in an arc
|
||||||
block_sidecar_pair: (*block_sidecar_pair).clone(),
|
(*block_sidecar_pair).clone(),
|
||||||
|
)
|
||||||
}),
|
}),
|
||||||
seen_timestamp,
|
seen_timestamp,
|
||||||
&mut self.network,
|
&mut self.network,
|
||||||
@ -940,9 +942,11 @@ impl<T: BeaconChainTypes> SyncManager<T> {
|
|||||||
RequestId::ParentLookup { id } => self.block_lookups.parent_lookup_response(
|
RequestId::ParentLookup { id } => self.block_lookups.parent_lookup_response(
|
||||||
id,
|
id,
|
||||||
peer_id,
|
peer_id,
|
||||||
block_sidecar_pair.map(|block_sidecar_pair| BlockWrapper::BlockAndBlob {
|
block_sidecar_pair.map(|block_sidecar_pair| {
|
||||||
|
BlockWrapper::BlockAndBlob(
|
||||||
// TODO: why is this in an arc
|
// TODO: why is this in an arc
|
||||||
block_sidecar_pair: (*block_sidecar_pair).clone(),
|
(*block_sidecar_pair).clone(),
|
||||||
|
)
|
||||||
}),
|
}),
|
||||||
seen_timestamp,
|
seen_timestamp,
|
||||||
&mut self.network,
|
&mut self.network,
|
||||||
|
@ -26,11 +26,11 @@ impl<T: EthSpec> BatchTy<T> {
|
|||||||
match self {
|
match self {
|
||||||
BatchTy::Blocks(blocks) => blocks
|
BatchTy::Blocks(blocks) => blocks
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|block| BlockWrapper::Block { block })
|
.map(|block| BlockWrapper::Block(block))
|
||||||
.collect(),
|
.collect(),
|
||||||
BatchTy::BlocksAndBlobs(block_sidecar_pair) => block_sidecar_pair
|
BatchTy::BlocksAndBlobs(block_sidecar_pair) => block_sidecar_pair
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|block_sidecar_pair| BlockWrapper::BlockAndBlob { block_sidecar_pair })
|
.map(|block_sidecar_pair| BlockWrapper::BlockAndBlob(block_sidecar_pair))
|
||||||
.collect(),
|
.collect(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -415,7 +415,7 @@ impl<T: EthSpec, B: BatchConfig> BatchInfo<T, B> {
|
|||||||
match self.batch_type {
|
match self.batch_type {
|
||||||
ExpectedBatchTy::OnlyBlockBlobs => {
|
ExpectedBatchTy::OnlyBlockBlobs => {
|
||||||
let blocks = blocks.into_iter().map(|block| {
|
let blocks = blocks.into_iter().map(|block| {
|
||||||
let BlockWrapper::BlockAndBlob { block_sidecar_pair: block_and_blob } = block else {
|
let BlockWrapper::BlockAndBlob(block_and_blob) = block else {
|
||||||
panic!("Batches should never have a mixed type. This is a bug. Contact D")
|
panic!("Batches should never have a mixed type. This is a bug. Contact D")
|
||||||
};
|
};
|
||||||
block_and_blob
|
block_and_blob
|
||||||
@ -424,7 +424,7 @@ impl<T: EthSpec, B: BatchConfig> BatchInfo<T, B> {
|
|||||||
}
|
}
|
||||||
ExpectedBatchTy::OnlyBlock => {
|
ExpectedBatchTy::OnlyBlock => {
|
||||||
let blocks = blocks.into_iter().map(|block| {
|
let blocks = blocks.into_iter().map(|block| {
|
||||||
let BlockWrapper::Block { block } = block else {
|
let BlockWrapper::Block(block) = block else {
|
||||||
panic!("Batches should never have a mixed type. This is a bug. Contact D")
|
panic!("Batches should never have a mixed type. This is a bug. Contact D")
|
||||||
};
|
};
|
||||||
block
|
block
|
||||||
@ -559,7 +559,7 @@ impl<T: EthSpec, B: BatchConfig> slog::KV for BatchInfo<T, B> {
|
|||||||
serializer.emit_usize("processed", self.failed_processing_attempts.len())?;
|
serializer.emit_usize("processed", self.failed_processing_attempts.len())?;
|
||||||
serializer.emit_u8("processed_no_penalty", self.non_faulty_processing_attempts)?;
|
serializer.emit_u8("processed_no_penalty", self.non_faulty_processing_attempts)?;
|
||||||
serializer.emit_arguments("state", &format_args!("{:?}", self.state))?;
|
serializer.emit_arguments("state", &format_args!("{:?}", self.state))?;
|
||||||
serializer.emit_arguments("batch_ty", &format_args!("{}", self.batch_type));
|
serializer.emit_arguments("batch_ty", &format_args!("{}", self.batch_type))?;
|
||||||
slog::Result::Ok(())
|
slog::Result::Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use crate::test_utils::TestRandom;
|
use crate::test_utils::TestRandom;
|
||||||
use crate::{Blob, EthSpec, Hash256, SignedRoot, Slot};
|
use crate::{Blob, EthSpec, Hash256, SignedRoot, Slot};
|
||||||
|
use derivative::Derivative;
|
||||||
use kzg::KzgProof;
|
use kzg::KzgProof;
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
use ssz::Encode;
|
use ssz::Encode;
|
||||||
@ -10,9 +11,10 @@ use tree_hash_derive::TreeHash;
|
|||||||
|
|
||||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||||
#[derive(
|
#[derive(
|
||||||
Debug, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, PartialEq, Default, TestRandom,
|
Debug, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, Default, TestRandom, Derivative,
|
||||||
)]
|
)]
|
||||||
#[serde(bound = "T: EthSpec")]
|
#[serde(bound = "T: EthSpec")]
|
||||||
|
#[derivative(PartialEq, Hash(bound = "T: EthSpec"))]
|
||||||
pub struct BlobsSidecar<T: EthSpec> {
|
pub struct BlobsSidecar<T: EthSpec> {
|
||||||
pub beacon_block_root: Hash256,
|
pub beacon_block_root: Hash256,
|
||||||
pub beacon_block_slot: Slot,
|
pub beacon_block_slot: Slot,
|
||||||
@ -28,6 +30,15 @@ impl<T: EthSpec> BlobsSidecar<T> {
|
|||||||
Self::default()
|
Self::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn empty_from_parts(beacon_block_root: Hash256, beacon_block_slot: Slot) -> Self {
|
||||||
|
Self {
|
||||||
|
beacon_block_root,
|
||||||
|
beacon_block_slot,
|
||||||
|
blobs: VariableList::empty(),
|
||||||
|
kzg_aggregated_proof: KzgProof::empty(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(clippy::integer_arithmetic)]
|
#[allow(clippy::integer_arithmetic)]
|
||||||
pub fn max_size() -> usize {
|
pub fn max_size() -> usize {
|
||||||
// Fixed part
|
// Fixed part
|
||||||
|
@ -36,6 +36,10 @@ impl From<SignedBeaconBlockHash> for Hash256 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum BlobReconstructionError {
|
||||||
|
BlobsMissing,
|
||||||
|
}
|
||||||
|
|
||||||
/// 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),
|
||||||
@ -235,6 +239,29 @@ impl<E: EthSpec, Payload: AbstractExecPayload<E>> SignedBeaconBlock<E, Payload>
|
|||||||
pub fn canonical_root(&self) -> Hash256 {
|
pub fn canonical_root(&self) -> Hash256 {
|
||||||
self.message().tree_hash_root()
|
self.message().tree_hash_root()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Reconstructs an empty `BlobsSidecar`, using the given block root if provided, else calculates it.
|
||||||
|
/// If this block has kzg commitments, an error will be returned. If this block is from prior to the
|
||||||
|
/// Eip4844 fork, `None` will be returned.
|
||||||
|
pub fn reconstruct_empty_blobs(
|
||||||
|
&self,
|
||||||
|
block_root_opt: Option<Hash256>,
|
||||||
|
) -> Result<Option<BlobsSidecar<E>>, BlobReconstructionError> {
|
||||||
|
self.message()
|
||||||
|
.body()
|
||||||
|
.blob_kzg_commitments()
|
||||||
|
.map(|kzg_commitments| {
|
||||||
|
if kzg_commitments.len() > 0 {
|
||||||
|
Err(BlobReconstructionError::BlobsMissing)
|
||||||
|
} else {
|
||||||
|
Ok(Some(BlobsSidecar::empty_from_parts(
|
||||||
|
block_root_opt.unwrap_or(self.canonical_root()),
|
||||||
|
self.slot(),
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.unwrap_or(Ok(None))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We can convert pre-Bellatrix blocks without payloads into blocks with payloads.
|
// We can convert pre-Bellatrix blocks without payloads into blocks with payloads.
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
|
use crate::signed_beacon_block::BlobReconstructionError;
|
||||||
use crate::{BlobsSidecar, EthSpec, Hash256, SignedBeaconBlock, SignedBeaconBlockEip4844, Slot};
|
use crate::{BlobsSidecar, EthSpec, Hash256, SignedBeaconBlock, SignedBeaconBlockEip4844, Slot};
|
||||||
|
use derivative::Derivative;
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
use ssz::{Decode, DecodeError};
|
use ssz::{Decode, DecodeError};
|
||||||
use ssz_derive::{Decode, Encode};
|
use ssz_derive::{Decode, Encode};
|
||||||
@ -12,8 +14,8 @@ pub struct SignedBeaconBlockAndBlobsSidecarDecode<T: EthSpec> {
|
|||||||
pub blobs_sidecar: BlobsSidecar<T>,
|
pub blobs_sidecar: BlobsSidecar<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Encode, TreeHash, PartialEq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Encode, TreeHash, Derivative)]
|
||||||
#[serde(bound = "T: EthSpec")]
|
#[derivative(PartialEq, Hash(bound = "T: EthSpec"))]
|
||||||
pub struct SignedBeaconBlockAndBlobsSidecar<T: EthSpec> {
|
pub struct SignedBeaconBlockAndBlobsSidecar<T: EthSpec> {
|
||||||
pub beacon_block: Arc<SignedBeaconBlock<T>>,
|
pub beacon_block: Arc<SignedBeaconBlock<T>>,
|
||||||
pub blobs_sidecar: Arc<BlobsSidecar<T>>,
|
pub blobs_sidecar: Arc<BlobsSidecar<T>>,
|
||||||
@ -33,62 +35,55 @@ impl<T: EthSpec> SignedBeaconBlockAndBlobsSidecar<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A wrapper over a [`SignedBeaconBlock`] or a [`SignedBeaconBlockAndBlobsSidecar`].
|
/// A wrapper over a [`SignedBeaconBlock`] or a [`SignedBeaconBlockAndBlobsSidecar`].
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug, Derivative)]
|
||||||
|
#[derivative(PartialEq, Hash(bound = "T: EthSpec"))]
|
||||||
pub enum BlockWrapper<T: EthSpec> {
|
pub enum BlockWrapper<T: EthSpec> {
|
||||||
Block {
|
Block(Arc<SignedBeaconBlock<T>>),
|
||||||
block: Arc<SignedBeaconBlock<T>>,
|
BlockAndBlob(SignedBeaconBlockAndBlobsSidecar<T>),
|
||||||
},
|
|
||||||
BlockAndBlob {
|
|
||||||
block_sidecar_pair: SignedBeaconBlockAndBlobsSidecar<T>,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: EthSpec> BlockWrapper<T> {
|
impl<T: EthSpec> BlockWrapper<T> {
|
||||||
pub fn slot(&self) -> Slot {
|
pub fn slot(&self) -> Slot {
|
||||||
match self {
|
match self {
|
||||||
BlockWrapper::Block { block } => block.slot(),
|
BlockWrapper::Block(block) => block.slot(),
|
||||||
BlockWrapper::BlockAndBlob { block_sidecar_pair } => {
|
BlockWrapper::BlockAndBlob(block_sidecar_pair) => {
|
||||||
block_sidecar_pair.beacon_block.slot()
|
block_sidecar_pair.beacon_block.slot()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn block(&self) -> &SignedBeaconBlock<T> {
|
pub fn block(&self) -> &SignedBeaconBlock<T> {
|
||||||
match self {
|
match self {
|
||||||
BlockWrapper::Block { block } => &block,
|
BlockWrapper::Block(block) => &block,
|
||||||
BlockWrapper::BlockAndBlob { block_sidecar_pair } => &block_sidecar_pair.beacon_block,
|
BlockWrapper::BlockAndBlob(block_sidecar_pair) => &block_sidecar_pair.beacon_block,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn block_cloned(&self) -> Arc<SignedBeaconBlock<T>> {
|
pub fn block_cloned(&self) -> Arc<SignedBeaconBlock<T>> {
|
||||||
match self {
|
match self {
|
||||||
BlockWrapper::Block { block } => block.clone(),
|
BlockWrapper::Block(block) => block.clone(),
|
||||||
BlockWrapper::BlockAndBlob { block_sidecar_pair } => {
|
BlockWrapper::BlockAndBlob(block_sidecar_pair) => {
|
||||||
block_sidecar_pair.beacon_block.clone()
|
block_sidecar_pair.beacon_block.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn blobs(&self) -> Option<&BlobsSidecar<T>> {
|
pub fn blobs(
|
||||||
|
&self,
|
||||||
|
block_root: Option<Hash256>,
|
||||||
|
) -> Result<Option<Arc<BlobsSidecar<T>>>, BlobReconstructionError> {
|
||||||
match self {
|
match self {
|
||||||
BlockWrapper::Block { .. } => None,
|
BlockWrapper::Block(block) => block
|
||||||
BlockWrapper::BlockAndBlob { block_sidecar_pair } => {
|
.reconstruct_empty_blobs(block_root)
|
||||||
Some(&block_sidecar_pair.blobs_sidecar)
|
.map(|blob_opt| blob_opt.map(Arc::new)),
|
||||||
}
|
BlockWrapper::BlockAndBlob(block_sidecar_pair) => {
|
||||||
}
|
Ok(Some(block_sidecar_pair.blobs_sidecar.clone()))
|
||||||
}
|
|
||||||
|
|
||||||
pub fn blobs_cloned(&self) -> Option<Arc<BlobsSidecar<T>>> {
|
|
||||||
match self {
|
|
||||||
BlockWrapper::Block { block: _ } => None,
|
|
||||||
BlockWrapper::BlockAndBlob { block_sidecar_pair } => {
|
|
||||||
Some(block_sidecar_pair.blobs_sidecar.clone())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn message(&self) -> crate::BeaconBlockRef<T> {
|
pub fn message(&self) -> crate::BeaconBlockRef<T> {
|
||||||
match self {
|
match self {
|
||||||
BlockWrapper::Block { block } => block.message(),
|
BlockWrapper::Block(block) => block.message(),
|
||||||
BlockWrapper::BlockAndBlob { block_sidecar_pair } => {
|
BlockWrapper::BlockAndBlob(block_sidecar_pair) => {
|
||||||
block_sidecar_pair.beacon_block.message()
|
block_sidecar_pair.beacon_block.message()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -98,43 +93,39 @@ impl<T: EthSpec> BlockWrapper<T> {
|
|||||||
self.block().parent_root()
|
self.block().parent_root()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deconstruct(self) -> (Arc<SignedBeaconBlock<T>>, Option<Arc<BlobsSidecar<T>>>) {
|
pub fn deconstruct(
|
||||||
|
self,
|
||||||
|
block_root: Option<Hash256>,
|
||||||
|
) -> (
|
||||||
|
Arc<SignedBeaconBlock<T>>,
|
||||||
|
Result<Option<Arc<BlobsSidecar<T>>>, BlobReconstructionError>,
|
||||||
|
) {
|
||||||
match self {
|
match self {
|
||||||
BlockWrapper::Block { block } => (block, None),
|
BlockWrapper::Block(block) => {
|
||||||
BlockWrapper::BlockAndBlob { block_sidecar_pair } => {
|
let blobs = block
|
||||||
|
.reconstruct_empty_blobs(block_root)
|
||||||
|
.map(|blob_opt| blob_opt.map(Arc::new));
|
||||||
|
(block, blobs)
|
||||||
|
}
|
||||||
|
BlockWrapper::BlockAndBlob(block_sidecar_pair) => {
|
||||||
let SignedBeaconBlockAndBlobsSidecar {
|
let SignedBeaconBlockAndBlobsSidecar {
|
||||||
beacon_block,
|
beacon_block,
|
||||||
blobs_sidecar,
|
blobs_sidecar,
|
||||||
} = block_sidecar_pair;
|
} = block_sidecar_pair;
|
||||||
(beacon_block, Some(blobs_sidecar))
|
(beacon_block, Ok(Some(blobs_sidecar)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: probably needes to be changed. This is needed because SignedBeaconBlockAndBlobsSidecar
|
|
||||||
// does not implement Hash
|
|
||||||
impl<T: EthSpec> std::hash::Hash for BlockWrapper<T> {
|
|
||||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
|
||||||
match self {
|
|
||||||
BlockWrapper::Block { block } => block.hash(state),
|
|
||||||
BlockWrapper::BlockAndBlob {
|
|
||||||
block_sidecar_pair: block_and_blob,
|
|
||||||
} => block_and_blob.beacon_block.hash(state),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: EthSpec> From<SignedBeaconBlock<T>> for BlockWrapper<T> {
|
impl<T: EthSpec> From<SignedBeaconBlock<T>> for BlockWrapper<T> {
|
||||||
fn from(block: SignedBeaconBlock<T>) -> Self {
|
fn from(block: SignedBeaconBlock<T>) -> Self {
|
||||||
BlockWrapper::Block {
|
BlockWrapper::Block(Arc::new(block))
|
||||||
block: Arc::new(block),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: EthSpec> From<Arc<SignedBeaconBlock<T>>> for BlockWrapper<T> {
|
impl<T: EthSpec> From<Arc<SignedBeaconBlock<T>>> for BlockWrapper<T> {
|
||||||
fn from(block: Arc<SignedBeaconBlock<T>>) -> Self {
|
fn from(block: Arc<SignedBeaconBlock<T>>) -> Self {
|
||||||
BlockWrapper::Block { block }
|
BlockWrapper::Block(block)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,14 @@ const KZG_PROOF_BYTES_LEN: usize = 48;
|
|||||||
#[ssz(struct_behaviour = "transparent")]
|
#[ssz(struct_behaviour = "transparent")]
|
||||||
pub struct KzgProof(pub [u8; KZG_PROOF_BYTES_LEN]);
|
pub struct KzgProof(pub [u8; KZG_PROOF_BYTES_LEN]);
|
||||||
|
|
||||||
|
impl KzgProof {
|
||||||
|
pub fn empty() -> Self {
|
||||||
|
let mut bytes = [0; KZG_PROOF_BYTES_LEN];
|
||||||
|
bytes[0] = 192;
|
||||||
|
Self(bytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl fmt::Display for KzgProof {
|
impl fmt::Display for KzgProof {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(f, "{}", eth2_serde_utils::hex::encode(self.0))
|
write!(f, "{}", eth2_serde_utils::hex::encode(self.0))
|
||||||
|
Loading…
Reference in New Issue
Block a user