|
|
|
|
@@ -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.
|
|
|
|
|
|