From 63b94ab3d6295b208952f7f90dfb37e084a277b3 Mon Sep 17 00:00:00 2001 From: Federico Gimenez Date: Sun, 19 Jan 2025 12:14:16 +0100 Subject: [PATCH] feat(trie): use Arc instead of references for nodes and state cursor factories --- crates/engine/tree/benches/state_root_task.rs | 4 +- crates/engine/tree/src/tree/mod.rs | 4 +- crates/engine/tree/src/tree/root.rs | 4 +- crates/trie/db/src/proof.rs | 15 +++-- crates/trie/db/src/state.rs | 33 ++++++++-- crates/trie/db/src/storage.rs | 8 ++- crates/trie/db/src/witness.rs | 7 ++- crates/trie/db/tests/fuzz_in_memory_nodes.rs | 14 ++--- crates/trie/db/tests/post_state.rs | 62 +++++++++++------- crates/trie/parallel/benches/root.rs | 6 +- crates/trie/parallel/src/proof.rs | 9 +-- crates/trie/parallel/src/root.rs | 13 ++-- crates/trie/sparse/benches/root.rs | 5 +- crates/trie/trie/src/forward_cursor.rs | 13 ++-- .../trie/trie/src/hashed_cursor/post_state.rs | 63 ++++++++++--------- crates/trie/trie/src/state.rs | 47 +++++++++----- crates/trie/trie/src/trie_cursor/in_memory.rs | 60 ++++++++++-------- 17 files changed, 226 insertions(+), 141 deletions(-) diff --git a/crates/engine/tree/benches/state_root_task.rs b/crates/engine/tree/benches/state_root_task.rs index 8c5b871385ab..9f802de87021 100644 --- a/crates/engine/tree/benches/state_root_task.rs +++ b/crates/engine/tree/benches/state_root_task.rs @@ -247,11 +247,11 @@ fn bench_state_root(c: &mut Criterion) { let blinded_provider_factory = ProofBlindedProviderFactory::new( InMemoryTrieCursorFactory::new( DatabaseTrieCursorFactory::new(provider.tx_ref()), - &nodes_sorted, + nodes_sorted, ), HashedPostStateCursorFactory::new( DatabaseHashedCursorFactory::new(provider.tx_ref()), - &state_sorted, + state_sorted, ), prefix_sets, ); diff --git a/crates/engine/tree/src/tree/mod.rs b/crates/engine/tree/src/tree/mod.rs index 059fde3d7414..4f52ba4490cd 100644 --- a/crates/engine/tree/src/tree/mod.rs +++ b/crates/engine/tree/src/tree/mod.rs @@ -2311,13 +2311,13 @@ where let in_memory_trie_cursor = InMemoryTrieCursorFactory::new( DatabaseTrieCursorFactory::new(context.provider_ro.tx_ref()), - &context.nodes_sorted, + context.nodes_sorted.clone(), ); let blinded_provider_factory = ProofBlindedProviderFactory::new( in_memory_trie_cursor.clone(), HashedPostStateCursorFactory::new( DatabaseHashedCursorFactory::new(context.provider_ro.tx_ref()), - &context.state_sorted, + context.state_sorted.clone(), ), context.prefix_sets.clone(), ); diff --git a/crates/engine/tree/src/tree/root.rs b/crates/engine/tree/src/tree/root.rs index 93cac7b435ed..0574cbc65653 100644 --- a/crates/engine/tree/src/tree/root.rs +++ b/crates/engine/tree/src/tree/root.rs @@ -973,11 +973,11 @@ mod tests { let blinded_provider_factory = ProofBlindedProviderFactory::new( InMemoryTrieCursorFactory::new( DatabaseTrieCursorFactory::new(provider.tx_ref()), - &nodes_sorted, + nodes_sorted, ), HashedPostStateCursorFactory::new( DatabaseHashedCursorFactory::new(provider.tx_ref()), - &state_sorted, + state_sorted, ), config.prefix_sets.clone(), ); diff --git a/crates/trie/db/src/proof.rs b/crates/trie/db/src/proof.rs index 137e661b0560..4a0db6ebe166 100644 --- a/crates/trie/db/src/proof.rs +++ b/crates/trie/db/src/proof.rs @@ -10,6 +10,9 @@ use reth_trie::{ StorageMultiProof, TrieInput, }; +extern crate alloc; +use alloc::sync::Arc; + /// Extends [`Proof`] with operations specific for working with a database transaction. pub trait DatabaseProof<'a, TX> { /// Create a new [Proof] from database transaction. @@ -50,11 +53,11 @@ impl<'a, TX: DbTx> DatabaseProof<'a, TX> Self::from_tx(tx) .with_trie_cursor_factory(InMemoryTrieCursorFactory::new( DatabaseTrieCursorFactory::new(tx), - &nodes_sorted, + Arc::new(nodes_sorted), )) .with_hashed_cursor_factory(HashedPostStateCursorFactory::new( DatabaseHashedCursorFactory::new(tx), - &state_sorted, + Arc::new(state_sorted), )) .with_prefix_sets_mut(input.prefix_sets) .account_proof(address, slots) @@ -70,11 +73,11 @@ impl<'a, TX: DbTx> DatabaseProof<'a, TX> Self::from_tx(tx) .with_trie_cursor_factory(InMemoryTrieCursorFactory::new( DatabaseTrieCursorFactory::new(tx), - &nodes_sorted, + Arc::new(nodes_sorted), )) .with_hashed_cursor_factory(HashedPostStateCursorFactory::new( DatabaseHashedCursorFactory::new(tx), - &state_sorted, + Arc::new(state_sorted), )) .with_prefix_sets_mut(input.prefix_sets) .multiproof(targets) @@ -125,7 +128,7 @@ impl<'a, TX: DbTx> DatabaseStorageProof<'a, TX> Self::from_tx(tx, address) .with_hashed_cursor_factory(HashedPostStateCursorFactory::new( DatabaseHashedCursorFactory::new(tx), - &state_sorted, + Arc::new(state_sorted), )) .with_prefix_set_mut(prefix_set) .storage_proof(slot) @@ -147,7 +150,7 @@ impl<'a, TX: DbTx> DatabaseStorageProof<'a, TX> Self::from_tx(tx, address) .with_hashed_cursor_factory(HashedPostStateCursorFactory::new( DatabaseHashedCursorFactory::new(tx), - &state_sorted, + Arc::new(state_sorted), )) .with_prefix_set_mut(prefix_set) .storage_multiproof(targets) diff --git a/crates/trie/db/src/state.rs b/crates/trie/db/src/state.rs index 992335896cd3..49671bc3e2f1 100644 --- a/crates/trie/db/src/state.rs +++ b/crates/trie/db/src/state.rs @@ -19,6 +19,9 @@ use reth_trie::{ use std::{collections::HashMap, ops::RangeInclusive}; use tracing::debug; +extern crate alloc; +use alloc::sync::Arc; + /// Extends [`StateRoot`] with operations specific for working with a database transaction. pub trait DatabaseStateRoot<'a, TX>: Sized { /// Create a new [`StateRoot`] instance. @@ -173,7 +176,10 @@ impl<'a, TX: DbTx> DatabaseStateRoot<'a, TX> let state_sorted = post_state.into_sorted(); StateRoot::new( DatabaseTrieCursorFactory::new(tx), - HashedPostStateCursorFactory::new(DatabaseHashedCursorFactory::new(tx), &state_sorted), + HashedPostStateCursorFactory::new( + DatabaseHashedCursorFactory::new(tx), + Arc::new(state_sorted), + ), ) .with_prefix_sets(prefix_sets) .root() @@ -187,7 +193,10 @@ impl<'a, TX: DbTx> DatabaseStateRoot<'a, TX> let state_sorted = post_state.into_sorted(); StateRoot::new( DatabaseTrieCursorFactory::new(tx), - HashedPostStateCursorFactory::new(DatabaseHashedCursorFactory::new(tx), &state_sorted), + HashedPostStateCursorFactory::new( + DatabaseHashedCursorFactory::new(tx), + Arc::new(state_sorted), + ), ) .with_prefix_sets(prefix_sets) .root_with_updates() @@ -197,8 +206,14 @@ impl<'a, TX: DbTx> DatabaseStateRoot<'a, TX> let state_sorted = input.state.into_sorted(); let nodes_sorted = input.nodes.into_sorted(); StateRoot::new( - InMemoryTrieCursorFactory::new(DatabaseTrieCursorFactory::new(tx), &nodes_sorted), - HashedPostStateCursorFactory::new(DatabaseHashedCursorFactory::new(tx), &state_sorted), + InMemoryTrieCursorFactory::new( + DatabaseTrieCursorFactory::new(tx), + Arc::new(nodes_sorted), + ), + HashedPostStateCursorFactory::new( + DatabaseHashedCursorFactory::new(tx), + Arc::new(state_sorted), + ), ) .with_prefix_sets(input.prefix_sets.freeze()) .root() @@ -211,8 +226,14 @@ impl<'a, TX: DbTx> DatabaseStateRoot<'a, TX> let state_sorted = input.state.into_sorted(); let nodes_sorted = input.nodes.into_sorted(); StateRoot::new( - InMemoryTrieCursorFactory::new(DatabaseTrieCursorFactory::new(tx), &nodes_sorted), - HashedPostStateCursorFactory::new(DatabaseHashedCursorFactory::new(tx), &state_sorted), + InMemoryTrieCursorFactory::new( + DatabaseTrieCursorFactory::new(tx), + Arc::new(nodes_sorted), + ), + HashedPostStateCursorFactory::new( + DatabaseHashedCursorFactory::new(tx), + Arc::new(state_sorted), + ), ) .with_prefix_sets(input.prefix_sets.freeze()) .root_with_updates() diff --git a/crates/trie/db/src/storage.rs b/crates/trie/db/src/storage.rs index 5b143ac7eeea..ea46fd94027b 100644 --- a/crates/trie/db/src/storage.rs +++ b/crates/trie/db/src/storage.rs @@ -7,6 +7,9 @@ use reth_trie::{ hashed_cursor::HashedPostStateCursorFactory, HashedPostState, HashedStorage, StorageRoot, }; +extern crate alloc; +use alloc::sync::Arc; + #[cfg(feature = "metrics")] use reth_trie::metrics::{TrieRootMetrics, TrieType}; @@ -68,7 +71,10 @@ impl<'a, TX: DbTx> DatabaseStorageRoot<'a, TX> HashedPostState::from_hashed_storage(keccak256(address), hashed_storage).into_sorted(); StorageRoot::new( DatabaseTrieCursorFactory::new(tx), - HashedPostStateCursorFactory::new(DatabaseHashedCursorFactory::new(tx), &state_sorted), + HashedPostStateCursorFactory::new( + DatabaseHashedCursorFactory::new(tx), + Arc::new(state_sorted), + ), address, prefix_set, #[cfg(feature = "metrics")] diff --git a/crates/trie/db/src/witness.rs b/crates/trie/db/src/witness.rs index c796933b90ed..3fe8ea03e046 100644 --- a/crates/trie/db/src/witness.rs +++ b/crates/trie/db/src/witness.rs @@ -7,6 +7,9 @@ use reth_trie::{ witness::TrieWitness, HashedPostState, TrieInput, }; +extern crate alloc; +use alloc::sync::Arc; + /// Extends [`TrieWitness`] with operations specific for working with a database transaction. pub trait DatabaseTrieWitness<'a, TX> { /// Create a new [`TrieWitness`] from database transaction. @@ -37,11 +40,11 @@ impl<'a, TX: DbTx> DatabaseTrieWitness<'a, TX> Self::from_tx(tx) .with_trie_cursor_factory(InMemoryTrieCursorFactory::new( DatabaseTrieCursorFactory::new(tx), - &nodes_sorted, + Arc::new(nodes_sorted), )) .with_hashed_cursor_factory(HashedPostStateCursorFactory::new( DatabaseHashedCursorFactory::new(tx), - &state_sorted, + Arc::new(state_sorted), )) .with_prefix_sets_mut(input.prefix_sets) .compute(target) diff --git a/crates/trie/db/tests/fuzz_in_memory_nodes.rs b/crates/trie/db/tests/fuzz_in_memory_nodes.rs index 874f71bfc40b..fadc0bdc37d7 100644 --- a/crates/trie/db/tests/fuzz_in_memory_nodes.rs +++ b/crates/trie/db/tests/fuzz_in_memory_nodes.rs @@ -16,13 +16,12 @@ use reth_trie::{ HashedPostState, HashedStorage, StateRoot, StorageRoot, }; use reth_trie_db::{DatabaseStateRoot, DatabaseStorageRoot, DatabaseTrieCursorFactory}; -use std::collections::BTreeMap; +use std::{collections::BTreeMap, sync::Arc}; proptest! { #![proptest_config(ProptestConfig { cases: 128, ..ProptestConfig::default() })] - #[test] fn fuzz_in_memory_account_nodes(mut init_state: BTreeMap, state_updates: [BTreeMap>; 10]) { let factory = create_test_provider_factory(); @@ -58,8 +57,8 @@ proptest! { // Compute root with in-memory trie nodes overlay let (state_root, trie_updates) = StateRoot::from_tx(provider.tx_ref()) .with_prefix_sets(hashed_state.construct_prefix_sets().freeze()) - .with_trie_cursor_factory(InMemoryTrieCursorFactory::new( - DatabaseTrieCursorFactory::new(provider.tx_ref()), &trie_nodes.clone().into_sorted()) + .with_trie_cursor_factory( + InMemoryTrieCursorFactory::new(DatabaseTrieCursorFactory::new(provider.tx_ref()), Arc::new(trie_nodes.clone().into_sorted())) ) .root_with_updates() .unwrap(); @@ -113,10 +112,9 @@ proptest! { let (storage_root, _, trie_updates) = StorageRoot::from_tx_hashed(provider.tx_ref(), hashed_address) .with_prefix_set(hashed_storage.construct_prefix_set().freeze()) - .with_trie_cursor_factory(InMemoryTrieCursorFactory::new( - DatabaseTrieCursorFactory::new(provider.tx_ref()), - &trie_nodes.into_sorted(), - )) + .with_trie_cursor_factory( + InMemoryTrieCursorFactory::new(DatabaseTrieCursorFactory::new(provider.tx_ref()), Arc::new(trie_nodes.clone().into_sorted())) + ) .root_with_updates() .unwrap(); diff --git a/crates/trie/db/tests/post_state.rs b/crates/trie/db/tests/post_state.rs index ce6f10d76aed..3f1c44ea1b1b 100644 --- a/crates/trie/db/tests/post_state.rs +++ b/crates/trie/db/tests/post_state.rs @@ -13,7 +13,7 @@ use reth_trie::{ HashedPostState, HashedStorage, }; use reth_trie_db::DatabaseHashedCursorFactory; -use std::collections::BTreeMap; +use std::{collections::BTreeMap, sync::Arc}; fn assert_account_cursor_order( factory: &impl HashedCursorFactory, @@ -66,7 +66,8 @@ fn post_state_only_accounts() { let sorted = hashed_post_state.into_sorted(); let tx = db.tx().unwrap(); - let factory = HashedPostStateCursorFactory::new(DatabaseHashedCursorFactory::new(&tx), &sorted); + let factory = + HashedPostStateCursorFactory::new(DatabaseHashedCursorFactory::new(&tx), Arc::new(sorted)); assert_account_cursor_order(&factory, accounts.into_iter()); } @@ -87,7 +88,7 @@ fn db_only_accounts() { let tx = db.tx().unwrap(); let factory = HashedPostStateCursorFactory::new( DatabaseHashedCursorFactory::new(&tx), - &sorted_post_state, + Arc::new(sorted_post_state), ); assert_account_cursor_order(&factory, accounts.into_iter()); } @@ -113,7 +114,8 @@ fn account_cursor_correct_order() { let sorted = hashed_post_state.into_sorted(); let tx = db.tx().unwrap(); - let factory = HashedPostStateCursorFactory::new(DatabaseHashedCursorFactory::new(&tx), &sorted); + let factory = + HashedPostStateCursorFactory::new(DatabaseHashedCursorFactory::new(&tx), Arc::new(sorted)); assert_account_cursor_order(&factory, accounts.into_iter()); } @@ -143,7 +145,8 @@ fn removed_accounts_are_discarded() { let sorted = hashed_post_state.into_sorted(); let tx = db.tx().unwrap(); - let factory = HashedPostStateCursorFactory::new(DatabaseHashedCursorFactory::new(&tx), &sorted); + let factory = + HashedPostStateCursorFactory::new(DatabaseHashedCursorFactory::new(&tx), Arc::new(sorted)); let expected = accounts.into_iter().filter(|x| !removed_keys.contains(&x.0)); assert_account_cursor_order(&factory, expected); } @@ -170,7 +173,8 @@ fn post_state_accounts_take_precedence() { let sorted = hashed_post_state.into_sorted(); let tx = db.tx().unwrap(); - let factory = HashedPostStateCursorFactory::new(DatabaseHashedCursorFactory::new(&tx), &sorted); + let factory = + HashedPostStateCursorFactory::new(DatabaseHashedCursorFactory::new(&tx), Arc::new(sorted)); assert_account_cursor_order(&factory, accounts.into_iter()); } @@ -202,7 +206,7 @@ fn fuzz_hashed_account_cursor() { let sorted = hashed_post_state.into_sorted(); let tx = db.tx().unwrap(); - let factory = HashedPostStateCursorFactory::new(DatabaseHashedCursorFactory::new(&tx), &sorted); + let factory = HashedPostStateCursorFactory::new(DatabaseHashedCursorFactory::new(&tx), Arc::new(sorted)); assert_account_cursor_order(&factory, expected.into_iter()); } ); @@ -217,8 +221,10 @@ fn storage_is_empty() { { let sorted = HashedPostState::default().into_sorted(); let tx = db.tx().unwrap(); - let factory = - HashedPostStateCursorFactory::new(DatabaseHashedCursorFactory::new(&tx), &sorted); + let factory = HashedPostStateCursorFactory::new( + DatabaseHashedCursorFactory::new(&tx), + Arc::new(sorted), + ); let mut cursor = factory.hashed_storage_cursor(address).unwrap(); assert!(cursor.is_storage_empty().unwrap()); } @@ -238,8 +244,10 @@ fn storage_is_empty() { { let sorted = HashedPostState::default().into_sorted(); let tx = db.tx().unwrap(); - let factory = - HashedPostStateCursorFactory::new(DatabaseHashedCursorFactory::new(&tx), &sorted); + let factory = HashedPostStateCursorFactory::new( + DatabaseHashedCursorFactory::new(&tx), + Arc::new(sorted), + ); let mut cursor = factory.hashed_storage_cursor(address).unwrap(); assert!(!cursor.is_storage_empty().unwrap()); } @@ -254,8 +262,10 @@ fn storage_is_empty() { let sorted = hashed_post_state.into_sorted(); let tx = db.tx().unwrap(); - let factory = - HashedPostStateCursorFactory::new(DatabaseHashedCursorFactory::new(&tx), &sorted); + let factory = HashedPostStateCursorFactory::new( + DatabaseHashedCursorFactory::new(&tx), + Arc::new(sorted), + ); let mut cursor = factory.hashed_storage_cursor(address).unwrap(); assert!(cursor.is_storage_empty().unwrap()); } @@ -271,8 +281,10 @@ fn storage_is_empty() { let sorted = hashed_post_state.into_sorted(); let tx = db.tx().unwrap(); - let factory = - HashedPostStateCursorFactory::new(DatabaseHashedCursorFactory::new(&tx), &sorted); + let factory = HashedPostStateCursorFactory::new( + DatabaseHashedCursorFactory::new(&tx), + Arc::new(sorted), + ); let mut cursor = factory.hashed_storage_cursor(address).unwrap(); assert!(cursor.is_storage_empty().unwrap()); } @@ -288,8 +300,10 @@ fn storage_is_empty() { let sorted = hashed_post_state.into_sorted(); let tx = db.tx().unwrap(); - let factory = - HashedPostStateCursorFactory::new(DatabaseHashedCursorFactory::new(&tx), &sorted); + let factory = HashedPostStateCursorFactory::new( + DatabaseHashedCursorFactory::new(&tx), + Arc::new(sorted), + ); let mut cursor = factory.hashed_storage_cursor(address).unwrap(); assert!(!cursor.is_storage_empty().unwrap()); } @@ -325,7 +339,8 @@ fn storage_cursor_correct_order() { let sorted = hashed_post_state.into_sorted(); let tx = db.tx().unwrap(); - let factory = HashedPostStateCursorFactory::new(DatabaseHashedCursorFactory::new(&tx), &sorted); + let factory = + HashedPostStateCursorFactory::new(DatabaseHashedCursorFactory::new(&tx), Arc::new(sorted)); let expected = std::iter::once((address, db_storage.into_iter().chain(post_state_storage).collect())); assert_storage_cursor_order(&factory, expected); @@ -362,7 +377,8 @@ fn zero_value_storage_entries_are_discarded() { let sorted = hashed_post_state.into_sorted(); let tx = db.tx().unwrap(); - let factory = HashedPostStateCursorFactory::new(DatabaseHashedCursorFactory::new(&tx), &sorted); + let factory = + HashedPostStateCursorFactory::new(DatabaseHashedCursorFactory::new(&tx), Arc::new(sorted)); let expected = std::iter::once(( address, post_state_storage.into_iter().filter(|(_, value)| *value > U256::ZERO).collect(), @@ -399,7 +415,8 @@ fn wiped_storage_is_discarded() { let sorted = hashed_post_state.into_sorted(); let tx = db.tx().unwrap(); - let factory = HashedPostStateCursorFactory::new(DatabaseHashedCursorFactory::new(&tx), &sorted); + let factory = + HashedPostStateCursorFactory::new(DatabaseHashedCursorFactory::new(&tx), Arc::new(sorted)); let expected = std::iter::once((address, post_state_storage)); assert_storage_cursor_order(&factory, expected); } @@ -434,7 +451,8 @@ fn post_state_storages_take_precedence() { let sorted = hashed_post_state.into_sorted(); let tx = db.tx().unwrap(); - let factory = HashedPostStateCursorFactory::new(DatabaseHashedCursorFactory::new(&tx), &sorted); + let factory = + HashedPostStateCursorFactory::new(DatabaseHashedCursorFactory::new(&tx), Arc::new(sorted)); let expected = std::iter::once((address, storage)); assert_storage_cursor_order(&factory, expected); } @@ -481,7 +499,7 @@ fn fuzz_hashed_storage_cursor() { let sorted = hashed_post_state.into_sorted(); let tx = db.tx().unwrap(); - let factory = HashedPostStateCursorFactory::new(DatabaseHashedCursorFactory::new(&tx), &sorted); + let factory = HashedPostStateCursorFactory::new(DatabaseHashedCursorFactory::new(&tx), Arc::new(sorted)); assert_storage_cursor_order(&factory, expected.into_iter()); }); } diff --git a/crates/trie/parallel/benches/root.rs b/crates/trie/parallel/benches/root.rs index ca96abbbb214..3c51ad20e838 100644 --- a/crates/trie/parallel/benches/root.rs +++ b/crates/trie/parallel/benches/root.rs @@ -13,7 +13,7 @@ use reth_trie::{ }; use reth_trie_db::{DatabaseHashedCursorFactory, DatabaseStateRoot}; use reth_trie_parallel::root::ParallelStateRoot; -use std::collections::HashMap; +use std::{collections::HashMap, sync::Arc}; pub fn calculate_state_root(c: &mut Criterion) { let mut group = c.benchmark_group("Calculate State Root"); @@ -43,7 +43,7 @@ pub fn calculate_state_root(c: &mut Criterion) { group.bench_function(BenchmarkId::new("sync root", size), |b| { b.iter_with_setup( || { - let sorted_state = updated_state.clone().into_sorted(); + let sorted_state = Arc::new(updated_state.clone().into_sorted()); let prefix_sets = updated_state.construct_prefix_sets().freeze(); let provider = provider_factory.provider().unwrap(); (provider, sorted_state, prefix_sets) @@ -51,7 +51,7 @@ pub fn calculate_state_root(c: &mut Criterion) { |(provider, sorted_state, prefix_sets)| { let hashed_cursor_factory = HashedPostStateCursorFactory::new( DatabaseHashedCursorFactory::new(provider.tx_ref()), - &sorted_state, + sorted_state, ); StateRoot::from_tx(provider.tx_ref()) .with_hashed_cursor_factory(hashed_cursor_factory) diff --git a/crates/trie/parallel/src/proof.rs b/crates/trie/parallel/src/proof.rs index f7716ee13161..644a48792500 100644 --- a/crates/trie/parallel/src/proof.rs +++ b/crates/trie/parallel/src/proof.rs @@ -162,12 +162,13 @@ where let cursor_start = Instant::now(); let trie_cursor_factory = InMemoryTrieCursorFactory::new( DatabaseTrieCursorFactory::new(provider_ro.tx_ref()), - &trie_nodes_sorted, + trie_nodes_sorted, ); let hashed_cursor_factory = HashedPostStateCursorFactory::new( DatabaseHashedCursorFactory::new(provider_ro.tx_ref()), - &hashed_state_sorted, + hashed_state_sorted, ); + trace!( target: "trie::parallel", ?hashed_address, @@ -215,11 +216,11 @@ where let provider_ro = self.view.provider_ro()?; let trie_cursor_factory = InMemoryTrieCursorFactory::new( DatabaseTrieCursorFactory::new(provider_ro.tx_ref()), - &self.nodes_sorted, + self.nodes_sorted, ); let hashed_cursor_factory = HashedPostStateCursorFactory::new( DatabaseHashedCursorFactory::new(provider_ro.tx_ref()), - &self.state_sorted, + self.state_sorted, ); // Create the walker. diff --git a/crates/trie/parallel/src/root.rs b/crates/trie/parallel/src/root.rs index 9ee8ed71e3c4..f25099bd4cf7 100644 --- a/crates/trie/parallel/src/root.rs +++ b/crates/trie/parallel/src/root.rs @@ -111,15 +111,16 @@ where let provider_ro = view.provider_ro()?; let trie_cursor_factory = InMemoryTrieCursorFactory::new( DatabaseTrieCursorFactory::new(provider_ro.tx_ref()), - &trie_nodes_sorted, + trie_nodes_sorted, ); - let hashed_state = HashedPostStateCursorFactory::new( + let hashed_cursor_factory = HashedPostStateCursorFactory::new( DatabaseHashedCursorFactory::new(provider_ro.tx_ref()), - &hashed_state_sorted, + hashed_state_sorted, ); + Ok(StorageRoot::new_hashed( trie_cursor_factory, - hashed_state, + hashed_cursor_factory, hashed_address, prefix_set, #[cfg(feature = "metrics")] @@ -138,11 +139,11 @@ where let provider_ro = self.view.provider_ro()?; let trie_cursor_factory = InMemoryTrieCursorFactory::new( DatabaseTrieCursorFactory::new(provider_ro.tx_ref()), - &trie_nodes_sorted, + trie_nodes_sorted, ); let hashed_cursor_factory = HashedPostStateCursorFactory::new( DatabaseHashedCursorFactory::new(provider_ro.tx_ref()), - &hashed_state_sorted, + hashed_state_sorted, ); let walker = TrieWalker::new( diff --git a/crates/trie/sparse/benches/root.rs b/crates/trie/sparse/benches/root.rs index e01f9825d8ee..a2483b23c71f 100644 --- a/crates/trie/sparse/benches/root.rs +++ b/crates/trie/sparse/benches/root.rs @@ -14,6 +14,7 @@ use reth_trie::{ }; use reth_trie_common::{HashBuilder, Nibbles}; use reth_trie_sparse::SparseTrie; +use std::sync::Arc; fn calculate_root_from_leaves(c: &mut Criterion) { let mut group = c.benchmark_group("calculate root from leaves"); @@ -133,7 +134,7 @@ fn calculate_root_from_leaves_repeated(c: &mut Criterion) { InMemoryStorageTrieCursor::new( B256::ZERO, NoopStorageTrieCursor::default(), - Some(&trie_updates_sorted), + Some(Arc::new(trie_updates_sorted)), ), prefix_set, ); @@ -141,7 +142,7 @@ fn calculate_root_from_leaves_repeated(c: &mut Criterion) { walker, HashedPostStateStorageCursor::new( NoopHashedStorageCursor::default(), - Some(&storage_sorted), + Some(Arc::new(storage_sorted)), ), ); diff --git a/crates/trie/trie/src/forward_cursor.rs b/crates/trie/trie/src/forward_cursor.rs index 745fc351b904..4eb3b5f6eea0 100644 --- a/crates/trie/trie/src/forward_cursor.rs +++ b/crates/trie/trie/src/forward_cursor.rs @@ -1,17 +1,20 @@ +extern crate alloc; +use alloc::sync::Arc; + /// The implementation of forward-only in memory cursor over the entries. /// The cursor operates under the assumption that the supplied collection is pre-sorted. #[derive(Debug)] -pub struct ForwardInMemoryCursor<'a, K, V> { +pub struct ForwardInMemoryCursor { /// The reference to the pre-sorted collection of entries. - entries: &'a Vec<(K, V)>, + entries: Arc>, /// The index where cursor is currently positioned. index: usize, } -impl<'a, K, V> ForwardInMemoryCursor<'a, K, V> { +impl ForwardInMemoryCursor { /// Create new forward cursor positioned at the beginning of the collection. /// The cursor expects all of the entries have been sorted in advance. - pub const fn new(entries: &'a Vec<(K, V)>) -> Self { + pub const fn new(entries: Arc>) -> Self { Self { entries, index: 0 } } @@ -21,7 +24,7 @@ impl<'a, K, V> ForwardInMemoryCursor<'a, K, V> { } } -impl ForwardInMemoryCursor<'_, K, V> +impl ForwardInMemoryCursor where K: PartialOrd + Clone, V: Clone, diff --git a/crates/trie/trie/src/hashed_cursor/post_state.rs b/crates/trie/trie/src/hashed_cursor/post_state.rs index a4ab1fa52eaf..65c2373267a8 100644 --- a/crates/trie/trie/src/hashed_cursor/post_state.rs +++ b/crates/trie/trie/src/hashed_cursor/post_state.rs @@ -7,27 +7,30 @@ use alloy_primitives::{map::B256HashSet, B256, U256}; use reth_primitives::Account; use reth_storage_errors::db::DatabaseError; +extern crate alloc; +use alloc::sync::Arc; + /// The hashed cursor factory for the post state. #[derive(Clone, Debug)] -pub struct HashedPostStateCursorFactory<'a, CF> { +pub struct HashedPostStateCursorFactory { cursor_factory: CF, - post_state: &'a HashedPostStateSorted, + post_state: Arc, } -impl<'a, CF> HashedPostStateCursorFactory<'a, CF> { +impl HashedPostStateCursorFactory { /// Create a new factory. - pub const fn new(cursor_factory: CF, post_state: &'a HashedPostStateSorted) -> Self { + pub const fn new(cursor_factory: CF, post_state: Arc) -> Self { Self { cursor_factory, post_state } } } -impl<'a, CF: HashedCursorFactory> HashedCursorFactory for HashedPostStateCursorFactory<'a, CF> { - type AccountCursor = HashedPostStateAccountCursor<'a, CF::AccountCursor>; - type StorageCursor = HashedPostStateStorageCursor<'a, CF::StorageCursor>; +impl HashedCursorFactory for HashedPostStateCursorFactory { + type AccountCursor = HashedPostStateAccountCursor; + type StorageCursor = HashedPostStateStorageCursor; fn hashed_account_cursor(&self) -> Result { let cursor = self.cursor_factory.hashed_account_cursor()?; - Ok(HashedPostStateAccountCursor::new(cursor, &self.post_state.accounts)) + Ok(HashedPostStateAccountCursor::new(cursor, self.post_state.accounts.clone())) } fn hashed_storage_cursor( @@ -35,33 +38,36 @@ impl<'a, CF: HashedCursorFactory> HashedCursorFactory for HashedPostStateCursorF hashed_address: B256, ) -> Result { let cursor = self.cursor_factory.hashed_storage_cursor(hashed_address)?; - Ok(HashedPostStateStorageCursor::new(cursor, self.post_state.storages.get(&hashed_address))) + Ok(HashedPostStateStorageCursor::new( + cursor, + self.post_state.storages.get(&hashed_address).cloned().map(Arc::new), + )) } } /// The cursor to iterate over post state hashed accounts and corresponding database entries. /// It will always give precedence to the data from the hashed post state. #[derive(Debug)] -pub struct HashedPostStateAccountCursor<'a, C> { +pub struct HashedPostStateAccountCursor { /// The database cursor. cursor: C, /// Forward-only in-memory cursor over accounts. - post_state_cursor: ForwardInMemoryCursor<'a, B256, Account>, + post_state_cursor: ForwardInMemoryCursor, /// Reference to the collection of account keys that were destroyed. - destroyed_accounts: &'a B256HashSet, + destroyed_accounts: Arc, /// The last hashed account that was returned by the cursor. /// De facto, this is a current cursor position. last_account: Option, } -impl<'a, C> HashedPostStateAccountCursor<'a, C> +impl HashedPostStateAccountCursor where C: HashedCursor, { /// Create new instance of [`HashedPostStateAccountCursor`]. - pub const fn new(cursor: C, post_state_accounts: &'a HashedAccountsSorted) -> Self { - let post_state_cursor = ForwardInMemoryCursor::new(&post_state_accounts.accounts); - let destroyed_accounts = &post_state_accounts.destroyed_accounts; + pub fn new(cursor: C, post_state_accounts: Arc) -> Self { + let post_state_cursor = ForwardInMemoryCursor::new(post_state_accounts.accounts.clone()); + let destroyed_accounts = post_state_accounts.destroyed_accounts.clone(); Self { cursor, post_state_cursor, destroyed_accounts, last_account: None } } @@ -131,7 +137,7 @@ where } } -impl HashedCursor for HashedPostStateAccountCursor<'_, C> +impl HashedCursor for HashedPostStateAccountCursor where C: HashedCursor, { @@ -176,13 +182,13 @@ where /// The cursor to iterate over post state hashed storages and corresponding database entries. /// It will always give precedence to the data from the post state. #[derive(Debug)] -pub struct HashedPostStateStorageCursor<'a, C> { +pub struct HashedPostStateStorageCursor { /// The database cursor. cursor: C, /// Forward-only in-memory cursor over non zero-valued account storage slots. - post_state_cursor: Option>, + post_state_cursor: Option>, /// Reference to the collection of storage slot keys that were cleared. - cleared_slots: Option<&'a B256HashSet>, + cleared_slots: Option>, /// Flag indicating whether database storage was wiped. storage_wiped: bool, /// The last slot that has been returned by the cursor. @@ -190,15 +196,16 @@ pub struct HashedPostStateStorageCursor<'a, C> { last_slot: Option, } -impl<'a, C> HashedPostStateStorageCursor<'a, C> +impl HashedPostStateStorageCursor where C: HashedStorageCursor, { /// Create new instance of [`HashedPostStateStorageCursor`] for the given hashed address. - pub fn new(cursor: C, post_state_storage: Option<&'a HashedStorageSorted>) -> Self { - let post_state_cursor = - post_state_storage.map(|s| ForwardInMemoryCursor::new(&s.non_zero_valued_slots)); - let cleared_slots = post_state_storage.map(|s| &s.zero_valued_slots); + pub fn new(cursor: C, post_state_storage: Option>) -> Self { + let post_state_cursor = post_state_storage + .as_ref() + .map(|s| ForwardInMemoryCursor::new(s.non_zero_valued_slots.clone())); + let cleared_slots = post_state_storage.as_ref().map(|s| s.zero_valued_slots.clone()); let storage_wiped = post_state_storage.is_some_and(|s| s.wiped); Self { cursor, post_state_cursor, cleared_slots, storage_wiped, last_slot: None } } @@ -206,7 +213,7 @@ where /// Check if the slot was zeroed out in the post state. /// The database is not checked since it already has no zero-valued slots. fn is_slot_zero_valued(&self, slot: &B256) -> bool { - self.cleared_slots.is_some_and(|s| s.contains(slot)) + self.cleared_slots.as_ref().is_some_and(|s| s.contains(slot)) } /// Find the storage entry in post state or database that's greater or equal to provided subkey. @@ -275,7 +282,7 @@ where } } -impl HashedCursor for HashedPostStateStorageCursor<'_, C> +impl HashedCursor for HashedPostStateStorageCursor where C: HashedStorageCursor, { @@ -303,7 +310,7 @@ where } } -impl HashedStorageCursor for HashedPostStateStorageCursor<'_, C> +impl HashedStorageCursor for HashedPostStateStorageCursor where C: HashedStorageCursor, { diff --git a/crates/trie/trie/src/state.rs b/crates/trie/trie/src/state.rs index 510b914ceaf9..2121362432ae 100644 --- a/crates/trie/trie/src/state.rs +++ b/crates/trie/trie/src/state.rs @@ -12,7 +12,7 @@ use rayon::prelude::{IntoParallelIterator, ParallelIterator}; use reth_primitives::Account; use reth_trie_common::KeyHasher; use revm::db::{states::CacheAccount, AccountStatus, BundleAccount}; -use std::borrow::Cow; +use std::{borrow::Cow, sync::Arc}; /// Representation of in-memory hashed state. #[derive(PartialEq, Eq, Clone, Default, Debug)] @@ -192,7 +192,7 @@ impl HashedPostState { } } updated_accounts.sort_unstable_by_key(|(address, _)| *address); - let accounts = HashedAccountsSorted { accounts: updated_accounts, destroyed_accounts }; + let accounts = HashedAccountsSorted::new(updated_accounts, destroyed_accounts); let storages = self .storages @@ -200,7 +200,7 @@ impl HashedPostState { .map(|(hashed_address, storage)| (hashed_address, storage.into_sorted())) .collect(); - HashedPostStateSorted { accounts, storages } + HashedPostStateSorted::new(accounts, storages) } } @@ -271,7 +271,7 @@ impl HashedStorage { } non_zero_valued_slots.sort_unstable_by_key(|(key, _)| *key); - HashedStorageSorted { non_zero_valued_slots, zero_valued_slots, wiped: self.wiped } + HashedStorageSorted::new(non_zero_valued_slots, zero_valued_slots, self.wiped) } } @@ -279,23 +279,20 @@ impl HashedStorage { #[derive(PartialEq, Eq, Clone, Default, Debug)] pub struct HashedPostStateSorted { /// Updated state of accounts. - pub(crate) accounts: HashedAccountsSorted, + pub(crate) accounts: Arc, /// Map of hashed addresses to hashed storage. pub(crate) storages: B256HashMap, } impl HashedPostStateSorted { /// Create new instance of [`HashedPostStateSorted`] - pub const fn new( - accounts: HashedAccountsSorted, - storages: B256HashMap, - ) -> Self { - Self { accounts, storages } + pub fn new(accounts: HashedAccountsSorted, storages: B256HashMap) -> Self { + Self { accounts: Arc::new(accounts), storages } } /// Returns reference to hashed accounts. - pub const fn accounts(&self) -> &HashedAccountsSorted { - &self.accounts + pub fn accounts(&self) -> Arc { + self.accounts.clone() } /// Returns reference to hashed account storages. @@ -308,12 +305,17 @@ impl HashedPostStateSorted { #[derive(Clone, Eq, PartialEq, Default, Debug)] pub struct HashedAccountsSorted { /// Sorted collection of hashed addresses and their account info. - pub(crate) accounts: Vec<(B256, Account)>, + pub(crate) accounts: Arc>, /// Set of destroyed account keys. - pub(crate) destroyed_accounts: B256HashSet, + pub(crate) destroyed_accounts: Arc, } impl HashedAccountsSorted { + /// Create new instance of [`HashedAccountsSorted`] + pub fn new(accounts: Vec<(B256, Account)>, destroyed_accounts: B256HashSet) -> Self { + Self { accounts: Arc::new(accounts), destroyed_accounts: Arc::new(destroyed_accounts) } + } + /// Returns a sorted iterator over updated accounts. pub fn accounts_sorted(&self) -> impl Iterator)> { self.accounts @@ -328,14 +330,27 @@ impl HashedAccountsSorted { #[derive(Clone, Eq, PartialEq, Debug)] pub struct HashedStorageSorted { /// Sorted hashed storage slots with non-zero value. - pub(crate) non_zero_valued_slots: Vec<(B256, U256)>, + pub(crate) non_zero_valued_slots: Arc>, /// Slots that have been zero valued. - pub(crate) zero_valued_slots: B256HashSet, + pub(crate) zero_valued_slots: Arc, /// Flag indicating whether the storage was wiped or not. pub(crate) wiped: bool, } impl HashedStorageSorted { + /// Create new instance of [`HashedStorageSorted`] + pub fn new( + non_zero_valued_slots: Vec<(B256, U256)>, + zero_valued_slots: B256HashSet, + wiped: bool, + ) -> Self { + Self { + non_zero_valued_slots: Arc::new(non_zero_valued_slots), + zero_valued_slots: Arc::new(zero_valued_slots), + wiped, + } + } + /// Returns `true` if the account was wiped. pub const fn is_wiped(&self) -> bool { self.wiped diff --git a/crates/trie/trie/src/trie_cursor/in_memory.rs b/crates/trie/trie/src/trie_cursor/in_memory.rs index 0e394fcf77f3..baf05de1ab90 100644 --- a/crates/trie/trie/src/trie_cursor/in_memory.rs +++ b/crates/trie/trie/src/trie_cursor/in_memory.rs @@ -7,29 +7,32 @@ use alloy_primitives::{map::HashSet, B256}; use reth_storage_errors::db::DatabaseError; use reth_trie_common::{BranchNodeCompact, Nibbles}; +extern crate alloc; +use alloc::sync::Arc; + /// The trie cursor factory for the trie updates. #[derive(Debug, Clone)] -pub struct InMemoryTrieCursorFactory<'a, CF> { +pub struct InMemoryTrieCursorFactory { /// Underlying trie cursor factory. cursor_factory: CF, /// Reference to sorted trie updates. - trie_updates: &'a TrieUpdatesSorted, + trie_updates: Arc, } -impl<'a, CF> InMemoryTrieCursorFactory<'a, CF> { +impl InMemoryTrieCursorFactory { /// Create a new trie cursor factory. - pub const fn new(cursor_factory: CF, trie_updates: &'a TrieUpdatesSorted) -> Self { + pub const fn new(cursor_factory: CF, trie_updates: Arc) -> Self { Self { cursor_factory, trie_updates } } } -impl<'a, CF: TrieCursorFactory> TrieCursorFactory for InMemoryTrieCursorFactory<'a, CF> { - type AccountTrieCursor = InMemoryAccountTrieCursor<'a, CF::AccountTrieCursor>; - type StorageTrieCursor = InMemoryStorageTrieCursor<'a, CF::StorageTrieCursor>; +impl TrieCursorFactory for InMemoryTrieCursorFactory { + type AccountTrieCursor = InMemoryAccountTrieCursor; + type StorageTrieCursor = InMemoryStorageTrieCursor; fn account_trie_cursor(&self) -> Result { let cursor = self.cursor_factory.account_trie_cursor()?; - Ok(InMemoryAccountTrieCursor::new(cursor, self.trie_updates)) + Ok(InMemoryAccountTrieCursor::new(cursor, self.trie_updates.clone())) } fn storage_trie_cursor( @@ -40,7 +43,10 @@ impl<'a, CF: TrieCursorFactory> TrieCursorFactory for InMemoryTrieCursorFactory< Ok(InMemoryStorageTrieCursor::new( hashed_address, cursor, - self.trie_updates.storage_tries.get(&hashed_address), + self.trie_updates + .storage_tries + .get(&hashed_address) + .map(|updates| Arc::new(updates.clone())), )) } } @@ -48,26 +54,27 @@ impl<'a, CF: TrieCursorFactory> TrieCursorFactory for InMemoryTrieCursorFactory< /// The cursor to iterate over account trie updates and corresponding database entries. /// It will always give precedence to the data from the trie updates. #[derive(Debug)] -pub struct InMemoryAccountTrieCursor<'a, C> { +pub struct InMemoryAccountTrieCursor { /// The underlying cursor. cursor: C, /// Forward-only in-memory cursor over storage trie nodes. - in_memory_cursor: ForwardInMemoryCursor<'a, Nibbles, BranchNodeCompact>, + in_memory_cursor: ForwardInMemoryCursor, /// Collection of removed trie nodes. - removed_nodes: &'a HashSet, + removed_nodes: HashSet, /// Last key returned by the cursor. last_key: Option, } -impl<'a, C: TrieCursor> InMemoryAccountTrieCursor<'a, C> { +impl InMemoryAccountTrieCursor { /// Create new account trie cursor from underlying cursor and reference to /// [`TrieUpdatesSorted`]. - pub const fn new(cursor: C, trie_updates: &'a TrieUpdatesSorted) -> Self { - let in_memory_cursor = ForwardInMemoryCursor::new(&trie_updates.account_nodes); + pub fn new(cursor: C, trie_updates: Arc) -> Self { + let in_memory_cursor = + ForwardInMemoryCursor::new(Arc::new(trie_updates.account_nodes.clone())); Self { cursor, in_memory_cursor, - removed_nodes: &trie_updates.removed_nodes, + removed_nodes: trie_updates.removed_nodes.clone(), last_key: None, } } @@ -114,7 +121,7 @@ impl<'a, C: TrieCursor> InMemoryAccountTrieCursor<'a, C> { } } -impl TrieCursor for InMemoryAccountTrieCursor<'_, C> { +impl TrieCursor for InMemoryAccountTrieCursor { fn seek_exact( &mut self, key: Nibbles, @@ -158,31 +165,32 @@ impl TrieCursor for InMemoryAccountTrieCursor<'_, C> { /// It will always give precedence to the data from the trie updates. #[derive(Debug)] #[allow(dead_code)] -pub struct InMemoryStorageTrieCursor<'a, C> { +pub struct InMemoryStorageTrieCursor { /// The hashed address of the account that trie belongs to. hashed_address: B256, /// The underlying cursor. cursor: C, /// Forward-only in-memory cursor over storage trie nodes. - in_memory_cursor: Option>, + in_memory_cursor: Option>, /// Reference to the set of removed storage node keys. - removed_nodes: Option<&'a HashSet>, + removed_nodes: Option>, /// The flag indicating whether the storage trie was cleared. storage_trie_cleared: bool, /// Last key returned by the cursor. last_key: Option, } -impl<'a, C> InMemoryStorageTrieCursor<'a, C> { +impl InMemoryStorageTrieCursor { /// Create new storage trie cursor from underlying cursor and reference to /// [`StorageTrieUpdatesSorted`]. pub fn new( hashed_address: B256, cursor: C, - updates: Option<&'a StorageTrieUpdatesSorted>, + updates: Option>, ) -> Self { - let in_memory_cursor = updates.map(|u| ForwardInMemoryCursor::new(&u.storage_nodes)); - let removed_nodes = updates.map(|u| &u.removed_nodes); + let in_memory_cursor = + updates.clone().map(|u| ForwardInMemoryCursor::new(Arc::new(u.storage_nodes.clone()))); + let removed_nodes = updates.clone().map(|u| u.removed_nodes.clone()); let storage_trie_cleared = updates.is_some_and(|u| u.is_deleted); Self { hashed_address, @@ -195,7 +203,7 @@ impl<'a, C> InMemoryStorageTrieCursor<'a, C> { } } -impl InMemoryStorageTrieCursor<'_, C> { +impl InMemoryStorageTrieCursor { fn seek_inner( &mut self, key: Nibbles, @@ -243,7 +251,7 @@ impl InMemoryStorageTrieCursor<'_, C> { } } -impl TrieCursor for InMemoryStorageTrieCursor<'_, C> { +impl TrieCursor for InMemoryStorageTrieCursor { fn seek_exact( &mut self, key: Nibbles,