mirror of
https://github.com/sigp/lighthouse.git
synced 2026-04-19 22:08:30 +00:00
Hierarchical state diffs in hot DB (#6750)
This PR implements https://github.com/sigp/lighthouse/pull/5978 (tree-states) but on the hot DB. It allows Lighthouse to massively reduce its disk footprint during non-finality and overall I/O in all cases.
Closes https://github.com/sigp/lighthouse/issues/6580
Conga into https://github.com/sigp/lighthouse/pull/6744
### TODOs
- [x] Fix OOM in CI https://github.com/sigp/lighthouse/pull/7176
- [x] optimise store_hot_state to avoid storing a duplicate state if the summary already exists (should be safe from races now that pruning is cleaner)
- [x] mispelled: get_ancenstor_state_root
- [x] get_ancestor_state_root should use state summaries
- [x] Prevent split from changing during ancestor calc
- [x] Use same hierarchy for hot and cold
### TODO Good optimization for future PRs
- [ ] On the migration, if the latest hot snapshot is aligned with the cold snapshot migrate the diffs instead of the full states.
```
align slot time
10485760 Nov-26-2024
12582912 Sep-14-2025
14680064 Jul-02-2026
```
### TODO Maybe things good to have
- [ ] Rename anchor_slot https://github.com/sigp/lighthouse/compare/tree-states-hot-rebase-oom...dapplion:lighthouse:tree-states-hot-anchor-slot-rename?expand=1
- [ ] Make anchor fields not public such that they must be mutated through a method. To prevent un-wanted changes of the anchor_slot
### NOTTODO
- [ ] Use fork-choice and a new method [`descendants_of_checkpoint`](ca2388e196 (diff-046fbdb517ca16b80e4464c2c824cf001a74a0a94ac0065e635768ac391062a8)) to filter only the state summaries that descend of finalized checkpoint]
This commit is contained in:
@@ -3,6 +3,7 @@ use std::{
|
||||
cmp::Ordering,
|
||||
collections::{btree_map::Entry, BTreeMap, HashMap},
|
||||
};
|
||||
use store::HotStateSummary;
|
||||
use types::{Hash256, Slot};
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
@@ -57,6 +58,12 @@ pub enum Error {
|
||||
root_state_root: Hash256,
|
||||
root_state_slot: Slot,
|
||||
},
|
||||
CircularAncestorChain {
|
||||
state_root: Hash256,
|
||||
previous_state_root: Hash256,
|
||||
slot: Slot,
|
||||
last_slot: Slot,
|
||||
},
|
||||
}
|
||||
|
||||
impl StateSummariesDAG {
|
||||
@@ -311,10 +318,24 @@ impl StateSummariesDAG {
|
||||
}
|
||||
|
||||
let mut ancestors = vec![];
|
||||
let mut last_slot = None;
|
||||
loop {
|
||||
if let Some(summary) = self.state_summaries_by_state_root.get(&state_root) {
|
||||
// Detect cycles, including the case where `previous_state_root == state_root`.
|
||||
if let Some(last_slot) = last_slot {
|
||||
if summary.slot >= last_slot {
|
||||
return Err(Error::CircularAncestorChain {
|
||||
state_root,
|
||||
previous_state_root: summary.previous_state_root,
|
||||
slot: summary.slot,
|
||||
last_slot,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
ancestors.push((state_root, summary.slot));
|
||||
state_root = summary.previous_state_root
|
||||
last_slot = Some(summary.slot);
|
||||
state_root = summary.previous_state_root;
|
||||
} else {
|
||||
return Ok(ancestors);
|
||||
}
|
||||
@@ -336,6 +357,17 @@ impl StateSummariesDAG {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<HotStateSummary> for DAGStateSummary {
|
||||
fn from(value: HotStateSummary) -> Self {
|
||||
Self {
|
||||
slot: value.slot,
|
||||
latest_block_root: value.latest_block_root,
|
||||
latest_block_slot: value.latest_block_slot,
|
||||
previous_state_root: value.previous_state_root,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{DAGStateSummaryV22, Error, StateSummariesDAG};
|
||||
|
||||
Reference in New Issue
Block a user