fix: revert slow path optimization that caused regression

The slow path optimization attempted to reuse ancestor cached overlays,
but those overlays were built with a DIFFERENT anchor_hash. Since the
slow path is triggered precisely because the anchor changed (after
persist/reorg), reusing overlays from the old anchor produces incorrect
results.

Reverted to the original slow path that rebuilds from each ancestor's
per-block state changes. The Arc::make_mut tracking metrics are kept.
This commit is contained in:
yongkangc
2026-01-06 23:26:01 +00:00
committed by Ubuntu
parent f073e6ec49
commit 5121ad2244

View File

@@ -256,36 +256,16 @@ impl DeferredTrieData {
/// Merge all ancestors into a single overlay.
///
/// This is the slow path used when the parent's overlay cannot be reused
/// (e.g., after persist when anchor changes).
/// (e.g., after persist when anchor changes). Iterates ancestors oldest -> newest
/// so newer state takes precedence.
///
/// # Optimization
/// Instead of iterating all ancestors from scratch, we find the most recent
/// ancestor that has a cached `anchored_trie_input` and use that as the base.
/// This reduces O(N) work to O(N - M) work where M is the cached depth.
/// Note: We intentionally do NOT reuse ancestor cached overlays here because
/// those overlays were built with a different anchor_hash. The slow path is
/// triggered precisely because the anchor changed, so we must rebuild from
/// each ancestor's per-block state changes.
fn merge_ancestors_into_overlay(ancestors: &[Self]) -> TrieInputSorted {
// Find the most recent ancestor (searching from newest to oldest) that has
// a cached trie_input overlay. We can use that as our base and only merge
// the remaining ancestors.
let mut base_idx = 0;
let mut overlay = TrieInputSorted::default();
for (idx, ancestor) in ancestors.iter().enumerate().rev() {
let ancestor_data = ancestor.wait_cloned();
if let Some(anchored) = &ancestor_data.anchored_trie_input {
// Found a cached overlay! Use it as our base.
// We only need to merge ancestors after this one.
overlay = TrieInputSorted::new(
Arc::clone(&anchored.trie_input.nodes),
Arc::clone(&anchored.trie_input.state),
Default::default(),
);
base_idx = idx + 1; // Start merging from the next ancestor
break;
}
}
// Merge only the ancestors after the cached base (if any)
for ancestor in &ancestors[base_idx..] {
for ancestor in ancestors {
let ancestor_data = ancestor.wait_cloned();
{
let will_clone = Arc::strong_count(&overlay.state) > 1;