Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
95 commits
Select commit Hold shift + click to select a range
be105d1
Drop head tracker for summaries dag
dapplion Dec 28, 2024
8c15bab
Improve state summary dag compute logic
dapplion Jan 10, 2025
8c9a1b2
Implement db schema upgrade and downgrade
dapplion Jan 20, 2025
10bbb2e
Log about multiple roots in dag tree
dapplion Feb 3, 2025
28d7b74
Add states descendants_of
dapplion Feb 3, 2025
c5b4293
Prune descendants of finalized checkpoint not finalized block
dapplion Feb 3, 2025
066f96a
Prevent very long log line
dapplion Feb 3, 2025
663dfd3
Update tests
dapplion Feb 3, 2025
979e43a
Tweak logs
michaelsproul Feb 3, 2025
e56299c
Annotate SummariesDagError error
dapplion Feb 3, 2025
91eab38
Deprecate block DAG for pruning
dapplion Feb 3, 2025
12fa5a8
Remove some persisted head stuff
michaelsproul Feb 3, 2025
ed97b97
Use slot clock in heads
dapplion Feb 4, 2025
b9d8ae7
Fix nodes_without_children
dapplion Feb 4, 2025
7033656
Fix compilation and remove error from `heads`
michaelsproul Feb 14, 2025
1dc6d5e
Merge remote-tracking branch 'origin/unstable' into drop-headtracker
michaelsproul Feb 14, 2025
f6786eb
Tidy and document `migrate_database`.
michaelsproul Feb 14, 2025
37be9ae
Tweaks in `prune_hot_db`.
michaelsproul Feb 14, 2025
cf3b776
Correct assert in `revert_minority_fork_on_resume`
michaelsproul Feb 18, 2025
54010b0
Update consensus/proto_array/src/proto_array.rs
dapplion Feb 19, 2025
7abbaeb
Use descent from finality instead of viability
michaelsproul Feb 20, 2025
5cc266c
Clean up DB migrations
michaelsproul Feb 20, 2025
abb3c3f
Prevent deletion of payloads >= split slot
michaelsproul Feb 20, 2025
8931141
Abolish temporary states concept
michaelsproul Mar 6, 2025
f8dbda4
Add more details to errors
dapplion Mar 6, 2025
d58d8ef
Update tests
dapplion Mar 6, 2025
e6fb686
Send it boy
dapplion Mar 6, 2025
33615ea
Document migration better
dapplion Mar 6, 2025
36ab17c
Better traceability for hdiff errors
dapplion Mar 7, 2025
ecb647f
Fix column prefix bug
dapplion Mar 7, 2025
f020adb
Store latest_block_slot in state summary
dapplion Mar 7, 2025
ceb59e3
Don't log extra diffs as roots
dapplion Mar 7, 2025
4e74ed1
Fix wrapping sub
dapplion Mar 7, 2025
ebd05c7
Merge remote-tracking branch 'origin/unstable' into drop-headtracker
michaelsproul Mar 10, 2025
a613662
Merge remote-tracking branch 'origin/unstable' into drop-headtracker
michaelsproul Mar 11, 2025
3f23942
Merge remote-tracking branch 'origin/drop-headtracker' into tree-stat…
michaelsproul Mar 11, 2025
a928d30
Fix merge snafu
michaelsproul Mar 11, 2025
b43c071
Merge remote-tracking branch 'origin/unstable' into drop-headtracker
michaelsproul Mar 13, 2025
a1b45e6
Persist states even if in cache
dapplion Mar 7, 2025
9f36dc8
Don't include massive lists in errors
dapplion Mar 7, 2025
5b8680a
Merge remote-tracking branch 'origin/drop-headtracker' into tree-stat…
michaelsproul Mar 13, 2025
11cfa1c
Purge temporary states more, fixing bug
michaelsproul Mar 13, 2025
1c81c93
Merge remote-tracking branch 'origin/drop-headtracker' into tree-stat…
michaelsproul Mar 13, 2025
f4dd6fe
Clean up temporary flags on migration
dapplion Mar 17, 2025
a322463
Fix compilation
michaelsproul Mar 18, 2025
b49272f
Merge remote-tracking branch 'origin/drop-headtracker' into tree-stat…
michaelsproul Mar 18, 2025
9151436
Fix test OOM issues on tree-states-hot (#7176)
michaelsproul Apr 3, 2025
fcc96a1
Merge remote-tracking branch 'origin/unstable' into tree-states-hot-r…
michaelsproul Apr 7, 2025
74ebf8b
Fix clippy and tests
michaelsproul Apr 7, 2025
8657b08
Add note about multiple DAG roots
michaelsproul Apr 10, 2025
f70e543
Fix anchor archives
michaelsproul Apr 10, 2025
990ba80
Merge remote-tracking branch 'origin/unstable' into tree-states-hot-r…
michaelsproul Apr 10, 2025
00fbd82
Delete `transaction_mutex` in store (#7311)
hopinheimer Apr 15, 2025
fcbec47
Merge branch 'unstable' into tree-states-hot-rebase
michaelsproul Apr 15, 2025
088cfa0
Simplify migration logic
michaelsproul Apr 29, 2025
1184d72
More type-safe diff base state
michaelsproul Apr 29, 2025
54ded28
Use 0u8 inside DiffBaseState::Snapshot
michaelsproul Apr 29, 2025
8fa3665
Remove non-contiguous DAG checks
michaelsproul May 1, 2025
e1475a1
Prevent split from changing during ancestor calc
michaelsproul May 8, 2025
7d8343f
Use same hierarchy for hot and cold
michaelsproul May 8, 2025
c74913f
Merge branch 'unstable' into tree-states-hot-rebase
michaelsproul May 15, 2025
00ef82a
Update comment/remove TODO
michaelsproul May 19, 2025
f83b083
WIP remove pruning checkpoint
michaelsproul May 19, 2025
b681648
Merge remote-tracking branch 'origin/unstable' into tree-states-hot-r…
michaelsproul May 19, 2025
b73cb1e
Finish PruningCheckpoint thing
michaelsproul May 19, 2025
6887ad7
Tweak comments in v24 migration
michaelsproul May 19, 2025
1096565
Move legacy state storage code into migration file
michaelsproul May 19, 2025
c12dd1c
Split hdiff metrics by hot/cold
michaelsproul May 20, 2025
c39daf2
Correct V23 -> V24 in load_split comment
michaelsproul May 20, 2025
a4f442c
Clean up some more TODOs
michaelsproul May 20, 2025
5d8ddb6
Delete temporary states on migration
michaelsproul May 21, 2025
444c1cd
Add a test for states retained for hot diffs
michaelsproul May 21, 2025
d045796
Align hot grid to freezer when migrating archive nodes
michaelsproul May 22, 2025
2485beb
Add logging for downgrade
michaelsproul May 22, 2025
9800ab8
Attempt to fix archive node V24 upgrade
michaelsproul May 26, 2025
b0191db
Fix split slot migration
michaelsproul May 26, 2025
8ebe1b2
Add test for get_ancestor_state_root
michaelsproul May 27, 2025
78d0496
Rework store config and compatibility checks
michaelsproul May 28, 2025
9acb1cf
Fix one schema test and add a new one that's broken :sunglasses:
michaelsproul May 28, 2025
5fb55be
Fix migration of dense diffs
michaelsproul May 28, 2025
bc47fd6
Avoid putting pre-split states in the state cache
michaelsproul May 28, 2025
f0823fe
Merge remote-tracking branch 'origin/unstable' into tree-states-hot-r…
michaelsproul May 28, 2025
03fece6
Skip migrating pre-split states in downgrade
michaelsproul May 29, 2025
064115c
Fix DB manager downgrade
michaelsproul May 29, 2025
06c2632
Typo fix
michaelsproul May 29, 2025
6094e23
Clean up test assert
michaelsproul May 29, 2025
bb23f2a
Add a new test and fix split loading
michaelsproul May 29, 2025
80a5353
Remove some stale FIXMEs/typos
michaelsproul May 29, 2025
4913987
Merge remote-tracking branch 'origin/unstable' into tree-states-hot-r…
michaelsproul Jun 2, 2025
9e77f82
Remove FIXMEs/mess
michaelsproul Jun 2, 2025
22f7f73
Merge remote-tracking branch 'origin/unstable' into tree-states-hot-r…
michaelsproul Jun 11, 2025
707557a
Clean up hdiff timing metrics
michaelsproul Jun 11, 2025
9c8e58c
Metric for hdiff sizes
michaelsproul Jun 13, 2025
629fa73
Tweak hdiff size metric buckets
michaelsproul Jun 14, 2025
cb81f07
Hot hdiff buffer cache (#7615)
michaelsproul Jun 19, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions account_manager/src/validator/slashing_protection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ pub fn cli_run<E: EthSpec>(
let slashing_protection_database =
SlashingDatabase::open_or_create(&slashing_protection_db_path).map_err(|e| {
format!(
"Unable to open database at {}: {:?}",
"Unable to open slashing protection database at {}: {:?}",
slashing_protection_db_path.display(),
e
)
Expand Down Expand Up @@ -198,7 +198,7 @@ pub fn cli_run<E: EthSpec>(
let slashing_protection_database = SlashingDatabase::open(&slashing_protection_db_path)
.map_err(|e| {
format!(
"Unable to open database at {}: {:?}",
"Unable to open slashing protection database at {}: {:?}",
slashing_protection_db_path.display(),
e
)
Expand Down
16 changes: 11 additions & 5 deletions beacon_node/beacon_chain/src/beacon_chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ use std::time::Duration;
use store::iter::{BlockRootsIterator, ParentRootBlockIterator, StateRootsIterator};
use store::{
BlobSidecarListFromRoot, DatabaseBlock, Error as DBError, HotColdDB, HotStateSummary,
KeyValueStore, KeyValueStoreOp, StoreItem, StoreOp,
KeyValueStoreOp, StoreItem, StoreOp,
};
use task_executor::{ShutdownReason, TaskExecutor};
use tokio_stream::Stream;
Expand Down Expand Up @@ -3986,8 +3986,6 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
ops.push(StoreOp::PutBlock(block_root, signed_block.clone()));
ops.push(StoreOp::PutState(block.state_root(), &state));

let txn_lock = self.store.hot_db.begin_rw_transaction();

if let Err(e) = self.store.do_atomically_with_block_and_blobs_cache(ops) {
error!(
msg = "Restoring fork choice from disk",
Expand All @@ -3999,7 +3997,6 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
.err()
.unwrap_or(e.into()));
}
drop(txn_lock);

// The fork choice write-lock is dropped *after* the on-disk database has been updated.
// This prevents inconsistency between the two at the expense of concurrency.
Expand Down Expand Up @@ -6794,13 +6791,22 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
#[allow(clippy::type_complexity)]
pub fn chain_dump(
&self,
) -> Result<Vec<BeaconSnapshot<T::EthSpec, BlindedPayload<T::EthSpec>>>, Error> {
self.chain_dump_from_slot(Slot::new(0))
}

/// As for `chain_dump` but dumping only the portion of the chain newer than `from_slot`.
#[allow(clippy::type_complexity)]
pub fn chain_dump_from_slot(
&self,
from_slot: Slot,
) -> Result<Vec<BeaconSnapshot<T::EthSpec, BlindedPayload<T::EthSpec>>>, Error> {
let mut dump = vec![];

let mut prev_block_root = None;
let mut prev_beacon_state = None;

for res in self.forwards_iter_block_roots(Slot::new(0))? {
for res in self.forwards_iter_block_roots(from_slot)? {
let (beacon_block_root, _) = res?;

// Do not include snapshots at skipped slots.
Expand Down
25 changes: 8 additions & 17 deletions beacon_node/beacon_chain/src/block_verification.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ use std::fmt::Debug;
use std::fs;
use std::io::Write;
use std::sync::Arc;
use store::{Error as DBError, HotStateSummary, KeyValueStore, StoreOp};
use store::{Error as DBError, KeyValueStore};
use strum::AsRefStr;
use task_executor::JoinHandle;
use tracing::{debug, error};
Expand Down Expand Up @@ -1477,28 +1477,19 @@ impl<T: BeaconChainTypes> ExecutionPendingBlock<T> {
// processing, but we get early access to it.
let state_root = state.update_tree_hash_cache()?;

// Store the state immediately.
let txn_lock = chain.store.hot_db.begin_rw_transaction();
// Store the state immediately. States are ONLY deleted on finalization pruning, so
// we won't have race conditions where we should have written a state and didn't.
let state_already_exists =
chain.store.load_hot_state_summary(&state_root)?.is_some();

let state_batch = if state_already_exists {
if state_already_exists {
// If the state exists, we do not need to re-write it.
vec![]
} else {
vec![if state.slot() % T::EthSpec::slots_per_epoch() == 0 {
StoreOp::PutState(state_root, &state)
} else {
StoreOp::PutStateSummary(
state_root,
HotStateSummary::new(&state_root, &state)?,
)
}]
// Recycle store codepath to create a state summary and store the state / diff
let mut ops = vec![];
chain.store.store_hot_state(&state_root, &state, &mut ops)?;
chain.store.hot_db.do_atomically(ops)?;
};
chain
.store
.do_atomically_with_block_and_blobs_cache(state_batch)?;
drop(txn_lock);

state_root
};
Expand Down
66 changes: 45 additions & 21 deletions beacon_node/beacon_chain/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ use store::{Error as StoreError, HotColdDB, ItemStore, KeyValueStoreOp};
use task_executor::{ShutdownReason, TaskExecutor};
use tracing::{debug, error, info};
use types::{
BeaconBlock, BeaconState, BlobSidecarList, ChainSpec, Checkpoint, DataColumnSidecarList, Epoch,
EthSpec, FixedBytesExtended, Hash256, Signature, SignedBeaconBlock, Slot,
BeaconBlock, BeaconState, BlobSidecarList, ChainSpec, DataColumnSidecarList, Epoch, EthSpec,
FixedBytesExtended, Hash256, Signature, SignedBeaconBlock, Slot,
};

/// An empty struct used to "witness" all the `BeaconChainTypes` traits. It has no user-facing
Expand Down Expand Up @@ -380,21 +380,29 @@ where
}

/// Starts a new chain from a genesis state.
pub fn genesis_state(mut self, beacon_state: BeaconState<E>) -> Result<Self, String> {
pub fn genesis_state(mut self, mut beacon_state: BeaconState<E>) -> Result<Self, String> {
let store = self.store.clone().ok_or("genesis_state requires a store")?;

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.
// Initialize anchor info before attempting to write the genesis state.
// 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;
let genesis_beacon_block = genesis_block(&mut beacon_state, &self.spec)?;
self.pending_io_batch.push(
store
.init_anchor_info(genesis.beacon_block.message(), retain_historic_states)
.init_anchor_info(
genesis_beacon_block.parent_root(),
genesis_beacon_block.slot(),
Slot::new(0),
retain_historic_states,
)
.map_err(|e| format!("Failed to initialize genesis anchor: {:?}", e))?,
);

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.
self.pending_io_batch.push(
store
.init_blob_info(genesis.beacon_block.slot())
Expand Down Expand Up @@ -519,6 +527,13 @@ where
}
}

debug!(
slot = %weak_subj_slot,
state_root = ?weak_subj_state_root,
block_root = ?weak_subj_block_root,
"Storing split from weak subjectivity state"
);

// 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, weak_subj_block_root);
Expand All @@ -539,6 +554,26 @@ where
.cold_db
.do_atomically(block_root_batch)
.map_err(|e| format!("Error writing frozen block roots: {e:?}"))?;
debug!(
from = %weak_subj_block.slot(),
to_excl = %weak_subj_state.slot(),
block_root = ?weak_subj_block_root,
"Stored frozen block roots at skipped slots"
);

// Write the anchor to memory before calling `put_state` otherwise hot hdiff can't store
// states that do not align with the `start_slot` grid.
let retain_historic_states = self.chain_config.reconstruct_historic_states;
self.pending_io_batch.push(
store
.init_anchor_info(
weak_subj_block.parent_root(),
weak_subj_block.slot(),
weak_subj_slot,
retain_historic_states,
)
.map_err(|e| format!("Failed to initialize anchor info: {:?}", e))?,
);

// Write the state, block and blobs non-atomically, it doesn't matter if they're forgotten
// about on a crash restart.
Expand All @@ -549,6 +584,8 @@ where
weak_subj_state.clone(),
)
.map_err(|e| format!("Failed to set checkpoint state as finalized state: {:?}", e))?;
// Note: post hot hdiff must update the anchor info before attempting to put_state otherwise
// the write will fail if the weak_subj_slot is not aligned with the snapshot moduli.
store
.put_state(&weak_subj_state_root, &weak_subj_state)
.map_err(|e| format!("Failed to store weak subjectivity state: {e:?}"))?;
Expand Down Expand Up @@ -578,13 +615,7 @@ 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(), retain_historic_states)
.map_err(|e| format!("Failed to initialize anchor info: {:?}", e))?,
);
self.pending_io_batch.push(
store
.init_blob_info(weak_subj_block.slot())
Expand All @@ -596,13 +627,6 @@ where
.map_err(|e| format!("Failed to initialize data column info: {:?}", e))?,
);

// Store pruning checkpoint to prevent attempting to prune before the anchor state.
self.pending_io_batch
.push(store.pruning_checkpoint_store_op(Checkpoint {
root: weak_subj_block_root,
epoch: weak_subj_state.slot().epoch(E::slots_per_epoch()),
}));

let snapshot = BeaconSnapshot {
beacon_block_root: weak_subj_block_root,
beacon_block: Arc::new(weak_subj_block),
Expand Down
1 change: 1 addition & 0 deletions beacon_node/beacon_chain/src/historical_blocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {

// Store block roots, including at all skip slots in the freezer DB.
for slot in (block.slot().as_u64()..prev_block_slot.as_u64()).rev() {
debug!(%slot, ?block_root, "Storing frozen block to root mapping");
cold_batch.push(KeyValueStoreOp::PutKeyValue(
DBColumn::BeaconBlockRoots,
slot.to_be_bytes().to_vec(),
Expand Down
Loading