Skip to content

Commit d58d8ef

Browse files
committed
Update tests
1 parent f8dbda4 commit d58d8ef

File tree

2 files changed

+30
-71
lines changed

2 files changed

+30
-71
lines changed

beacon_node/beacon_chain/tests/store_tests.rs

Lines changed: 22 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ use store::{
3131
BlobInfo, DBColumn, HotColdDB, StoreConfig,
3232
};
3333
use tempfile::{tempdir, TempDir};
34-
use tokio::time::sleep;
3534
use types::test_utils::{SeedableRng, XorShiftRng};
3635
use types::*;
3736

@@ -119,6 +118,17 @@ fn get_harness_generic(
119118
harness
120119
}
121120

121+
fn count_states_descendant_of_block(
122+
store: &HotColdDB<E, BeaconNodeBackend<E>, BeaconNodeBackend<E>>,
123+
block_root: Hash256,
124+
) -> usize {
125+
let summaries = store.load_hot_state_summaries().unwrap();
126+
summaries
127+
.iter()
128+
.filter(|(_, s)| s.latest_block_root == block_root)
129+
.count()
130+
}
131+
122132
#[tokio::test]
123133
async fn light_client_bootstrap_test() {
124134
let spec = test_spec::<E>();
@@ -2136,64 +2146,6 @@ async fn pruning_test(
21362146
check_no_blocks_exist(&harness, stray_blocks.values());
21372147
}
21382148

2139-
#[tokio::test]
2140-
async fn garbage_collect_temp_states_from_failed_block_on_startup() {
2141-
let db_path = tempdir().unwrap();
2142-
2143-
// Wrap these functions to ensure the variables are dropped before we try to open another
2144-
// instance of the store.
2145-
let mut store = {
2146-
let store = get_store(&db_path);
2147-
let harness = get_harness(store.clone(), LOW_VALIDATOR_COUNT);
2148-
2149-
let slots_per_epoch = E::slots_per_epoch();
2150-
2151-
let genesis_state = harness.get_current_state();
2152-
let block_slot = Slot::new(2 * slots_per_epoch);
2153-
let ((signed_block, _), state) = harness.make_block(genesis_state, block_slot).await;
2154-
2155-
let (mut block, _) = (*signed_block).clone().deconstruct();
2156-
2157-
// Mutate the block to make it invalid, and re-sign it.
2158-
*block.state_root_mut() = Hash256::repeat_byte(0xff);
2159-
let proposer_index = block.proposer_index() as usize;
2160-
let block = Arc::new(block.sign(
2161-
&harness.validator_keypairs[proposer_index].sk,
2162-
&state.fork(),
2163-
state.genesis_validators_root(),
2164-
&harness.spec,
2165-
));
2166-
2167-
// The block should be rejected, but should store a bunch of temporary states.
2168-
harness.set_current_slot(block_slot);
2169-
harness
2170-
.process_block_result((block, None))
2171-
.await
2172-
.unwrap_err();
2173-
2174-
assert_eq!(
2175-
store.iter_temporary_state_roots().count(),
2176-
block_slot.as_usize() - 1
2177-
);
2178-
store
2179-
};
2180-
2181-
// Wait until all the references to the store have been dropped, this helps ensure we can
2182-
// re-open the store later.
2183-
loop {
2184-
store = if let Err(store_arc) = Arc::try_unwrap(store) {
2185-
sleep(Duration::from_millis(500)).await;
2186-
store_arc
2187-
} else {
2188-
break;
2189-
}
2190-
}
2191-
2192-
// On startup, the store should garbage collect all the temporary states.
2193-
let store = get_store(&db_path);
2194-
assert_eq!(store.iter_temporary_state_roots().count(), 0);
2195-
}
2196-
21972149
#[tokio::test]
21982150
async fn garbage_collect_temp_states_from_failed_block_on_finalization() {
21992151
let db_path = tempdir().unwrap();
@@ -2208,6 +2160,7 @@ async fn garbage_collect_temp_states_from_failed_block_on_finalization() {
22082160
let ((signed_block, _), state) = harness.make_block(genesis_state, block_slot).await;
22092161

22102162
let (mut block, _) = (*signed_block).clone().deconstruct();
2163+
let bad_block_parent_root = block.parent_root();
22112164

22122165
// Mutate the block to make it invalid, and re-sign it.
22132166
*block.state_root_mut() = Hash256::repeat_byte(0xff);
@@ -2226,9 +2179,11 @@ async fn garbage_collect_temp_states_from_failed_block_on_finalization() {
22262179
.await
22272180
.unwrap_err();
22282181

2182+
// The bad block parent root is the genesis block root. There's `block_slot - 1` temporary
2183+
// states to remove + the genesis state = block_slot.
22292184
assert_eq!(
2230-
store.iter_temporary_state_roots().count(),
2231-
block_slot.as_usize() - 1
2185+
count_states_descendant_of_block(&store, bad_block_parent_root),
2186+
block_slot.as_usize(),
22322187
);
22332188

22342189
// Finalize the chain without the block, which should result in pruning of all temporary states.
@@ -2245,8 +2200,12 @@ async fn garbage_collect_temp_states_from_failed_block_on_finalization() {
22452200
// Check that the finalization migration ran.
22462201
assert_ne!(store.get_split_slot(), 0);
22472202

2248-
// Check that temporary states have been pruned.
2249-
assert_eq!(store.iter_temporary_state_roots().count(), 0);
2203+
// Check that temporary states have been pruned. The genesis block is not a descendant of the
2204+
// latest finalized checkpoint, so all its states have been pruned from the hot DB, = 0.
2205+
assert_eq!(
2206+
count_states_descendant_of_block(&store, bad_block_parent_root),
2207+
0
2208+
);
22502209
}
22512210

22522211
#[tokio::test]

beacon_node/store/src/hot_cold_store.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ use crate::metadata::{
1414
};
1515
use crate::state_cache::{PutStateOutcome, StateCache};
1616
use crate::{
17-
get_data_column_key, metrics, parse_data_column_key, BlobSidecarListFromRoot, ColumnKeyIter,
18-
DBColumn, DatabaseBlock, Error, ItemStore, KeyValueStore, KeyValueStoreOp, StoreItem, StoreOp,
17+
get_data_column_key, metrics, parse_data_column_key, BlobSidecarListFromRoot, DBColumn,
18+
DatabaseBlock, Error, ItemStore, KeyValueStoreOp, StoreItem, StoreOp,
1919
};
2020
use itertools::{process_results, Itertools};
2121
use lru::LruCache;
@@ -395,6 +395,12 @@ impl<E: EthSpec> HotColdDB<E, BeaconNodeBackend<E>, BeaconNodeBackend<E>> {
395395
}
396396
db.store_config()?;
397397

398+
// TODO(tree-states): Here we can choose to prune advanced states to reclaim disk space. As
399+
// it's a foreground task there's no risk of race condition that can corrupt the DB.
400+
// Advanced states for invalid blocks that were never written to the DB, or descendants of
401+
// heads can be safely pruned at the expense of potentially having to recompute them in the
402+
// future. However this would require a new dedicated pruning routine.
403+
398404
// If configured, run a foreground compaction pass.
399405
if db.config.compact_on_init {
400406
info!(db.log, "Running foreground compaction");
@@ -404,12 +410,6 @@ impl<E: EthSpec> HotColdDB<E, BeaconNodeBackend<E>, BeaconNodeBackend<E>> {
404410

405411
Ok(db)
406412
}
407-
408-
/// Return an iterator over the state roots of all temporary states.
409-
pub fn iter_temporary_state_roots(&self) -> ColumnKeyIter<Hash256> {
410-
self.hot_db
411-
.iter_column_keys::<Hash256>(DBColumn::BeaconStateTemporary)
412-
}
413413
}
414414

415415
impl<E: EthSpec, Hot: ItemStore<E>, Cold: ItemStore<E>> HotColdDB<E, Hot, Cold> {

0 commit comments

Comments
 (0)