Merge branch 'unstable' into merge-unstable-to-deneb-20230822
# Conflicts: # beacon_node/beacon_chain/src/builder.rs # beacon_node/beacon_chain/tests/store_tests.rs # beacon_node/client/src/builder.rs # beacon_node/src/config.rs # beacon_node/store/src/hot_cold_store.rs # lighthouse/tests/beacon_node.rs
This commit is contained in:
@@ -4943,6 +4943,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
self.log,
|
||||
"Produced block on state";
|
||||
"block_size" => block_size,
|
||||
"slot" => block.slot(),
|
||||
);
|
||||
|
||||
metrics::observe(&metrics::BLOCK_SIZE, block_size as f64);
|
||||
@@ -5921,14 +5922,16 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
let (mut state, state_root) = if let Some((state, state_root)) = head_state_opt {
|
||||
(state, state_root)
|
||||
} else {
|
||||
let state_root = head_block.state_root;
|
||||
let state = self
|
||||
let block_state_root = head_block.state_root;
|
||||
let max_slot = shuffling_epoch.start_slot(T::EthSpec::slots_per_epoch());
|
||||
let (state_root, state) = self
|
||||
.store
|
||||
.get_inconsistent_state_for_attestation_verification_only(
|
||||
&state_root,
|
||||
Some(head_block.slot),
|
||||
&head_block_root,
|
||||
max_slot,
|
||||
block_state_root,
|
||||
)?
|
||||
.ok_or(Error::MissingBeaconState(head_block.state_root))?;
|
||||
.ok_or(Error::MissingBeaconState(block_state_root))?;
|
||||
(state, state_root)
|
||||
};
|
||||
|
||||
|
||||
@@ -321,9 +321,17 @@ where
|
||||
.deconstruct()
|
||||
.0;
|
||||
|
||||
let state = self
|
||||
let max_slot = self
|
||||
.justified_checkpoint
|
||||
.epoch
|
||||
.start_slot(E::slots_per_epoch());
|
||||
let (_, state) = self
|
||||
.store
|
||||
.get_state(&justified_block.state_root(), Some(justified_block.slot()))
|
||||
.get_advanced_hot_state(
|
||||
self.justified_checkpoint.root,
|
||||
max_slot,
|
||||
justified_block.state_root(),
|
||||
)
|
||||
.map_err(Error::FailedToReadState)?
|
||||
.ok_or_else(|| Error::MissingState(justified_block.state_root()))?;
|
||||
|
||||
|
||||
@@ -1358,7 +1358,7 @@ impl<T: BeaconChainTypes> ExecutionPendingBlock<T> {
|
||||
|
||||
// Perform a sanity check on the pre-state.
|
||||
let parent_slot = parent.beacon_block.slot();
|
||||
if state.slot() < parent_slot || state.slot() > parent_slot + 1 {
|
||||
if state.slot() < parent_slot || state.slot() > block.slot() {
|
||||
return Err(BeaconChainError::BadPreState {
|
||||
parent_root: parent.beacon_block_root,
|
||||
parent_slot,
|
||||
@@ -1860,13 +1860,18 @@ fn load_parent<T: BeaconChainTypes, B: AsBlock<T::EthSpec>>(
|
||||
BlockError::from(BeaconChainError::MissingBeaconBlock(block.parent_root()))
|
||||
})?;
|
||||
|
||||
// Load the parent blocks state from the database, returning an error if it is not found.
|
||||
// Load the parent block's state from the database, returning an error if it is not found.
|
||||
// It is an error because if we know the parent block we should also know the parent state.
|
||||
let parent_state_root = parent_block.state_root();
|
||||
let parent_state = chain
|
||||
.get_state(&parent_state_root, Some(parent_block.slot()))?
|
||||
// Retrieve any state that is advanced through to at most `block.slot()`: this is
|
||||
// particularly important if `block` descends from the finalized/split block, but at a slot
|
||||
// prior to the finalized slot (which is invalid and inaccessible in our DB schema).
|
||||
let (parent_state_root, parent_state) = chain
|
||||
.store
|
||||
.get_advanced_hot_state(root, block.slot(), parent_block.state_root())?
|
||||
.ok_or_else(|| {
|
||||
BeaconChainError::DBInconsistent(format!("Missing state {:?}", parent_state_root))
|
||||
BeaconChainError::DBInconsistent(
|
||||
format!("Missing state for parent block {root:?}",),
|
||||
)
|
||||
})?;
|
||||
|
||||
metrics::inc_counter(&metrics::BLOCK_PROCESSING_SNAPSHOT_CACHE_MISSES);
|
||||
|
||||
@@ -26,8 +26,9 @@ use operation_pool::{OperationPool, PersistedOperationPool};
|
||||
use parking_lot::RwLock;
|
||||
use proto_array::{DisallowedReOrgOffsets, ReOrgThreshold};
|
||||
use slasher::Slasher;
|
||||
use slog::{crit, error, info, Logger};
|
||||
use slog::{crit, debug, error, info, Logger};
|
||||
use slot_clock::{SlotClock, TestingSlotClock};
|
||||
use state_processing::per_slot_processing;
|
||||
use std::marker::PhantomData;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
@@ -291,7 +292,7 @@ where
|
||||
let genesis_state = store
|
||||
.get_state(&genesis_block.state_root(), Some(genesis_block.slot()))
|
||||
.map_err(|e| descriptive_db_error("genesis state", &e))?
|
||||
.ok_or("Genesis block not found in store")?;
|
||||
.ok_or("Genesis state not found in store")?;
|
||||
|
||||
self.genesis_time = Some(genesis_state.genesis_time());
|
||||
|
||||
@@ -386,6 +387,16 @@ where
|
||||
let (genesis, updated_builder) = self.set_genesis_state(beacon_state)?;
|
||||
self = updated_builder;
|
||||
|
||||
// Stage the database's metadata fields for atomic storage when `build` is called.
|
||||
// Since v4.4.0 we will set the anchor with a dummy state upper limit in order to prevent
|
||||
// historic states from being retained (unless `--reconstruct-historic-states` is set).
|
||||
let retain_historic_states = self.chain_config.reconstruct_historic_states;
|
||||
self.pending_io_batch.push(
|
||||
store
|
||||
.init_anchor_info(genesis.beacon_block.message(), retain_historic_states)
|
||||
.map_err(|e| format!("Failed to initialize genesis anchor: {:?}", e))?,
|
||||
);
|
||||
|
||||
let fc_store = BeaconForkChoiceStore::get_forkchoice_store(store, &genesis)
|
||||
.map_err(|e| format!("Unable to initialize fork choice store: {e:?}"))?;
|
||||
let current_slot = None;
|
||||
@@ -412,21 +423,28 @@ where
|
||||
weak_subj_block: SignedBeaconBlock<TEthSpec>,
|
||||
genesis_state: BeaconState<TEthSpec>,
|
||||
) -> Result<Self, String> {
|
||||
let store = self.store.clone().ok_or("genesis_state requires a store")?;
|
||||
let store = self
|
||||
.store
|
||||
.clone()
|
||||
.ok_or("weak_subjectivity_state requires a store")?;
|
||||
let log = self
|
||||
.log
|
||||
.as_ref()
|
||||
.ok_or("weak_subjectivity_state requires a log")?;
|
||||
|
||||
let weak_subj_slot = weak_subj_state.slot();
|
||||
let weak_subj_block_root = weak_subj_block.canonical_root();
|
||||
let weak_subj_state_root = weak_subj_block.state_root();
|
||||
|
||||
// Check that the given state lies on an epoch boundary. Due to the database only storing
|
||||
// full states on epoch boundaries and at restore points it would be difficult to support
|
||||
// starting from a mid-epoch state.
|
||||
if weak_subj_slot % TEthSpec::slots_per_epoch() != 0 {
|
||||
return Err(format!(
|
||||
"Checkpoint state at slot {} is not aligned to epoch start. \
|
||||
Please supply an aligned checkpoint with state.slot % 32 == 0",
|
||||
weak_subj_slot,
|
||||
));
|
||||
// Ensure the state is advanced to an epoch boundary.
|
||||
let slots_per_epoch = TEthSpec::slots_per_epoch();
|
||||
if weak_subj_state.slot() % slots_per_epoch != 0 {
|
||||
debug!(
|
||||
log,
|
||||
"Advancing checkpoint state to boundary";
|
||||
"state_slot" => weak_subj_state.slot(),
|
||||
"block_slot" => weak_subj_block.slot(),
|
||||
);
|
||||
while weak_subj_state.slot() % slots_per_epoch != 0 {
|
||||
per_slot_processing(&mut weak_subj_state, None, &self.spec)
|
||||
.map_err(|e| format!("Error advancing state: {e:?}"))?;
|
||||
}
|
||||
}
|
||||
|
||||
// Prime all caches before storing the state in the database and computing the tree hash
|
||||
@@ -434,21 +452,20 @@ where
|
||||
weak_subj_state
|
||||
.build_caches(&self.spec)
|
||||
.map_err(|e| format!("Error building caches on checkpoint state: {e:?}"))?;
|
||||
weak_subj_state
|
||||
let weak_subj_state_root = weak_subj_state
|
||||
.update_tree_hash_cache()
|
||||
.map_err(|e| format!("Error computing checkpoint state root: {:?}", e))?;
|
||||
|
||||
let latest_block_slot = weak_subj_state.latest_block_header().slot;
|
||||
let weak_subj_slot = weak_subj_state.slot();
|
||||
let weak_subj_block_root = weak_subj_block.canonical_root();
|
||||
|
||||
// We can only validate the block root if it exists in the state. We can't calculated it
|
||||
// from the `latest_block_header` because the state root might be set to the zero hash.
|
||||
if let Ok(state_slot_block_root) = weak_subj_state.get_block_root(latest_block_slot) {
|
||||
if weak_subj_block_root != *state_slot_block_root {
|
||||
return Err(format!(
|
||||
"Snapshot state's most recent block root does not match block, expected: {:?}, got: {:?}",
|
||||
weak_subj_block_root, state_slot_block_root
|
||||
));
|
||||
}
|
||||
// Validate the state's `latest_block_header` against the checkpoint block.
|
||||
let state_latest_block_root = weak_subj_state.get_latest_block_root(weak_subj_state_root);
|
||||
if weak_subj_block_root != state_latest_block_root {
|
||||
return Err(format!(
|
||||
"Snapshot state's most recent block root does not match block, expected: {:?}, got: {:?}",
|
||||
weak_subj_block_root, state_latest_block_root
|
||||
));
|
||||
}
|
||||
|
||||
// Check that the checkpoint state is for the same network as the genesis state.
|
||||
@@ -464,7 +481,7 @@ where
|
||||
|
||||
// Set the store's split point *before* storing genesis so that genesis is stored
|
||||
// immediately in the freezer DB.
|
||||
store.set_split(weak_subj_slot, weak_subj_state_root);
|
||||
store.set_split(weak_subj_slot, weak_subj_state_root, weak_subj_block_root);
|
||||
let (_, updated_builder) = self.set_genesis_state(genesis_state)?;
|
||||
self = updated_builder;
|
||||
|
||||
@@ -480,10 +497,11 @@ where
|
||||
// Stage the database's metadata fields for atomic storage when `build` is called.
|
||||
// This prevents the database from restarting in an inconsistent state if the anchor
|
||||
// info or split point is written before the `PersistedBeaconChain`.
|
||||
let retain_historic_states = self.chain_config.reconstruct_historic_states;
|
||||
self.pending_io_batch.push(store.store_split_in_batch());
|
||||
self.pending_io_batch.push(
|
||||
store
|
||||
.init_anchor_info(weak_subj_block.message())
|
||||
.init_anchor_info(weak_subj_block.message(), retain_historic_states)
|
||||
.map_err(|e| format!("Failed to initialize anchor info: {:?}", e))?,
|
||||
);
|
||||
|
||||
@@ -685,9 +703,8 @@ where
|
||||
Err(e) => return Err(descriptive_db_error("head block", &e)),
|
||||
};
|
||||
|
||||
let head_state_root = head_block.state_root();
|
||||
let head_state = store
|
||||
.get_state(&head_state_root, Some(head_block.slot()))
|
||||
let (_head_state_root, head_state) = store
|
||||
.get_advanced_hot_state(head_block_root, current_slot, head_block.state_root())
|
||||
.map_err(|e| descriptive_db_error("head state", &e))?
|
||||
.ok_or("Head state not found in store")?;
|
||||
|
||||
|
||||
@@ -47,7 +47,8 @@ use crate::{
|
||||
};
|
||||
use eth2::types::{EventKind, SseChainReorg, SseFinalizedCheckpoint, SseHead, SseLateHead};
|
||||
use fork_choice::{
|
||||
ExecutionStatus, ForkChoiceView, ForkchoiceUpdateParameters, ProtoBlock, ResetPayloadStatuses,
|
||||
ExecutionStatus, ForkChoiceStore, ForkChoiceView, ForkchoiceUpdateParameters, ProtoBlock,
|
||||
ResetPayloadStatuses,
|
||||
};
|
||||
use itertools::process_results;
|
||||
use parking_lot::{Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard};
|
||||
@@ -298,10 +299,10 @@ impl<T: BeaconChainTypes> CanonicalHead<T> {
|
||||
let beacon_block = store
|
||||
.get_full_block(&beacon_block_root)?
|
||||
.ok_or(Error::MissingBeaconBlock(beacon_block_root))?;
|
||||
let beacon_state_root = beacon_block.state_root();
|
||||
let beacon_state = store
|
||||
.get_state(&beacon_state_root, Some(beacon_block.slot()))?
|
||||
.ok_or(Error::MissingBeaconState(beacon_state_root))?;
|
||||
let current_slot = fork_choice.fc_store().get_current_slot();
|
||||
let (_, beacon_state) = store
|
||||
.get_advanced_hot_state(beacon_block_root, current_slot, beacon_block.state_root())?
|
||||
.ok_or(Error::MissingBeaconState(beacon_block.state_root()))?;
|
||||
|
||||
let snapshot = BeaconSnapshot {
|
||||
beacon_block_root,
|
||||
@@ -669,10 +670,14 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
.get_full_block(&new_view.head_block_root)?
|
||||
.ok_or(Error::MissingBeaconBlock(new_view.head_block_root))?;
|
||||
|
||||
let beacon_state_root = beacon_block.state_root();
|
||||
let beacon_state: BeaconState<T::EthSpec> = self
|
||||
.get_state(&beacon_state_root, Some(beacon_block.slot()))?
|
||||
.ok_or(Error::MissingBeaconState(beacon_state_root))?;
|
||||
let (_, beacon_state) = self
|
||||
.store
|
||||
.get_advanced_hot_state(
|
||||
new_view.head_block_root,
|
||||
current_slot,
|
||||
beacon_block.state_root(),
|
||||
)?
|
||||
.ok_or(Error::MissingBeaconState(beacon_block.state_root()))?;
|
||||
|
||||
Ok(BeaconSnapshot {
|
||||
beacon_block: Arc::new(beacon_block),
|
||||
|
||||
@@ -21,8 +21,11 @@ pub struct ServerSentEventHandler<T: EthSpec> {
|
||||
}
|
||||
|
||||
impl<T: EthSpec> ServerSentEventHandler<T> {
|
||||
pub fn new(log: Logger) -> Self {
|
||||
Self::new_with_capacity(log, DEFAULT_CHANNEL_CAPACITY)
|
||||
pub fn new(log: Logger, capacity_multiplier: usize) -> Self {
|
||||
Self::new_with_capacity(
|
||||
log,
|
||||
capacity_multiplier.saturating_mul(DEFAULT_CHANNEL_CAPACITY),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn new_with_capacity(log: Logger, capacity: usize) -> Self {
|
||||
|
||||
@@ -289,6 +289,7 @@ impl<E: EthSpec, Hot: ItemStore<E>, Cold: ItemStore<E>> BackgroundMigrator<E, Ho
|
||||
debug!(log, "Database consolidation started");
|
||||
|
||||
let finalized_state_root = notif.finalized_state_root;
|
||||
let finalized_block_root = notif.finalized_checkpoint.root;
|
||||
|
||||
let finalized_state = match db.get_state(&finalized_state_root.into(), None) {
|
||||
Ok(Some(state)) => state,
|
||||
@@ -342,7 +343,12 @@ impl<E: EthSpec, Hot: ItemStore<E>, Cold: ItemStore<E>> BackgroundMigrator<E, Ho
|
||||
}
|
||||
};
|
||||
|
||||
match migrate_database(db.clone(), finalized_state_root.into(), &finalized_state) {
|
||||
match migrate_database(
|
||||
db.clone(),
|
||||
finalized_state_root.into(),
|
||||
finalized_block_root,
|
||||
&finalized_state,
|
||||
) {
|
||||
Ok(()) => {}
|
||||
Err(Error::HotColdDBError(HotColdDBError::FreezeSlotUnaligned(slot))) => {
|
||||
debug!(
|
||||
|
||||
@@ -9,7 +9,7 @@ use beacon_chain::{
|
||||
test_utils::{
|
||||
test_spec, AttestationStrategy, BeaconChainHarness, BlockStrategy, EphemeralHarnessType,
|
||||
},
|
||||
BeaconChain, BeaconChainError, BeaconChainTypes, WhenSlotSkipped,
|
||||
BeaconChain, BeaconChainError, BeaconChainTypes, ChainConfig, WhenSlotSkipped,
|
||||
};
|
||||
use genesis::{interop_genesis_state, DEFAULT_ETH1_BLOCK_HASH};
|
||||
use int_to_bytes::int_to_bytes32;
|
||||
@@ -47,6 +47,10 @@ fn get_harness(validator_count: usize) -> BeaconChainHarness<EphemeralHarnessTyp
|
||||
|
||||
let harness = BeaconChainHarness::builder(MainnetEthSpec)
|
||||
.spec(spec)
|
||||
.chain_config(ChainConfig {
|
||||
reconstruct_historic_states: true,
|
||||
..ChainConfig::default()
|
||||
})
|
||||
.keypairs(KEYPAIRS[0..validator_count].to_vec())
|
||||
.fresh_ephemeral_store()
|
||||
.mock_execution_layer()
|
||||
@@ -79,6 +83,10 @@ fn get_harness_capella_spec(
|
||||
|
||||
let harness = BeaconChainHarness::builder(MainnetEthSpec)
|
||||
.spec(spec.clone())
|
||||
.chain_config(ChainConfig {
|
||||
reconstruct_historic_states: true,
|
||||
..ChainConfig::default()
|
||||
})
|
||||
.keypairs(validator_keypairs)
|
||||
.withdrawal_keypairs(
|
||||
KEYPAIRS[0..validator_count]
|
||||
|
||||
@@ -7,7 +7,8 @@ use beacon_chain::{
|
||||
AvailabilityProcessingStatus, BeaconChain, BeaconChainTypes, ExecutionPendingBlock,
|
||||
};
|
||||
use beacon_chain::{
|
||||
BeaconSnapshot, BlockError, ChainSegmentResult, IntoExecutionPendingBlock, NotifyExecutionLayer,
|
||||
BeaconSnapshot, BlockError, ChainConfig, ChainSegmentResult, IntoExecutionPendingBlock,
|
||||
NotifyExecutionLayer,
|
||||
};
|
||||
use lazy_static::lazy_static;
|
||||
use logging::test_logger;
|
||||
@@ -138,6 +139,10 @@ async fn get_chain_segment_with_signed_blobs() -> (
|
||||
fn get_harness(validator_count: usize) -> BeaconChainHarness<EphemeralHarnessType<E>> {
|
||||
let harness = BeaconChainHarness::builder(MainnetEthSpec)
|
||||
.default_spec()
|
||||
.chain_config(ChainConfig {
|
||||
reconstruct_historic_states: true,
|
||||
..ChainConfig::default()
|
||||
})
|
||||
.keypairs(KEYPAIRS[0..validator_count].to_vec())
|
||||
.fresh_ephemeral_store()
|
||||
.mock_execution_layer()
|
||||
|
||||
@@ -7,7 +7,7 @@ use beacon_chain::otb_verification_service::{
|
||||
use beacon_chain::{
|
||||
canonical_head::{CachedHead, CanonicalHead},
|
||||
test_utils::{BeaconChainHarness, EphemeralHarnessType},
|
||||
BeaconChainError, BlockError, ExecutionPayloadError, NotifyExecutionLayer,
|
||||
BeaconChainError, BlockError, ChainConfig, ExecutionPayloadError, NotifyExecutionLayer,
|
||||
OverrideForkchoiceUpdate, StateSkipConfig, WhenSlotSkipped,
|
||||
INVALID_FINALIZED_MERGE_TRANSITION_BLOCK_SHUTDOWN_REASON,
|
||||
INVALID_JUSTIFIED_PAYLOAD_SHUTDOWN_REASON,
|
||||
@@ -59,6 +59,10 @@ impl InvalidPayloadRig {
|
||||
|
||||
let harness = BeaconChainHarness::builder(MainnetEthSpec)
|
||||
.spec(spec)
|
||||
.chain_config(ChainConfig {
|
||||
reconstruct_historic_states: true,
|
||||
..ChainConfig::default()
|
||||
})
|
||||
.logger(test_logger())
|
||||
.deterministic_keypairs(VALIDATOR_COUNT)
|
||||
.mock_execution_layer()
|
||||
|
||||
@@ -12,7 +12,7 @@ use beacon_chain::validator_monitor::DEFAULT_INDIVIDUAL_TRACKING_THRESHOLD;
|
||||
use beacon_chain::{
|
||||
data_availability_checker::MaybeAvailableBlock, historical_blocks::HistoricalBlockError,
|
||||
migrate::MigratorConfig, BeaconChain, BeaconChainError, BeaconChainTypes, BeaconSnapshot,
|
||||
ChainConfig, NotifyExecutionLayer, ServerSentEventHandler, WhenSlotSkipped,
|
||||
BlockError, ChainConfig, NotifyExecutionLayer, ServerSentEventHandler, WhenSlotSkipped,
|
||||
};
|
||||
use eth2_network_config::get_trusted_setup;
|
||||
use kzg::TrustedSetup;
|
||||
@@ -20,7 +20,8 @@ use lazy_static::lazy_static;
|
||||
use logging::test_logger;
|
||||
use maplit::hashset;
|
||||
use rand::Rng;
|
||||
use state_processing::BlockReplayer;
|
||||
use slot_clock::{SlotClock, TestingSlotClock};
|
||||
use state_processing::{state_advance::complete_state_advance, BlockReplayer};
|
||||
use std::collections::HashMap;
|
||||
use std::collections::HashSet;
|
||||
use std::convert::TryInto;
|
||||
@@ -77,6 +78,19 @@ fn get_store_with_spec(
|
||||
fn get_harness(
|
||||
store: Arc<HotColdDB<E, LevelDB<E>, LevelDB<E>>>,
|
||||
validator_count: usize,
|
||||
) -> TestHarness {
|
||||
// Most tests expect to retain historic states, so we use this as the default.
|
||||
let chain_config = ChainConfig {
|
||||
reconstruct_historic_states: true,
|
||||
..ChainConfig::default()
|
||||
};
|
||||
get_harness_generic(store, validator_count, chain_config)
|
||||
}
|
||||
|
||||
fn get_harness_generic(
|
||||
store: Arc<HotColdDB<E, LevelDB<E>, LevelDB<E>>>,
|
||||
validator_count: usize,
|
||||
chain_config: ChainConfig,
|
||||
) -> TestHarness {
|
||||
let harness = TestHarness::builder(MinimalEthSpec)
|
||||
.default_spec()
|
||||
@@ -84,6 +98,7 @@ fn get_harness(
|
||||
.logger(store.logger().clone())
|
||||
.fresh_disk_store(store)
|
||||
.mock_execution_layer()
|
||||
.chain_config(chain_config)
|
||||
.build();
|
||||
harness.advance_slot();
|
||||
harness
|
||||
@@ -472,13 +487,15 @@ async fn block_replay_with_inaccurate_state_roots() {
|
||||
.await;
|
||||
|
||||
// Slot must not be 0 mod 32 or else no blocks will be replayed.
|
||||
let (mut head_state, head_root) = harness.get_current_state_and_root();
|
||||
let (mut head_state, head_state_root) = harness.get_current_state_and_root();
|
||||
let head_block_root = harness.head_block_root();
|
||||
assert_ne!(head_state.slot() % 32, 0);
|
||||
|
||||
let mut fast_head_state = store
|
||||
let (_, mut fast_head_state) = store
|
||||
.get_inconsistent_state_for_attestation_verification_only(
|
||||
&head_root,
|
||||
Some(head_state.slot()),
|
||||
&head_block_root,
|
||||
head_state.slot(),
|
||||
head_state_root,
|
||||
)
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
@@ -577,14 +594,7 @@ async fn block_replayer_hooks() {
|
||||
async fn delete_blocks_and_states() {
|
||||
let db_path = tempdir().unwrap();
|
||||
let store = get_store(&db_path);
|
||||
let validators_keypairs =
|
||||
types::test_utils::generate_deterministic_keypairs(LOW_VALIDATOR_COUNT);
|
||||
let harness = TestHarness::builder(MinimalEthSpec)
|
||||
.default_spec()
|
||||
.keypairs(validators_keypairs)
|
||||
.fresh_disk_store(store.clone())
|
||||
.mock_execution_layer()
|
||||
.build();
|
||||
let harness = get_harness(store.clone(), LOW_VALIDATOR_COUNT);
|
||||
|
||||
let unforked_blocks: u64 = 4 * E::slots_per_epoch();
|
||||
|
||||
@@ -1027,18 +1037,14 @@ fn check_shuffling_compatible(
|
||||
// Ensure blocks from abandoned forks are pruned from the Hot DB
|
||||
#[tokio::test]
|
||||
async fn prunes_abandoned_fork_between_two_finalized_checkpoints() {
|
||||
const HONEST_VALIDATOR_COUNT: usize = 32 + 0;
|
||||
const ADVERSARIAL_VALIDATOR_COUNT: usize = 16 - 0;
|
||||
const HONEST_VALIDATOR_COUNT: usize = 32;
|
||||
const ADVERSARIAL_VALIDATOR_COUNT: usize = 16;
|
||||
const VALIDATOR_COUNT: usize = HONEST_VALIDATOR_COUNT + ADVERSARIAL_VALIDATOR_COUNT;
|
||||
let validators_keypairs = types::test_utils::generate_deterministic_keypairs(VALIDATOR_COUNT);
|
||||
let honest_validators: Vec<usize> = (0..HONEST_VALIDATOR_COUNT).collect();
|
||||
let adversarial_validators: Vec<usize> = (HONEST_VALIDATOR_COUNT..VALIDATOR_COUNT).collect();
|
||||
let rig = BeaconChainHarness::builder(MinimalEthSpec)
|
||||
.default_spec()
|
||||
.keypairs(validators_keypairs)
|
||||
.fresh_ephemeral_store()
|
||||
.mock_execution_layer()
|
||||
.build();
|
||||
let db_path = tempdir().unwrap();
|
||||
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();
|
||||
|
||||
@@ -1137,18 +1143,14 @@ async fn prunes_abandoned_fork_between_two_finalized_checkpoints() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn pruning_does_not_touch_abandoned_block_shared_with_canonical_chain() {
|
||||
const HONEST_VALIDATOR_COUNT: usize = 32 + 0;
|
||||
const ADVERSARIAL_VALIDATOR_COUNT: usize = 16 - 0;
|
||||
const HONEST_VALIDATOR_COUNT: usize = 32;
|
||||
const ADVERSARIAL_VALIDATOR_COUNT: usize = 16;
|
||||
const VALIDATOR_COUNT: usize = HONEST_VALIDATOR_COUNT + ADVERSARIAL_VALIDATOR_COUNT;
|
||||
let validators_keypairs = types::test_utils::generate_deterministic_keypairs(VALIDATOR_COUNT);
|
||||
let honest_validators: Vec<usize> = (0..HONEST_VALIDATOR_COUNT).collect();
|
||||
let adversarial_validators: Vec<usize> = (HONEST_VALIDATOR_COUNT..VALIDATOR_COUNT).collect();
|
||||
let rig = BeaconChainHarness::builder(MinimalEthSpec)
|
||||
.default_spec()
|
||||
.keypairs(validators_keypairs)
|
||||
.fresh_ephemeral_store()
|
||||
.mock_execution_layer()
|
||||
.build();
|
||||
let db_path = tempdir().unwrap();
|
||||
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();
|
||||
|
||||
@@ -1272,15 +1274,11 @@ async fn pruning_does_not_touch_blocks_prior_to_finalization() {
|
||||
const HONEST_VALIDATOR_COUNT: usize = 32;
|
||||
const ADVERSARIAL_VALIDATOR_COUNT: usize = 16;
|
||||
const VALIDATOR_COUNT: usize = HONEST_VALIDATOR_COUNT + ADVERSARIAL_VALIDATOR_COUNT;
|
||||
let validators_keypairs = types::test_utils::generate_deterministic_keypairs(VALIDATOR_COUNT);
|
||||
let honest_validators: Vec<usize> = (0..HONEST_VALIDATOR_COUNT).collect();
|
||||
let adversarial_validators: Vec<usize> = (HONEST_VALIDATOR_COUNT..VALIDATOR_COUNT).collect();
|
||||
let rig = BeaconChainHarness::builder(MinimalEthSpec)
|
||||
.default_spec()
|
||||
.keypairs(validators_keypairs)
|
||||
.fresh_ephemeral_store()
|
||||
.mock_execution_layer()
|
||||
.build();
|
||||
let db_path = tempdir().unwrap();
|
||||
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();
|
||||
|
||||
@@ -1364,18 +1362,14 @@ async fn pruning_does_not_touch_blocks_prior_to_finalization() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn prunes_fork_growing_past_youngest_finalized_checkpoint() {
|
||||
const HONEST_VALIDATOR_COUNT: usize = 32 + 0;
|
||||
const ADVERSARIAL_VALIDATOR_COUNT: usize = 16 - 0;
|
||||
const HONEST_VALIDATOR_COUNT: usize = 32;
|
||||
const ADVERSARIAL_VALIDATOR_COUNT: usize = 16;
|
||||
const VALIDATOR_COUNT: usize = HONEST_VALIDATOR_COUNT + ADVERSARIAL_VALIDATOR_COUNT;
|
||||
let validators_keypairs = types::test_utils::generate_deterministic_keypairs(VALIDATOR_COUNT);
|
||||
let honest_validators: Vec<usize> = (0..HONEST_VALIDATOR_COUNT).collect();
|
||||
let adversarial_validators: Vec<usize> = (HONEST_VALIDATOR_COUNT..VALIDATOR_COUNT).collect();
|
||||
let rig = BeaconChainHarness::builder(MinimalEthSpec)
|
||||
.default_spec()
|
||||
.keypairs(validators_keypairs)
|
||||
.fresh_ephemeral_store()
|
||||
.mock_execution_layer()
|
||||
.build();
|
||||
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();
|
||||
|
||||
// Fill up 0th epoch with canonical chain blocks
|
||||
@@ -1509,18 +1503,14 @@ async fn prunes_fork_growing_past_youngest_finalized_checkpoint() {
|
||||
// This is to check if state outside of normal block processing are pruned correctly.
|
||||
#[tokio::test]
|
||||
async fn prunes_skipped_slots_states() {
|
||||
const HONEST_VALIDATOR_COUNT: usize = 32 + 0;
|
||||
const ADVERSARIAL_VALIDATOR_COUNT: usize = 16 - 0;
|
||||
const HONEST_VALIDATOR_COUNT: usize = 32;
|
||||
const ADVERSARIAL_VALIDATOR_COUNT: usize = 16;
|
||||
const VALIDATOR_COUNT: usize = HONEST_VALIDATOR_COUNT + ADVERSARIAL_VALIDATOR_COUNT;
|
||||
let validators_keypairs = types::test_utils::generate_deterministic_keypairs(VALIDATOR_COUNT);
|
||||
let honest_validators: Vec<usize> = (0..HONEST_VALIDATOR_COUNT).collect();
|
||||
let adversarial_validators: Vec<usize> = (HONEST_VALIDATOR_COUNT..VALIDATOR_COUNT).collect();
|
||||
let rig = BeaconChainHarness::builder(MinimalEthSpec)
|
||||
.default_spec()
|
||||
.keypairs(validators_keypairs)
|
||||
.fresh_ephemeral_store()
|
||||
.mock_execution_layer()
|
||||
.build();
|
||||
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 canonical_slots_zeroth_epoch: Vec<Slot> =
|
||||
@@ -1638,18 +1628,14 @@ async fn prunes_skipped_slots_states() {
|
||||
// This is to check if state outside of normal block processing are pruned correctly.
|
||||
#[tokio::test]
|
||||
async fn finalizes_non_epoch_start_slot() {
|
||||
const HONEST_VALIDATOR_COUNT: usize = 32 + 0;
|
||||
const ADVERSARIAL_VALIDATOR_COUNT: usize = 16 - 0;
|
||||
const HONEST_VALIDATOR_COUNT: usize = 32;
|
||||
const ADVERSARIAL_VALIDATOR_COUNT: usize = 16;
|
||||
const VALIDATOR_COUNT: usize = HONEST_VALIDATOR_COUNT + ADVERSARIAL_VALIDATOR_COUNT;
|
||||
let validators_keypairs = types::test_utils::generate_deterministic_keypairs(VALIDATOR_COUNT);
|
||||
let honest_validators: Vec<usize> = (0..HONEST_VALIDATOR_COUNT).collect();
|
||||
let adversarial_validators: Vec<usize> = (HONEST_VALIDATOR_COUNT..VALIDATOR_COUNT).collect();
|
||||
let rig = BeaconChainHarness::builder(MinimalEthSpec)
|
||||
.default_spec()
|
||||
.keypairs(validators_keypairs)
|
||||
.fresh_ephemeral_store()
|
||||
.mock_execution_layer()
|
||||
.build();
|
||||
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 canonical_slots_zeroth_epoch: Vec<Slot> =
|
||||
@@ -2068,39 +2054,82 @@ async fn garbage_collect_temp_states_from_failed_block() {
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn weak_subjectivity_sync() {
|
||||
async fn weak_subjectivity_sync_easy() {
|
||||
let num_initial_slots = E::slots_per_epoch() * 11;
|
||||
let checkpoint_slot = Slot::new(E::slots_per_epoch() * 9);
|
||||
let slots = (1..num_initial_slots).map(Slot::new).collect();
|
||||
weak_subjectivity_sync_test(slots, checkpoint_slot).await
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn weak_subjectivity_sync_unaligned_advanced_checkpoint() {
|
||||
let num_initial_slots = E::slots_per_epoch() * 11;
|
||||
let checkpoint_slot = Slot::new(E::slots_per_epoch() * 9);
|
||||
let slots = (1..num_initial_slots)
|
||||
.map(Slot::new)
|
||||
.filter(|&slot| {
|
||||
// Skip 3 slots leading up to the checkpoint slot.
|
||||
slot <= checkpoint_slot - 3 || slot > checkpoint_slot
|
||||
})
|
||||
.collect();
|
||||
weak_subjectivity_sync_test(slots, checkpoint_slot).await
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn weak_subjectivity_sync_unaligned_unadvanced_checkpoint() {
|
||||
let num_initial_slots = E::slots_per_epoch() * 11;
|
||||
let checkpoint_slot = Slot::new(E::slots_per_epoch() * 9 - 3);
|
||||
let slots = (1..num_initial_slots)
|
||||
.map(Slot::new)
|
||||
.filter(|&slot| {
|
||||
// Skip 3 slots after the checkpoint slot.
|
||||
slot <= checkpoint_slot || slot > checkpoint_slot + 3
|
||||
})
|
||||
.collect();
|
||||
weak_subjectivity_sync_test(slots, checkpoint_slot).await
|
||||
}
|
||||
|
||||
async fn weak_subjectivity_sync_test(slots: Vec<Slot>, checkpoint_slot: Slot) {
|
||||
// Build an initial chain on one harness, representing a synced node with full history.
|
||||
let num_initial_blocks = E::slots_per_epoch() * 11;
|
||||
let num_final_blocks = E::slots_per_epoch() * 2;
|
||||
|
||||
let temp1 = tempdir().unwrap();
|
||||
let full_store = get_store(&temp1);
|
||||
let harness = get_harness(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();
|
||||
harness
|
||||
.extend_chain(
|
||||
num_initial_blocks as usize,
|
||||
BlockStrategy::OnCanonicalHead,
|
||||
AttestationStrategy::AllValidators,
|
||||
.add_attested_blocks_at_slots(
|
||||
genesis_state.clone(),
|
||||
genesis_state_root,
|
||||
&slots,
|
||||
&all_validators,
|
||||
)
|
||||
.await;
|
||||
|
||||
let genesis_state = full_store
|
||||
.get_state(&harness.chain.genesis_state_root, Some(Slot::new(0)))
|
||||
let wss_block_root = harness
|
||||
.chain
|
||||
.block_root_at_slot(checkpoint_slot, WhenSlotSkipped::Prev)
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
let wss_checkpoint = harness.finalized_checkpoint();
|
||||
let wss_state_root = harness
|
||||
.chain
|
||||
.state_root_at_slot(checkpoint_slot)
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
|
||||
let wss_block = harness
|
||||
.chain
|
||||
.store
|
||||
.get_full_block(&wss_checkpoint.root)
|
||||
.get_full_block(&wss_block_root)
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
let wss_state = full_store
|
||||
.get_state(&wss_block.state_root(), None)
|
||||
.get_state(&wss_state_root, Some(checkpoint_slot))
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
let wss_slot = wss_block.slot();
|
||||
|
||||
// Add more blocks that advance finalization further.
|
||||
harness.advance_slot();
|
||||
@@ -2130,19 +2159,25 @@ async fn weak_subjectivity_sync() {
|
||||
None,
|
||||
);
|
||||
|
||||
// Initialise a new beacon chain from the finalized checkpoint
|
||||
// Initialise a new beacon chain from the finalized checkpoint.
|
||||
// The slot clock must be set to a time ahead of the checkpoint state.
|
||||
let slot_clock = TestingSlotClock::new(
|
||||
Slot::new(0),
|
||||
Duration::from_secs(harness.chain.genesis_time),
|
||||
Duration::from_secs(seconds_per_slot),
|
||||
);
|
||||
slot_clock.set_slot(harness.get_current_slot().as_u64());
|
||||
let beacon_chain = BeaconChainBuilder::<DiskHarnessType<E>>::new(MinimalEthSpec)
|
||||
.store(store.clone())
|
||||
.custom_spec(test_spec::<E>())
|
||||
.task_executor(harness.chain.task_executor.clone())
|
||||
.logger(log.clone())
|
||||
.weak_subjectivity_state(wss_state, wss_block.clone(), genesis_state)
|
||||
.unwrap()
|
||||
.logger(log.clone())
|
||||
.store_migrator_config(MigratorConfig::default().blocking())
|
||||
.dummy_eth1_backend()
|
||||
.expect("should build dummy backend")
|
||||
.testing_slot_clock(Duration::from_secs(seconds_per_slot))
|
||||
.expect("should configure testing slot clock")
|
||||
.slot_clock(slot_clock)
|
||||
.shutdown_sender(shutdown_tx)
|
||||
.chain_config(ChainConfig::default())
|
||||
.event_handler(Some(ServerSentEventHandler::new_with_capacity(
|
||||
@@ -2159,9 +2194,9 @@ async fn weak_subjectivity_sync() {
|
||||
|
||||
// Apply blocks forward to reach head.
|
||||
let chain_dump = harness.chain.chain_dump().unwrap();
|
||||
let new_blocks = &chain_dump[wss_slot.as_usize() + 1..];
|
||||
|
||||
assert_eq!(new_blocks[0].beacon_block.slot(), wss_slot + 1);
|
||||
let new_blocks = chain_dump
|
||||
.iter()
|
||||
.filter(|snapshot| snapshot.beacon_block.slot() > checkpoint_slot);
|
||||
|
||||
for snapshot in new_blocks {
|
||||
let block_root = snapshot.beacon_block_root;
|
||||
@@ -2271,13 +2306,17 @@ async fn weak_subjectivity_sync() {
|
||||
assert_eq!(forwards, expected);
|
||||
|
||||
// All blocks can be loaded.
|
||||
let mut prev_block_root = Hash256::zero();
|
||||
for (block_root, slot) in beacon_chain
|
||||
.forwards_iter_block_roots(Slot::new(0))
|
||||
.unwrap()
|
||||
.map(Result::unwrap)
|
||||
{
|
||||
let block = store.get_blinded_block(&block_root).unwrap().unwrap();
|
||||
assert_eq!(block.slot(), slot);
|
||||
if block_root != prev_block_root {
|
||||
assert_eq!(block.slot(), slot);
|
||||
}
|
||||
prev_block_root = block_root;
|
||||
}
|
||||
|
||||
// All states from the oldest state slot can be loaded.
|
||||
@@ -2292,14 +2331,141 @@ async fn weak_subjectivity_sync() {
|
||||
assert_eq!(state.canonical_root(), state_root);
|
||||
}
|
||||
|
||||
// Anchor slot is still set to the starting slot.
|
||||
assert_eq!(store.get_anchor_slot(), Some(wss_slot));
|
||||
// Anchor slot is still set to the slot of the checkpoint block.
|
||||
assert_eq!(store.get_anchor_slot(), Some(wss_block.slot()));
|
||||
|
||||
// Reconstruct states.
|
||||
store.clone().reconstruct_historic_states().unwrap();
|
||||
assert_eq!(store.get_anchor_slot(), None);
|
||||
}
|
||||
|
||||
/// Test that blocks and attestations that refer to states around an unaligned split state are
|
||||
/// processed correctly.
|
||||
#[tokio::test]
|
||||
async fn process_blocks_and_attestations_for_unaligned_checkpoint() {
|
||||
let temp = tempdir().unwrap();
|
||||
let store = get_store(&temp);
|
||||
let chain_config = ChainConfig {
|
||||
reconstruct_historic_states: false,
|
||||
..ChainConfig::default()
|
||||
};
|
||||
let harness = get_harness_generic(store.clone(), LOW_VALIDATOR_COUNT, chain_config);
|
||||
|
||||
let all_validators = (0..LOW_VALIDATOR_COUNT).collect::<Vec<_>>();
|
||||
|
||||
let split_slot = Slot::new(E::slots_per_epoch() * 4);
|
||||
let pre_skips = 1;
|
||||
let post_skips = 1;
|
||||
|
||||
// Build the chain up to the intended split slot, with 3 skips before the split.
|
||||
let slots = (1..=split_slot.as_u64() - pre_skips)
|
||||
.map(Slot::new)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let (genesis_state, genesis_state_root) = harness.get_current_state_and_root();
|
||||
harness
|
||||
.add_attested_blocks_at_slots(
|
||||
genesis_state.clone(),
|
||||
genesis_state_root,
|
||||
&slots,
|
||||
&all_validators,
|
||||
)
|
||||
.await;
|
||||
|
||||
// Before the split slot becomes finalized, create two forking blocks that build on the split
|
||||
// block:
|
||||
//
|
||||
// - one that is invalid because it conflicts with finalization (slot <= finalized_slot)
|
||||
// - one that is valid because its slot is not finalized (slot > finalized_slot)
|
||||
let (unadvanced_split_state, unadvanced_split_state_root) =
|
||||
harness.get_current_state_and_root();
|
||||
|
||||
let (invalid_fork_block, _) = harness
|
||||
.make_block(unadvanced_split_state.clone(), split_slot)
|
||||
.await;
|
||||
let (valid_fork_block, _) = harness
|
||||
.make_block(unadvanced_split_state.clone(), split_slot + 1)
|
||||
.await;
|
||||
|
||||
// Advance the chain so that the intended split slot is finalized.
|
||||
// Do not attest in the epoch boundary slot, to make attestation production later easier (no
|
||||
// equivocations).
|
||||
let finalizing_slot = split_slot + 2 * E::slots_per_epoch();
|
||||
for _ in 0..pre_skips + post_skips {
|
||||
harness.advance_slot();
|
||||
}
|
||||
harness.extend_to_slot(finalizing_slot - 1).await;
|
||||
harness
|
||||
.add_block_at_slot(finalizing_slot, harness.get_current_state())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Check that the split slot is as intended.
|
||||
let split = store.get_split_info();
|
||||
assert_eq!(split.slot, split_slot);
|
||||
assert_eq!(split.block_root, valid_fork_block.parent_root());
|
||||
assert_ne!(split.state_root, unadvanced_split_state_root);
|
||||
|
||||
// Applying the invalid block should fail.
|
||||
let err = harness
|
||||
.chain
|
||||
.process_block(
|
||||
invalid_fork_block.canonical_root(),
|
||||
Arc::new(invalid_fork_block.clone()),
|
||||
NotifyExecutionLayer::Yes,
|
||||
|| Ok(()),
|
||||
)
|
||||
.await
|
||||
.unwrap_err();
|
||||
assert!(matches!(err, BlockError::WouldRevertFinalizedSlot { .. }));
|
||||
|
||||
// Applying the valid block should succeed, but it should not become head.
|
||||
harness
|
||||
.chain
|
||||
.process_block(
|
||||
valid_fork_block.canonical_root(),
|
||||
Arc::new(valid_fork_block.clone()),
|
||||
NotifyExecutionLayer::Yes,
|
||||
|| Ok(()),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
harness.chain.recompute_head_at_current_slot().await;
|
||||
assert_ne!(harness.head_block_root(), valid_fork_block.canonical_root());
|
||||
|
||||
// Attestations to the split block in the next 2 epochs should be processed successfully.
|
||||
let attestation_start_slot = harness.get_current_slot();
|
||||
let attestation_end_slot = attestation_start_slot + 2 * E::slots_per_epoch();
|
||||
let (split_state_root, mut advanced_split_state) = harness
|
||||
.chain
|
||||
.store
|
||||
.get_advanced_hot_state(split.block_root, split.slot, split.state_root)
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
complete_state_advance(
|
||||
&mut advanced_split_state,
|
||||
Some(split_state_root),
|
||||
attestation_start_slot,
|
||||
&harness.chain.spec,
|
||||
)
|
||||
.unwrap();
|
||||
advanced_split_state
|
||||
.build_caches(&harness.chain.spec)
|
||||
.unwrap();
|
||||
let advanced_split_state_root = advanced_split_state.update_tree_hash_cache().unwrap();
|
||||
for slot in (attestation_start_slot.as_u64()..attestation_end_slot.as_u64()).map(Slot::new) {
|
||||
let attestations = harness.make_attestations(
|
||||
&all_validators,
|
||||
&advanced_split_state,
|
||||
advanced_split_state_root,
|
||||
split.block_root.into(),
|
||||
slot,
|
||||
);
|
||||
harness.advance_slot();
|
||||
harness.process_attestations(attestations);
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn finalizes_after_resuming_from_db() {
|
||||
let validator_count = 16;
|
||||
@@ -2358,6 +2524,7 @@ async fn finalizes_after_resuming_from_db() {
|
||||
.default_spec()
|
||||
.keypairs(KEYPAIRS[0..validator_count].to_vec())
|
||||
.resumed_disk_store(store)
|
||||
.testing_slot_clock(original_chain.slot_clock.clone())
|
||||
.execution_layer(original_chain.execution_layer.clone())
|
||||
.build();
|
||||
|
||||
@@ -2611,6 +2778,9 @@ async fn schema_downgrade_to_min_version() {
|
||||
SchemaVersion(11)
|
||||
};
|
||||
|
||||
// Save the slot clock so that the new harness doesn't revert in time.
|
||||
let slot_clock = harness.chain.slot_clock.clone();
|
||||
|
||||
// Close the database to ensure everything is written to disk.
|
||||
drop(store);
|
||||
drop(harness);
|
||||
@@ -2641,11 +2811,21 @@ async fn schema_downgrade_to_min_version() {
|
||||
)
|
||||
.expect("schema upgrade from minimum version should work");
|
||||
|
||||
// Rescreate the harness.
|
||||
// Recreate the harness.
|
||||
/*
|
||||
let slot_clock = TestingSlotClock::new(
|
||||
Slot::new(0),
|
||||
Duration::from_secs(harness.chain.genesis_time),
|
||||
Duration::from_secs(spec.seconds_per_slot),
|
||||
);
|
||||
slot_clock.set_slot(harness.get_current_slot().as_u64());
|
||||
*/
|
||||
|
||||
let harness = BeaconChainHarness::builder(MinimalEthSpec)
|
||||
.default_spec()
|
||||
.keypairs(KEYPAIRS[0..LOW_VALIDATOR_COUNT].to_vec())
|
||||
.logger(store.logger().clone())
|
||||
.testing_slot_clock(slot_clock)
|
||||
.resumed_disk_store(store.clone())
|
||||
.mock_execution_layer()
|
||||
.build();
|
||||
|
||||
@@ -6,7 +6,7 @@ use beacon_chain::{
|
||||
AttestationStrategy, BeaconChainHarness, BlockStrategy, EphemeralHarnessType,
|
||||
OP_POOL_DB_KEY,
|
||||
},
|
||||
BeaconChain, NotifyExecutionLayer, StateSkipConfig, WhenSlotSkipped,
|
||||
BeaconChain, ChainConfig, NotifyExecutionLayer, StateSkipConfig, WhenSlotSkipped,
|
||||
};
|
||||
use lazy_static::lazy_static;
|
||||
use operation_pool::PersistedOperationPool;
|
||||
@@ -28,6 +28,10 @@ lazy_static! {
|
||||
fn get_harness(validator_count: usize) -> BeaconChainHarness<EphemeralHarnessType<MinimalEthSpec>> {
|
||||
let harness = BeaconChainHarness::builder(MinimalEthSpec)
|
||||
.default_spec()
|
||||
.chain_config(ChainConfig {
|
||||
reconstruct_historic_states: true,
|
||||
..ChainConfig::default()
|
||||
})
|
||||
.keypairs(KEYPAIRS[0..validator_count].to_vec())
|
||||
.fresh_ephemeral_store()
|
||||
.mock_execution_layer()
|
||||
|
||||
Reference in New Issue
Block a user