From 2f8eafa31dbb629d591ef59aee7aa4ecd2b4a3a2 Mon Sep 17 00:00:00 2001 From: Federico Gimenez Date: Fri, 29 Nov 2024 13:29:58 +0100 Subject: [PATCH] show storage trie updates diff --- crates/engine/tree/src/tree/mod.rs | 153 ++++++++++++++++++++++++++++- 1 file changed, 151 insertions(+), 2 deletions(-) diff --git a/crates/engine/tree/src/tree/mod.rs b/crates/engine/tree/src/tree/mod.rs index 68acc808fedc6..633b81ce0f81a 100644 --- a/crates/engine/tree/src/tree/mod.rs +++ b/crates/engine/tree/src/tree/mod.rs @@ -46,7 +46,10 @@ use reth_provider::{ }; use reth_revm::database::StateProviderDatabase; use reth_stages_api::ControlFlow; -use reth_trie::{updates::TrieUpdates, HashedPostState, TrieInput}; +use reth_trie::{ + updates::{StorageTrieUpdates, TrieUpdates}, + HashedPostState, Nibbles, TrieInput, +}; use reth_trie_parallel::root::{ParallelStateRoot, ParallelStateRootError}; use revm_primitives::EvmState; use root::{StateRootConfig, StateRootMessage, StateRootTask}; @@ -2286,7 +2289,17 @@ where match state_root_handle.wait_for_result() { Ok(state_root_task_result) => { info!(target: "engine::tree", block=?sealed_block.num_hash(), state_root_task_result=?state_root_task_result.0, regular_state_root_result = ?result.0); - info!(target: "engine::tree", block=?sealed_block.num_hash(), state_root_task_trie_updates=?state_root_task_result.1, regular_state_root_trie_updates = ?result.1); + let diff = compare_trie_updates(&state_root_task_result.1, &result.1); + if diff.has_differences() { + info!(target: "engine::tree", + block=?sealed_block.num_hash(), + storage_nodes_only_in_first= ?diff.storage_nodes_only_in_first, + storage_nodes_only_in_second= ?diff.storage_nodes_only_in_second, + storage_nodes_with_differences= ?diff.storage_nodes_with_differences, + "Found differences in TrieUpdates"); + } else { + debug!(target: "engine::tree", block=?sealed_block.num_hash(), "TrieUpdates match exactly"); + } } Err(e) => { info!(target: "engine::tree", error=?e, "on state root task wait_for_result") @@ -2643,6 +2656,142 @@ pub enum AdvancePersistenceError { Provider(#[from] ProviderError), } +#[derive(Debug, Default)] +struct TrieUpdatesDiff { + pub account_nodes_only_in_first: HashSet, + pub account_nodes_only_in_second: HashSet, + pub account_nodes_with_different_values: HashSet, + pub removed_nodes_only_in_first: HashSet, + pub removed_nodes_only_in_second: HashSet, + pub storage_tries_only_in_first: HashSet, + pub storage_tries_only_in_second: HashSet, + pub storage_tries_with_differences: HashMap, +} + +#[derive(Debug, Default)] +struct StorageTrieUpdatesDiff { + pub is_deleted_differs: bool, + pub storage_nodes_only_in_first: HashSet, + pub storage_nodes_only_in_second: HashSet, + pub storage_nodes_with_different_values: HashSet, + pub removed_nodes_only_in_first: HashSet, + pub removed_nodes_only_in_second: HashSet, +} + +fn compare_trie_updates(first: &TrieUpdates, second: &TrieUpdates) -> TrieUpdatesDiff { + let mut diff = TrieUpdatesDiff::default(); + + // compare account nodes + for key in first.account_nodes.keys() { + if !second.account_nodes.contains_key(key) { + diff.account_nodes_only_in_first.insert(key.clone()); + } else if first.account_nodes.get(key) != second.account_nodes.get(key) { + diff.account_nodes_with_different_values.insert(key.clone()); + } + } + for key in second.account_nodes.keys() { + if !first.account_nodes.contains_key(key) { + diff.account_nodes_only_in_second.insert(key.clone()); + } + } + + // compare removed nodes + for node in &first.removed_nodes { + if !second.removed_nodes.contains(node) { + diff.removed_nodes_only_in_first.insert(node.clone()); + } + } + for node in &second.removed_nodes { + if !first.removed_nodes.contains(node) { + diff.removed_nodes_only_in_second.insert(node.clone()); + } + } + + // compare storage tries + for key in first.storage_tries.keys() { + if second.storage_tries.contains_key(key) { + let storage_diff = compare_storage_trie_updates( + first.storage_tries.get(key).unwrap(), + second.storage_tries.get(key).unwrap(), + ); + if storage_diff.has_differences() { + diff.storage_tries_with_differences.insert(*key, storage_diff); + } + } else { + diff.storage_tries_only_in_first.insert(*key); + } + } + for key in second.storage_tries.keys() { + if !first.storage_tries.contains_key(key) { + diff.storage_tries_only_in_second.insert(*key); + } + } + + diff +} + +fn compare_storage_trie_updates( + first: &StorageTrieUpdates, + second: &StorageTrieUpdates, +) -> StorageTrieUpdatesDiff { + let mut diff = StorageTrieUpdatesDiff { + is_deleted_differs: first.is_deleted != second.is_deleted, + ..Default::default() + }; + + // compare storage nodes + for key in first.storage_nodes.keys() { + if !second.storage_nodes.contains_key(key) { + diff.storage_nodes_only_in_first.insert(key.clone()); + } else if first.storage_nodes.get(key) != second.storage_nodes.get(key) { + diff.storage_nodes_with_different_values.insert(key.clone()); + } + } + for key in second.storage_nodes.keys() { + if !first.storage_nodes.contains_key(key) { + diff.storage_nodes_only_in_second.insert(key.clone()); + } + } + + // compare removed nodes + for node in &first.removed_nodes { + if !second.removed_nodes.contains(node) { + diff.removed_nodes_only_in_first.insert(node.clone()); + } + } + for node in &second.removed_nodes { + if !first.removed_nodes.contains(node) { + diff.removed_nodes_only_in_second.insert(node.clone()); + } + } + + diff +} + +impl StorageTrieUpdatesDiff { + fn has_differences(&self) -> bool { + self.is_deleted_differs || + !self.storage_nodes_only_in_first.is_empty() || + !self.storage_nodes_only_in_second.is_empty() || + !self.storage_nodes_with_different_values.is_empty() || + !self.removed_nodes_only_in_first.is_empty() || + !self.removed_nodes_only_in_second.is_empty() + } +} + +impl TrieUpdatesDiff { + fn has_differences(&self) -> bool { + !self.account_nodes_only_in_first.is_empty() || + !self.account_nodes_only_in_second.is_empty() || + !self.account_nodes_with_different_values.is_empty() || + !self.removed_nodes_only_in_first.is_empty() || + !self.removed_nodes_only_in_second.is_empty() || + !self.storage_tries_only_in_first.is_empty() || + !self.storage_tries_only_in_second.is_empty() || + !self.storage_tries_with_differences.is_empty() + } +} + #[cfg(test)] mod tests { use super::*;