Skip to content

Commit d57ce1b

Browse files
authored
Merge branch 'unstable' into full-block-macro
2 parents eccb3cc + 2c76ee5 commit d57ce1b

54 files changed

Lines changed: 2890 additions & 630 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

beacon_node/beacon_chain/benches/benches.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,21 @@ fn all_benches(c: &mut Criterion) {
5353
)
5454
.unwrap();
5555

56+
let kzg_commitments = signed_block
57+
.message()
58+
.body()
59+
.blob_kzg_commitments()
60+
.unwrap()
61+
.clone();
62+
5663
let spec = spec.clone();
5764

5865
c.bench_function(&format!("reconstruct_{}", blob_count), |b| {
5966
b.iter(|| {
6067
black_box(reconstruct_data_columns(
6168
&kzg,
6269
column_sidecars.iter().as_slice()[0..column_sidecars.len() / 2].to_vec(),
70+
&kzg_commitments,
6371
spec.as_ref(),
6472
))
6573
})

beacon_node/beacon_chain/src/beacon_chain.rs

Lines changed: 275 additions & 151 deletions
Large diffs are not rendered by default.

beacon_node/beacon_chain/src/block_verification.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,10 @@ pub enum BlockError {
286286
/// TODO: We may need to penalize the peer that gave us a potentially invalid rpc blob.
287287
/// https://github.com/sigp/lighthouse/issues/4546
288288
AvailabilityCheck(AvailabilityCheckError),
289+
/// The payload envelope's block root is unknown.
290+
EnvelopeBlockRootUnknown(Hash256),
291+
/// Optimistic sync is not supported for Gloas payload envelopes.
292+
OptimisticSyncNotSupported { block_root: Hash256 },
289293
/// A Blob with a slot after PeerDAS is received and is not required to be imported.
290294
/// This can happen because we stay subscribed to the blob subnet after 2 epochs, as we could
291295
/// still receive valid blobs from a Deneb epoch after PeerDAS is activated.
@@ -624,7 +628,8 @@ pub fn signature_verify_chain_segment<T: BeaconChainTypes>(
624628
consensus_context,
625629
});
626630
}
627-
631+
// TODO(gloas) When implementing range and backfill sync for gloas
632+
// we need a batch verify kzg function in the new da checker as well.
628633
chain
629634
.data_availability_checker
630635
.batch_verify_kzg_for_available_blocks(&available_blocks)?;

beacon_node/beacon_chain/src/builder.rs

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use crate::kzg_utils::{build_data_column_sidecars_fulu, build_data_column_sideca
1212
use crate::light_client_server_cache::LightClientServerCache;
1313
use crate::migrate::{BackgroundMigrator, MigratorConfig};
1414
use crate::observed_data_sidecars::ObservedDataSidecars;
15+
use crate::pending_payload_cache::PendingPayloadCache;
1516
use crate::persisted_beacon_chain::PersistedBeaconChain;
1617
use crate::persisted_custody::load_custody_context;
1718
use crate::shuffling_cache::{BlockShufflingIds, ShufflingCache};
@@ -849,12 +850,13 @@ where
849850
It is highly recommended to purge your db and checkpoint sync. For more information please \
850851
read this blog post: https://blog.ethereum.org/2014/11/25/proof-stake-learned-love-weak-subjectivity"
851852
)
853+
} else {
854+
return Err(
855+
"The current head state is outside the weak subjectivity period. A node in this state is susceptible to long range attacks. You should purge your db and \
856+
checkpoint sync. For more information please read this blog post: https://blog.ethereum.org/2014/11/25/proof-stake-learned-love-weak-subjectivity \
857+
If you understand the risks, it is possible to ignore this error with the --ignore-ws-check flag.".to_string()
858+
);
852859
}
853-
return Err(
854-
"The current head state is outside the weak subjectivity period. A node in this state is susceptible to long range attacks. You should purge your db and \
855-
checkpoint sync. For more information please read this blog post: https://blog.ethereum.org/2014/11/25/proof-stake-learned-love-weak-subjectivity \
856-
If you understand the risks, it is possible to ignore this error with the --ignore-ws-check flag.".to_string()
857-
);
858860
}
859861

860862
let validator_pubkey_cache = self
@@ -986,6 +988,7 @@ where
986988
)
987989
};
988990
debug!(?custody_context, "Loaded persisted custody context");
991+
let custody_context = Arc::new(custody_context);
989992

990993
let beacon_chain = BeaconChain {
991994
spec: self.spec.clone(),
@@ -1061,14 +1064,22 @@ where
10611064
data_availability_checker: Arc::new(
10621065
DataAvailabilityChecker::new(
10631066
complete_blob_backfill,
1064-
slot_clock,
1067+
slot_clock.clone(),
10651068
self.kzg.clone(),
1066-
Arc::new(custody_context),
1067-
self.spec,
1069+
custody_context.clone(),
1070+
self.spec.clone(),
10681071
enable_partial_columns,
10691072
)
10701073
.map_err(|e| format!("Error initializing DataAvailabilityChecker: {:?}", e))?,
10711074
),
1075+
pending_payload_cache: Arc::new(
1076+
PendingPayloadCache::new(
1077+
self.kzg.clone(),
1078+
custody_context.clone(),
1079+
self.spec.clone(),
1080+
)
1081+
.map_err(|e| format!("Error initializing PendingPayloadCache: {:?}", e))?,
1082+
),
10721083
kzg: self.kzg.clone(),
10731084
rng: Arc::new(Mutex::new(rng)),
10741085
gossip_verified_payload_bid_cache: <_>::default(),

beacon_node/beacon_chain/src/canonical_head.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -988,6 +988,25 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
988988
.start_slot(T::EthSpec::slots_per_epoch()),
989989
);
990990

991+
// Prune the Gloas pending-payload cache. Anything older than the data-availability
992+
// boundary cannot still be in flight; finalised entries are also safe to drop.
993+
if self.spec.gloas_fork_epoch.is_some() {
994+
let finalized_epoch = new_view.finalized_checkpoint.epoch;
995+
let current_epoch = new_snapshot
996+
.beacon_state
997+
.slot()
998+
.epoch(T::EthSpec::slots_per_epoch());
999+
if let Some(min_epochs_for_blobs) = self
1000+
.spec
1001+
.min_epoch_data_availability_boundary(current_epoch)
1002+
{
1003+
let cutoff_epoch = std::cmp::max(finalized_epoch + 1, min_epochs_for_blobs);
1004+
if let Err(e) = self.pending_payload_cache.do_maintenance(cutoff_epoch) {
1005+
error!(error = ?e, "Failed to prune pending payload cache on finalization");
1006+
}
1007+
}
1008+
}
1009+
9911010
if let Some(event_handler) = self.event_handler.as_ref()
9921011
&& event_handler.has_finalized_subscribers()
9931012
{

beacon_node/beacon_chain/src/data_availability_checker.rs

Lines changed: 59 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ use crate::data_column_verification::{
3333
GossipVerifiedDataColumn, KzgVerifiedCustodyDataColumn, KzgVerifiedDataColumn,
3434
verify_kzg_for_data_column_list,
3535
};
36+
use crate::kzg_utils::validate_data_columns_with_commitments;
3637
use crate::metrics::{
3738
KZG_DATA_COLUMN_RECONSTRUCTION_ATTEMPTS, KZG_DATA_COLUMN_RECONSTRUCTION_FAILURES,
3839
};
@@ -490,8 +491,7 @@ impl<T: BeaconChainTypes> DataAvailabilityChecker<T> {
490491
AvailableBlockData::Blobs(blobs) => verify_kzg_for_blob_list(blobs.iter(), &self.kzg)
491492
.map_err(AvailabilityCheckError::InvalidBlobs),
492493
AvailableBlockData::DataColumns(columns) => {
493-
verify_kzg_for_data_column_list(columns.iter(), &self.kzg)
494-
.map_err(AvailabilityCheckError::InvalidColumn)
494+
verify_columns_against_block(&self.kzg, available_block.block(), columns)
495495
}
496496
}
497497
}
@@ -504,13 +504,17 @@ impl<T: BeaconChainTypes> DataAvailabilityChecker<T> {
504504
available_blocks: &[AvailableBlock<T::EthSpec>],
505505
) -> Result<(), AvailabilityCheckError> {
506506
let mut all_blobs = Vec::new();
507-
let mut all_data_columns = Vec::new();
508507

509508
for available_block in available_blocks {
510-
match available_block.data().to_owned() {
509+
match available_block.data() {
511510
AvailableBlockData::NoData => {}
512-
AvailableBlockData::Blobs(blobs) => all_blobs.extend(blobs),
513-
AvailableBlockData::DataColumns(columns) => all_data_columns.extend(columns),
511+
AvailableBlockData::Blobs(blobs) => all_blobs.extend(blobs.iter().cloned()),
512+
AvailableBlockData::DataColumns(columns) => {
513+
// Each block has its own commitments. For Gloas they live in the bid; for
514+
// Fulu they live inline on the column. Verify per block and let the helper
515+
// pick the right path.
516+
verify_columns_against_block(&self.kzg, available_block.block(), columns)?;
517+
}
514518
}
515519
}
516520

@@ -519,11 +523,6 @@ impl<T: BeaconChainTypes> DataAvailabilityChecker<T> {
519523
.map_err(AvailabilityCheckError::InvalidBlobs)?;
520524
}
521525

522-
if !all_data_columns.is_empty() {
523-
verify_kzg_for_data_column_list(all_data_columns.iter(), &self.kzg)
524-
.map_err(AvailabilityCheckError::InvalidColumn)?;
525-
}
526-
527526
Ok(())
528527
}
529528

@@ -605,9 +604,21 @@ impl<T: BeaconChainTypes> DataAvailabilityChecker<T> {
605604
metrics::inc_counter(&KZG_DATA_COLUMN_RECONSTRUCTION_ATTEMPTS);
606605
let timer = metrics::start_timer(&metrics::DATA_AVAILABILITY_RECONSTRUCTION_TIME);
607606

607+
let columns: Vec<_> = verified_data_columns
608+
.into_iter()
609+
.map(|c| c.into_inner())
610+
.collect();
611+
// Fulu columns carry their commitments; reconstruction needs the count to drive the
612+
// per-blob recovery loop.
613+
let kzg_commitments = columns
614+
.first()
615+
.and_then(|c| c.kzg_commitments().ok().cloned())
616+
.ok_or(AvailabilityCheckError::InvalidVariant)?;
617+
608618
let all_data_columns = KzgVerifiedCustodyDataColumn::reconstruct_columns(
609619
&self.kzg,
610-
&verified_data_columns,
620+
columns,
621+
&kzg_commitments,
611622
&self.spec,
612623
)
613624
.map_err(|e| {
@@ -676,6 +687,35 @@ impl<T: BeaconChainTypes> DataAvailabilityChecker<T> {
676687
}
677688
}
678689

690+
/// Verify a batch of data columns belonging to a single block, picking the right commitment
691+
/// source for the block's fork (Fulu: inline on column; Gloas: from the embedded payload bid).
692+
fn verify_columns_against_block<E: EthSpec>(
693+
kzg: &Kzg,
694+
block: &SignedBeaconBlock<E>,
695+
columns: &[Arc<DataColumnSidecar<E>>],
696+
) -> Result<(), AvailabilityCheckError> {
697+
if columns.is_empty() {
698+
return Ok(());
699+
}
700+
if block.fork_name_unchecked().gloas_enabled() {
701+
let commitments = block
702+
.message()
703+
.body()
704+
.signed_execution_payload_bid()
705+
.map(|bid| bid.message.blob_kzg_commitments.clone())
706+
.map_err(|_| {
707+
AvailabilityCheckError::Unexpected(
708+
"Gloas block missing signed_execution_payload_bid".to_string(),
709+
)
710+
})?;
711+
validate_data_columns_with_commitments(kzg, columns.iter(), commitments.as_ref())
712+
.map_err(AvailabilityCheckError::InvalidColumn)
713+
} else {
714+
verify_kzg_for_data_column_list(columns.iter(), kzg)
715+
.map_err(AvailabilityCheckError::InvalidColumn)
716+
}
717+
}
718+
679719
/// Helper struct to group data availability checker metrics.
680720
pub struct DataAvailabilityCheckerMetrics {
681721
pub block_cache_size: usize,
@@ -874,10 +914,13 @@ impl<E: EthSpec> AvailableBlock<E> {
874914

875915
match &block_data {
876916
AvailableBlockData::NoData => {
877-
if columns_required {
878-
return Err(AvailabilityCheckError::MissingCustodyColumns);
879-
} else if blobs_required {
880-
return Err(AvailabilityCheckError::MissingBlobs);
917+
// For Gloas, DA is checked for the PayloadEnvelope, not for the block.
918+
if !block.fork_name_unchecked().gloas_enabled() {
919+
if columns_required {
920+
return Err(AvailabilityCheckError::MissingCustodyColumns);
921+
} else if blobs_required {
922+
return Err(AvailabilityCheckError::MissingBlobs);
923+
}
881924
}
882925
}
883926
AvailableBlockData::Blobs(blobs) => {

beacon_node/beacon_chain/src/data_availability_checker/error.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use types::{BeaconStateError, ColumnIndex, Hash256};
44
#[derive(Debug)]
55
pub enum Error {
66
InvalidBlobs(KzgError),
7+
MissingBid(Hash256),
78
InvalidColumn((Option<ColumnIndex>, KzgError)),
89
ReconstructColumnsError(KzgError),
910
KzgCommitmentMismatch {
@@ -23,6 +24,7 @@ pub enum Error {
2324
RebuildingStateCaches(BeaconStateError),
2425
SlotClockError,
2526
InvalidAvailableBlockData,
27+
InvalidVariant,
2628
}
2729

2830
#[derive(PartialEq, Eq)]
@@ -38,6 +40,7 @@ impl Error {
3840
match self {
3941
Error::SszTypes(_)
4042
| Error::MissingBlobs
43+
| Error::MissingBid(_)
4144
| Error::MissingCustodyColumns
4245
| Error::StoreError(_)
4346
| Error::DecodeError(_)
@@ -46,7 +49,8 @@ impl Error {
4649
| Error::BlockReplayError(_)
4750
| Error::RebuildingStateCaches(_)
4851
| Error::SlotClockError
49-
| Error::InvalidAvailableBlockData => ErrorCategory::Internal,
52+
| Error::InvalidAvailableBlockData
53+
| Error::InvalidVariant => ErrorCategory::Internal,
5054
Error::InvalidBlobs { .. }
5155
| Error::InvalidColumn { .. }
5256
| Error::ReconstructColumnsError { .. }

beacon_node/beacon_chain/src/data_availability_checker/overflow_lru_cache.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ impl<E: EthSpec> PendingComponents<E> {
109109
.unwrap_or(false)
110110
}
111111

112-
/// Returns the indices of cached custody columns
112+
/// Returns the indices of cached sampling columns
113113
pub fn get_cached_data_columns_indices(&self) -> Vec<ColumnIndex> {
114114
self.verified_data_columns
115115
.iter()

0 commit comments

Comments
 (0)