Resolve merge confklicts

This commit is contained in:
Eitan Seri-Levi
2026-05-18 23:12:53 +03:00
58 changed files with 2570 additions and 922 deletions

View File

@@ -323,18 +323,34 @@ fn update_data_column_signed_header<E: EthSpec>(
) {
for old_custody_column_sidecar in data_columns.as_mut_slice() {
let old_column_sidecar = old_custody_column_sidecar.as_data_column();
let new_column_sidecar = Arc::new(DataColumnSidecar::Fulu(DataColumnSidecarFulu {
index: *old_column_sidecar.index(),
column: old_column_sidecar.column().clone(),
kzg_commitments: old_column_sidecar.kzg_commitments().unwrap().clone(),
kzg_proofs: old_column_sidecar.kzg_proofs().clone(),
signed_block_header: signed_block.signed_block_header(),
kzg_commitments_inclusion_proof: signed_block
.message()
.body()
.kzg_commitments_merkle_proof()
.unwrap(),
}));
let new_column_sidecar = match old_column_sidecar.as_ref() {
DataColumnSidecar::Fulu(_) => {
Arc::new(DataColumnSidecar::Fulu(DataColumnSidecarFulu {
index: *old_column_sidecar.index(),
column: old_column_sidecar.column().clone(),
kzg_commitments: old_column_sidecar.kzg_commitments().unwrap().clone(),
kzg_proofs: old_column_sidecar.kzg_proofs().clone(),
signed_block_header: signed_block.signed_block_header(),
kzg_commitments_inclusion_proof: signed_block
.message()
.body()
.kzg_commitments_merkle_proof()
.unwrap(),
}))
}
// Gloas columns reference the block by `beacon_block_root` instead of holding the
// block header inline, so updating the parent root just means re-keying the column to
// the new canonical root.
DataColumnSidecar::Gloas(g) => {
Arc::new(DataColumnSidecar::Gloas(types::DataColumnSidecarGloas {
index: g.index,
column: g.column.clone(),
kzg_proofs: g.kzg_proofs.clone(),
slot: g.slot,
beacon_block_root: signed_block.canonical_root(),
}))
}
};
*old_custody_column_sidecar = CustodyDataColumn::from_asserted_custody(new_column_sidecar);
}
}
@@ -1159,8 +1175,13 @@ async fn block_gossip_verification() {
)
.await
.expect("should import valid gossip verified block");
if let Some(data_sidecars) = blobs_opt {
verify_and_process_gossip_data_sidecars(&harness, data_sidecars).await;
}
// Post-Gloas, store the execution payload envelope so that subsequent blocks can look up
// the parent envelope.
// the parent envelope. This must run after gossip column processing because marking the
// payload as received in fork choice causes the gossip column path's
// `is_block_data_imported` gate to reject otherwise-valid columns as duplicates.
if let Some(ref envelope) = snapshot.execution_envelope {
harness
.chain
@@ -1174,9 +1195,6 @@ async fn block_gossip_verification() {
.on_valid_payload_envelope_received(snapshot.beacon_block_root)
.expect("should update fork choice with envelope");
}
if let Some(data_sidecars) = blobs_opt {
verify_and_process_gossip_data_sidecars(&harness, data_sidecars).await;
}
}
// Recompute the head to ensure we cache the latest view of fork choice.
@@ -2255,7 +2273,6 @@ async fn rpc_block_allows_construction_past_da_boundary() {
// Now verify the block is past the DA boundary
let da_boundary = harness
.chain
.data_availability_checker
.data_availability_boundary()
.expect("DA boundary should be set");
assert!(

View File

@@ -11,7 +11,8 @@ use std::sync::Arc;
use types::data::FixedBlobSidecarList;
use types::{
BlobSidecar, DataColumnSidecar, DataColumnSidecarFulu, DataColumnSidecarGloas, Domain, EthSpec,
MinimalEthSpec, PayloadAttestationData, PayloadAttestationMessage, SignedRoot, Slot,
MinimalEthSpec, PayloadAttestationData, PayloadAttestationMessage, SignedExecutionPayloadBid,
SignedExecutionPayloadBidGloas, SignedRoot, Slot,
};
type E = MinimalEthSpec;
@@ -84,6 +85,16 @@ async fn data_column_sidecar_event_on_process_gossip_data_column() {
let epoch = slot.epoch(E::slots_per_epoch());
random_sidecar.slot = slot;
random_sidecar.index = harness.chain.sampling_columns_for_epoch(epoch)[0];
// For gloas, the bid must be known, e.g. in the pending payload cache
let mut bid = SignedExecutionPayloadBidGloas::<E>::empty();
bid.message.slot = Slot::new(10);
let bid = SignedExecutionPayloadBid::Gloas(bid);
harness
.chain
.pending_payload_cache
.insert_bid(random_sidecar.beacon_block_root, Arc::new(bid));
DataColumnSidecar::Gloas(random_sidecar)
} else {
let mut random_sidecar = DataColumnSidecarFulu::arbitrary(&mut u).unwrap();

View File

@@ -105,11 +105,11 @@ async fn test_sync_committee_rewards() {
// Add block
let chain = &harness.chain;
let (head_state, head_state_root) = harness.get_current_state_and_root();
let head_state = harness.get_current_state();
let target_slot = harness.get_current_slot() + 1;
let (block_root, mut state) = harness
.add_attested_block_at_slot(target_slot, head_state, head_state_root, &[])
.add_attested_block_at_slot(target_slot, head_state, &[])
.await
.unwrap();

View File

@@ -23,6 +23,7 @@ use beacon_chain::{
},
custody_context::NodeCustodyType,
historical_blocks::HistoricalBlockError,
kzg_utils::reconstruct_blobs,
migrate::MigratorConfig,
};
use bls::{Keypair, Signature, SignatureBytes};
@@ -68,6 +69,43 @@ static KEYPAIRS: LazyLock<Vec<Keypair>> =
type E = MinimalEthSpec;
type TestHarness = BeaconChainHarness<DiskHarnessType<E>>;
/// Retrieve or reconstruct blobs for a given block root. This uses the block's epoch to determine
/// whether to retrieve blobs directly or reconstruct them from columns.
///
/// Returns `None` for Gloas blocks (which have no blob sidecar representation).
fn get_or_reconstruct_blobs<T: BeaconChainTypes>(
chain: &BeaconChain<T>,
block_root: &Hash256,
) -> Result<Option<BlobSidecarList<T::EthSpec>>, BeaconChainError> {
let Some(block) = chain.store.get_blinded_block(block_root)? else {
return Ok(None);
};
if block.fork_name_unchecked().gloas_enabled() {
return Ok(None);
}
if chain.spec.is_peer_das_enabled_for_epoch(block.epoch()) {
let fork_name = chain.spec.fork_name_at_epoch(block.epoch());
if let Some(columns) = chain.store.get_data_columns(block_root, fork_name)? {
let num_required_columns = T::EthSpec::number_of_columns() / 2;
if columns.len() >= num_required_columns {
reconstruct_blobs(&chain.kzg, columns, None, &block, &chain.spec)
.map(Some)
.map_err(BeaconChainError::FailedToReconstructBlobs)
} else {
Err(BeaconChainError::InsufficientColumnsToReconstructBlobs {
columns_found: columns.len(),
})
}
} else {
Ok(None)
}
} else {
Ok(chain.get_blobs(block_root)?.blobs())
}
}
fn get_store(db_path: &TempDir) -> Arc<HotColdDB<E, BeaconNodeBackend<E>, BeaconNodeBackend<E>>> {
let store_config = StoreConfig {
prune_payloads: false,
@@ -198,11 +236,10 @@ async fn light_client_bootstrap_test() {
let num_initial_slots = E::slots_per_epoch() * 7;
let slots: Vec<Slot> = (1..num_initial_slots).map(Slot::new).collect();
let (genesis_state, genesis_state_root) = harness.get_current_state_and_root();
let genesis_state = harness.get_current_state();
harness
.add_attested_blocks_at_slots_with_lc_data(
genesis_state.clone(),
genesis_state_root,
&slots,
&all_validators,
None,
@@ -258,14 +295,9 @@ async fn light_client_updates_test() {
let num_initial_slots = E::slots_per_epoch() * 10;
let slots: Vec<Slot> = (1..num_initial_slots).map(Slot::new).collect();
let (genesis_state, genesis_state_root) = harness.get_current_state_and_root();
let genesis_state = harness.get_current_state();
harness
.add_attested_blocks_at_slots(
genesis_state.clone(),
genesis_state_root,
&slots,
&all_validators,
)
.add_attested_blocks_at_slots(genesis_state.clone(), &slots, &all_validators)
.await;
harness.advance_slot();
@@ -639,7 +671,7 @@ async fn forwards_iter_block_and_state_roots_until() {
for slot in (1..=num_blocks_produced).map(Slot::from) {
let (block_root, mut state) = harness
.add_attested_block_at_slot(slot, head_state, head_state_root, all_validators)
.add_attested_block_at_slot(slot, head_state, all_validators)
.await
.unwrap();
head_state_root = state.update_tree_hash_cache().unwrap();
@@ -714,10 +746,10 @@ async fn block_replayer_hooks() {
let max_slot = *block_slots.last().unwrap();
let all_slots = (0..=max_slot.as_u64()).map(Slot::new).collect::<Vec<_>>();
let (state, state_root) = harness.get_current_state_and_root();
let state = harness.get_current_state();
let all_validators = harness.get_all_validators();
let (_, _, end_block_root, mut end_state) = harness
.add_attested_blocks_at_slots(state.clone(), state_root, &block_slots, &all_validators)
.add_attested_blocks_at_slots(state.clone(), &block_slots, &all_validators)
.await;
let blocks = store
@@ -786,10 +818,10 @@ async fn delete_blocks_and_states() {
// Finalize an initial portion of the chain.
let initial_slots: Vec<Slot> = (1..=unforked_blocks).map(Into::into).collect();
let (state, state_root) = harness.get_current_state_and_root();
let state = harness.get_current_state();
let all_validators = harness.get_all_validators();
harness
.add_attested_blocks_at_slots(state, state_root, &initial_slots, &all_validators)
.add_attested_blocks_at_slots(state, &initial_slots, &all_validators)
.await;
// Create a fork post-finalization.
@@ -924,10 +956,10 @@ async fn multi_epoch_fork_valid_blocks_test(
// Create the initial portion of the chain
if initial_blocks > 0 {
let initial_slots: Vec<Slot> = (1..=initial_blocks).map(Into::into).collect();
let (state, state_root) = harness.get_current_state_and_root();
let state = harness.get_current_state();
let all_validators = harness.get_all_validators();
harness
.add_attested_blocks_at_slots(state, state_root, &initial_slots, &all_validators)
.add_attested_blocks_at_slots(state, &initial_slots, &all_validators)
.await;
}
@@ -1269,17 +1301,17 @@ async fn proposer_shuffling_root_consistency_test(
// Build chain out to parent block.
let initial_slots: Vec<Slot> = (1..=parent_slot).map(Into::into).collect();
let (state, state_root) = harness.get_current_state_and_root();
let state = harness.get_current_state();
let all_validators = harness.get_all_validators();
let (_, _, parent_root, _) = harness
.add_attested_blocks_at_slots(state, state_root, &initial_slots, &all_validators)
.add_attested_blocks_at_slots(state, &initial_slots, &all_validators)
.await;
// Add the child block.
let (state, state_root) = harness.get_current_state_and_root();
let state = harness.get_current_state();
let all_validators = harness.get_all_validators();
let (_, _, child_root, child_block_state) = harness
.add_attested_blocks_at_slots(state, state_root, &[child_slot], &all_validators)
.add_attested_blocks_at_slots(state, &[child_slot], &all_validators)
.await;
let child_block_epoch = child_slot.epoch(E::slots_per_epoch());
@@ -1591,10 +1623,10 @@ async fn proposer_duties_from_head_fulu() {
// Build chain out to parent block.
let initial_slots: Vec<Slot> = (1..=initial_blocks).map(Into::into).collect();
let (state, state_root) = harness.get_current_state_and_root();
let state = harness.get_current_state();
let all_validators = harness.get_all_validators();
let (_, _, head_block_root, head_state) = harness
.add_attested_blocks_at_slots(state, state_root, &initial_slots, &all_validators)
.add_attested_blocks_at_slots(state, &initial_slots, &all_validators)
.await;
// Compute the proposer duties at the next epoch from the head
@@ -1642,10 +1674,10 @@ async fn proposer_lookahead_gloas_fork_epoch() {
// Build chain out to parent block.
let initial_slots: Vec<Slot> = (1..=initial_blocks).map(Into::into).collect();
let (state, state_root) = harness.get_current_state_and_root();
let state = harness.get_current_state();
let all_validators = harness.get_all_validators();
let (_, _, head_block_root, mut head_state) = harness
.add_attested_blocks_at_slots(state, state_root, &initial_slots, &all_validators)
.add_attested_blocks_at_slots(state, &initial_slots, &all_validators)
.await;
let head_state_root = head_state.canonical_root().unwrap();
@@ -1681,7 +1713,7 @@ async fn proposer_lookahead_gloas_fork_epoch() {
// Build a block in the Gloas fork epoch and assert that the shuffling does not change.
let gloas_slots = vec![gloas_fork_epoch.start_slot(E::slots_per_epoch())];
let (_, _, _, _) = harness
.add_attested_blocks_at_slots(head_state, head_state_root, &gloas_slots, &all_validators)
.add_attested_blocks_at_slots(head_state, &gloas_slots, &all_validators)
.await;
let (no_lookahead_indices, no_lookahead_dependent_root, _, _, no_lookahead_fork) =
@@ -1704,16 +1736,11 @@ async fn prunes_abandoned_fork_between_two_finalized_checkpoints() {
let store = get_store(&db_path);
let rig = get_harness(store.clone(), VALIDATOR_COUNT);
let slots_per_epoch = rig.slots_per_epoch();
let (mut state, state_root) = rig.get_current_state_and_root();
let mut state = rig.get_current_state();
let canonical_chain_slots: Vec<Slot> = (1..=rig.epoch_start_slot(1)).map(Slot::new).collect();
let (canonical_chain_blocks_pre_finalization, _, _, new_state) = rig
.add_attested_blocks_at_slots(
state,
state_root,
&canonical_chain_slots,
&honest_validators,
)
.add_attested_blocks_at_slots(state, &canonical_chain_slots, &honest_validators)
.await;
state = new_state;
let canonical_chain_slot: u64 = rig.get_current_slot().into();
@@ -1721,14 +1748,9 @@ async fn prunes_abandoned_fork_between_two_finalized_checkpoints() {
let stray_slots: Vec<Slot> = (canonical_chain_slot + 1..rig.epoch_start_slot(2))
.map(Slot::new)
.collect();
let (current_state, current_state_root) = rig.get_current_state_and_root();
let current_state = rig.get_current_state();
let (stray_blocks, stray_states, stray_head, _) = rig
.add_attested_blocks_at_slots(
current_state,
current_state_root,
&stray_slots,
&adversarial_validators,
)
.add_attested_blocks_at_slots(current_state, &stray_slots, &adversarial_validators)
.await;
// Precondition: Ensure all stray_blocks blocks are still known
@@ -1758,9 +1780,8 @@ async fn prunes_abandoned_fork_between_two_finalized_checkpoints() {
..=(canonical_chain_slot + slots_per_epoch * 5))
.map(Slot::new)
.collect();
let state_root = state.update_tree_hash_cache().unwrap();
let (canonical_chain_blocks_post_finalization, _, _, _) = rig
.add_attested_blocks_at_slots(state, state_root, &finalization_slots, &honest_validators)
.add_attested_blocks_at_slots(state, &finalization_slots, &honest_validators)
.await;
// Postcondition: New blocks got finalized
@@ -1815,15 +1836,14 @@ async fn pruning_does_not_touch_abandoned_block_shared_with_canonical_chain() {
let store = get_store(&db_path);
let rig = get_harness(store.clone(), VALIDATOR_COUNT);
let slots_per_epoch = rig.slots_per_epoch();
let (state, state_root) = rig.get_current_state_and_root();
let state = rig.get_current_state();
// Fill up 0th epoch
let canonical_chain_slots_zeroth_epoch: Vec<Slot> =
(1..rig.epoch_start_slot(1)).map(Slot::new).collect();
let (_, _, _, mut state) = rig
let (_, _, _, state) = rig
.add_attested_blocks_at_slots(
state,
state_root,
&canonical_chain_slots_zeroth_epoch,
&honest_validators,
)
@@ -1834,11 +1854,9 @@ async fn pruning_does_not_touch_abandoned_block_shared_with_canonical_chain() {
..=rig.epoch_start_slot(1) + 1)
.map(Slot::new)
.collect();
let state_root = state.update_tree_hash_cache().unwrap();
let (canonical_chain_blocks_first_epoch, _, shared_head, mut state) = rig
let (canonical_chain_blocks_first_epoch, _, shared_head, state) = rig
.add_attested_blocks_at_slots(
state.clone(),
state_root,
&canonical_chain_slots_first_epoch,
&honest_validators,
)
@@ -1849,11 +1867,9 @@ async fn pruning_does_not_touch_abandoned_block_shared_with_canonical_chain() {
..=rig.epoch_start_slot(1) + 2)
.map(Slot::new)
.collect();
let state_root = state.update_tree_hash_cache().unwrap();
let (stray_blocks, stray_states, stray_head, _) = rig
.add_attested_blocks_at_slots(
state.clone(),
state_root,
&stray_chain_slots_first_epoch,
&adversarial_validators,
)
@@ -1890,9 +1906,8 @@ async fn pruning_does_not_touch_abandoned_block_shared_with_canonical_chain() {
..=(canonical_chain_slot + slots_per_epoch * 5))
.map(Slot::new)
.collect();
let state_root = state.update_tree_hash_cache().unwrap();
let (canonical_chain_blocks, _, _, _) = rig
.add_attested_blocks_at_slots(state, state_root, &finalization_slots, &honest_validators)
.add_attested_blocks_at_slots(state, &finalization_slots, &honest_validators)
.await;
// Postconditions
@@ -1945,12 +1960,12 @@ async fn pruning_does_not_touch_blocks_prior_to_finalization() {
let store = get_store(&db_path);
let rig = get_harness(store.clone(), VALIDATOR_COUNT);
let slots_per_epoch = rig.slots_per_epoch();
let (mut state, state_root) = rig.get_current_state_and_root();
let mut state = rig.get_current_state();
// Fill up 0th epoch with canonical chain blocks
let zeroth_epoch_slots: Vec<Slot> = (1..=rig.epoch_start_slot(1)).map(Slot::new).collect();
let (canonical_chain_blocks, _, _, new_state) = rig
.add_attested_blocks_at_slots(state, state_root, &zeroth_epoch_slots, &honest_validators)
.add_attested_blocks_at_slots(state, &zeroth_epoch_slots, &honest_validators)
.await;
state = new_state;
let canonical_chain_slot: u64 = rig.get_current_slot().into();
@@ -1959,14 +1974,8 @@ async fn pruning_does_not_touch_blocks_prior_to_finalization() {
let first_epoch_slots: Vec<Slot> = ((rig.epoch_start_slot(1) + 1)..(rig.epoch_start_slot(2)))
.map(Slot::new)
.collect();
let state_root = state.update_tree_hash_cache().unwrap();
let (stray_blocks, stray_states, stray_head, _) = rig
.add_attested_blocks_at_slots(
state.clone(),
state_root,
&first_epoch_slots,
&adversarial_validators,
)
.add_attested_blocks_at_slots(state.clone(), &first_epoch_slots, &adversarial_validators)
.await;
// Preconditions
@@ -1994,9 +2003,8 @@ async fn pruning_does_not_touch_blocks_prior_to_finalization() {
..=(canonical_chain_slot + slots_per_epoch * 4))
.map(Slot::new)
.collect();
let state_root = state.update_tree_hash_cache().unwrap();
let (_, _, _, _) = rig
.add_attested_blocks_at_slots(state, state_root, &slots, &honest_validators)
.add_attested_blocks_at_slots(state, &slots, &honest_validators)
.await;
// Postconditions
@@ -2037,29 +2045,23 @@ async fn prunes_fork_growing_past_youngest_finalized_checkpoint() {
let db_path = tempdir().unwrap();
let store = get_store(&db_path);
let rig = get_harness(store.clone(), VALIDATOR_COUNT);
let (state, state_root) = rig.get_current_state_and_root();
let state = rig.get_current_state();
// Fill up 0th epoch with canonical chain blocks
let zeroth_epoch_slots: Vec<Slot> = (1..=rig.epoch_start_slot(1)).map(Slot::new).collect();
let (canonical_blocks_zeroth_epoch, _, _, mut state) = rig
.add_attested_blocks_at_slots(state, state_root, &zeroth_epoch_slots, &honest_validators)
let (canonical_blocks_zeroth_epoch, _, _, state) = rig
.add_attested_blocks_at_slots(state, &zeroth_epoch_slots, &honest_validators)
.await;
// Fill up 1st epoch. Contains a fork.
let slots_first_epoch: Vec<Slot> = (rig.epoch_start_slot(1) + 1..rig.epoch_start_slot(2))
.map(Into::into)
.collect();
let state_root = state.update_tree_hash_cache().unwrap();
let (stray_blocks_first_epoch, stray_states_first_epoch, _, mut stray_state) = rig
.add_attested_blocks_at_slots(
state.clone(),
state_root,
&slots_first_epoch,
&adversarial_validators,
)
let (stray_blocks_first_epoch, stray_states_first_epoch, _, stray_state) = rig
.add_attested_blocks_at_slots(state.clone(), &slots_first_epoch, &adversarial_validators)
.await;
let (canonical_blocks_first_epoch, _, _, mut canonical_state) = rig
.add_attested_blocks_at_slots(state, state_root, &slots_first_epoch, &honest_validators)
let (canonical_blocks_first_epoch, _, _, canonical_state) = rig
.add_attested_blocks_at_slots(state, &slots_first_epoch, &honest_validators)
.await;
// Fill up 2nd epoch. Extends both the canonical chain and the fork.
@@ -2067,11 +2069,9 @@ async fn prunes_fork_growing_past_youngest_finalized_checkpoint() {
..=rig.epoch_start_slot(2) + 1)
.map(Into::into)
.collect();
let stray_state_root = stray_state.update_tree_hash_cache().unwrap();
let (stray_blocks_second_epoch, stray_states_second_epoch, stray_head, _) = rig
.add_attested_blocks_at_slots(
stray_state,
stray_state_root,
&stray_slots_second_epoch,
&adversarial_validators,
)
@@ -2114,10 +2114,8 @@ async fn prunes_fork_growing_past_youngest_finalized_checkpoint() {
let canonical_slots: Vec<Slot> = (rig.epoch_start_slot(2)..=rig.epoch_start_slot(6))
.map(Into::into)
.collect();
let canonical_state_root = canonical_state.update_tree_hash_cache().unwrap();
let (canonical_blocks, _, _, _) = Box::pin(rig.add_attested_blocks_at_slots(
canonical_state,
canonical_state_root,
&canonical_slots,
&honest_validators,
))
@@ -2179,14 +2177,13 @@ async fn prunes_skipped_slots_states() {
let db_path = tempdir().unwrap();
let store = get_store(&db_path);
let rig = get_harness(store.clone(), VALIDATOR_COUNT);
let (state, state_root) = rig.get_current_state_and_root();
let state = rig.get_current_state();
let canonical_slots_zeroth_epoch: Vec<Slot> =
(1..=rig.epoch_start_slot(1)).map(Into::into).collect();
let (canonical_blocks_zeroth_epoch, _, _, mut canonical_state) = rig
let (canonical_blocks_zeroth_epoch, _, _, canonical_state) = rig
.add_attested_blocks_at_slots(
state.clone(),
state_root,
&canonical_slots_zeroth_epoch,
&honest_validators,
)
@@ -2197,11 +2194,9 @@ async fn prunes_skipped_slots_states() {
let stray_slots: Vec<Slot> = ((skipped_slot + 1).into()..rig.epoch_start_slot(2))
.map(Into::into)
.collect();
let canonical_state_root = canonical_state.update_tree_hash_cache().unwrap();
let (stray_blocks, stray_states, _, stray_state) = rig
.add_attested_blocks_at_slots(
canonical_state.clone(),
canonical_state_root,
&stray_slots,
&adversarial_validators,
)
@@ -2242,14 +2237,8 @@ async fn prunes_skipped_slots_states() {
let canonical_slots: Vec<Slot> = ((skipped_slot + 1).into()..rig.epoch_start_slot(7))
.map(Into::into)
.collect();
let canonical_state_root = canonical_state.update_tree_hash_cache().unwrap();
let (canonical_blocks_post_finalization, _, _, _) = rig
.add_attested_blocks_at_slots(
canonical_state,
canonical_state_root,
&canonical_slots,
&honest_validators,
)
.add_attested_blocks_at_slots(canonical_state, &canonical_slots, &honest_validators)
.await;
// Postconditions
@@ -2304,14 +2293,13 @@ async fn finalizes_non_epoch_start_slot() {
let db_path = tempdir().unwrap();
let store = get_store(&db_path);
let rig = get_harness(store.clone(), VALIDATOR_COUNT);
let (state, state_root) = rig.get_current_state_and_root();
let state = rig.get_current_state();
let canonical_slots_zeroth_epoch: Vec<Slot> =
(1..rig.epoch_start_slot(1)).map(Into::into).collect();
let (canonical_blocks_zeroth_epoch, _, _, mut canonical_state) = rig
let (canonical_blocks_zeroth_epoch, _, _, canonical_state) = rig
.add_attested_blocks_at_slots(
state.clone(),
state_root,
&canonical_slots_zeroth_epoch,
&honest_validators,
)
@@ -2322,11 +2310,9 @@ async fn finalizes_non_epoch_start_slot() {
let stray_slots: Vec<Slot> = ((skipped_slot + 1).into()..rig.epoch_start_slot(2))
.map(Into::into)
.collect();
let canonical_state_root = canonical_state.update_tree_hash_cache().unwrap();
let (stray_blocks, stray_states, _, stray_state) = rig
.add_attested_blocks_at_slots(
canonical_state.clone(),
canonical_state_root,
&stray_slots,
&adversarial_validators,
)
@@ -2367,14 +2353,8 @@ async fn finalizes_non_epoch_start_slot() {
let canonical_slots: Vec<Slot> = ((skipped_slot + 1).into()..rig.epoch_start_slot(7))
.map(Into::into)
.collect();
let canonical_state_root = canonical_state.update_tree_hash_cache().unwrap();
let (canonical_blocks_post_finalization, _, _, _) = rig
.add_attested_blocks_at_slots(
canonical_state,
canonical_state_root,
&canonical_slots,
&honest_validators,
)
.add_attested_blocks_at_slots(canonical_state, &canonical_slots, &honest_validators)
.await;
// Postconditions
@@ -2597,11 +2577,10 @@ async fn pruning_test(
let start_slot = Slot::new(1);
let divergence_slot = start_slot + num_initial_blocks;
let (state, state_root) = harness.get_current_state_and_root();
let state = harness.get_current_state();
let (_, _, _, divergence_state) = harness
.add_attested_blocks_at_slots(
state,
state_root,
&slots(start_slot, num_initial_blocks)[..],
&honest_validators,
)
@@ -2626,7 +2605,7 @@ async fn pruning_test(
),
])
.await;
let (_, _, _, mut canonical_state) = chains.remove(0);
let (_, _, _, canonical_state) = chains.remove(0);
let (stray_blocks, stray_states, _, stray_head_state) = chains.remove(0);
let stray_head_slot = divergence_slot + num_fork_skips + num_fork_blocks - 1;
@@ -2650,11 +2629,9 @@ async fn pruning_test(
// Trigger finalization
let num_finalization_blocks = 4 * E::slots_per_epoch();
let canonical_slot = divergence_slot + num_canonical_skips + num_canonical_middle_blocks;
let canonical_state_root = canonical_state.update_tree_hash_cache().unwrap();
harness
.add_attested_blocks_at_slots(
canonical_state,
canonical_state_root,
&slots(canonical_slot, num_finalization_blocks),
&honest_validators,
)
@@ -2862,14 +2839,9 @@ async fn reproduction_unaligned_checkpoint_sync_pruned_payload() {
let harness = get_harness_import_all_data_columns(full_store.clone(), LOW_VALIDATOR_COUNT);
let all_validators = (0..LOW_VALIDATOR_COUNT).collect::<Vec<_>>();
let (genesis_state, genesis_state_root) = harness.get_current_state_and_root();
let genesis_state = harness.get_current_state();
harness
.add_attested_blocks_at_slots(
genesis_state.clone(),
genesis_state_root,
&slots,
&all_validators,
)
.add_attested_blocks_at_slots(genesis_state.clone(), &slots, &all_validators)
.await;
// Extract snapshot data from the harness.
@@ -2901,10 +2873,7 @@ async fn reproduction_unaligned_checkpoint_sync_pruned_payload() {
.is_ok()
);
let wss_blobs_opt = harness
.chain
.get_or_reconstruct_blobs(&wss_block_root)
.unwrap();
let wss_blobs_opt = get_or_reconstruct_blobs(&harness.chain, &wss_block_root).unwrap();
let wss_state = full_store
.get_state(&wss_state_root, Some(checkpoint_slot), CACHE_STATE_IN_TESTS)
@@ -3016,14 +2985,9 @@ async fn weak_subjectivity_sync_test(
let all_validators = (0..LOW_VALIDATOR_COUNT).collect::<Vec<_>>();
let (genesis_state, genesis_state_root) = harness.get_current_state_and_root();
let genesis_state = harness.get_current_state();
harness
.add_attested_blocks_at_slots(
genesis_state.clone(),
genesis_state_root,
&slots,
&all_validators,
)
.add_attested_blocks_at_slots(genesis_state.clone(), &slots, &all_validators)
.await;
let wss_block_root = harness
@@ -3042,10 +3006,7 @@ async fn weak_subjectivity_sync_test(
.state_root_at_slot(checkpoint_slot)
.unwrap()
.unwrap();
let wss_blobs_opt = harness
.chain
.get_or_reconstruct_blobs(&wss_block_root)
.unwrap();
let wss_blobs_opt = get_or_reconstruct_blobs(&harness.chain, &wss_block_root).unwrap();
let wss_state = full_store
.get_state(&wss_state_root, Some(checkpoint_slot), CACHE_STATE_IN_TESTS)
.unwrap()
@@ -3134,6 +3095,29 @@ async fn weak_subjectivity_sync_test(
let beacon_chain = Arc::new(beacon_chain);
let wss_block_root = wss_block.canonical_root();
// For Gloas, blobs aren't a standalone shape — the WSS data is the column sidecar set, which
// `get_or_reconstruct_blobs` returns `None` for. Copy the WSS block's columns straight from
// the source store so that the destination has them after checkpoint sync, matching what
// network-driven WSS would produce in production.
if wss_block.fork_name_unchecked().gloas_enabled()
&& let Ok(Some(source_columns)) = harness
.chain
.store
.get_data_columns(&wss_block_root, ForkName::Gloas)
&& !source_columns.is_empty()
&& let Some(store_op) = beacon_chain.get_blobs_or_columns_store_op(
wss_block_root,
wss_block.slot(),
beacon_chain::block_verification_types::AvailableBlockData::DataColumns(source_columns),
)
{
beacon_chain
.store
.do_atomically_with_block_and_blobs_cache(vec![store_op])
.unwrap();
}
let store_wss_block = harness
.chain
.get_block(&wss_block_root)
@@ -3141,9 +3125,7 @@ async fn weak_subjectivity_sync_test(
.unwrap()
.unwrap();
// This test may break in the future if we no longer store the full checkpoint data columns.
let store_wss_blobs_opt = beacon_chain
.get_or_reconstruct_blobs(&wss_block_root)
.unwrap();
let store_wss_blobs_opt = get_or_reconstruct_blobs(&beacon_chain, &wss_block_root).unwrap();
assert_eq!(store_wss_block, wss_block);
// TODO(fulu): Remove this condition once #6760 (PeerDAS checkpoint sync) is merged.
@@ -3201,12 +3183,43 @@ async fn weak_subjectivity_sync_test(
.await
.unwrap();
// Store the envelope and apply it to fork choice.
// Store the envelope, its columns, and apply to fork choice.
if let Some(envelope) = &snapshot.execution_envelope {
// Persist data columns for Gloas blocks. This mirrors what production does in
// `import_available_execution_payload_envelope` and what the harness now does in
// `process_envelope` — the WSS forward-sync loop bypasses both, so do it directly.
let mut ops = vec![];
let columns_block = beacon_chain
.store
.get_blinded_block(&block_root)
.unwrap()
.and_then(|b| beacon_chain.store.make_full_block(&block_root, b).ok());
if let Some(full_block) = columns_block {
let columns = beacon_chain::test_utils::generate_data_column_sidecars_from_block(
&full_block,
&beacon_chain.spec,
);
if !columns.is_empty()
&& let Some(store_op) = beacon_chain.get_blobs_or_columns_store_op(
block_root,
full_block.slot(),
beacon_chain::block_verification_types::AvailableBlockData::DataColumns(
columns,
),
)
{
ops.push(store_op);
}
}
ops.push(store::StoreOp::PutPayloadEnvelope(
block_root,
std::sync::Arc::new(envelope.as_ref().clone()),
));
beacon_chain
.store
.put_payload_envelope(&block_root, envelope)
.do_atomically_with_block_and_blobs_cache(ops)
.unwrap();
// Update fork choice so head selection accounts for Full payload status.
beacon_chain
.canonical_head
@@ -3831,14 +3844,9 @@ async fn process_blocks_and_attestations_for_unaligned_checkpoint() {
.map(Slot::new)
.collect::<Vec<_>>();
let (genesis_state, genesis_state_root) = harness.get_current_state_and_root();
let genesis_state = harness.get_current_state();
harness
.add_attested_blocks_at_slots(
genesis_state.clone(),
genesis_state_root,
&slots,
&all_validators,
)
.add_attested_blocks_at_slots(genesis_state.clone(), &slots, &all_validators)
.await;
// Before the split slot becomes finalized, create two forking blocks that build on the split
@@ -5706,7 +5714,7 @@ async fn test_gloas_block_replay_with_envelopes() {
let harness = get_harness(store.clone(), LOW_VALIDATOR_COUNT);
let num_blocks = 16u64;
let (genesis_state, _genesis_state_root) = harness.get_current_state_and_root();
let genesis_state = harness.get_current_state();
let mut state = genesis_state.clone();
let mut last_block_root = Hash256::zero();
@@ -5782,7 +5790,7 @@ async fn test_gloas_hot_state_hierarchy() {
let num_blocks = E::slots_per_epoch() * 5;
let all_validators = (0..LOW_VALIDATOR_COUNT).collect::<Vec<_>>();
let (genesis_state, _genesis_state_root) = harness.get_current_state_and_root();
let genesis_state = harness.get_current_state();
// Use manual block building with envelopes for the first few blocks,
// then use the standard attested-blocks path once we've verified envelope handling.

View File

@@ -185,7 +185,6 @@ async fn aggregated_gossip_verification() {
harness
.add_attested_blocks_at_slots(
state,
Hash256::zero(),
&[Slot::new(1), Slot::new(2)],
(0..VALIDATOR_COUNT).collect::<Vec<_>>().as_slice(),
)
@@ -495,7 +494,7 @@ async fn aggregated_gossip_verification() {
);
harness
.add_attested_block_at_slot(target_slot, state, Hash256::zero(), &[])
.add_attested_block_at_slot(target_slot, state, &[])
.await
.expect("should add block");
@@ -519,7 +518,6 @@ async fn unaggregated_gossip_verification() {
harness
.add_attested_blocks_at_slots(
state,
Hash256::zero(),
&[Slot::new(1), Slot::new(2)],
(0..VALIDATOR_COUNT).collect::<Vec<_>>().as_slice(),
)
@@ -801,7 +799,7 @@ async fn unaggregated_gossip_verification() {
);
harness
.add_attested_block_at_slot(target_slot, state, Hash256::zero(), &[])
.add_attested_block_at_slot(target_slot, state, &[])
.await
.expect("should add block");

View File

@@ -46,8 +46,7 @@ async fn missed_blocks_across_epochs() {
let harness = get_harness(VALIDATOR_COUNT, vec![]);
let validator_monitor = &harness.chain.validator_monitor;
let mut genesis_state = harness.get_current_state();
let genesis_state_root = genesis_state.update_tree_hash_cache().unwrap();
let genesis_state = harness.get_current_state();
let genesis_block_root = harness.head_block_root();
// Skip a slot in the first epoch (to prime the cache inside the missed block function) and then
@@ -64,7 +63,7 @@ async fn missed_blocks_across_epochs() {
.collect::<Vec<_>>();
let (block_roots_by_slot, state_roots_by_slot, _, head_state) = harness
.add_attested_blocks_at_slots(genesis_state, genesis_state_root, &slots, &all_validators)
.add_attested_blocks_at_slots(genesis_state, &slots, &all_validators)
.await;
// Prime the proposer shuffling cache.