From b401cae82009c8859b9a019ed6e9d0f0fec57ec0 Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Mon, 8 Dec 2025 14:55:55 +0100 Subject: [PATCH 01/18] Receive sorted updates from chain --- crates/chain-state/src/in_memory.rs | 12 ++-- crates/evm/execution-types/src/chain.rs | 37 ++++++------ crates/optimism/exex/src/lib.rs | 10 +--- crates/optimism/trie/src/api.rs | 14 ++--- crates/optimism/trie/src/db/store.rs | 4 +- crates/optimism/trie/src/in_memory.rs | 75 ++++++++----------------- crates/optimism/trie/src/live.rs | 21 +++---- crates/trie/common/src/hashed_state.rs | 2 + 8 files changed, 72 insertions(+), 103 deletions(-) diff --git a/crates/chain-state/src/in_memory.rs b/crates/chain-state/src/in_memory.rs index 2cbb9aea667..730760a93e9 100644 --- a/crates/chain-state/src/in_memory.rs +++ b/crates/chain-state/src/in_memory.rs @@ -927,8 +927,8 @@ impl> NewCanonicalChain { chain.append_block( exec.recovered_block().clone(), exec.execution_outcome().clone(), - Arc::new((*exec.trie_updates()).clone().into()), - Arc::new((*exec.hashed_state()).clone().into()), + exec.trie_updates(), + exec.hashed_state(), ); chain })); @@ -939,8 +939,8 @@ impl> NewCanonicalChain { chain.append_block( exec.recovered_block().clone(), exec.execution_outcome().clone(), - Arc::new((*exec.trie_updates()).clone().into()), - Arc::new((*exec.hashed_state()).clone().into()), + exec.trie_updates(), + exec.hashed_state(), ); chain })); @@ -948,8 +948,8 @@ impl> NewCanonicalChain { chain.append_block( exec.recovered_block().clone(), exec.execution_outcome().clone(), - Arc::new((*exec.trie_updates()).clone().into()), - Arc::new((*exec.hashed_state()).clone().into()), + exec.trie_updates(), + exec.hashed_state(), ); chain })); diff --git a/crates/evm/execution-types/src/chain.rs b/crates/evm/execution-types/src/chain.rs index ae6719246c1..6f3da889328 100644 --- a/crates/evm/execution-types/src/chain.rs +++ b/crates/evm/execution-types/src/chain.rs @@ -10,7 +10,7 @@ use reth_primitives_traits::{ transaction::signed::SignedTransaction, Block, BlockBody, NodePrimitives, RecoveredBlock, SealedHeader, }; -use reth_trie_common::{updates::TrieUpdates, HashedPostState}; +use reth_trie_common::{updates::TrieUpdatesSorted, HashedPostStateSorted}; /// A chain of blocks and their final state. /// @@ -35,9 +35,9 @@ pub struct Chain { /// Additionally, it includes the individual state changes that led to the current state. execution_outcome: ExecutionOutcome, /// State trie updates for each block in the chain, keyed by block number. - trie_updates: BTreeMap>, + trie_updates: BTreeMap>, /// Hashed post state for each block in the chain, keyed by block number. - hashed_state: BTreeMap>, + hashed_state: BTreeMap>, } impl Default for Chain { @@ -60,8 +60,8 @@ impl Chain { pub fn new( blocks: impl IntoIterator>, execution_outcome: ExecutionOutcome, - trie_updates: BTreeMap>, - hashed_state: BTreeMap>, + trie_updates: BTreeMap>, + hashed_state: BTreeMap>, ) -> Self { let blocks = blocks.into_iter().map(|b| (b.header().number(), b)).collect::>(); @@ -74,8 +74,8 @@ impl Chain { pub fn from_block( block: RecoveredBlock, execution_outcome: ExecutionOutcome, - trie_updates: Arc, - hashed_state: Arc, + trie_updates: Arc, + hashed_state: Arc, ) -> Self { let block_number = block.header().number(); let trie_updates_map = BTreeMap::from([(block_number, trie_updates)]); @@ -99,12 +99,12 @@ impl Chain { } /// Get all trie updates for this chain. - pub const fn trie_updates(&self) -> &BTreeMap> { + pub const fn trie_updates(&self) -> &BTreeMap> { &self.trie_updates } /// Get trie updates for a specific block number. - pub fn trie_updates_at(&self, block_number: BlockNumber) -> Option<&Arc> { + pub fn trie_updates_at(&self, block_number: BlockNumber) -> Option<&Arc> { self.trie_updates.get(&block_number) } @@ -114,12 +114,15 @@ impl Chain { } /// Get all hashed states for this chain. - pub const fn hashed_state(&self) -> &BTreeMap> { + pub const fn hashed_state(&self) -> &BTreeMap> { &self.hashed_state } /// Get hashed state for a specific block number. - pub fn hashed_state_at(&self, block_number: BlockNumber) -> Option<&Arc> { + pub fn hashed_state_at( + &self, + block_number: BlockNumber, + ) -> Option<&Arc> { self.hashed_state.get(&block_number) } @@ -181,8 +184,8 @@ impl Chain { ) -> ( ChainBlocks<'static, N::Block>, ExecutionOutcome, - BTreeMap>, - BTreeMap>, + BTreeMap>, + BTreeMap>, ) { ( ChainBlocks { blocks: Cow::Owned(self.blocks) }, @@ -301,8 +304,8 @@ impl Chain { &mut self, block: RecoveredBlock, execution_outcome: ExecutionOutcome, - trie_updates: Arc, - hashed_state: Arc, + trie_updates: Arc, + hashed_state: Arc, ) { let block_number = block.header().number(); self.blocks.insert(block_number, block); @@ -491,9 +494,9 @@ pub(super) mod serde_bincode_compat { #[serde(default, rename = "trie_updates_legacy")] _trie_updates_legacy: Option>, #[serde(default)] - trie_updates: BTreeMap>, + trie_updates: BTreeMap>, #[serde(default)] - hashed_state: BTreeMap>, + hashed_state: BTreeMap>, } #[derive(Debug)] diff --git a/crates/optimism/exex/src/lib.rs b/crates/optimism/exex/src/lib.rs index 06f1f67b712..0de02a78906 100644 --- a/crates/optimism/exex/src/lib.rs +++ b/crates/optimism/exex/src/lib.rs @@ -253,8 +253,8 @@ where collector .store_block_updates( block.block_with_parent(), - trie_updates.clone(), - hashed_state.clone(), + (*trie_updates).clone(), + (*hashed_state).clone(), ) .await?; @@ -329,11 +329,7 @@ where eyre::eyre!("Missing Hashed state for block {} in new chain", block_number) })?; - block_updates.push(( - block.block_with_parent(), - trie_updates.clone(), - hashed_state.clone(), - )); + block_updates.push((block.block_with_parent(), trie_updates, hashed_state)); } collector.unwind_and_store_block_updates(block_updates).await?; diff --git a/crates/optimism/trie/src/api.rs b/crates/optimism/trie/src/api.rs index 67c2ff9c544..b272170c4d2 100644 --- a/crates/optimism/trie/src/api.rs +++ b/crates/optimism/trie/src/api.rs @@ -8,8 +8,8 @@ use reth_primitives_traits::Account; use reth_trie::{ hashed_cursor::{HashedCursor, HashedStorageCursor}, trie_cursor::{TrieCursor, TrieStorageCursor}, - updates::TrieUpdates, - BranchNodeCompact, HashedPostState, Nibbles, + updates::TrieUpdatesSorted, + BranchNodeCompact, HashedPostStateSorted, Nibbles, }; use std::{fmt::Debug, time::Duration}; @@ -17,16 +17,16 @@ use std::{fmt::Debug, time::Duration}; #[derive(Debug, Clone, Default)] pub struct BlockStateDiff { /// Trie updates for branch nodes - pub trie_updates: TrieUpdates, + pub trie_updates: TrieUpdatesSorted, /// Post state for leaf nodes (accounts and storage) - pub post_state: HashedPostState, + pub post_state: HashedPostStateSorted, } impl BlockStateDiff { /// Extend the [` BlockStateDiff`] from other latest [`BlockStateDiff`] - pub fn extend(&mut self, other: Self) { - self.trie_updates.extend(other.trie_updates); - self.post_state.extend(other.post_state); + pub fn extend_ref(&mut self, other: &Self) { + self.trie_updates.extend_ref(other.trie_updates); + self.post_state.extend_ref(other.post_state); } } diff --git a/crates/optimism/trie/src/db/store.rs b/crates/optimism/trie/src/db/store.rs index fde0caf91aa..68098698f88 100644 --- a/crates/optimism/trie/src/db/store.rs +++ b/crates/optimism/trie/src/db/store.rs @@ -272,7 +272,7 @@ impl MdbxProofsStorage { block_state_diff: BlockStateDiff, soft_delete: bool, ) -> OpProofsStorageResult { - let sorted_trie_updates = block_state_diff.trie_updates.into_sorted(); + let BlockStateDiff { sorted_trie_updates, .. } = block_state_diff; // Sorted list of updated and removed account nodes let sorted_account_nodes = sorted_trie_updates.account_nodes; @@ -284,7 +284,7 @@ impl MdbxProofsStorage { .sorted_by_key(|(hashed_address, _)| *hashed_address) .collect::>(); - let sorted_post_state = block_state_diff.post_state.into_sorted(); + BlockStateDiff { sorted_post_state, .. } = block_state_diff; let sorted_storage = sorted_post_state .account_storages() diff --git a/crates/optimism/trie/src/in_memory.rs b/crates/optimism/trie/src/in_memory.rs index ff02bc23494..f4648af6ee2 100644 --- a/crates/optimism/trie/src/in_memory.rs +++ b/crates/optimism/trie/src/in_memory.rs @@ -10,11 +10,11 @@ use reth_primitives_traits::Account; use reth_trie::{ hashed_cursor::{HashedCursor, HashedStorageCursor}, trie_cursor::{TrieCursor, TrieStorageCursor}, - updates::TrieUpdates, - BranchNodeCompact, HashedPostState, Nibbles, + updates::TrieUpdatesSorted, + BranchNodeCompact, HashedPostStateSorted, Nibbles, }; use std::{collections::BTreeMap, sync::Arc}; -use tokio::sync::RwLock; +use tokio::sync::{broadcast, RwLock}; /// In-memory implementation of [`OpProofsStore`] for testing purposes #[derive(Debug, Clone)] @@ -38,10 +38,10 @@ struct InMemoryStorageInner { hashed_storages: BTreeMap<(u64, B256, B256), U256>, /// Trie updates by block number - trie_updates: BTreeMap, + trie_updates: BTreeMap, /// Post state by block number - post_states: BTreeMap, + post_states: BTreeMap, /// Earliest block number and hash earliest_block: Option<(u64, B256)>, @@ -57,23 +57,7 @@ impl InMemoryStorageInner { // Store account branch nodes for (path, branch) in block_state_diff.trie_updates.account_nodes_ref() { - self.account_branches.insert((block_number, *path), Some(branch.clone())); - result.account_trie_updates_written_total += 1; - } - - // Store removed account nodes - let account_removals = block_state_diff - .trie_updates - .removed_nodes_ref() - .iter() - .filter_map(|n| { - (!block_state_diff.trie_updates.account_nodes_ref().contains_key(n)) - .then_some((n, None)) - }) - .collect::>(); - - for (path, branch) in account_removals { - self.account_branches.insert((block_number, *path), branch); + self.account_branches.insert((block_number, *path), branch.clone()); result.account_trie_updates_written_total += 1; } @@ -81,21 +65,7 @@ impl InMemoryStorageInner { for (address, storage_trie_updates) in block_state_diff.trie_updates.storage_tries_ref() { // Store storage branch nodes for (path, branch) in storage_trie_updates.storage_nodes_ref() { - self.storage_branches.insert((block_number, *address, *path), Some(branch.clone())); - result.storage_trie_updates_written_total += 1; - } - - // Store removed storage nodes - let storage_removals = storage_trie_updates - .removed_nodes_ref() - .iter() - .filter_map(|n| { - (!storage_trie_updates.storage_nodes_ref().contains_key(n)).then_some((n, None)) - }) - .collect::>(); - - for (path, branch) in storage_removals { - self.storage_branches.insert((block_number, *address, *path), branch); + self.storage_branches.insert((block_number, *address, *path), branch.clone()); result.storage_trie_updates_written_total += 1; } } @@ -134,7 +104,7 @@ impl InMemoryStorageInner { } } } else { - for (slot, value) in &storage.storage { + for (slot, value) in storage.storage_slots_ref() { self.hashed_storages.insert((block_number, *hashed_address, *slot), *value); result.hashed_storages_written_total += 1; } @@ -646,22 +616,23 @@ impl OpProofsStore for InMemoryProofsStorage { // Apply branch updates to the earliest state (block 0) for (path, branch) in &branches_diff.account_nodes { - inner.account_branches.insert((0, *path), Some(branch.clone())); - } - - // Remove pruned account branches - for path in &branches_diff.removed_nodes { - inner.account_branches.remove(&(0, *path)); + match branch { + Some(br) => _ = inner.account_branches.insert((0, *path), Some(br.clone())), + None => _ = inner.account_branches.remove(&(0, *path)), + } } // Apply storage trie updates for (hashed_address, storage_updates) in &branches_diff.storage_tries { for (path, branch) in &storage_updates.storage_nodes { - inner.storage_branches.insert((0, *hashed_address, *path), Some(branch.clone())); - } - - for path in &storage_updates.removed_nodes { - inner.storage_branches.remove(&(0, *hashed_address, *path)); + match branch { + Some(br) => { + _ = inner + .storage_branches + .insert((0, *hashed_address, *path), Some(br.clone())) + } + None => _ = inner.storage_branches.remove(&(0, *hashed_address, *path)), + } } } @@ -672,7 +643,7 @@ impl OpProofsStore for InMemoryProofsStorage { // Apply storage updates for (hashed_address, storage) in &leaves_diff.storages { - for (slot, value) in &storage.storage { + for (slot, value) in storage.storage_slots_ref() { inner.hashed_storages.insert((0, *hashed_address, *slot), *value); } } @@ -787,8 +758,8 @@ mod tests { async fn test_trie_updates_storage() -> Result<(), OpProofsStorageError> { let storage = InMemoryProofsStorage::new(); - let trie_updates = TrieUpdates::default(); - let post_state = HashedPostState::default(); + let trie_updates = TrieUpdatesSorted::default(); + let post_state = HashedPostStateSorted::default(); let block_state_diff = BlockStateDiff { trie_updates: trie_updates.clone(), post_state: post_state.clone() }; diff --git a/crates/optimism/trie/src/live.rs b/crates/optimism/trie/src/live.rs index b1ee6f88cdb..01fc89c33cb 100644 --- a/crates/optimism/trie/src/live.rs +++ b/crates/optimism/trie/src/live.rs @@ -14,7 +14,7 @@ use reth_provider::{ StateRootProvider, }; use reth_revm::database::StateProviderDatabase; -use reth_trie::{updates::TrieUpdates, HashedPostState}; +use reth_trie::{updates::TrieUpdatesSorted, HashedPostStateSorted}; use std::{sync::Arc, time::Instant}; use tracing::info; @@ -105,7 +105,10 @@ where .storage .store_trie_updates( block_ref, - BlockStateDiff { trie_updates, post_state: hashed_state }, + BlockStateDiff { + trie_updates: trie_updates.into_sorted(), + post_state: hashed_state.into_sorted(), + }, ) .await?; @@ -135,21 +138,15 @@ where pub async fn store_block_updates( &self, block: BlockWithParent, - trie_updates: Arc, - hashed_state: Arc, + trie_updates: TrieUpdatesSorted, + post_state: HashedPostStateSorted, ) -> eyre::Result<()> { let start = Instant::now(); let mut operation_durations = OperationDurations::default(); let storage_result = self .storage - .store_trie_updates( - block, - BlockStateDiff { - trie_updates: (*trie_updates).clone(), - post_state: (*hashed_state).clone(), - }, - ) + .store_trie_updates(block, BlockStateDiff { trie_updates, post_state }) .await?; let write_duration = start.elapsed(); @@ -185,7 +182,7 @@ where /// blocks to be added to the trie storage. pub async fn unwind_and_store_block_updates( &self, - block_updates: Vec<(BlockWithParent, Arc, Arc)>, + block_updates: Vec<(BlockWithParent, Arc, Arc)>, ) -> eyre::Result<()> { if block_updates.is_empty() { return Ok(()); diff --git a/crates/trie/common/src/hashed_state.rs b/crates/trie/common/src/hashed_state.rs index edfb821bc66..fe9cc78af4c 100644 --- a/crates/trie/common/src/hashed_state.rs +++ b/crates/trie/common/src/hashed_state.rs @@ -496,6 +496,7 @@ impl HashedStorage { /// Sorted hashed post state optimized for iterating during state trie calculation. #[derive(PartialEq, Eq, Clone, Default, Debug)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct HashedPostStateSorted { /// Sorted collection of account updates. `None` indicates a destroyed account. pub accounts: Vec<(B256, Option)>, @@ -602,6 +603,7 @@ impl AsRef for HashedPostStateSorted { /// Sorted hashed storage optimized for iterating during state trie calculation. #[derive(Clone, Eq, PartialEq, Debug)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct HashedStorageSorted { /// Sorted collection of updated storage slots. [`U256::ZERO`] indicates a deleted value. pub storage_slots: Vec<(B256, U256)>, From 3b574aeafcef4ff3f9f58ea09d90917c52e2bfab Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Mon, 8 Dec 2025 15:37:20 +0100 Subject: [PATCH 02/18] Fix BlockStateDiff field naming --- crates/optimism/trie/src/api.rs | 8 +- crates/optimism/trie/src/db/store.rs | 210 +++++++++++++---------- crates/optimism/trie/src/in_memory.rs | 32 ++-- crates/optimism/trie/src/live.rs | 13 +- crates/optimism/trie/src/prune/pruner.rs | 40 ++--- crates/optimism/trie/tests/lib.rs | 76 ++++---- 6 files changed, 217 insertions(+), 162 deletions(-) diff --git a/crates/optimism/trie/src/api.rs b/crates/optimism/trie/src/api.rs index b272170c4d2..9581f8e3adf 100644 --- a/crates/optimism/trie/src/api.rs +++ b/crates/optimism/trie/src/api.rs @@ -17,16 +17,16 @@ use std::{fmt::Debug, time::Duration}; #[derive(Debug, Clone, Default)] pub struct BlockStateDiff { /// Trie updates for branch nodes - pub trie_updates: TrieUpdatesSorted, + pub sorted_trie_updates: TrieUpdatesSorted, /// Post state for leaf nodes (accounts and storage) - pub post_state: HashedPostStateSorted, + pub sorted_post_state: HashedPostStateSorted, } impl BlockStateDiff { /// Extend the [` BlockStateDiff`] from other latest [`BlockStateDiff`] pub fn extend_ref(&mut self, other: &Self) { - self.trie_updates.extend_ref(other.trie_updates); - self.post_state.extend_ref(other.post_state); + self.sorted_trie_updates.extend_ref(&other.sorted_trie_updates); + self.sorted_post_state.extend_ref(&other.sorted_post_state); } } diff --git a/crates/optimism/trie/src/db/store.rs b/crates/optimism/trie/src/db/store.rs index 68098698f88..2924e93afd2 100644 --- a/crates/optimism/trie/src/db/store.rs +++ b/crates/optimism/trie/src/db/store.rs @@ -600,9 +600,9 @@ impl OpProofsStore for MdbxProofsStorage { }; if let Some(value) = entry { - block_state_diff.trie_updates.account_nodes.insert(key.0, value); + block_state_diff.sorted_trie_updates.account_nodes.insert(key.0, value); } else { - block_state_diff.trie_updates.removed_nodes.insert(key.0); + block_state_diff.sorted_trie_updates.account_nodes.insert(key.0, B256::ZERO); } } @@ -620,7 +620,7 @@ impl OpProofsStore for MdbxProofsStorage { }; let stu = block_state_diff - .trie_updates + .sorted_trie_updates .storage_tries .entry(key.hashed_address) .or_insert_with(StorageTrieUpdates::default); @@ -645,7 +645,7 @@ impl OpProofsStore for MdbxProofsStorage { } }; - block_state_diff.post_state.accounts.insert(key, entry); + block_state_diff.sorted_post_state.accounts.insert(key, entry); } for key in change_set.hashed_storage_keys { @@ -662,7 +662,7 @@ impl OpProofsStore for MdbxProofsStorage { }; let hs = block_state_diff - .post_state + .sorted_post_state .storages .entry(key.hashed_address) .or_insert_with(HashedStorage::default); @@ -1352,31 +1352,37 @@ mod tests { let mut block_state_diff = BlockStateDiff::default(); // Add account trie nodes - block_state_diff.trie_updates.account_nodes.insert(account_path1, account_node1.clone()); - block_state_diff.trie_updates.account_nodes.insert(account_path2, account_node2.clone()); - block_state_diff.trie_updates.removed_nodes.insert(removed_account_path); + block_state_diff + .sorted_trie_updates + .account_nodes + .insert(account_path1, account_node1.clone()); + block_state_diff + .sorted_trie_updates + .account_nodes + .insert(account_path2, account_node2.clone()); + block_state_diff.sorted_trie_updates.removed_nodes.insert(removed_account_path); // Add storage trie nodes for two addresses let mut storage_nodes1 = StorageTrieUpdates::default(); storage_nodes1.storage_nodes.insert(storage_path1, storage_node1.clone()); - block_state_diff.trie_updates.storage_tries.insert(addr1, storage_nodes1); + block_state_diff.sorted_trie_updates.storage_tries.insert(addr1, storage_nodes1); let mut storage_nodes2 = StorageTrieUpdates::default(); storage_nodes2.storage_nodes.insert(storage_path2, storage_node2.clone()); - block_state_diff.trie_updates.storage_tries.insert(addr2, storage_nodes2); + block_state_diff.sorted_trie_updates.storage_tries.insert(addr2, storage_nodes2); // Add hashed accounts (one Some, one None) - block_state_diff.post_state.accounts.insert(addr1, Some(acc1)); - block_state_diff.post_state.accounts.insert(addr2, None); // Deletion + block_state_diff.sorted_post_state.accounts.insert(addr1, Some(acc1)); + block_state_diff.sorted_post_state.accounts.insert(addr2, None); // Deletion // Add storage slots for both addresses let mut storage1 = HashedStorage::default(); storage1.storage.insert(slot1, val1); - block_state_diff.post_state.storages.insert(addr1, storage1); + block_state_diff.sorted_post_state.storages.insert(addr1, storage1); let mut storage2 = HashedStorage::default(); storage2.storage.insert(slot2, val2); - block_state_diff.post_state.storages.insert(addr2, storage2); + block_state_diff.sorted_post_state.storages.insert(addr2, storage2); // Store everything store.store_trie_updates(BLOCK, block_state_diff).await.expect("store"); @@ -1526,14 +1532,17 @@ mod tests { // block A (parent = ZERO) let block_a = BlockWithParent::new(B256::ZERO, NumHash::new(1, B256::random())); let mut diff_a = BlockStateDiff::default(); - diff_a.post_state.accounts.insert(addr, Some(Account::default())); + diff_a.sorted_post_state.accounts.insert(addr, Some(Account::default())); store.store_trie_updates(block_a, diff_a).await.expect("store A"); // block B (parent = hash of A) let block_b = BlockWithParent::new(block_a.block.hash, NumHash::new(2, B256::random())); let mut diff_b = BlockStateDiff::default(); - diff_b.post_state.accounts.insert(addr, Some(Account { nonce: 5, ..Default::default() })); + diff_b + .sorted_post_state + .accounts + .insert(addr, Some(Account { nonce: 5, ..Default::default() })); store.store_trie_updates(block_b, diff_b).await.expect("store B"); @@ -1603,11 +1612,11 @@ mod tests { store.store_trie_updates(block, diff).await.expect("store"); let got = store.fetch_trie_updates(1).await.expect("fetch"); - assert!(got.trie_updates.account_nodes.is_empty()); - assert!(got.trie_updates.removed_nodes.is_empty()); - assert!(got.trie_updates.storage_tries.is_empty()); - assert!(got.post_state.accounts.is_empty()); - assert!(got.post_state.storages.is_empty()); + assert!(got.sorted_trie_updates.account_nodes.is_empty()); + assert!(got.sorted_trie_updates.removed_nodes.is_empty()); + assert!(got.sorted_trie_updates.storage_tries.is_empty()); + assert!(got.sorted_post_state.accounts.is_empty()); + assert!(got.sorted_post_state.storages.is_empty()); } #[tokio::test] @@ -1895,38 +1904,53 @@ mod tests { // Construct BlockStateDiff let mut block_state_diff = BlockStateDiff::default(); - block_state_diff.trie_updates.account_nodes.insert(account_path1, account_node1.clone()); - block_state_diff.trie_updates.account_nodes.insert(account_path2, account_node2.clone()); + block_state_diff + .sorted_trie_updates + .account_nodes + .insert(account_path1, account_node1.clone()); + block_state_diff + .sorted_trie_updates + .account_nodes + .insert(account_path2, account_node2.clone()); // storage trie for addr1 let mut storage_nodes1 = StorageTrieUpdates::default(); storage_nodes1.storage_nodes.insert(storage_path1, storage_node1.clone()); - block_state_diff.trie_updates.storage_tries.insert(addr1, storage_nodes1); + block_state_diff.sorted_trie_updates.storage_tries.insert(addr1, storage_nodes1); // hashed accounts: addr1 -> Some, addr2 -> None - block_state_diff.post_state.accounts.insert(addr1, Some(acc1)); - block_state_diff.post_state.accounts.insert(addr2, None); + block_state_diff.sorted_post_state.accounts.insert(addr1, Some(acc1)); + block_state_diff.sorted_post_state.accounts.insert(addr2, None); // hashed storages let mut storage1 = HashedStorage::default(); storage1.storage.insert(slot1, val1); - block_state_diff.post_state.storages.insert(addr1, storage1); + block_state_diff.sorted_post_state.storages.insert(addr1, storage1); let mut storage2 = HashedStorage::default(); storage2.storage.insert(slot2, val2); - block_state_diff.post_state.storages.insert(addr2, storage2); + block_state_diff.sorted_post_state.storages.insert(addr2, storage2); // store then fetch store.store_trie_updates(block, block_state_diff.clone()).await.expect("store"); let got = store.fetch_trie_updates(1).await.expect("fetch"); // verify trie updates - assert_eq!(got.trie_updates.account_nodes, block_state_diff.trie_updates.account_nodes,); - assert_eq!(got.trie_updates.removed_nodes, block_state_diff.trie_updates.removed_nodes,); - assert_eq!(got.trie_updates.storage_tries, block_state_diff.trie_updates.storage_tries,); + assert_eq!( + got.sorted_trie_updates.account_nodes, + block_state_diff.sorted_trie_updates.account_nodes, + ); + assert_eq!( + got.sorted_trie_updates.removed_nodes, + block_state_diff.sorted_trie_updates.removed_nodes, + ); + assert_eq!( + got.sorted_trie_updates.storage_tries, + block_state_diff.sorted_trie_updates.storage_tries, + ); // verify post state - assert_eq!(got.post_state.accounts, block_state_diff.post_state.accounts); - assert_eq!(got.post_state.storages, block_state_diff.post_state.storages); + assert_eq!(got.sorted_post_state.accounts, block_state_diff.sorted_post_state.accounts); + assert_eq!(got.sorted_post_state.storages, block_state_diff.sorted_post_state.storages); } #[tokio::test] @@ -1939,7 +1963,7 @@ mod tests { // Insert a single entry to be pruned let addr = B256::random(); let mut state_diff = BlockStateDiff::default(); - state_diff.post_state.accounts.insert(addr, Some(Account::default())); + state_diff.sorted_post_state.accounts.insert(addr, Some(Account::default())); store.store_trie_updates(block, state_diff).await.unwrap(); // Prune the entry - pass empty diff since we're just removing data @@ -1970,8 +1994,8 @@ mod tests { let addr1 = B256::random(); let addr2 = B256::random(); let mut state_diff = BlockStateDiff::default(); - state_diff.post_state.accounts.insert(addr1, Some(Account::default())); - state_diff.post_state.accounts.insert(addr2, Some(Account::default())); + state_diff.sorted_post_state.accounts.insert(addr1, Some(Account::default())); + state_diff.sorted_post_state.accounts.insert(addr2, Some(Account::default())); store.store_trie_updates(block, state_diff).await.unwrap(); // Prune the entries @@ -2001,11 +2025,11 @@ mod tests { let addr1 = B256::random(); let addr2 = B256::random(); let mut state_diff1 = BlockStateDiff::default(); - state_diff1.post_state.accounts.insert(addr1, Some(Account::default())); + state_diff1.sorted_post_state.accounts.insert(addr1, Some(Account::default())); store.store_trie_updates(block_1, state_diff1).await.unwrap(); let mut state_diff2 = BlockStateDiff::default(); - state_diff2.post_state.accounts.insert(addr2, Some(Account::default())); + state_diff2.sorted_post_state.accounts.insert(addr2, Some(Account::default())); store.store_trie_updates(block_2, state_diff2).await.unwrap(); // Prune up to block 3 (should remove blocks 1 and 2) @@ -2066,12 +2090,12 @@ mod tests { let block_1 = BlockWithParent::new(B256::ZERO, NumHash::new(1, B256::random())); let mut state_diff1 = BlockStateDiff::default(); - state_diff1.post_state.accounts.insert(addr1, Some(acc1)); + state_diff1.sorted_post_state.accounts.insert(addr1, Some(acc1)); store.store_trie_updates(block_1, state_diff1).await.unwrap(); let block_2 = BlockWithParent::new(block_1.block.hash, NumHash::new(2, B256::random())); let mut state_diff2 = BlockStateDiff::default(); - state_diff2.post_state.accounts.insert(addr2, Some(acc2)); + state_diff2.sorted_post_state.accounts.insert(addr2, Some(acc2)); store.store_trie_updates(block_2, state_diff2).await.unwrap(); // Now prune to block 3, passing a diff that represents the new initial state @@ -2079,9 +2103,9 @@ mod tests { Account { nonce: 10, balance: U256::from(1000), ..Default::default() }; let new_addr = B256::random(); let mut prune_diff = BlockStateDiff::default(); - prune_diff.post_state.accounts.insert(addr1, Some(acc1)); - prune_diff.post_state.accounts.insert(addr2, Some(acc2)); - prune_diff.post_state.accounts.insert(new_addr, Some(new_initial_account)); + prune_diff.sorted_post_state.accounts.insert(addr1, Some(acc1)); + prune_diff.sorted_post_state.accounts.insert(addr2, Some(acc2)); + prune_diff.sorted_post_state.accounts.insert(new_addr, Some(new_initial_account)); let block_3 = BlockWithParent::new(block_2.block.hash, NumHash::new(3, B256::random())); store.prune_earliest_state(block_3, prune_diff).await.unwrap(); @@ -2130,12 +2154,12 @@ mod tests { let block_1 = BlockWithParent::new(B256::ZERO, NumHash::new(1, B256::random())); let mut diff1 = BlockStateDiff::default(); - diff1.trie_updates.account_nodes.insert(path1, node1.clone()); + diff1.sorted_trie_updates.account_nodes.insert(path1, node1.clone()); store.store_trie_updates(block_1, diff1).await.unwrap(); let block_2 = BlockWithParent::new(block_1.block.hash, NumHash::new(2, B256::random())); let mut diff2 = BlockStateDiff::default(); - diff2.trie_updates.account_nodes.insert(path2, node2.clone()); + diff2.sorted_trie_updates.account_nodes.insert(path2, node2.clone()); store.store_trie_updates(block_2, diff2).await.unwrap(); // In block 3, path1 is deleted (stored as None in the database) @@ -2177,8 +2201,8 @@ mod tests { // - path2 should be included with its value (it still exists from block 2) let block_5 = BlockWithParent::new(B256::random(), NumHash::new(5, B256::random())); let mut prune_diff = BlockStateDiff::default(); - prune_diff.trie_updates.removed_nodes.insert(path1); - prune_diff.trie_updates.account_nodes.insert(path2, node2.clone()); + prune_diff.sorted_trie_updates.removed_nodes.insert(path1); + prune_diff.sorted_trie_updates.account_nodes.insert(path2, node2.clone()); store.prune_earliest_state(block_5, prune_diff).await.unwrap(); // Verify that all entries for path1 before block 5 were removed @@ -2228,12 +2252,12 @@ mod tests { let block_1 = BlockWithParent::new(B256::ZERO, NumHash::new(1, B256::random())); let mut diff1 = BlockStateDiff::default(); - diff1.post_state.accounts.insert(addr1, Some(acc1)); + diff1.sorted_post_state.accounts.insert(addr1, Some(acc1)); store.store_trie_updates(block_1, diff1).await.unwrap(); let block_2 = BlockWithParent::new(block_1.block.hash, NumHash::new(2, B256::random())); let mut diff2 = BlockStateDiff::default(); - diff2.post_state.accounts.insert(addr1, Some(acc2)); + diff2.sorted_post_state.accounts.insert(addr1, Some(acc2)); store.store_trie_updates(block_2, diff2).await.unwrap(); // Prune to block 3, with new initial state including: @@ -2241,8 +2265,8 @@ mod tests { // - addr2 as a new account let block_3 = BlockWithParent::new(block_2.block.hash, NumHash::new(3, B256::random())); let mut prune_diff = BlockStateDiff::default(); - prune_diff.post_state.accounts.insert(addr1, Some(acc2)); - prune_diff.post_state.accounts.insert(addr2, Some(new_acc)); + prune_diff.sorted_post_state.accounts.insert(addr1, Some(acc2)); + prune_diff.sorted_post_state.accounts.insert(addr2, Some(new_acc)); store.prune_earliest_state(block_3, prune_diff).await.unwrap(); // Verify old versions of addr1 were pruned @@ -2298,21 +2322,21 @@ mod tests { // Block 1: Insert account, trie node, and storage for addr1 let block_1 = BlockWithParent::new(B256::ZERO, NumHash::new(1, B256::random())); let mut diff1 = BlockStateDiff::default(); - diff1.post_state.accounts.insert(addr1, Some(acc1)); - diff1.trie_updates.account_nodes.insert(path1, node1.clone()); + diff1.sorted_post_state.accounts.insert(addr1, Some(acc1)); + diff1.sorted_trie_updates.account_nodes.insert(path1, node1.clone()); let mut storage1 = HashedStorage::default(); storage1.storage.insert(slot1, U256::from(1234)); - diff1.post_state.storages.insert(addr1, storage1.clone()); + diff1.sorted_post_state.storages.insert(addr1, storage1.clone()); let mut storage_updates1 = StorageTrieUpdates::default(); storage_updates1.storage_nodes.insert(storage_path1, storage_node1.clone()); - diff1.trie_updates.storage_tries.insert(addr1, storage_updates1.clone()); + diff1.sorted_trie_updates.storage_tries.insert(addr1, storage_updates1.clone()); store.store_trie_updates(block_1, diff1).await.unwrap(); // Block 2: Update account let acc2 = Account { nonce: 2, balance: U256::from(200), ..Default::default() }; let block_2 = BlockWithParent::new(block_1.block.hash, NumHash::new(2, B256::random())); let mut diff2 = BlockStateDiff::default(); - diff2.post_state.accounts.insert(addr1, Some(acc2)); + diff2.sorted_post_state.accounts.insert(addr1, Some(acc2)); store.store_trie_updates(block_2, diff2).await.unwrap(); // Prune to block 3 with new initial state for DIFFERENT keys (addr2, path2, etc.) @@ -2322,19 +2346,19 @@ mod tests { let block_3 = BlockWithParent::new(block_2.block.hash, NumHash::new(3, B256::random())); let mut prune_diff = BlockStateDiff::default(); - prune_diff.post_state.accounts.insert(addr1, Some(acc2)); - prune_diff.post_state.accounts.insert(addr2, Some(new_acc)); - prune_diff.trie_updates.account_nodes.insert(path1, node1.clone()); - prune_diff.trie_updates.account_nodes.insert(path2, new_node.clone()); - prune_diff.post_state.storages.insert(addr1, storage1); - prune_diff.trie_updates.storage_tries.insert(addr1, storage_updates1); + prune_diff.sorted_post_state.accounts.insert(addr1, Some(acc2)); + prune_diff.sorted_post_state.accounts.insert(addr2, Some(new_acc)); + prune_diff.sorted_trie_updates.account_nodes.insert(path1, node1.clone()); + prune_diff.sorted_trie_updates.account_nodes.insert(path2, new_node.clone()); + prune_diff.sorted_post_state.storages.insert(addr1, storage1); + prune_diff.sorted_trie_updates.storage_tries.insert(addr1, storage_updates1); let mut new_storage = HashedStorage::default(); new_storage.storage.insert(slot2, U256::from(9999)); - prune_diff.post_state.storages.insert(addr2, new_storage); + prune_diff.sorted_post_state.storages.insert(addr2, new_storage); let mut new_storage_updates = StorageTrieUpdates::default(); new_storage_updates.storage_nodes.insert(storage_path2, new_storage_node.clone()); - prune_diff.trie_updates.storage_tries.insert(addr2, new_storage_updates); + prune_diff.sorted_trie_updates.storage_tries.insert(addr2, new_storage_updates); store.prune_earliest_state(block_3, prune_diff).await.unwrap(); @@ -2466,7 +2490,7 @@ mod tests { // Prepare a BlockStateDiff that removes an account trie node at `acc_path` let acc_path = Nibbles::from_nibbles_unchecked([0x0A, 0x0B, 0x0C]); let mut diff = BlockStateDiff::default(); - diff.trie_updates.removed_nodes.insert(acc_path); + diff.sorted_trie_updates.removed_nodes.insert(acc_path); store.store_trie_updates(BLOCK, diff).await.expect("store"); @@ -2497,7 +2521,7 @@ mod tests { let mut st_updates = reth_trie::updates::StorageTrieUpdates::default(); // mark this storage trie node as removed st_updates.removed_nodes.insert(st_path); - diff.trie_updates.storage_tries.insert(addr, st_updates); + diff.sorted_trie_updates.storage_tries.insert(addr, st_updates); store.store_trie_updates(BLOCK, diff).await.expect("store"); @@ -2543,14 +2567,14 @@ mod tests { // Wipe for addr_wiped let mut wiped_updates = StorageTrieUpdates::default(); wiped_updates.set_deleted(true); - diff.trie_updates.storage_tries.insert(addr_wiped, wiped_updates); + diff.sorted_trie_updates.storage_tries.insert(addr_wiped, wiped_updates); // Normal update for addr_live let live_path = Nibbles::from_nibbles_unchecked([0xEE, 0xFF]); let live_node = BranchNodeCompact::default(); let mut live_updates = StorageTrieUpdates::default(); live_updates.storage_nodes.insert(live_path, live_node.clone()); - diff.trie_updates.storage_tries.insert(addr_live, live_updates); + diff.sorted_trie_updates.storage_tries.insert(addr_live, live_updates); // Execute the store store.store_trie_updates(BLOCK, diff).await.expect("store"); @@ -2610,7 +2634,7 @@ mod tests { let wiped = reth_trie::HashedStorage::new(true); - diff.post_state.storages.insert(addr, wiped); + diff.sorted_post_state.storages.insert(addr, wiped); // Execute store.store_trie_updates(BLOCK, diff).await.expect("store"); @@ -2667,12 +2691,12 @@ mod tests { // Wiped storage for addr_wiped let wiped = reth_trie::HashedStorage::new(true); - diff.post_state.storages.insert(addr_wiped, wiped); + diff.sorted_post_state.storages.insert(addr_wiped, wiped); // Non-wiped storage for addr_live (append new value) let mut live = reth_trie::HashedStorage::default(); live.storage.insert(ls1, lv1_new); - diff.post_state.storages.insert(addr_live, live); + diff.sorted_post_state.storages.insert(addr_live, live); // Execute store.store_trie_updates(BLOCK, diff).await.expect("store"); @@ -2753,7 +2777,9 @@ mod tests { let addr = B256::from([0xAB; 32]); let make_diff = |nonce: u64| { let mut d = BlockStateDiff::default(); - d.post_state.accounts.insert(addr, Some(Account { nonce, ..Default::default() })); + d.sorted_post_state + .accounts + .insert(addr, Some(Account { nonce, ..Default::default() })); d }; @@ -2839,7 +2865,9 @@ mod tests { let addr = B256::random(); let make_diff = |nonce: u64| { let mut d = BlockStateDiff::default(); - d.post_state.accounts.insert(addr, Some(Account { nonce, ..Default::default() })); + d.sorted_post_state + .accounts + .insert(addr, Some(Account { nonce, ..Default::default() })); d }; @@ -2886,7 +2914,9 @@ mod tests { let addr = B256::random(); let make_diff = |nonce: u64| { let mut d = BlockStateDiff::default(); - d.post_state.accounts.insert(addr, Some(Account { nonce, ..Default::default() })); + d.sorted_post_state + .accounts + .insert(addr, Some(Account { nonce, ..Default::default() })); d }; @@ -2919,10 +2949,12 @@ mod tests { let make_diff = |nonce: u64, slot_value: u64| { let mut d = BlockStateDiff::default(); - d.post_state.accounts.insert(addr, Some(Account { nonce, ..Default::default() })); + d.sorted_post_state + .accounts + .insert(addr, Some(Account { nonce, ..Default::default() })); let mut storage = HashedStorage::default(); storage.storage.insert(slot, U256::from(slot_value)); - d.post_state.storages.insert(addr, storage); + d.sorted_post_state.storages.insert(addr, storage); d }; @@ -2985,7 +3017,7 @@ mod tests { let make_diff = |path: Nibbles, node: BranchNodeCompact| { let mut d = BlockStateDiff::default(); - d.trie_updates.account_nodes.insert(path, node); + d.sorted_trie_updates.account_nodes.insert(path, node); d }; @@ -3048,30 +3080,30 @@ mod tests { // Block 1: Insert multiple types of data let b1 = BlockWithParent::new(b0.hash, NumHash::new(1, B256::random())); let mut diff1 = BlockStateDiff::default(); - diff1.post_state.accounts.insert(addr1, Some(acc1)); - diff1.trie_updates.account_nodes.insert(path1, node1.clone()); + diff1.sorted_post_state.accounts.insert(addr1, Some(acc1)); + diff1.sorted_trie_updates.account_nodes.insert(path1, node1.clone()); let mut storage1 = HashedStorage::default(); storage1.storage.insert(slot1, U256::from(1111)); - diff1.post_state.storages.insert(addr1, storage1); + diff1.sorted_post_state.storages.insert(addr1, storage1); let mut storage_updates1 = StorageTrieUpdates::default(); storage_updates1.storage_nodes.insert(storage_path1, storage_node1.clone()); - diff1.trie_updates.storage_tries.insert(addr1, storage_updates1); + diff1.sorted_trie_updates.storage_tries.insert(addr1, storage_updates1); store.store_trie_updates(b1, diff1).await.expect("store b1"); // Block 2: More updates let b2 = BlockWithParent::new(b1.block.hash, NumHash::new(2, B256::random())); let mut diff2 = BlockStateDiff::default(); - diff2.post_state.accounts.insert(addr2, Some(acc2)); - diff2.trie_updates.account_nodes.insert(path2, node2.clone()); + diff2.sorted_post_state.accounts.insert(addr2, Some(acc2)); + diff2.sorted_trie_updates.account_nodes.insert(path2, node2.clone()); let mut storage2 = HashedStorage::default(); storage2.storage.insert(slot2, U256::from(2222)); - diff2.post_state.storages.insert(addr2, storage2); + diff2.sorted_post_state.storages.insert(addr2, storage2); store.store_trie_updates(b2, diff2).await.expect("store b2"); // Block 3: Additional updates let b3 = BlockWithParent::new(b2.block.hash, NumHash::new(3, B256::random())); let mut diff3 = BlockStateDiff::default(); - diff3.post_state.accounts.insert(addr1, Some(acc2)); // update addr1 + diff3.sorted_post_state.accounts.insert(addr1, Some(acc2)); // update addr1 store.store_trie_updates(b3, diff3).await.expect("store b3"); // Unwind to block 1 @@ -3145,7 +3177,9 @@ mod tests { let addr = B256::random(); let make_diff = |nonce: u64| { let mut d = BlockStateDiff::default(); - d.post_state.accounts.insert(addr, Some(Account { nonce, ..Default::default() })); + d.sorted_post_state + .accounts + .insert(addr, Some(Account { nonce, ..Default::default() })); d }; @@ -3183,7 +3217,9 @@ mod tests { let addr = B256::random(); let make_diff = |nonce: u64| { let mut d = BlockStateDiff::default(); - d.post_state.accounts.insert(addr, Some(Account { nonce, ..Default::default() })); + d.sorted_post_state + .accounts + .insert(addr, Some(Account { nonce, ..Default::default() })); d }; diff --git a/crates/optimism/trie/src/in_memory.rs b/crates/optimism/trie/src/in_memory.rs index f4648af6ee2..32a46a82363 100644 --- a/crates/optimism/trie/src/in_memory.rs +++ b/crates/optimism/trie/src/in_memory.rs @@ -14,7 +14,7 @@ use reth_trie::{ BranchNodeCompact, HashedPostStateSorted, Nibbles, }; use std::{collections::BTreeMap, sync::Arc}; -use tokio::sync::{broadcast, RwLock}; +use tokio::sync::RwLock; /// In-memory implementation of [`OpProofsStore`] for testing purposes #[derive(Debug, Clone)] @@ -56,13 +56,15 @@ impl InMemoryStorageInner { let mut result = WriteCounts::default(); // Store account branch nodes - for (path, branch) in block_state_diff.trie_updates.account_nodes_ref() { + for (path, branch) in block_state_diff.sorted_trie_updates.account_nodes_ref() { self.account_branches.insert((block_number, *path), branch.clone()); result.account_trie_updates_written_total += 1; } // Store storage branch nodes and removals - for (address, storage_trie_updates) in block_state_diff.trie_updates.storage_tries_ref() { + for (address, storage_trie_updates) in + block_state_diff.sorted_trie_updates.storage_tries_ref() + { // Store storage branch nodes for (path, branch) in storage_trie_updates.storage_nodes_ref() { self.storage_branches.insert((block_number, *address, *path), branch.clone()); @@ -70,12 +72,12 @@ impl InMemoryStorageInner { } } - for (address, account) in &block_state_diff.post_state.accounts { + for (address, account) in &block_state_diff.sorted_post_state.accounts { self.hashed_accounts.insert((block_number, *address), *account); result.hashed_accounts_written_total += 1; } - for (hashed_address, storage) in &block_state_diff.post_state.storages { + for (hashed_address, storage) in &block_state_diff.sorted_post_state.storages { // Handle wiped storage: iterate all existing values and mark them as deleted // This is an expensive operation and should never happen for blocks going forward. if storage.wiped { @@ -111,8 +113,8 @@ impl InMemoryStorageInner { } } - self.trie_updates.insert(block_number, block_state_diff.trie_updates.clone()); - self.post_states.insert(block_number, block_state_diff.post_state.clone()); + self.trie_updates.insert(block_number, block_state_diff.sorted_trie_updates.clone()); + self.post_states.insert(block_number, block_state_diff.sorted_post_state.clone()); result } @@ -601,7 +603,7 @@ impl OpProofsStore for InMemoryProofsStorage { let trie_updates = inner.trie_updates.get(&block_number).cloned().unwrap_or_default(); let post_state = inner.post_states.get(&block_number).cloned().unwrap_or_default(); - Ok(BlockStateDiff { trie_updates, post_state }) + Ok(BlockStateDiff { sorted_trie_updates: trie_updates, sorted_post_state: post_state }) } async fn prune_earliest_state( @@ -611,8 +613,8 @@ impl OpProofsStore for InMemoryProofsStorage { ) -> OpProofsStorageResult<()> { let mut inner = self.inner.write().await; - let branches_diff = diff.trie_updates; - let leaves_diff = diff.post_state; + let branches_diff = diff.sorted_trie_updates; + let leaves_diff = diff.sorted_post_state; // Apply branch updates to the earliest state (block 0) for (path, branch) in &branches_diff.account_nodes { @@ -760,16 +762,18 @@ mod tests { let trie_updates = TrieUpdatesSorted::default(); let post_state = HashedPostStateSorted::default(); - let block_state_diff = - BlockStateDiff { trie_updates: trie_updates.clone(), post_state: post_state.clone() }; + let block_state_diff = BlockStateDiff { + sorted_trie_updates: trie_updates.clone(), + sorted_post_state: post_state.clone(), + }; const BLOCK: BlockWithParent = BlockWithParent::new(B256::ZERO, NumHash::new(5, B256::ZERO)); storage.store_trie_updates(BLOCK, block_state_diff).await?; let retrieved_diff = storage.fetch_trie_updates(BLOCK.block.number).await?; - assert_eq!(retrieved_diff.trie_updates, trie_updates); - assert_eq!(retrieved_diff.post_state, post_state); + assert_eq!(retrieved_diff.sorted_trie_updates, trie_updates); + assert_eq!(retrieved_diff.sorted_post_state, post_state); Ok(()) } diff --git a/crates/optimism/trie/src/live.rs b/crates/optimism/trie/src/live.rs index 01fc89c33cb..85c1ab1d2d7 100644 --- a/crates/optimism/trie/src/live.rs +++ b/crates/optimism/trie/src/live.rs @@ -106,8 +106,8 @@ where .store_trie_updates( block_ref, BlockStateDiff { - trie_updates: trie_updates.into_sorted(), - post_state: hashed_state.into_sorted(), + sorted_trie_updates: trie_updates.into_sorted(), + sorted_post_state: hashed_state.into_sorted(), }, ) .await?; @@ -146,7 +146,10 @@ where let storage_result = self .storage - .store_trie_updates(block, BlockStateDiff { trie_updates, post_state }) + .store_trie_updates( + block, + BlockStateDiff { sorted_trie_updates: trie_updates, sorted_post_state: post_state }, + ) .await?; let write_duration = start.elapsed(); @@ -199,8 +202,8 @@ where block_trie_updates.insert( *block, BlockStateDiff { - trie_updates: (**trie_updates).clone(), - post_state: (**hashed_state).clone(), + sorted_trie_updates: (**trie_updates).clone(), + sorted_post_state: (**hashed_state).clone(), }, ); } diff --git a/crates/optimism/trie/src/prune/pruner.rs b/crates/optimism/trie/src/prune/pruner.rs index 14d2346ccd3..01752943511 100644 --- a/crates/optimism/trie/src/prune/pruner.rs +++ b/crates/optimism/trie/src/prune/pruner.rs @@ -90,7 +90,7 @@ where "Failed to fetch trie updates for block during pruning" ) })?; - final_diff.extend(diff); + final_diff.extend_ref(&diff); } let stat_diff_fetch_duration = t.elapsed(); @@ -244,11 +244,11 @@ mod tests { let b1 = block(1, parent); let mut d = BlockStateDiff::default(); - d.post_state.accounts.insert( + d.sorted_post_state.accounts.insert( a1, Some(Account { nonce: 1, balance: U256::from(1_001), ..Default::default() }), ); - d.post_state.accounts.insert( + d.sorted_post_state.accounts.insert( a2, Some(Account { nonce: 1, balance: U256::from(1_002), ..Default::default() }), ); @@ -256,10 +256,10 @@ mod tests { let mut hs = HashedStorage::default(); hs.storage.insert(s1, U256::from(100)); hs.storage.insert(s2, U256::from(200)); - d.post_state.storages.insert(stor_addr, hs); + d.sorted_post_state.storages.insert(stor_addr, hs); - d.trie_updates.account_nodes.insert(p1, node_p1.clone()); - let e = d.trie_updates.storage_tries.entry(stor_addr).or_default(); + d.sorted_trie_updates.account_nodes.insert(p1, node_p1.clone()); + let e = d.soretd_trie_updates.storage_tries.entry(stor_addr).or_default(); e.storage_nodes.insert(st1, BranchNodeCompact::default()); store.store_trie_updates(b1, d).await.expect("b1"); @@ -271,11 +271,11 @@ mod tests { let b2 = block(2, parent); let mut d = BlockStateDiff::default(); - d.post_state.accounts.insert( + d.sorted_post_state.accounts.insert( a2, Some(Account { nonce: 2, balance: U256::from(2_002), ..Default::default() }), ); - d.post_state.accounts.insert( + d.sorted_post_state.accounts.insert( a3, Some(Account { nonce: 1, balance: U256::from(1_003), ..Default::default() }), ); @@ -283,10 +283,10 @@ mod tests { let mut hs = HashedStorage::default(); hs.storage.insert(s2, U256::from(220)); hs.storage.insert(s3, U256::from(300)); - d.post_state.storages.insert(stor_addr, hs); + d.sorted_post_state.storages.insert(stor_addr, hs); - d.trie_updates.account_nodes.insert(p2, node_p2.clone()); - let e = d.trie_updates.storage_tries.entry(stor_addr).or_default(); + d.sorted_trie_updates.account_nodes.insert(p2, node_p2.clone()); + let e = d.sorted_trie_updates.storage_tries.entry(stor_addr).or_default(); e.storage_nodes.insert(st2, node_st2.clone()); store.store_trie_updates(b2, d).await.expect("b2"); @@ -299,15 +299,15 @@ mod tests { let mut d = BlockStateDiff::default(); // delete a1, keep a2 & a3 values unchanged for this block - d.post_state.accounts.insert(a1, None); + d.sorted_post_state.accounts.insert(a1, None); // remove account trie node p1 - d.trie_updates.removed_nodes.insert(p1); + d.sorted_trie_updates.removed_nodes.insert(p1); // remove storage-trie node st1 let mut st_upd = StorageTrieUpdates::default(); st_upd.removed_nodes.insert(st1); - d.trie_updates.storage_tries.insert(stor_addr, st_upd); + d.sorted_trie_updates.storage_tries.insert(stor_addr, st_upd); store.store_trie_updates(b3, d).await.expect("b3"); parent = b256(3); @@ -318,17 +318,17 @@ mod tests { let b4 = block(4, parent); let mut d = BlockStateDiff::default(); - d.post_state.accounts.insert( + d.sorted_post_state.accounts.insert( a2, Some(Account { nonce: 3, balance: U256::from(3_002), ..Default::default() }), ); let mut hs = HashedStorage::default(); hs.storage.insert(s1, U256::from(140)); - d.post_state.storages.insert(stor_addr, hs); + d.sorted_post_state.storages.insert(stor_addr, hs); - d.trie_updates.account_nodes.insert(p3, node_p3.clone()); - let e = d.trie_updates.storage_tries.entry(stor_addr).or_default(); + d.sorted_trie_updates.account_nodes.insert(p3, node_p3.clone()); + let e = d.sorted_trie_updates.storage_tries.entry(stor_addr).or_default(); e.storage_nodes.insert(st3, node_st3.clone()); store.store_trie_updates(b4, d).await.expect("b4"); @@ -340,14 +340,14 @@ mod tests { let b5 = block(5, parent); let mut d = BlockStateDiff::default(); - d.post_state.accounts.insert( + d.sorted_post_state.accounts.insert( a3, Some(Account { nonce: 2, balance: U256::from(2_003), ..Default::default() }), ); let mut hs = HashedStorage::default(); hs.storage.insert(s3, U256::from(330)); - d.post_state.storages.insert(stor_addr, hs); + d.sorted_post_state.storages.insert(stor_addr, hs); store.store_trie_updates(b5, d).await.expect("b5"); } diff --git a/crates/optimism/trie/tests/lib.rs b/crates/optimism/trie/tests/lib.rs index db884f1391c..b99e66da687 100644 --- a/crates/optimism/trie/tests/lib.rs +++ b/crates/optimism/trie/tests/lib.rs @@ -108,16 +108,18 @@ async fn test_trie_updates_operations( let block_ref = BlockWithParent::new(B256::ZERO, NumHash::new(50, B256::repeat_byte(0x96))); let trie_updates = TrieUpdates::default(); let post_state = HashedPostState::default(); - let block_state_diff = - BlockStateDiff { trie_updates: trie_updates.clone(), post_state: post_state.clone() }; + let block_state_diff = BlockStateDiff { + sorted_trie_updates: trie_updates.clone(), + sorted_post_state: post_state.clone(), + }; // Store trie updates storage.store_trie_updates(block_ref, block_state_diff).await?; // Retrieve and verify let retrieved_diff = storage.fetch_trie_updates(block_ref.block.number).await?; - assert_eq!(retrieved_diff.trie_updates, trie_updates); - assert_eq!(retrieved_diff.post_state, post_state); + assert_eq!(retrieved_diff.sorted_trie_updates, trie_updates); + assert_eq!(retrieved_diff.sorted_post_state, post_state); Ok(()) } @@ -560,7 +562,7 @@ async fn test_deleted_branch_nodes( assert!(cursor75.seek_exact(path)?.is_some()); let mut block_state_diff = BlockStateDiff::default(); - block_state_diff.trie_updates.removed_nodes.insert(path); + block_state_diff.sorted_trie_updates.removed_nodes.insert(path); storage.store_trie_updates(block_ref, block_state_diff).await?; // Cursor after deletion should not see the node @@ -1050,7 +1052,7 @@ async fn test_storage_zero_value_deletion( let mut block_state_diff = BlockStateDiff::default(); let mut hashed_storage = HashedStorage::default(); hashed_storage.storage.insert(storage_key, U256::ZERO); - block_state_diff.post_state.storages.insert(hashed_address, hashed_storage); + block_state_diff.sorted_post_state.storages.insert(hashed_address, hashed_storage); let block_ref: BlockWithParent = BlockWithParent::new(B256::ZERO, NumHash::new(100, B256::repeat_byte(0x96))); @@ -1243,7 +1245,10 @@ async fn test_store_trie_updates_with_wiped_storage( let wiped_storage = HashedStorage::new(true); // wiped=true, empty storage map post_state.storages.insert(hashed_address, wiped_storage); - let block_state_diff = BlockStateDiff { trie_updates: TrieUpdates::default(), post_state }; + let block_state_diff = BlockStateDiff { + sorted_trie_updates: TrieUpdates::default(), + sorted_post_state: post_state, + }; // Store the wiped state storage.store_trie_updates(block_ref, block_state_diff).await?; @@ -1359,7 +1364,8 @@ async fn test_store_trie_updates_comprehensive( hashed_storage.storage.insert(B256::repeat_byte(0x03), U256::ZERO); // Deleted storage post_state.storages.insert(storage_addr, hashed_storage); - let block_state_diff = BlockStateDiff { trie_updates, post_state }; + let block_state_diff = + BlockStateDiff { sorted_trie_updates: trie_updates, sorted_post_state: post_state }; // Store the updates storage.store_trie_updates(block_ref, block_state_diff).await?; @@ -1438,23 +1444,23 @@ async fn test_store_trie_updates_comprehensive( // Check that trie updates are stored assert_eq!( - fetched_diff.trie_updates.account_nodes_ref().len(), + fetched_diff.sorted_trie_updates.account_nodes_ref().len(), 2, "Should have 2 account nodes" ); assert_eq!( - fetched_diff.trie_updates.storage_tries_ref().len(), + fetched_diff.sorted_trie_updates.storage_tries_ref().len(), 1, "Should have 1 storage trie" ); // Check that post state is stored assert_eq!( - fetched_diff.post_state.accounts.len(), + fetched_diff.sorted_post_state.accounts.len(), 3, "Should have 3 accounts (including deleted)" ); - assert_eq!(fetched_diff.post_state.storages.len(), 1, "Should have 1 storage entry"); + assert_eq!(fetched_diff.sorted_post_state.storages.len(), 1, "Should have 1 storage entry"); Ok(()) } @@ -1493,8 +1499,10 @@ async fn test_replace_updates_applies_all_updates( let mut initial_post_state_50 = HashedPostState::default(); initial_post_state_50.accounts.insert(initial_account_addr, Some(initial_account)); - let initial_diff_50 = - BlockStateDiff { trie_updates: initial_trie_updates_50, post_state: initial_post_state_50 }; + let initial_diff_50 = BlockStateDiff { + sorted_trie_updates: initial_trie_updates_50, + sorted_post_state: initial_post_state_50, + }; storage.store_trie_updates(block_ref_50, initial_diff_50).await?; // Store data at block 100 (common block) @@ -1508,8 +1516,8 @@ async fn test_replace_updates_applies_all_updates( initial_post_state_100.storages.insert(initial_storage_addr, initial_storage_100); let initial_diff_100 = BlockStateDiff { - trie_updates: initial_trie_updates_100, - post_state: initial_post_state_100, + sorted_trie_updates: initial_trie_updates_100, + sorted_post_state: initial_post_state_100, }; let block_ref_100 = @@ -1528,8 +1536,8 @@ async fn test_replace_updates_applies_all_updates( initial_post_state_101.accounts.insert(old_account_addr, Some(old_account)); let initial_diff_101 = BlockStateDiff { - trie_updates: initial_trie_updates_101, - post_state: initial_post_state_101, + sorted_trie_updates: initial_trie_updates_101, + sorted_post_state: initial_post_state_101, }; let block_ref_101 = BlockWithParent::new(block_ref_100.block.hash, NumHash::new(101, B256::repeat_byte(0x98))); @@ -1593,7 +1601,7 @@ async fn test_replace_updates_applies_all_updates( blocks_to_add.insert( block_ref_101, - BlockStateDiff { trie_updates: new_trie_updates, post_state: new_post_state }, + BlockStateDiff { sorted_trie_updates: new_trie_updates, sorted_post_state: new_post_state }, ); // New data for block 102 @@ -1609,7 +1617,7 @@ async fn test_replace_updates_applies_all_updates( blocks_to_add.insert( block_ref_102, - BlockStateDiff { trie_updates: trie_updates_102, post_state: post_state_102 }, + BlockStateDiff { sorted_trie_updates: trie_updates_102, sorted_post_state: post_state_102 }, ); // Execute replace_updates @@ -1696,17 +1704,21 @@ async fn test_replace_updates_applies_all_updates( // Verify fetch_trie_updates returns the new data let fetched_101 = storage.fetch_trie_updates(101).await?; assert_eq!( - fetched_101.trie_updates.account_nodes_ref().len(), + fetched_101.sorted_trie_updates.account_nodes_ref().len(), 1, "Should have 1 account branch node at block 101" ); assert!( - fetched_101.trie_updates.account_nodes_ref().contains_key(&new_branch_path), + fetched_101.sorted_trie_updates.account_nodes_ref().contains_key(&new_branch_path), "New branch path should be in trie_updates" ); - assert_eq!(fetched_101.post_state.accounts.len(), 1, "Should have 1 account at block 101"); + assert_eq!( + fetched_101.sorted_post_state.accounts.len(), + 1, + "Should have 1 account at block 101" + ); assert!( - fetched_101.post_state.accounts.contains_key(&new_account_addr), + fetched_101.sorted_post_state.accounts.contains_key(&new_account_addr), "New account should be in post_state" ); @@ -1745,8 +1757,8 @@ async fn test_pure_deletions_stored_correctly( initial_trie_updates.insert_storage_updates(storage_address, storage_trie); let initial_diff = BlockStateDiff { - trie_updates: initial_trie_updates, - post_state: HashedPostState::default(), + sorted_trie_updates: initial_trie_updates, + sorted_post_state: HashedPostState::default(), }; let block_ref_50 = BlockWithParent::new(B256::ZERO, NumHash::new(50, B256::repeat_byte(0x96))); @@ -1786,8 +1798,8 @@ async fn test_pure_deletions_stored_correctly( deletion_trie_updates.insert_storage_updates(storage_address, deletion_storage_trie); let deletion_diff = BlockStateDiff { - trie_updates: deletion_trie_updates, - post_state: HashedPostState::default(), + sorted_trie_updates: deletion_trie_updates, + sorted_post_state: HashedPostState::default(), }; let block_ref_100 = @@ -1876,8 +1888,8 @@ async fn test_updates_take_precedence_over_removals( initial_trie_updates.insert_storage_updates(storage_address, storage_trie); let initial_diff = BlockStateDiff { - trie_updates: initial_trie_updates, - post_state: HashedPostState::default(), + sorted_trie_updates: initial_trie_updates, + sorted_post_state: HashedPostState::default(), }; let block_ref_50 = BlockWithParent::new(B256::ZERO, NumHash::new(50, B256::repeat_byte(0x96))); @@ -1917,8 +1929,8 @@ async fn test_updates_take_precedence_over_removals( conflicting_trie_updates.insert_storage_updates(storage_address, conflicting_storage_trie); let conflicting_diff = BlockStateDiff { - trie_updates: conflicting_trie_updates, - post_state: HashedPostState::default(), + sorted_trie_updates: conflicting_trie_updates, + sorted_post_state: HashedPostState::default(), }; let block_ref_100 = From b2b968a513bb81e5583a3dd24b38ab53feef972e Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Tue, 9 Dec 2025 11:32:50 +0100 Subject: [PATCH 03/18] Sort updates upon retrieval --- crates/optimism/trie/src/db/store.rs | 31 +++++++++++++++------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/crates/optimism/trie/src/db/store.rs b/crates/optimism/trie/src/db/store.rs index 2924e93afd2..60c8c8a348f 100644 --- a/crates/optimism/trie/src/db/store.rs +++ b/crates/optimism/trie/src/db/store.rs @@ -26,8 +26,10 @@ use reth_db::{ }; use reth_primitives_traits::Account; use reth_trie::{ - hashed_cursor::HashedCursor, trie_cursor::TrieCursor, updates::StorageTrieUpdates, - BranchNodeCompact, HashedStorage, Nibbles, + hashed_cursor::HashedCursor, + trie_cursor::TrieCursor, + updates::{StorageTrieUpdates, TrieUpdates}, + BranchNodeCompact, HashedPostState, HashedStorage, Nibbles, }; use std::{cmp::max, ops::RangeBounds, path::Path}; @@ -272,7 +274,7 @@ impl MdbxProofsStorage { block_state_diff: BlockStateDiff, soft_delete: bool, ) -> OpProofsStorageResult { - let BlockStateDiff { sorted_trie_updates, .. } = block_state_diff; + let BlockStateDiff { sorted_trie_updates, sorted_post_state } = block_state_diff; // Sorted list of updated and removed account nodes let sorted_account_nodes = sorted_trie_updates.account_nodes; @@ -284,8 +286,6 @@ impl MdbxProofsStorage { .sorted_by_key(|(hashed_address, _)| *hashed_address) .collect::>(); - BlockStateDiff { sorted_post_state, .. } = block_state_diff; - let sorted_storage = sorted_post_state .account_storages() .iter() @@ -586,7 +586,7 @@ impl OpProofsStore for MdbxProofsStorage { let mut hashed_account_cursor = tx.new_cursor::()?; let mut hashed_storage_cursor = tx.new_cursor::()?; - let mut block_state_diff = BlockStateDiff::default(); + let mut trie_updates = TrieUpdates::default(); for key in change_set.account_trie_keys { let entry = match account_trie_cursor.seek_by_key_subkey(key.clone(), block_number)? { @@ -600,9 +600,9 @@ impl OpProofsStore for MdbxProofsStorage { }; if let Some(value) = entry { - block_state_diff.sorted_trie_updates.account_nodes.insert(key.0, value); + trie_updates.account_nodes.insert(key.0, value); } else { - block_state_diff.sorted_trie_updates.account_nodes.insert(key.0, B256::ZERO); + trie_updates.removed_nodes.insert(key.0); } } @@ -619,8 +619,7 @@ impl OpProofsStore for MdbxProofsStorage { } }; - let stu = block_state_diff - .sorted_trie_updates + let stu = trie_updates .storage_tries .entry(key.hashed_address) .or_insert_with(StorageTrieUpdates::default); @@ -634,6 +633,8 @@ impl OpProofsStore for MdbxProofsStorage { } } + let mut post_state = + HashedPostState::with_capacity(change_set.hashed_account_keys.len()); for key in change_set.hashed_account_keys { let entry = match hashed_account_cursor.seek_by_key_subkey(key, block_number)? { Some(v) if v.block_number == block_number => v.value.0, @@ -645,7 +646,7 @@ impl OpProofsStore for MdbxProofsStorage { } }; - block_state_diff.sorted_post_state.accounts.insert(key, entry); + post_state.accounts.insert(key, entry); } for key in change_set.hashed_storage_keys { @@ -661,8 +662,7 @@ impl OpProofsStore for MdbxProofsStorage { } }; - let hs = block_state_diff - .sorted_post_state + let hs = post_state .storages .entry(key.hashed_address) .or_insert_with(HashedStorage::default); @@ -676,7 +676,10 @@ impl OpProofsStore for MdbxProofsStorage { } } - Ok(block_state_diff) + Ok(BlockStateDiff { + sorted_trie_updates: trie_updates.into_sorted(), + sorted_post_state: post_state.into_sorted(), + }) })? } From 165337d47a4f5c3e54b3b9d917df2657922bc5a4 Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Tue, 9 Dec 2025 11:51:02 +0100 Subject: [PATCH 04/18] Fix lint lib --- crates/optimism/trie/src/db/store.rs | 7 ++----- crates/optimism/trie/src/in_memory.rs | 2 +- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/crates/optimism/trie/src/db/store.rs b/crates/optimism/trie/src/db/store.rs index 60c8c8a348f..39b1ad349ff 100644 --- a/crates/optimism/trie/src/db/store.rs +++ b/crates/optimism/trie/src/db/store.rs @@ -29,7 +29,7 @@ use reth_trie::{ hashed_cursor::HashedCursor, trie_cursor::TrieCursor, updates::{StorageTrieUpdates, TrieUpdates}, - BranchNodeCompact, HashedPostState, HashedStorage, Nibbles, + BranchNodeCompact, HashedPostState, Nibbles, }; use std::{cmp::max, ops::RangeBounds, path::Path}; @@ -662,10 +662,7 @@ impl OpProofsStore for MdbxProofsStorage { } }; - let hs = post_state - .storages - .entry(key.hashed_address) - .or_insert_with(HashedStorage::default); + let hs = post_state.storages.entry(key.hashed_address).or_default(); // handle wiped storage scenario // Issue: https://github.com/op-rs/op-reth/issues/323 diff --git a/crates/optimism/trie/src/in_memory.rs b/crates/optimism/trie/src/in_memory.rs index 32a46a82363..87490f9527d 100644 --- a/crates/optimism/trie/src/in_memory.rs +++ b/crates/optimism/trie/src/in_memory.rs @@ -114,7 +114,7 @@ impl InMemoryStorageInner { } self.trie_updates.insert(block_number, block_state_diff.sorted_trie_updates.clone()); - self.post_states.insert(block_number, block_state_diff.sorted_post_state.clone()); + self.post_states.insert(block_number, block_state_diff.sorted_post_state); result } From 388967102b7c2a10bbf7d210b92896da87769fbf Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Tue, 9 Dec 2025 13:50:11 +0100 Subject: [PATCH 05/18] Fix BlockStateDiff in pruner tests --- crates/optimism/trie/src/prune/pruner.rs | 84 ++++++++++++++++-------- 1 file changed, 57 insertions(+), 27 deletions(-) diff --git a/crates/optimism/trie/src/prune/pruner.rs b/crates/optimism/trie/src/prune/pruner.rs index 01752943511..0834f6fdc9d 100644 --- a/crates/optimism/trie/src/prune/pruner.rs +++ b/crates/optimism/trie/src/prune/pruner.rs @@ -164,8 +164,10 @@ mod tests { use reth_primitives_traits::Account; use reth_storage_errors::provider::ProviderResult; use reth_trie::{ - hashed_cursor::HashedCursor, trie_cursor::TrieCursor, updates::StorageTrieUpdates, - BranchNodeCompact, HashedStorage, Nibbles, + hashed_cursor::HashedCursor, + trie_cursor::TrieCursor, + updates::{StorageTrieUpdates, TrieUpdates, TrieUpdatesSorted}, + BranchNodeCompact, HashedPostState, HashedStorage, Nibbles, }; use std::sync::Arc; use tempfile::TempDir; @@ -242,13 +244,15 @@ mod tests { // Block 1: add a1,a2; s1=100, s2=200; add p1, st1 { let b1 = block(1, parent); - let mut d = BlockStateDiff::default(); - d.sorted_post_state.accounts.insert( + let mut d_trie_updates = TrieUpdates::default(); + let mut d_post_state = HashedPostState::default(); + + d_post_state.accounts.insert( a1, Some(Account { nonce: 1, balance: U256::from(1_001), ..Default::default() }), ); - d.sorted_post_state.accounts.insert( + d_post_state.accounts.insert( a2, Some(Account { nonce: 1, balance: U256::from(1_002), ..Default::default() }), ); @@ -256,12 +260,16 @@ mod tests { let mut hs = HashedStorage::default(); hs.storage.insert(s1, U256::from(100)); hs.storage.insert(s2, U256::from(200)); - d.sorted_post_state.storages.insert(stor_addr, hs); + d_post_state.storages.insert(stor_addr, hs); - d.sorted_trie_updates.account_nodes.insert(p1, node_p1.clone()); - let e = d.soretd_trie_updates.storage_tries.entry(stor_addr).or_default(); + d_trie_updates.account_nodes.insert(p1, node_p1.clone()); + let e = d_trie_updates.storage_tries.entry(stor_addr).or_default(); e.storage_nodes.insert(st1, BranchNodeCompact::default()); + let d = BlockStateDiff { + sorted_post_state: d_post_state.into_sorted(), + sorted_trie_updates: d_trie_updates.into_sorted(), + }; store.store_trie_updates(b1, d).await.expect("b1"); parent = b256(1); } @@ -269,13 +277,15 @@ mod tests { // Block 2: update a2; add a3; s2=220, s3=300; add p2, st2 { let b2 = block(2, parent); - let mut d = BlockStateDiff::default(); - d.sorted_post_state.accounts.insert( + let mut d_trie_updates = TrieUpdates::default(); + let mut d_post_state = HashedPostState::default(); + + d_post_state.accounts.insert( a2, Some(Account { nonce: 2, balance: U256::from(2_002), ..Default::default() }), ); - d.sorted_post_state.accounts.insert( + d_post_state.accounts.insert( a3, Some(Account { nonce: 1, balance: U256::from(1_003), ..Default::default() }), ); @@ -283,12 +293,16 @@ mod tests { let mut hs = HashedStorage::default(); hs.storage.insert(s2, U256::from(220)); hs.storage.insert(s3, U256::from(300)); - d.sorted_post_state.storages.insert(stor_addr, hs); + d_post_state.storages.insert(stor_addr, hs); - d.sorted_trie_updates.account_nodes.insert(p2, node_p2.clone()); - let e = d.sorted_trie_updates.storage_tries.entry(stor_addr).or_default(); + d_trie_updates.account_nodes.insert(p2, node_p2.clone()); + let e = d_trie_updates.storage_tries.entry(stor_addr).or_default(); e.storage_nodes.insert(st2, node_st2.clone()); + let d = BlockStateDiff { + sorted_post_state: d_post_state.into_sorted(), + sorted_trie_updates: d_trie_updates.into_sorted(), + }; store.store_trie_updates(b2, d).await.expect("b2"); parent = b256(2); } @@ -296,19 +310,25 @@ mod tests { // Block 3: delete a1; leave a2,a3; remove p1; remove st1 (storage-trie) { let b3 = block(3, parent); - let mut d = BlockStateDiff::default(); + + let mut d_trie_updates = TrieUpdates::default(); + let mut d_post_state = HashedPostState::default(); // delete a1, keep a2 & a3 values unchanged for this block - d.sorted_post_state.accounts.insert(a1, None); + d_post_state.accounts.insert(a1, None); // remove account trie node p1 - d.sorted_trie_updates.removed_nodes.insert(p1); + d_trie_updates.removed_nodes.insert(p1); // remove storage-trie node st1 let mut st_upd = StorageTrieUpdates::default(); st_upd.removed_nodes.insert(st1); - d.sorted_trie_updates.storage_tries.insert(stor_addr, st_upd); + d_trie_updates.storage_tries.insert(stor_addr, st_upd); + let d = BlockStateDiff { + sorted_post_state: d_post_state.into_sorted(), + sorted_trie_updates: d_trie_updates.into_sorted(), + }; store.store_trie_updates(b3, d).await.expect("b3"); parent = b256(3); } @@ -316,21 +336,26 @@ mod tests { // Block 4 (kept): update a2; s1=140; add p3, st3 { let b4 = block(4, parent); - let mut d = BlockStateDiff::default(); - d.sorted_post_state.accounts.insert( + let mut d_trie_updates = TrieUpdates::default(); + let mut d_post_state = HashedPostState::default(); + + d_post_state.accounts.insert( a2, Some(Account { nonce: 3, balance: U256::from(3_002), ..Default::default() }), ); let mut hs = HashedStorage::default(); hs.storage.insert(s1, U256::from(140)); - d.sorted_post_state.storages.insert(stor_addr, hs); - - d.sorted_trie_updates.account_nodes.insert(p3, node_p3.clone()); - let e = d.sorted_trie_updates.storage_tries.entry(stor_addr).or_default(); + d_post_state.storages.insert(stor_addr, hs); + d_trie_updates.account_nodes.insert(p3, node_p3.clone()); + let e = d_trie_updates.storage_tries.entry(stor_addr).or_default(); e.storage_nodes.insert(st3, node_st3.clone()); + let d = BlockStateDiff { + sorted_post_state: d_post_state.into_sorted(), + sorted_trie_updates: d_trie_updates.into_sorted(), + }; store.store_trie_updates(b4, d).await.expect("b4"); parent = b256(4); } @@ -338,17 +363,22 @@ mod tests { // Block 5 (kept): update a3; s3=330 { let b5 = block(5, parent); - let mut d = BlockStateDiff::default(); - d.sorted_post_state.accounts.insert( + let mut d_post_state = HashedPostState::default(); + + d_post_state.accounts.insert( a3, Some(Account { nonce: 2, balance: U256::from(2_003), ..Default::default() }), ); let mut hs = HashedStorage::default(); hs.storage.insert(s3, U256::from(330)); - d.sorted_post_state.storages.insert(stor_addr, hs); + d_post_state.storages.insert(stor_addr, hs); + let d = BlockStateDiff { + sorted_post_state: d_post_state.into_sorted(), + sorted_trie_updates: TrieUpdatesSorted::default(), + }; store.store_trie_updates(b5, d).await.expect("b5"); } From 82695f719d81001ccd77f977d215b426d7108d36 Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Tue, 9 Dec 2025 14:09:51 +0100 Subject: [PATCH 06/18] Fix BlockStateDiff in store tests --- crates/optimism/trie/src/db/store.rs | 201 +++++++++++++++++---------- 1 file changed, 128 insertions(+), 73 deletions(-) diff --git a/crates/optimism/trie/src/db/store.rs b/crates/optimism/trie/src/db/store.rs index 39b1ad349ff..a1204e4c92e 100644 --- a/crates/optimism/trie/src/db/store.rs +++ b/crates/optimism/trie/src/db/store.rs @@ -891,6 +891,7 @@ mod tests { models::{AccountTrieHistory, StorageTrieHistory}, StorageTrieKey, }; + use alloy_consensus::Block; use alloy_eips::NumHash; use alloy_primitives::B256; use reth_db::{ @@ -899,7 +900,8 @@ mod tests { DatabaseError, }; use reth_trie::{ - updates::StorageTrieUpdates, BranchNodeCompact, HashedStorage, Nibbles, StoredNibbles, + updates::{StorageTrieUpdates, TrieUpdatesSorted}, + BranchNodeCompact, HashedPostStateSorted, HashedStorage, Nibbles, StoredNibbles, }; use tempfile::TempDir; @@ -2321,22 +2323,37 @@ mod tests { // Block 1: Insert account, trie node, and storage for addr1 let block_1 = BlockWithParent::new(B256::ZERO, NumHash::new(1, B256::random())); - let mut diff1 = BlockStateDiff::default(); - diff1.sorted_post_state.accounts.insert(addr1, Some(acc1)); - diff1.sorted_trie_updates.account_nodes.insert(path1, node1.clone()); + + let mut diff1_trie_updates = TrieUpdates::default(); + let mut diff1_post_state = HashedPostState::default(); + + diff1_post_state.accounts.insert(addr1, Some(acc1)); + diff1_trie_updates.account_nodes.insert(path1, node1.clone()); let mut storage1 = HashedStorage::default(); storage1.storage.insert(slot1, U256::from(1234)); - diff1.sorted_post_state.storages.insert(addr1, storage1.clone()); + diff1_post_state.storages.insert(addr1, storage1.clone()); let mut storage_updates1 = StorageTrieUpdates::default(); storage_updates1.storage_nodes.insert(storage_path1, storage_node1.clone()); - diff1.sorted_trie_updates.storage_tries.insert(addr1, storage_updates1.clone()); - store.store_trie_updates(block_1, diff1).await.unwrap(); + diff1_trie_updates.storage_tries.insert(addr1, storage_updates1.clone()); + + let diff_1 = BlockStateDiff { + sorted_trie_updates: diff1_trie_updates.into_sorted(), + sorted_post_state: diff1_post_state.into_sorted(), + }; + store.store_trie_updates(block_1, diff_1).await.unwrap(); // Block 2: Update account let acc2 = Account { nonce: 2, balance: U256::from(200), ..Default::default() }; let block_2 = BlockWithParent::new(block_1.block.hash, NumHash::new(2, B256::random())); - let mut diff2 = BlockStateDiff::default(); - diff2.sorted_post_state.accounts.insert(addr1, Some(acc2)); + + let mut diff2_post_state = HashedPostState::default(); + + diff2_post_state.accounts.insert(addr1, Some(acc2)); + + let diff2 = BlockStateDiff { + sorted_trie_updates: TrieUpdatesSorted::default(), + sorted_post_state: diff2_post_state.into_sorted(), + }; store.store_trie_updates(block_2, diff2).await.unwrap(); // Prune to block 3 with new initial state for DIFFERENT keys (addr2, path2, etc.) @@ -2345,21 +2362,28 @@ mod tests { let new_storage_node = BranchNodeCompact::new(0b100, 0, 0, vec![], Some(B256::random())); let block_3 = BlockWithParent::new(block_2.block.hash, NumHash::new(3, B256::random())); - let mut prune_diff = BlockStateDiff::default(); - prune_diff.sorted_post_state.accounts.insert(addr1, Some(acc2)); - prune_diff.sorted_post_state.accounts.insert(addr2, Some(new_acc)); - prune_diff.sorted_trie_updates.account_nodes.insert(path1, node1.clone()); - prune_diff.sorted_trie_updates.account_nodes.insert(path2, new_node.clone()); - prune_diff.sorted_post_state.storages.insert(addr1, storage1); - prune_diff.sorted_trie_updates.storage_tries.insert(addr1, storage_updates1); + + let mut prune_diff_trie_updates = TrieUpdates::default(); + let mut prune_diff_post_state = HashedPostState::default(); + + prune_diff_post_state.accounts.insert(addr1, Some(acc2)); + prune_diff_post_state.accounts.insert(addr2, Some(new_acc)); + prune_diff_trie_updates.account_nodes.insert(path1, node1.clone()); + prune_diff_trie_updates.account_nodes.insert(path2, new_node.clone()); + prune_diff_post_state.storages.insert(addr1, storage1); + prune_diff_trie_updates.storage_tries.insert(addr1, storage_updates1); let mut new_storage = HashedStorage::default(); new_storage.storage.insert(slot2, U256::from(9999)); - prune_diff.sorted_post_state.storages.insert(addr2, new_storage); + prune_diff_post_state.storages.insert(addr2, new_storage); let mut new_storage_updates = StorageTrieUpdates::default(); new_storage_updates.storage_nodes.insert(storage_path2, new_storage_node.clone()); - prune_diff.sorted_trie_updates.storage_tries.insert(addr2, new_storage_updates); + prune_diff_trie_updates.storage_tries.insert(addr2, new_storage_updates); + let prune_diff = BlockStateDiff { + sorted_trie_updates: prune_diff_trie_updates.into_sorted(), + sorted_post_state: prune_diff_post_state.into_sorted(), + }; store.prune_earliest_state(block_3, prune_diff).await.unwrap(); let tx = store.env.tx().unwrap(); @@ -2489,9 +2513,12 @@ mod tests { // Prepare a BlockStateDiff that removes an account trie node at `acc_path` let acc_path = Nibbles::from_nibbles_unchecked([0x0A, 0x0B, 0x0C]); - let mut diff = BlockStateDiff::default(); - diff.sorted_trie_updates.removed_nodes.insert(acc_path); - + let mut diff_trie_updates = TrieUpdates::default(); + diff_trie_updates.removed_nodes.insert(acc_path); + let diff = BlockStateDiff { + sorted_trie_updates: diff_trie_updates.into_sorted(), + sorted_post_state: HashedPostStateSorted::default(), + }; store.store_trie_updates(BLOCK, diff).await.expect("store"); // Verify deletion was written at BLOCK @@ -2517,12 +2544,15 @@ mod tests { let addr = B256::from([0xAB; 32]); let st_path = Nibbles::from_nibbles_unchecked([0x01, 0x02, 0x03]); - let mut diff = BlockStateDiff::default(); + let mut diff_trie_updates = TrieUpdates::default(); let mut st_updates = reth_trie::updates::StorageTrieUpdates::default(); // mark this storage trie node as removed st_updates.removed_nodes.insert(st_path); - diff.sorted_trie_updates.storage_tries.insert(addr, st_updates); - + diff_trie_updates.storage_tries.insert(addr, st_updates); + let diff = BlockStateDiff { + sorted_trie_updates: diff_trie_updates.into_sorted(), + sorted_post_state: HashedPostStateSorted::default(), + }; store.store_trie_updates(BLOCK, diff).await.expect("store"); // Verify deletion was written at BLOCK @@ -2562,21 +2592,25 @@ mod tests { // also adds a normal storage-trie node for addr_live. const BLOCK: BlockWithParent = BlockWithParent::new(B256::ZERO, NumHash::new(123, B256::ZERO)); - let mut diff = BlockStateDiff::default(); + let mut diff_trie_updates = TrieUpdates::default(); // Wipe for addr_wiped let mut wiped_updates = StorageTrieUpdates::default(); wiped_updates.set_deleted(true); - diff.sorted_trie_updates.storage_tries.insert(addr_wiped, wiped_updates); + diff_trie_updates.storage_tries.insert(addr_wiped, wiped_updates); // Normal update for addr_live let live_path = Nibbles::from_nibbles_unchecked([0xEE, 0xFF]); let live_node = BranchNodeCompact::default(); let mut live_updates = StorageTrieUpdates::default(); live_updates.storage_nodes.insert(live_path, live_node.clone()); - diff.sorted_trie_updates.storage_tries.insert(addr_live, live_updates); + diff_trie_updates.storage_tries.insert(addr_live, live_updates); // Execute the store + let diff = BlockStateDiff { + sorted_trie_updates: diff_trie_updates.into_sorted(), + sorted_post_state: HashedPostStateSorted::default(), + }; store.store_trie_updates(BLOCK, diff).await.expect("store"); // Verify: for addr_wiped, each previously existing path now has a deletion tombstone at @@ -2630,13 +2664,17 @@ mod tests { store.store_hashed_storages(addr, vec![(s1, v1), (s2, v2)]).await.expect("seed"); // Build BlockStateDiff that marks this address as wiped at BLOCK - let mut diff = BlockStateDiff::default(); + let mut diff_post_state = HashedPostState::default(); let wiped = reth_trie::HashedStorage::new(true); - diff.sorted_post_state.storages.insert(addr, wiped); + diff_post_state.storages.insert(addr, wiped); // Execute + let diff = BlockStateDiff { + sorted_trie_updates: TrieUpdatesSorted::default(), + sorted_post_state: diff_post_state.into_sorted(), + }; store.store_trie_updates(BLOCK, diff).await.expect("store"); // Verify: for each pre-existing slot, there should be a tombstone (MaybeDeleted(None)) at @@ -2687,18 +2725,22 @@ mod tests { // Build diff: wiped first (by address sort), then non-wiped with a write const BLOCK: BlockWithParent = BlockWithParent::new(B256::ZERO, NumHash::new(77, B256::ZERO)); - let mut diff = BlockStateDiff::default(); + let mut diff_post_state = HashedPostState::default(); // Wiped storage for addr_wiped let wiped = reth_trie::HashedStorage::new(true); - diff.sorted_post_state.storages.insert(addr_wiped, wiped); + diff_post_state.storages.insert(addr_wiped, wiped); // Non-wiped storage for addr_live (append new value) let mut live = reth_trie::HashedStorage::default(); live.storage.insert(ls1, lv1_new); - diff.sorted_post_state.storages.insert(addr_live, live); + diff_post_state.storages.insert(addr_live, live); // Execute + let diff = BlockStateDiff { + sorted_trie_updates: TrieUpdatesSorted::default(), + sorted_post_state: diff_post_state.into_sorted(), + }; store.store_trie_updates(BLOCK, diff).await.expect("store"); // Verify: wiped address got tombstones at BLOCK for each pre-existing slot @@ -2776,10 +2818,8 @@ mod tests { // Test address and helper to make diffs with distinct nonces. let addr = B256::from([0xAB; 32]); let make_diff = |nonce: u64| { - let mut d = BlockStateDiff::default(); - d.sorted_post_state - .accounts - .insert(addr, Some(Account { nonce, ..Default::default() })); + let mut d_post_state = HashedPostState::default(); + d_post_state.accounts.insert(addr, Some(Account { nonce, ..Default::default() })); d }; @@ -2864,11 +2904,12 @@ mod tests { let addr = B256::random(); let make_diff = |nonce: u64| { - let mut d = BlockStateDiff::default(); - d.sorted_post_state - .accounts - .insert(addr, Some(Account { nonce, ..Default::default() })); - d + let mut d_post_state = HashedPostState::default(); + d_post_state.accounts.insert(addr, Some(Account { nonce, ..Default::default() })); + BlockStateDiff { + sorted_trie_updates: TrieUpdatesSorted::default(), + sorted_post_state: d_post_state.into_sorted(), + } }; // Build chain: blocks 1 -> 2 -> 3 -> 4 @@ -2913,10 +2954,8 @@ mod tests { let addr = B256::random(); let make_diff = |nonce: u64| { - let mut d = BlockStateDiff::default(); - d.sorted_post_state - .accounts - .insert(addr, Some(Account { nonce, ..Default::default() })); + let mut d_post_state = HashedPostState::default(); + d_post_state.accounts.insert(addr, Some(Account { nonce, ..Default::default() })); d }; @@ -2948,14 +2987,15 @@ mod tests { let slot = B256::random(); let make_diff = |nonce: u64, slot_value: u64| { - let mut d = BlockStateDiff::default(); - d.sorted_post_state - .accounts - .insert(addr, Some(Account { nonce, ..Default::default() })); + let mut d_post_state = HashedPostState::default(); + d_post_state.accounts.insert(addr, Some(Account { nonce, ..Default::default() })); let mut storage = HashedStorage::default(); storage.storage.insert(slot, U256::from(slot_value)); - d.sorted_post_state.storages.insert(addr, storage); - d + d_post_state.storages.insert(addr, storage); + BlockStateDiff { + sorted_trie_updates: TrieUpdatesSorted::default(), + sorted_post_state: d_post_state.into_sorted(), + } }; // Build chain with storage changes @@ -3016,9 +3056,12 @@ mod tests { let node2 = BranchNodeCompact::new(0b10, 0, 0, vec![], Some(B256::random())); let make_diff = |path: Nibbles, node: BranchNodeCompact| { - let mut d = BlockStateDiff::default(); - d.sorted_trie_updates.account_nodes.insert(path, node); - d + let mut d_trie_updates = TrieUpdatesSorted::default(); + d_trie_updates.account_nodes.insert(path, node); + BlockStateDiff { + sorted_trie_updates: d_trie_updates, + sorted_post_state: HashedPostStateSorted::default(), + } }; // Build chain with trie updates @@ -3079,25 +3122,35 @@ mod tests { // Block 1: Insert multiple types of data let b1 = BlockWithParent::new(b0.hash, NumHash::new(1, B256::random())); - let mut diff1 = BlockStateDiff::default(); - diff1.sorted_post_state.accounts.insert(addr1, Some(acc1)); - diff1.sorted_trie_updates.account_nodes.insert(path1, node1.clone()); + let mut diff_1_trie_updates = TrieUpdates::default(); + let mut diff_1_post_state = HashedPostState::default(); + diff1_post_state.accounts.insert(addr1, Some(acc1)); + diff1_trie_updates.account_nodes.insert(path1, node1.clone()); let mut storage1 = HashedStorage::default(); storage1.storage.insert(slot1, U256::from(1111)); - diff1.sorted_post_state.storages.insert(addr1, storage1); + diff1_post_state.storages.insert(addr1, storage1); let mut storage_updates1 = StorageTrieUpdates::default(); storage_updates1.storage_nodes.insert(storage_path1, storage_node1.clone()); - diff1.sorted_trie_updates.storage_tries.insert(addr1, storage_updates1); + diff_1_trie_updates.storage_tries.insert(addr1, storage_updates1); + let diff1 = BlockStateDiff { + sorted_trie_updates: diff_1_trie_updates.into_sorted(), + sorted_post_state: diff_1_post_state.into_sorted(), + }; store.store_trie_updates(b1, diff1).await.expect("store b1"); // Block 2: More updates let b2 = BlockWithParent::new(b1.block.hash, NumHash::new(2, B256::random())); - let mut diff2 = BlockStateDiff::default(); - diff2.sorted_post_state.accounts.insert(addr2, Some(acc2)); - diff2.sorted_trie_updates.account_nodes.insert(path2, node2.clone()); + let mut diff2_trie_updates = TrieUpdates::default(); + let mut diff2_post_state = HashedPostState::default(); + diff2_post_state.accounts.insert(addr2, Some(acc2)); + diff2_trie_updates.account_nodes.insert(path2, node2.clone()); let mut storage2 = HashedStorage::default(); storage2.storage.insert(slot2, U256::from(2222)); - diff2.sorted_post_state.storages.insert(addr2, storage2); + diff2_post_state.storages.insert(addr2, storage2); + let diff2 = BlockStateDiff { + sorted_trie_updates: diff2_trie_updates.into_sorted(), + sorted_post_state: diff2_post_state.into_sorted(), + }; store.store_trie_updates(b2, diff2).await.expect("store b2"); // Block 3: Additional updates @@ -3176,11 +3229,12 @@ mod tests { let addr = B256::random(); let make_diff = |nonce: u64| { - let mut d = BlockStateDiff::default(); - d.sorted_post_state - .accounts - .insert(addr, Some(Account { nonce, ..Default::default() })); - d + let mut d_post_state = HashedPostState::default(); + d_post_state.accounts.insert(addr, Some(Account { nonce, ..Default::default() })); + BlockStateDiff { + sorted_trie_updates: TrieUpdatesSorted::default(), + sorted_post_state: d_post_state.into_sorted(), + } }; // Build chain: blocks 1 -> 2 -> 3 @@ -3216,11 +3270,12 @@ mod tests { let addr = B256::random(); let make_diff = |nonce: u64| { - let mut d = BlockStateDiff::default(); - d.sorted_post_state - .accounts - .insert(addr, Some(Account { nonce, ..Default::default() })); - d + let mut d_oost_state = HashedPostState::default(); + d_post_state.accounts.insert(addr, Some(Account { nonce, ..Default::default() })); + BlockStateDiff { + sorted_trie_updates: TrieUpdatesSorted::default(), + sorted_post_state: d_post_state.into_sorted(), + } }; // Build chain: blocks 1 -> 2 -> 3 From 86b887c2b0624b33aa2b152a2a300172736512a7 Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Tue, 9 Dec 2025 14:15:14 +0100 Subject: [PATCH 07/18] Fix BlockStateDiff in trie integration tests --- crates/optimism/trie/tests/lib.rs | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/crates/optimism/trie/tests/lib.rs b/crates/optimism/trie/tests/lib.rs index b99e66da687..ad7609564a9 100644 --- a/crates/optimism/trie/tests/lib.rs +++ b/crates/optimism/trie/tests/lib.rs @@ -2,6 +2,7 @@ use alloy_eips::{eip1898::BlockWithParent, NumHash}; use alloy_primitives::{map::HashMap, B256, U256}; +use reth_evm::block; use reth_optimism_trie::{ db::MdbxProofsStorage, BlockStateDiff, InMemoryProofsStorage, OpProofsStorageError, OpProofsStore, @@ -9,7 +10,7 @@ use reth_optimism_trie::{ use reth_primitives_traits::Account; use reth_trie::{ hashed_cursor::HashedCursor, trie_cursor::TrieCursor, updates::TrieUpdates, BranchNodeCompact, - HashedPostState, HashedStorage, Nibbles, TrieMask, + HashedPostState, HashedPostStateSorted, HashedStorage, Nibbles, TrieMask, }; use serial_test::serial; use std::sync::Arc; @@ -109,8 +110,8 @@ async fn test_trie_updates_operations( let trie_updates = TrieUpdates::default(); let post_state = HashedPostState::default(); let block_state_diff = BlockStateDiff { - sorted_trie_updates: trie_updates.clone(), - sorted_post_state: post_state.clone(), + sorted_trie_updates: trie_updates.into_sorted(), + sorted_post_state: post_state.into_sorted(), }; // Store trie updates @@ -561,8 +562,12 @@ async fn test_deleted_branch_nodes( let mut cursor75 = storage.account_trie_cursor(75)?; assert!(cursor75.seek_exact(path)?.is_some()); - let mut block_state_diff = BlockStateDiff::default(); - block_state_diff.sorted_trie_updates.removed_nodes.insert(path); + let mut block_state_diff_trie_updates = TrieUpdates::default(); + block_state_diff_trie_updates.removed_nodes.insert(path); + let block_state_diff = BlockStateDiff { + sorted_trie_updates: block_state_diff_trie_updates, + sorted_post_state: HashedPostStateSorted::default(), + }; storage.store_trie_updates(block_ref, block_state_diff).await?; // Cursor after deletion should not see the node @@ -1049,13 +1054,17 @@ async fn test_storage_zero_value_deletion( assert_eq!(result75.1, U256::from(100)); // "Delete" by storing zero value at block 100 - let mut block_state_diff = BlockStateDiff::default(); + let mut block_state_diff_post_state = HashedPostState::default(); let mut hashed_storage = HashedStorage::default(); hashed_storage.storage.insert(storage_key, U256::ZERO); - block_state_diff.sorted_post_state.storages.insert(hashed_address, hashed_storage); + block_state_diff_post_state.storages.insert(hashed_address, hashed_storage); let block_ref: BlockWithParent = BlockWithParent::new(B256::ZERO, NumHash::new(100, B256::repeat_byte(0x96))); + let block_state_diff = BlockStateDiff { + sorted_trie_updates: TrieUpdatesSorted::default(), + sorted_post_state: block_state_diff_post_state.into_sorted(), + }; storage.store_trie_updates(block_ref, block_state_diff).await?; // Cursor after deletion should NOT see the entry (zero values are skipped) From 3d526149c46136470ebb75cf064739204b371625 Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Tue, 9 Dec 2025 14:19:49 +0100 Subject: [PATCH 08/18] fixup! Fix BlockStateDiff in trie integration tests --- crates/optimism/trie/tests/lib.rs | 37 ++++++++++++++++++------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/crates/optimism/trie/tests/lib.rs b/crates/optimism/trie/tests/lib.rs index ad7609564a9..66aaaee227e 100644 --- a/crates/optimism/trie/tests/lib.rs +++ b/crates/optimism/trie/tests/lib.rs @@ -9,8 +9,10 @@ use reth_optimism_trie::{ }; use reth_primitives_traits::Account; use reth_trie::{ - hashed_cursor::HashedCursor, trie_cursor::TrieCursor, updates::TrieUpdates, BranchNodeCompact, - HashedPostState, HashedPostStateSorted, HashedStorage, Nibbles, TrieMask, + hashed_cursor::HashedCursor, + trie_cursor::TrieCursor, + updates::{TrieUpdates, TrieUpdatesSorted}, + BranchNodeCompact, HashedPostState, HashedPostStateSorted, HashedStorage, Nibbles, TrieMask, }; use serial_test::serial; use std::sync::Arc; @@ -1545,8 +1547,8 @@ async fn test_replace_updates_applies_all_updates( initial_post_state_101.accounts.insert(old_account_addr, Some(old_account)); let initial_diff_101 = BlockStateDiff { - sorted_trie_updates: initial_trie_updates_101, - sorted_post_state: initial_post_state_101, + sorted_trie_updates: initial_trie_updates_101.into_sorted(), + sorted_post_state: initial_post_state_101.into_sorted(), }; let block_ref_101 = BlockWithParent::new(block_ref_100.block.hash, NumHash::new(101, B256::repeat_byte(0x98))); @@ -1610,7 +1612,10 @@ async fn test_replace_updates_applies_all_updates( blocks_to_add.insert( block_ref_101, - BlockStateDiff { sorted_trie_updates: new_trie_updates, sorted_post_state: new_post_state }, + BlockStateDiff { + sorted_trie_updates: new_trie_updates.into_sorted(), + sorted_post_state: new_post_state.into_sorted(), + }, ); // New data for block 102 @@ -1626,12 +1631,14 @@ async fn test_replace_updates_applies_all_updates( blocks_to_add.insert( block_ref_102, - BlockStateDiff { sorted_trie_updates: trie_updates_102, sorted_post_state: post_state_102 }, + BlockStateDiff { + sorted_trie_updates: trie_updates_102.into_sorted(), + sorted_post_state: post_state_102.into_sorted(), + }, ); // Execute replace_updates storage.replace_updates(100, blocks_to_add).await?; - // ========== Verify that data up to block 100 still exists ========== let mut cursor_50 = storage.account_trie_cursor(75)?; assert!( @@ -1766,8 +1773,8 @@ async fn test_pure_deletions_stored_correctly( initial_trie_updates.insert_storage_updates(storage_address, storage_trie); let initial_diff = BlockStateDiff { - sorted_trie_updates: initial_trie_updates, - sorted_post_state: HashedPostState::default(), + sorted_trie_updates: initial_trie_updates.into_sorted(), + sorted_post_state: HashedPostStateSorted::default(), }; let block_ref_50 = BlockWithParent::new(B256::ZERO, NumHash::new(50, B256::repeat_byte(0x96))); @@ -1807,8 +1814,8 @@ async fn test_pure_deletions_stored_correctly( deletion_trie_updates.insert_storage_updates(storage_address, deletion_storage_trie); let deletion_diff = BlockStateDiff { - sorted_trie_updates: deletion_trie_updates, - sorted_post_state: HashedPostState::default(), + sorted_trie_updates: deletion_trie_updates.into_sorted(), + sorted_post_state: HashedPostStateSorted::default(), }; let block_ref_100 = @@ -1897,8 +1904,8 @@ async fn test_updates_take_precedence_over_removals( initial_trie_updates.insert_storage_updates(storage_address, storage_trie); let initial_diff = BlockStateDiff { - sorted_trie_updates: initial_trie_updates, - sorted_post_state: HashedPostState::default(), + sorted_trie_updates: initial_trie_updates.into_sorted(), + sorted_post_state: HashedPostStateSorted::default(), }; let block_ref_50 = BlockWithParent::new(B256::ZERO, NumHash::new(50, B256::repeat_byte(0x96))); @@ -1938,8 +1945,8 @@ async fn test_updates_take_precedence_over_removals( conflicting_trie_updates.insert_storage_updates(storage_address, conflicting_storage_trie); let conflicting_diff = BlockStateDiff { - sorted_trie_updates: conflicting_trie_updates, - sorted_post_state: HashedPostState::default(), + sorted_trie_updates: conflicting_trie_updates.into_sorted(), + sorted_post_state: HashedPostStateSorted::default(), }; let block_ref_100 = From 293fa95cbcbeff528e593f65d051bcb19551ea33 Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Tue, 9 Dec 2025 14:24:23 +0100 Subject: [PATCH 09/18] Fix BlockStateDiff in InMemory tests --- crates/optimism/trie/src/in_memory.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/optimism/trie/src/in_memory.rs b/crates/optimism/trie/src/in_memory.rs index 87490f9527d..e6d69f40f1b 100644 --- a/crates/optimism/trie/src/in_memory.rs +++ b/crates/optimism/trie/src/in_memory.rs @@ -763,8 +763,8 @@ mod tests { let trie_updates = TrieUpdatesSorted::default(); let post_state = HashedPostStateSorted::default(); let block_state_diff = BlockStateDiff { - sorted_trie_updates: trie_updates.clone(), - sorted_post_state: post_state.clone(), + sorted_trie_updates: trie_updates.into_sorted(), + sorted_post_state: post_state.into_sorted(), }; const BLOCK: BlockWithParent = From 34a42793ca7166cc28b4957a10e94c8766c82c44 Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Tue, 9 Dec 2025 14:24:39 +0100 Subject: [PATCH 10/18] fixup! Fix BlockStateDiff in store tests --- crates/optimism/trie/src/db/store.rs | 35 ++++++++++++++++++---------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/crates/optimism/trie/src/db/store.rs b/crates/optimism/trie/src/db/store.rs index a1204e4c92e..d2f942cb0dd 100644 --- a/crates/optimism/trie/src/db/store.rs +++ b/crates/optimism/trie/src/db/store.rs @@ -2160,8 +2160,12 @@ mod tests { store.store_trie_updates(block_1, diff1).await.unwrap(); let block_2 = BlockWithParent::new(block_1.block.hash, NumHash::new(2, B256::random())); - let mut diff2 = BlockStateDiff::default(); - diff2.sorted_trie_updates.account_nodes.insert(path2, node2.clone()); + let mut diff2_trie_updates = TrieUpdates::default(); + diff2_trie_updates.account_nodes.insert(path2, node2.clone()); + let diff2 = BlockStateDiff { + sorted_trie_updates: diff2_trie_updates.into_sorted(), + ..Default::default() + }; store.store_trie_updates(block_2, diff2).await.unwrap(); // In block 3, path1 is deleted (stored as None in the database) @@ -2202,9 +2206,13 @@ mod tests { // - path1 should be in removed_nodes (it was deleted in block 3) // - path2 should be included with its value (it still exists from block 2) let block_5 = BlockWithParent::new(B256::random(), NumHash::new(5, B256::random())); - let mut prune_diff = BlockStateDiff::default(); - prune_diff.sorted_trie_updates.removed_nodes.insert(path1); - prune_diff.sorted_trie_updates.account_nodes.insert(path2, node2.clone()); + let mut prune_diff_trie_updates = TrieUpdates::default(); + prune_diff_trie_updates.removed_nodes.insert(path1); + prune_diff_trie_updates.account_nodes.insert(path2, node2.clone()); + let prune_diff = BlockStateDiff { + sorted_trie_updates: prune_diff_trie_updates.into_sorted(), + ..Default::default() + }; store.prune_earliest_state(block_5, prune_diff).await.unwrap(); // Verify that all entries for path1 before block 5 were removed @@ -2820,7 +2828,10 @@ mod tests { let make_diff = |nonce: u64| { let mut d_post_state = HashedPostState::default(); d_post_state.accounts.insert(addr, Some(Account { nonce, ..Default::default() })); - d + BlockStateDiff { + sorted_trie_updates: TrieUpdatesSorted::default(), + sorted_post_state: d_post_state.into_sorted(), + } }; // --- Build initial canonical chain: 1 -> 2 -> 3 --- @@ -3056,7 +3067,7 @@ mod tests { let node2 = BranchNodeCompact::new(0b10, 0, 0, vec![], Some(B256::random())); let make_diff = |path: Nibbles, node: BranchNodeCompact| { - let mut d_trie_updates = TrieUpdatesSorted::default(); + let mut d_trie_updates = TrieUpdates::default(); d_trie_updates.account_nodes.insert(path, node); BlockStateDiff { sorted_trie_updates: d_trie_updates, @@ -3122,8 +3133,8 @@ mod tests { // Block 1: Insert multiple types of data let b1 = BlockWithParent::new(b0.hash, NumHash::new(1, B256::random())); - let mut diff_1_trie_updates = TrieUpdates::default(); - let mut diff_1_post_state = HashedPostState::default(); + let mut diff1_trie_updates = TrieUpdates::default(); + let mut diff1_post_state = HashedPostState::default(); diff1_post_state.accounts.insert(addr1, Some(acc1)); diff1_trie_updates.account_nodes.insert(path1, node1.clone()); let mut storage1 = HashedStorage::default(); @@ -3131,10 +3142,10 @@ mod tests { diff1_post_state.storages.insert(addr1, storage1); let mut storage_updates1 = StorageTrieUpdates::default(); storage_updates1.storage_nodes.insert(storage_path1, storage_node1.clone()); - diff_1_trie_updates.storage_tries.insert(addr1, storage_updates1); + diff1_trie_updates.storage_tries.insert(addr1, storage_updates1); let diff1 = BlockStateDiff { - sorted_trie_updates: diff_1_trie_updates.into_sorted(), - sorted_post_state: diff_1_post_state.into_sorted(), + sorted_trie_updates: diff1_trie_updates.into_sorted(), + sorted_post_state: diff1_post_state.into_sorted(), }; store.store_trie_updates(b1, diff1).await.expect("store b1"); From 599c0f071cfb87b69cc6a4cc8775ff9a05997be1 Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Tue, 9 Dec 2025 14:28:13 +0100 Subject: [PATCH 11/18] Fix tests --- crates/optimism/trie/src/db/store.rs | 44 +++++++++++++++++++-------- crates/optimism/trie/src/in_memory.rs | 9 ++---- crates/optimism/trie/tests/lib.rs | 9 ++---- 3 files changed, 38 insertions(+), 24 deletions(-) diff --git a/crates/optimism/trie/src/db/store.rs b/crates/optimism/trie/src/db/store.rs index d2f942cb0dd..a730e7efe3b 100644 --- a/crates/optimism/trie/src/db/store.rs +++ b/crates/optimism/trie/src/db/store.rs @@ -2155,8 +2155,12 @@ mod tests { let node2 = BranchNodeCompact::new(0b10, 0, 0, vec![], Some(B256::random())); let block_1 = BlockWithParent::new(B256::ZERO, NumHash::new(1, B256::random())); - let mut diff1 = BlockStateDiff::default(); - diff1.sorted_trie_updates.account_nodes.insert(path1, node1.clone()); + let mut diff1_trie_updates = TrieUpdates::default(); + diff1_trie_updates.account_nodes.insert(path1, node1.clone()); + let diff1 = BlockStateDiff { + sorted_trie_updates: diff1_trie_updates.into_sorted(), + ..Default::default() + }; store.store_trie_updates(block_1, diff1).await.unwrap(); let block_2 = BlockWithParent::new(block_1.block.hash, NumHash::new(2, B256::random())); @@ -2261,22 +2265,34 @@ mod tests { let new_acc = Account { nonce: 10, balance: U256::from(500), ..Default::default() }; let block_1 = BlockWithParent::new(B256::ZERO, NumHash::new(1, B256::random())); - let mut diff1 = BlockStateDiff::default(); - diff1.sorted_post_state.accounts.insert(addr1, Some(acc1)); + let mut diff1_post_state = HashedPostState::default(); + diff1_post_state.accounts.insert(addr1, Some(acc1)); + let diff1 = BlockStateDiff { + sorted_post_state: diff1_post_state.into_sorted(), + ..Default::default() + }; store.store_trie_updates(block_1, diff1).await.unwrap(); let block_2 = BlockWithParent::new(block_1.block.hash, NumHash::new(2, B256::random())); - let mut diff2 = BlockStateDiff::default(); - diff2.sorted_post_state.accounts.insert(addr1, Some(acc2)); + let mut diff2_post_state = HashedPostState::default(); + diff2_post_state.accounts.insert(addr1, Some(acc2)); + let diff2 = BlockStateDiff { + sorted_post_state: diff2_post_state.into_sorted(), + ..Default::default() + }; store.store_trie_updates(block_2, diff2).await.unwrap(); // Prune to block 3, with new initial state including: // - addr1 with its final value (acc2) from block 2 // - addr2 as a new account let block_3 = BlockWithParent::new(block_2.block.hash, NumHash::new(3, B256::random())); - let mut prune_diff = BlockStateDiff::default(); - prune_diff.sorted_post_state.accounts.insert(addr1, Some(acc2)); - prune_diff.sorted_post_state.accounts.insert(addr2, Some(new_acc)); + let mut prune_diff_post_state = HashedPostState::default(); + prune_diff_post_state.accounts.insert(addr1, Some(acc2)); + prune_diff_post_state.accounts.insert(addr2, Some(new_acc)); + let prune_diff = BlockStateDiff { + sorted_post_state: prune_diff_post_state.into_sorted(), + ..Default::default() + }; store.prune_earliest_state(block_3, prune_diff).await.unwrap(); // Verify old versions of addr1 were pruned @@ -3070,7 +3086,7 @@ mod tests { let mut d_trie_updates = TrieUpdates::default(); d_trie_updates.account_nodes.insert(path, node); BlockStateDiff { - sorted_trie_updates: d_trie_updates, + sorted_trie_updates: d_trie_updates.into_sorted(), sorted_post_state: HashedPostStateSorted::default(), } }; @@ -3166,8 +3182,12 @@ mod tests { // Block 3: Additional updates let b3 = BlockWithParent::new(b2.block.hash, NumHash::new(3, B256::random())); - let mut diff3 = BlockStateDiff::default(); - diff3.sorted_post_state.accounts.insert(addr1, Some(acc2)); // update addr1 + let mut diff3_post_state = HashedPostState::default(); + diff3_post_state.accounts.insert(addr1, Some(acc2)); // update addr1 + let diff3 = BlockStateDiff { + sorted_trie_updates: TrieUpdatesSorted::default(), + sorted_post_state: diff3_post_state.into_sorted(), + }; store.store_trie_updates(b3, diff3).await.expect("store b3"); // Unwind to block 1 diff --git a/crates/optimism/trie/src/in_memory.rs b/crates/optimism/trie/src/in_memory.rs index e6d69f40f1b..3b6f39b9c21 100644 --- a/crates/optimism/trie/src/in_memory.rs +++ b/crates/optimism/trie/src/in_memory.rs @@ -760,12 +760,9 @@ mod tests { async fn test_trie_updates_storage() -> Result<(), OpProofsStorageError> { let storage = InMemoryProofsStorage::new(); - let trie_updates = TrieUpdatesSorted::default(); - let post_state = HashedPostStateSorted::default(); - let block_state_diff = BlockStateDiff { - sorted_trie_updates: trie_updates.into_sorted(), - sorted_post_state: post_state.into_sorted(), - }; + let sorted_trie_updates = TrieUpdatesSorted::default(); + let sorted_post_state = HashedPostStateSorted::default(); + let block_state_diff = BlockStateDiff { sorted_trie_updates, sorted_post_state }; const BLOCK: BlockWithParent = BlockWithParent::new(B256::ZERO, NumHash::new(5, B256::ZERO)); diff --git a/crates/optimism/trie/tests/lib.rs b/crates/optimism/trie/tests/lib.rs index 66aaaee227e..32b13ca430f 100644 --- a/crates/optimism/trie/tests/lib.rs +++ b/crates/optimism/trie/tests/lib.rs @@ -109,12 +109,9 @@ async fn test_trie_updates_operations( storage: S, ) -> Result<(), OpProofsStorageError> { let block_ref = BlockWithParent::new(B256::ZERO, NumHash::new(50, B256::repeat_byte(0x96))); - let trie_updates = TrieUpdates::default(); - let post_state = HashedPostState::default(); - let block_state_diff = BlockStateDiff { - sorted_trie_updates: trie_updates.into_sorted(), - sorted_post_state: post_state.into_sorted(), - }; + let sorted_trie_updates = TrieUpdatesSorted::default(); + let sorted_post_state = HashedPostStateSorted::default(); + let block_state_diff = BlockStateDiff { sorted_trie_updates, sorted_post_state }; // Store trie updates storage.store_trie_updates(block_ref, block_state_diff).await?; From caf02144540426a8983952bada11aa3c9223c35c Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Tue, 9 Dec 2025 14:31:12 +0100 Subject: [PATCH 12/18] Fix tests --- crates/optimism/trie/src/db/store.rs | 61 ++++++++++++++++------------ crates/optimism/trie/tests/lib.rs | 2 +- 2 files changed, 37 insertions(+), 26 deletions(-) diff --git a/crates/optimism/trie/src/db/store.rs b/crates/optimism/trie/src/db/store.rs index a730e7efe3b..d8bac197df0 100644 --- a/crates/optimism/trie/src/db/store.rs +++ b/crates/optimism/trie/src/db/store.rs @@ -887,9 +887,12 @@ impl reth_db::database_metrics::DatabaseMetrics for MdbxProofsStorage { #[cfg(test)] mod tests { use super::*; - use crate::db::{ - models::{AccountTrieHistory, StorageTrieHistory}, - StorageTrieKey, + use crate::{ + db::{ + models::{AccountTrieHistory, StorageTrieHistory}, + StorageTrieKey, + }, + prune, }; use alloy_consensus::Block; use alloy_eips::NumHash; @@ -899,6 +902,7 @@ mod tests { transaction::{DbTx, DbTxMut}, DatabaseError, }; + use reth_revm::db::states::state; use reth_trie::{ updates::{StorageTrieUpdates, TrieUpdatesSorted}, BranchNodeCompact, HashedPostStateSorted, HashedStorage, Nibbles, StoredNibbles, @@ -1351,42 +1355,41 @@ mod tests { let storage_node2 = BranchNodeCompact::default(); // Construct test BlockStateDiff - let mut block_state_diff = BlockStateDiff::default(); + let mut block_state_diff_trie_updates = TrieUpdates::default(); + let mut block_state_diff_post_state = HashedPostState::default(); // Add account trie nodes - block_state_diff - .sorted_trie_updates - .account_nodes - .insert(account_path1, account_node1.clone()); - block_state_diff - .sorted_trie_updates - .account_nodes - .insert(account_path2, account_node2.clone()); - block_state_diff.sorted_trie_updates.removed_nodes.insert(removed_account_path); + block_state_diff_trie_updates.account_nodes.insert(account_path1, account_node1.clone()); + block_state_diff_trie_updates.account_nodes.insert(account_path2, account_node2.clone()); + block_state_diff_trie_updates.removed_nodes.insert(removed_account_path); // Add storage trie nodes for two addresses let mut storage_nodes1 = StorageTrieUpdates::default(); storage_nodes1.storage_nodes.insert(storage_path1, storage_node1.clone()); - block_state_diff.sorted_trie_updates.storage_tries.insert(addr1, storage_nodes1); + block_state_diff_trie_updates.storage_tries.insert(addr1, storage_nodes1); let mut storage_nodes2 = StorageTrieUpdates::default(); storage_nodes2.storage_nodes.insert(storage_path2, storage_node2.clone()); - block_state_diff.sorted_trie_updates.storage_tries.insert(addr2, storage_nodes2); + block_state_diff_trie_updates.storage_tries.insert(addr2, storage_nodes2); // Add hashed accounts (one Some, one None) - block_state_diff.sorted_post_state.accounts.insert(addr1, Some(acc1)); - block_state_diff.sorted_post_state.accounts.insert(addr2, None); // Deletion + block_state_diff_state.accounts.insert(addr1, Some(acc1)); + block_state_diff_post_state.accounts.insert(addr2, None); // Deletion // Add storage slots for both addresses let mut storage1 = HashedStorage::default(); storage1.storage.insert(slot1, val1); - block_state_diff.sorted_post_state.storages.insert(addr1, storage1); + block_state_diff_post_state.storages.insert(addr1, storage1); let mut storage2 = HashedStorage::default(); storage2.storage.insert(slot2, val2); - block_state_diff.sorted_post_state.storages.insert(addr2, storage2); + block_state_diff_post_state.storages.insert(addr2, storage2); // Store everything + let block_state_diff = BlockStateDiff { + sorted_trie_updates: block_state_diff_trie_updates.into_sorted(), + sorted_post_state: block_state_diff_post_state.into_sorted(), + }; store.store_trie_updates(BLOCK, block_state_diff).await.expect("store"); // Verify account trie nodes @@ -2096,20 +2099,28 @@ mod tests { store.store_trie_updates(block_1, state_diff1).await.unwrap(); let block_2 = BlockWithParent::new(block_1.block.hash, NumHash::new(2, B256::random())); - let mut state_diff2 = BlockStateDiff::default(); - state_diff2.sorted_post_state.accounts.insert(addr2, Some(acc2)); + let mut state_diff2_post_state = HashedPostState::default(); + state_diff2_post_state.accounts.insert(addr2, Some(acc2)); + let state_diff2 = BlockStateDiff { + sorted_post_state: state_diff2_post_state.into_sorted(), + ..Default::default() + }; store.store_trie_updates(block_2, state_diff2).await.unwrap(); // Now prune to block 3, passing a diff that represents the new initial state let new_initial_account = Account { nonce: 10, balance: U256::from(1000), ..Default::default() }; let new_addr = B256::random(); - let mut prune_diff = BlockStateDiff::default(); - prune_diff.sorted_post_state.accounts.insert(addr1, Some(acc1)); - prune_diff.sorted_post_state.accounts.insert(addr2, Some(acc2)); - prune_diff.sorted_post_state.accounts.insert(new_addr, Some(new_initial_account)); + let mut prune_diff_post_state = HashedPostState::default(); + prune_diff_post_state.accounts.insert(addr1, Some(acc1)); + prune_diff_post_state.accounts.insert(addr2, Some(acc2)); + prune_diff_post_state.accounts.insert(new_addr, Some(new_initial_account)); let block_3 = BlockWithParent::new(block_2.block.hash, NumHash::new(3, B256::random())); + let prune_diff = BlockStateDiff { + sorted_post_state: prune_diff_post_state.into_sorted(), + ..Default::default() + }; store.prune_earliest_state(block_3, prune_diff).await.unwrap(); // Verify that blocks 1 and 2 entries were pruned diff --git a/crates/optimism/trie/tests/lib.rs b/crates/optimism/trie/tests/lib.rs index 32b13ca430f..f6e1a6407a2 100644 --- a/crates/optimism/trie/tests/lib.rs +++ b/crates/optimism/trie/tests/lib.rs @@ -564,7 +564,7 @@ async fn test_deleted_branch_nodes( let mut block_state_diff_trie_updates = TrieUpdates::default(); block_state_diff_trie_updates.removed_nodes.insert(path); let block_state_diff = BlockStateDiff { - sorted_trie_updates: block_state_diff_trie_updates, + sorted_trie_updates: block_state_diff_trie_updates.into_sorted(), sorted_post_state: HashedPostStateSorted::default(), }; storage.store_trie_updates(block_ref, block_state_diff).await?; From 6c9c0b112eb6343ec07e19ac1686b05b9784e378 Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Tue, 9 Dec 2025 14:40:12 +0100 Subject: [PATCH 13/18] Remove redundant sort on proofs db write --- crates/optimism/trie/src/db/store.rs | 28 ++++++---------------------- 1 file changed, 6 insertions(+), 22 deletions(-) diff --git a/crates/optimism/trie/src/db/store.rs b/crates/optimism/trie/src/db/store.rs index d8bac197df0..79bb2c40797 100644 --- a/crates/optimism/trie/src/db/store.rs +++ b/crates/optimism/trie/src/db/store.rs @@ -276,40 +276,24 @@ impl MdbxProofsStorage { ) -> OpProofsStorageResult { let BlockStateDiff { sorted_trie_updates, sorted_post_state } = block_state_diff; - // Sorted list of updated and removed account nodes - let sorted_account_nodes = sorted_trie_updates.account_nodes; - - // Sorted list of updated and removed storage nodes - let sorted_storage_nodes = sorted_trie_updates - .storage_tries - .into_iter() - .sorted_by_key(|(hashed_address, _)| *hashed_address) - .collect::>(); - - let sorted_storage = sorted_post_state - .account_storages() - .iter() - .map(|(k, v)| (*k, v.clone())) - .collect::>(); - - let storage_trie_len = sorted_storage_nodes.len(); - let hashed_storage_len = sorted_storage.len(); + let storage_trie_len = sorted_trie_updates.storage_tries.len(); + let hashed_storage_len = sorted_post_state.storages.len(); let account_trie_keys = self.append_or_delete_dup_sorted( tx, block_number, - sorted_account_nodes.into_iter(), + sorted_trie_updates.account_nodes.into_iter(), soft_delete, )?; let hashed_account_keys = self.append_or_delete_dup_sorted( tx, block_number, - sorted_post_state.accounts().iter().copied(), + sorted_post_state.accounts.iter().copied(), soft_delete, )?; let mut storage_trie_keys = Vec::::with_capacity(storage_trie_len); - for (hashed_address, nodes) in sorted_storage_nodes { + for (hashed_address, nodes) in sorted_trie_updates.storage_tries { // Handle wiped - mark all storage trie as deleted at the current block number if nodes.is_deleted && soft_delete { // Yet to have any update for the current block number - So just using up to @@ -334,7 +318,7 @@ impl MdbxProofsStorage { } let mut hashed_storage_keys = Vec::::with_capacity(hashed_storage_len); - for (hashed_address, storage) in sorted_storage { + for (hashed_address, storage) in sorted_post_state.storages { // Handle wiped - mark all storage slots as deleted at the current block number if soft_delete && storage.is_wiped() { // Yet to have any update for the current block number - So just using up to From 0cf2bbc480ea116731a54813222d767f08dbffb7 Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Wed, 10 Dec 2025 16:16:26 +0100 Subject: [PATCH 14/18] Fix lint --- Cargo.lock | 1 - crates/optimism/trie/Cargo.toml | 1 - crates/optimism/trie/src/db/store.rs | 1 - 3 files changed, 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d0654fc67ee..34d7480a4e3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9894,7 +9894,6 @@ dependencies = [ "bytes", "derive_more", "eyre", - "itertools 0.14.0", "metrics", "mockall", "reth-chainspec", diff --git a/crates/optimism/trie/Cargo.toml b/crates/optimism/trie/Cargo.toml index 02b7362893a..d5ee4d639a2 100644 --- a/crates/optimism/trie/Cargo.toml +++ b/crates/optimism/trie/Cargo.toml @@ -45,7 +45,6 @@ eyre.workspace = true strum.workspace = true tracing.workspace = true derive_more.workspace = true -itertools.workspace = true [dev-dependencies] reth-codecs = { workspace = true, features = ["test-utils"] } diff --git a/crates/optimism/trie/src/db/store.rs b/crates/optimism/trie/src/db/store.rs index 79bb2c40797..12cd6d0fcdc 100644 --- a/crates/optimism/trie/src/db/store.rs +++ b/crates/optimism/trie/src/db/store.rs @@ -14,7 +14,6 @@ use crate::{ }; use alloy_eips::{eip1898::BlockWithParent, NumHash}; use alloy_primitives::{map::HashMap, B256, U256}; -use itertools::Itertools; #[cfg(feature = "metrics")] use metrics::{gauge, Label}; use reth_db::{ From 9d16451c5bba4980dec93600939396ff2b5d2254 Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Fri, 12 Dec 2025 18:04:32 +0100 Subject: [PATCH 15/18] Fix BlockStateDiff refactor in tests --- crates/optimism/exex/src/lib.rs | 19 +++-- crates/optimism/trie/src/db/store.rs | 113 +++++++++++++++----------- crates/optimism/trie/src/in_memory.rs | 9 +- crates/optimism/trie/src/live.rs | 9 +- crates/optimism/trie/tests/lib.rs | 36 ++++---- 5 files changed, 109 insertions(+), 77 deletions(-) diff --git a/crates/optimism/exex/src/lib.rs b/crates/optimism/exex/src/lib.rs index 0de02a78906..e8c47af9273 100644 --- a/crates/optimism/exex/src/lib.rs +++ b/crates/optimism/exex/src/lib.rs @@ -20,7 +20,7 @@ use reth_optimism_trie::{ live::LiveTrieCollector, OpProofStoragePrunerTask, OpProofsStorage, OpProofsStore, }; use reth_provider::{BlockReader, TransactionVariant}; -use reth_trie::{updates::TrieUpdates, HashedPostState}; +use reth_trie::{updates::TrieUpdatesSorted, HashedPostStateSorted}; use std::{sync::Arc, time::Duration}; use tracing::{debug, info}; @@ -253,8 +253,8 @@ where collector .store_block_updates( block.block_with_parent(), - (*trie_updates).clone(), - (*hashed_state).clone(), + (**trie_updates).clone(), + (**hashed_state).clone(), ) .await?; @@ -306,8 +306,11 @@ where } // find the common ancestor - let mut block_updates: Vec<(BlockWithParent, Arc, Arc)> = - Vec::with_capacity(new.len()); + let mut block_updates: Vec<( + BlockWithParent, + Arc, + Arc, + )> = Vec::with_capacity(new.len()); for block_number in new.blocks().keys() { // verify if the fork point matches if old.fork_block() != new.fork_block() { @@ -329,7 +332,11 @@ where eyre::eyre!("Missing Hashed state for block {} in new chain", block_number) })?; - block_updates.push((block.block_with_parent(), trie_updates, hashed_state)); + block_updates.push(( + block.block_with_parent(), + trie_updates.clone(), + hashed_state.clone(), + )); } collector.unwind_and_store_block_updates(block_updates).await?; diff --git a/crates/optimism/trie/src/db/store.rs b/crates/optimism/trie/src/db/store.rs index 12cd6d0fcdc..5db93c30000 100644 --- a/crates/optimism/trie/src/db/store.rs +++ b/crates/optimism/trie/src/db/store.rs @@ -870,14 +870,10 @@ impl reth_db::database_metrics::DatabaseMetrics for MdbxProofsStorage { #[cfg(test)] mod tests { use super::*; - use crate::{ - db::{ - models::{AccountTrieHistory, StorageTrieHistory}, - StorageTrieKey, - }, - prune, + use crate::db::{ + models::{AccountTrieHistory, StorageTrieHistory}, + StorageTrieKey, }; - use alloy_consensus::Block; use alloy_eips::NumHash; use alloy_primitives::B256; use reth_db::{ @@ -885,7 +881,6 @@ mod tests { transaction::{DbTx, DbTxMut}, DatabaseError, }; - use reth_revm::db::states::state; use reth_trie::{ updates::{StorageTrieUpdates, TrieUpdatesSorted}, BranchNodeCompact, HashedPostStateSorted, HashedStorage, Nibbles, StoredNibbles, @@ -1356,7 +1351,7 @@ mod tests { block_state_diff_trie_updates.storage_tries.insert(addr2, storage_nodes2); // Add hashed accounts (one Some, one None) - block_state_diff_state.accounts.insert(addr1, Some(acc1)); + block_state_diff_post_state.accounts.insert(addr1, Some(acc1)); block_state_diff_post_state.accounts.insert(addr2, None); // Deletion // Add storage slots for both addresses @@ -1519,19 +1514,24 @@ mod tests { let addr = B256::from([0x21; 32]); // block A (parent = ZERO) let block_a = BlockWithParent::new(B256::ZERO, NumHash::new(1, B256::random())); - let mut diff_a = BlockStateDiff::default(); - diff_a.sorted_post_state.accounts.insert(addr, Some(Account::default())); + let mut diff_a_post_state = HashedPostState::default(); + diff_a_post_state.accounts.insert(addr, Some(Account::default())); + let diff_a = BlockStateDiff { + sorted_trie_updates: TrieUpdatesSorted::default(), + sorted_post_state: diff_a_post_state.into_sorted(), + }; store.store_trie_updates(block_a, diff_a).await.expect("store A"); // block B (parent = hash of A) let block_b = BlockWithParent::new(block_a.block.hash, NumHash::new(2, B256::random())); - let mut diff_b = BlockStateDiff::default(); - diff_b - .sorted_post_state - .accounts - .insert(addr, Some(Account { nonce: 5, ..Default::default() })); + let mut diff_b_post_state = HashedPostState::default(); + diff_b_post_state.accounts.insert(addr, Some(Account { nonce: 5, ..Default::default() })); + let diff_b = BlockStateDiff { + sorted_trie_updates: TrieUpdatesSorted::default(), + sorted_post_state: diff_b_post_state.into_sorted(), + }; store.store_trie_updates(block_b, diff_b).await.expect("store B"); // verify we can retrieve entries for both block numbers @@ -1601,7 +1601,6 @@ mod tests { store.store_trie_updates(block, diff).await.expect("store"); let got = store.fetch_trie_updates(1).await.expect("fetch"); assert!(got.sorted_trie_updates.account_nodes.is_empty()); - assert!(got.sorted_trie_updates.removed_nodes.is_empty()); assert!(got.sorted_trie_updates.storage_tries.is_empty()); assert!(got.sorted_post_state.accounts.is_empty()); assert!(got.sorted_post_state.storages.is_empty()); @@ -1891,34 +1890,33 @@ mod tests { BranchNodeCompact { root_hash: Some(B256::random()), ..Default::default() }; // Construct BlockStateDiff - let mut block_state_diff = BlockStateDiff::default(); - block_state_diff - .sorted_trie_updates - .account_nodes - .insert(account_path1, account_node1.clone()); - block_state_diff - .sorted_trie_updates - .account_nodes - .insert(account_path2, account_node2.clone()); + let mut block_state_diff_trie_updates = TrieUpdates::default(); + block_state_diff_trie_updates.account_nodes.insert(account_path1, account_node1.clone()); + block_state_diff_trie_updates.account_nodes.insert(account_path2, account_node2.clone()); // storage trie for addr1 let mut storage_nodes1 = StorageTrieUpdates::default(); storage_nodes1.storage_nodes.insert(storage_path1, storage_node1.clone()); - block_state_diff.sorted_trie_updates.storage_tries.insert(addr1, storage_nodes1); + block_state_diff_trie_updates.storage_tries.insert(addr1, storage_nodes1); // hashed accounts: addr1 -> Some, addr2 -> None - block_state_diff.sorted_post_state.accounts.insert(addr1, Some(acc1)); - block_state_diff.sorted_post_state.accounts.insert(addr2, None); + let mut block_state_diff_post_state = HashedPostState::default(); + block_state_diff_post_state.accounts.insert(addr1, Some(acc1)); + block_state_diff_post_state.accounts.insert(addr2, None); // hashed storages let mut storage1 = HashedStorage::default(); storage1.storage.insert(slot1, val1); - block_state_diff.sorted_post_state.storages.insert(addr1, storage1); + block_state_diff_post_state.storages.insert(addr1, storage1); let mut storage2 = HashedStorage::default(); storage2.storage.insert(slot2, val2); - block_state_diff.sorted_post_state.storages.insert(addr2, storage2); + block_state_diff_post_state.storages.insert(addr2, storage2); // store then fetch + let block_state_diff = BlockStateDiff { + sorted_trie_updates: block_state_diff_trie_updates.into_sorted(), + sorted_post_state: block_state_diff_post_state.into_sorted(), + }; store.store_trie_updates(block, block_state_diff.clone()).await.expect("store"); let got = store.fetch_trie_updates(1).await.expect("fetch"); @@ -1927,10 +1925,6 @@ mod tests { got.sorted_trie_updates.account_nodes, block_state_diff.sorted_trie_updates.account_nodes, ); - assert_eq!( - got.sorted_trie_updates.removed_nodes, - block_state_diff.sorted_trie_updates.removed_nodes, - ); assert_eq!( got.sorted_trie_updates.storage_tries, block_state_diff.sorted_trie_updates.storage_tries, @@ -1950,8 +1944,12 @@ mod tests { // Insert a single entry to be pruned let addr = B256::random(); - let mut state_diff = BlockStateDiff::default(); - state_diff.sorted_post_state.accounts.insert(addr, Some(Account::default())); + let mut state_diff_post_state = HashedPostState::default(); + state_diff_post_state.accounts.insert(addr, Some(Account::default())); + let state_diff = BlockStateDiff { + sorted_post_state: state_diff_post_state.into_sorted(), + ..Default::default() + }; store.store_trie_updates(block, state_diff).await.unwrap(); // Prune the entry - pass empty diff since we're just removing data @@ -1981,9 +1979,13 @@ mod tests { // Insert multiple entries for the same block let addr1 = B256::random(); let addr2 = B256::random(); - let mut state_diff = BlockStateDiff::default(); - state_diff.sorted_post_state.accounts.insert(addr1, Some(Account::default())); - state_diff.sorted_post_state.accounts.insert(addr2, Some(Account::default())); + let mut state_diff_post_state = HashedPostState::default(); + state_diff_post_state.accounts.insert(addr1, Some(Account::default())); + state_diff_post_state.accounts.insert(addr2, Some(Account::default())); + let state_diff = BlockStateDiff { + sorted_post_state: state_diff_post_state.into_sorted(), + ..Default::default() + }; store.store_trie_updates(block, state_diff).await.unwrap(); // Prune the entries @@ -2012,12 +2014,20 @@ mod tests { // Insert entries for multiple blocks let addr1 = B256::random(); let addr2 = B256::random(); - let mut state_diff1 = BlockStateDiff::default(); - state_diff1.sorted_post_state.accounts.insert(addr1, Some(Account::default())); + let mut state_diff1_post_state = HashedPostState::default(); + state_diff1_post_state.accounts.insert(addr1, Some(Account::default())); + let state_diff1 = BlockStateDiff { + sorted_post_state: state_diff1_post_state.into_sorted(), + ..Default::default() + }; store.store_trie_updates(block_1, state_diff1).await.unwrap(); - let mut state_diff2 = BlockStateDiff::default(); - state_diff2.sorted_post_state.accounts.insert(addr2, Some(Account::default())); + let mut state_diff2_post_state = HashedPostState::default(); + state_diff2_post_state.accounts.insert(addr2, Some(Account::default())); + let state_diff2 = BlockStateDiff { + sorted_post_state: state_diff2_post_state.into_sorted(), + ..Default::default() + }; store.store_trie_updates(block_2, state_diff2).await.unwrap(); // Prune up to block 3 (should remove blocks 1 and 2) @@ -2077,8 +2087,12 @@ mod tests { let acc2 = Account { nonce: 2, balance: U256::from(200), ..Default::default() }; let block_1 = BlockWithParent::new(B256::ZERO, NumHash::new(1, B256::random())); - let mut state_diff1 = BlockStateDiff::default(); - state_diff1.sorted_post_state.accounts.insert(addr1, Some(acc1)); + let mut state_diff1_post_state = HashedPostState::default(); + state_diff1_post_state.accounts.insert(addr1, Some(acc1)); + let state_diff1 = BlockStateDiff { + sorted_post_state: state_diff1_post_state.into_sorted(), + ..Default::default() + }; store.store_trie_updates(block_1, state_diff1).await.unwrap(); let block_2 = BlockWithParent::new(block_1.block.hash, NumHash::new(2, B256::random())); @@ -2977,7 +2991,10 @@ mod tests { let make_diff = |nonce: u64| { let mut d_post_state = HashedPostState::default(); d_post_state.accounts.insert(addr, Some(Account { nonce, ..Default::default() })); - d + BlockStateDiff { + sorted_trie_updates: TrieUpdatesSorted::default(), + sorted_post_state: d_post_state.into_sorted(), + } }; // Build chain: blocks 1 -> 2 -> 3 @@ -3295,7 +3312,7 @@ mod tests { let addr = B256::random(); let make_diff = |nonce: u64| { - let mut d_oost_state = HashedPostState::default(); + let mut d_post_state = HashedPostState::default(); d_post_state.accounts.insert(addr, Some(Account { nonce, ..Default::default() })); BlockStateDiff { sorted_trie_updates: TrieUpdatesSorted::default(), diff --git a/crates/optimism/trie/src/in_memory.rs b/crates/optimism/trie/src/in_memory.rs index 3b6f39b9c21..ac868f79745 100644 --- a/crates/optimism/trie/src/in_memory.rs +++ b/crates/optimism/trie/src/in_memory.rs @@ -762,15 +762,18 @@ mod tests { let sorted_trie_updates = TrieUpdatesSorted::default(); let sorted_post_state = HashedPostStateSorted::default(); - let block_state_diff = BlockStateDiff { sorted_trie_updates, sorted_post_state }; + let block_state_diff = BlockStateDiff { + sorted_trie_updates: sorted_trie_updates.clone(), + sorted_post_state: sorted_post_state.clone(), + }; const BLOCK: BlockWithParent = BlockWithParent::new(B256::ZERO, NumHash::new(5, B256::ZERO)); storage.store_trie_updates(BLOCK, block_state_diff).await?; let retrieved_diff = storage.fetch_trie_updates(BLOCK.block.number).await?; - assert_eq!(retrieved_diff.sorted_trie_updates, trie_updates); - assert_eq!(retrieved_diff.sorted_post_state, post_state); + assert_eq!(retrieved_diff.sorted_trie_updates, sorted_trie_updates); + assert_eq!(retrieved_diff.sorted_post_state, sorted_post_state); Ok(()) } diff --git a/crates/optimism/trie/src/live.rs b/crates/optimism/trie/src/live.rs index 85c1ab1d2d7..694c00a53d7 100644 --- a/crates/optimism/trie/src/live.rs +++ b/crates/optimism/trie/src/live.rs @@ -138,18 +138,15 @@ where pub async fn store_block_updates( &self, block: BlockWithParent, - trie_updates: TrieUpdatesSorted, - post_state: HashedPostStateSorted, + sorted_trie_updates: TrieUpdatesSorted, + sorted_post_state: HashedPostStateSorted, ) -> eyre::Result<()> { let start = Instant::now(); let mut operation_durations = OperationDurations::default(); let storage_result = self .storage - .store_trie_updates( - block, - BlockStateDiff { sorted_trie_updates: trie_updates, sorted_post_state: post_state }, - ) + .store_trie_updates(block, BlockStateDiff { sorted_trie_updates, sorted_post_state }) .await?; let write_duration = start.elapsed(); diff --git a/crates/optimism/trie/tests/lib.rs b/crates/optimism/trie/tests/lib.rs index f6e1a6407a2..3fb6c3d67b8 100644 --- a/crates/optimism/trie/tests/lib.rs +++ b/crates/optimism/trie/tests/lib.rs @@ -2,7 +2,6 @@ use alloy_eips::{eip1898::BlockWithParent, NumHash}; use alloy_primitives::{map::HashMap, B256, U256}; -use reth_evm::block; use reth_optimism_trie::{ db::MdbxProofsStorage, BlockStateDiff, InMemoryProofsStorage, OpProofsStorageError, OpProofsStore, @@ -111,15 +110,18 @@ async fn test_trie_updates_operations( let block_ref = BlockWithParent::new(B256::ZERO, NumHash::new(50, B256::repeat_byte(0x96))); let sorted_trie_updates = TrieUpdatesSorted::default(); let sorted_post_state = HashedPostStateSorted::default(); - let block_state_diff = BlockStateDiff { sorted_trie_updates, sorted_post_state }; + let block_state_diff = BlockStateDiff { + sorted_trie_updates: sorted_trie_updates.clone(), + sorted_post_state: sorted_post_state.clone(), + }; // Store trie updates storage.store_trie_updates(block_ref, block_state_diff).await?; // Retrieve and verify let retrieved_diff = storage.fetch_trie_updates(block_ref.block.number).await?; - assert_eq!(retrieved_diff.sorted_trie_updates, trie_updates); - assert_eq!(retrieved_diff.sorted_post_state, post_state); + assert_eq!(retrieved_diff.sorted_trie_updates, sorted_trie_updates); + assert_eq!(retrieved_diff.sorted_post_state, sorted_post_state); Ok(()) } @@ -1254,8 +1256,8 @@ async fn test_store_trie_updates_with_wiped_storage( post_state.storages.insert(hashed_address, wiped_storage); let block_state_diff = BlockStateDiff { - sorted_trie_updates: TrieUpdates::default(), - sorted_post_state: post_state, + sorted_trie_updates: TrieUpdatesSorted::default(), + sorted_post_state: post_state.into_sorted(), }; // Store the wiped state @@ -1372,8 +1374,10 @@ async fn test_store_trie_updates_comprehensive( hashed_storage.storage.insert(B256::repeat_byte(0x03), U256::ZERO); // Deleted storage post_state.storages.insert(storage_addr, hashed_storage); - let block_state_diff = - BlockStateDiff { sorted_trie_updates: trie_updates, sorted_post_state: post_state }; + let block_state_diff = BlockStateDiff { + sorted_trie_updates: trie_updates.into_sorted(), + sorted_post_state: post_state.into_sorted(), + }; // Store the updates storage.store_trie_updates(block_ref, block_state_diff).await?; @@ -1508,8 +1512,8 @@ async fn test_replace_updates_applies_all_updates( initial_post_state_50.accounts.insert(initial_account_addr, Some(initial_account)); let initial_diff_50 = BlockStateDiff { - sorted_trie_updates: initial_trie_updates_50, - sorted_post_state: initial_post_state_50, + sorted_trie_updates: initial_trie_updates_50.into_sorted(), + sorted_post_state: initial_post_state_50.into_sorted(), }; storage.store_trie_updates(block_ref_50, initial_diff_50).await?; @@ -1524,8 +1528,8 @@ async fn test_replace_updates_applies_all_updates( initial_post_state_100.storages.insert(initial_storage_addr, initial_storage_100); let initial_diff_100 = BlockStateDiff { - sorted_trie_updates: initial_trie_updates_100, - sorted_post_state: initial_post_state_100, + sorted_trie_updates: initial_trie_updates_100.into_sorted(), + sorted_post_state: initial_post_state_100.into_sorted(), }; let block_ref_100 = @@ -1722,7 +1726,11 @@ async fn test_replace_updates_applies_all_updates( "Should have 1 account branch node at block 101" ); assert!( - fetched_101.sorted_trie_updates.account_nodes_ref().contains_key(&new_branch_path), + fetched_101 + .sorted_trie_updates + .account_nodes_ref() + .iter() + .any(|(addr, _)| *addr == new_branch_path), "New branch path should be in trie_updates" ); assert_eq!( @@ -1731,7 +1739,7 @@ async fn test_replace_updates_applies_all_updates( "Should have 1 account at block 101" ); assert!( - fetched_101.sorted_post_state.accounts.contains_key(&new_account_addr), + fetched_101.sorted_post_state.accounts.iter().any(|(addr, _)| *addr == new_account_addr), "New account should be in post_state" ); From 42a66efcbc2467230a9812db9c86e02b0b2c611b Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Fri, 12 Dec 2025 18:23:35 +0100 Subject: [PATCH 16/18] Fix calls to Chain constructor in tests --- crates/chain-state/src/in_memory.rs | 71 +++++++++++++++++++---------- 1 file changed, 47 insertions(+), 24 deletions(-) diff --git a/crates/chain-state/src/in_memory.rs b/crates/chain-state/src/in_memory.rs index 730760a93e9..a41a6fcee05 100644 --- a/crates/chain-state/src/in_memory.rs +++ b/crates/chain-state/src/in_memory.rs @@ -1536,19 +1536,24 @@ mod tests { let chain_commit = NewCanonicalChain::Commit { new: vec![block0.clone(), block1.clone()] }; // Build expected trie updates map - let mut expected_trie_updates: BTreeMap> = BTreeMap::new(); + let mut expected_trie_updates: BTreeMap> = + BTreeMap::new(); expected_trie_updates - .insert(0, Arc::new(TrieUpdates::from((*block0.trie_updates()).clone()))); + .insert(0, Arc::new(TrieUpdates::from((*block0.trie_updates()).clone()).into_sorted())); expected_trie_updates - .insert(1, Arc::new(TrieUpdates::from((*block1.trie_updates()).clone()))); + .insert(1, Arc::new(TrieUpdates::from((*block1.trie_updates()).clone()).into_sorted())); // Build expected hashed state map - let mut expected_hashed_state: BTreeMap> = + let mut expected_hashed_state: BTreeMap> = BTreeMap::new(); - expected_hashed_state - .insert(0, Arc::new(HashedPostState::from((*block0.hashed_state()).clone()))); - expected_hashed_state - .insert(1, Arc::new(HashedPostState::from((*block1.hashed_state()).clone()))); + expected_hashed_state.insert( + 0, + Arc::new(HashedPostState::from((*block0.hashed_state()).clone()).into_sorted()), + ); + expected_hashed_state.insert( + 1, + Arc::new(HashedPostState::from((*block1.hashed_state()).clone()).into_sorted()), + ); assert_eq!( chain_commit.to_chain_notification(), @@ -1569,26 +1574,44 @@ mod tests { }; // Build expected trie updates for old chain - let mut old_trie_updates: BTreeMap> = BTreeMap::new(); - old_trie_updates.insert(1, Arc::new(TrieUpdates::from((*block1.trie_updates()).clone()))); - old_trie_updates.insert(2, Arc::new(TrieUpdates::from((*block2.trie_updates()).clone()))); + let mut old_trie_updates: BTreeMap> = BTreeMap::new(); + old_trie_updates + .insert(1, Arc::new(TrieUpdates::from((*block1.trie_updates()).clone()).into_sorted())); + old_trie_updates + .insert(2, Arc::new(TrieUpdates::from((*block2.trie_updates()).clone()).into_sorted())); // Build expected trie updates for new chain - let mut new_trie_updates: BTreeMap> = BTreeMap::new(); - new_trie_updates.insert(1, Arc::new(TrieUpdates::from((*block1a.trie_updates()).clone()))); - new_trie_updates.insert(2, Arc::new(TrieUpdates::from((*block2a.trie_updates()).clone()))); + let mut new_trie_updates: BTreeMap> = BTreeMap::new(); + new_trie_updates.insert( + 1, + Arc::new(TrieUpdates::from((*block1a.trie_updates()).clone()).into_sorted()), + ); + new_trie_updates.insert( + 2, + Arc::new(TrieUpdates::from((*block2a.trie_updates()).clone()).into_sorted()), + ); // Build expected hashed state for old chain - let mut old_hashed_state: BTreeMap> = BTreeMap::new(); - old_hashed_state - .insert(1, Arc::new(HashedPostState::from((*block1.hashed_state()).clone()))); - old_hashed_state - .insert(2, Arc::new(HashedPostState::from((*block2.hashed_state()).clone()))); + let mut old_hashed_state: BTreeMap> = + BTreeMap::new(); + old_hashed_state.insert( + 1, + Arc::new(HashedPostState::from((*block1.hashed_state()).clone()).into_sorted()), + ); + old_hashed_state.insert( + 2, + Arc::new(HashedPostState::from((*block2.hashed_state()).clone()).into_sorted()), + ); // Build expected hashed state for new chain - let mut new_hashed_state: BTreeMap> = BTreeMap::new(); - new_hashed_state - .insert(1, Arc::new(HashedPostState::from((*block1a.hashed_state()).clone()))); - new_hashed_state - .insert(2, Arc::new(HashedPostState::from((*block2a.hashed_state()).clone()))); + let mut new_hashed_state: BTreeMap> = + BTreeMap::new(); + new_hashed_state.insert( + 1, + Arc::new(HashedPostState::from((*block1a.hashed_state()).clone()).into_sorted()), + ); + new_hashed_state.insert( + 2, + Arc::new(HashedPostState::from((*block2a.hashed_state()).clone()).into_sorted()), + ); assert_eq!( chain_reorg.to_chain_notification(), CanonStateNotification::Reorg { From 23ee2d2b13e4e5e3399b7c99864a14cb094648bb Mon Sep 17 00:00:00 2001 From: Arun Dhyani Date: Mon, 15 Dec 2025 14:08:58 +0530 Subject: [PATCH 17/18] fix test case --- crates/optimism/trie/tests/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/optimism/trie/tests/lib.rs b/crates/optimism/trie/tests/lib.rs index 3fb6c3d67b8..7bd13ccf582 100644 --- a/crates/optimism/trie/tests/lib.rs +++ b/crates/optimism/trie/tests/lib.rs @@ -1457,8 +1457,8 @@ async fn test_store_trie_updates_comprehensive( // Check that trie updates are stored assert_eq!( fetched_diff.sorted_trie_updates.account_nodes_ref().len(), - 2, - "Should have 2 account nodes" + 3, + "Should have 3 account nodes, including removed" ); assert_eq!( fetched_diff.sorted_trie_updates.storage_tries_ref().len(), From 6f11ca28c6378d6e24113d7450807bdb54365f8d Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Mon, 15 Dec 2025 15:37:23 +0100 Subject: [PATCH 18/18] Fix misleading docs --- crates/trie/common/src/updates.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/trie/common/src/updates.rs b/crates/trie/common/src/updates.rs index 60d5686bee0..93f1015f5fc 100644 --- a/crates/trie/common/src/updates.rs +++ b/crates/trie/common/src/updates.rs @@ -492,7 +492,7 @@ pub struct TrieUpdatesSorted { /// Sorted collection of updated state nodes with corresponding paths. None indicates that a /// node was removed. pub account_nodes: Vec<(Nibbles, Option)>, - /// Storage tries stored by hashed address of the account the trie belongs to. + /// Map of hashed addresses to their storage tries stored by path. pub storage_tries: B256Map, }