chore(trie): introduce wrapper struct for hashed cursor related impls (#9707)

This commit is contained in:
Roman Krasiuk
2024-07-22 09:01:06 -07:00
committed by GitHub
parent 935327c4f7
commit f2279a81c0
11 changed files with 137 additions and 60 deletions

View File

@ -2,7 +2,9 @@ use reth_db_api::transaction::DbTx;
use reth_execution_errors::StateRootError;
use reth_primitives::{BlockNumber, B256};
use reth_trie::{
hashed_cursor::HashedPostStateCursorFactory, prefix_set::PrefixSetLoader, updates::TrieUpdates,
hashed_cursor::{DatabaseHashedCursorFactory, HashedPostStateCursorFactory},
prefix_set::PrefixSetLoader,
updates::TrieUpdates,
HashedPostState, StateRoot, StateRootProgress,
};
use std::ops::RangeInclusive;
@ -100,9 +102,11 @@ pub trait DatabaseStateRoot<'a, TX>: Sized {
) -> Result<(B256, TrieUpdates), StateRootError>;
}
impl<'a, TX: DbTx> DatabaseStateRoot<'a, TX> for StateRoot<&'a TX, &'a TX> {
impl<'a, TX: DbTx> DatabaseStateRoot<'a, TX>
for StateRoot<&'a TX, DatabaseHashedCursorFactory<'a, TX>>
{
fn from_tx(tx: &'a TX) -> Self {
Self::new(tx, tx)
Self::new(tx, DatabaseHashedCursorFactory::new(tx))
}
fn incremental_root_calculator(
@ -140,10 +144,12 @@ impl<'a, TX: DbTx> DatabaseStateRoot<'a, TX> for StateRoot<&'a TX, &'a TX> {
fn overlay_root(tx: &'a TX, post_state: HashedPostState) -> Result<B256, StateRootError> {
let prefix_sets = post_state.construct_prefix_sets().freeze();
let sorted = post_state.into_sorted();
Self::from_tx(tx)
.with_hashed_cursor_factory(HashedPostStateCursorFactory::new(tx, &sorted))
.with_prefix_sets(prefix_sets)
.root()
StateRoot::new(
tx,
HashedPostStateCursorFactory::new(DatabaseHashedCursorFactory::new(tx), &sorted),
)
.with_prefix_sets(prefix_sets)
.root()
}
fn overlay_root_with_updates(
@ -152,10 +158,12 @@ impl<'a, TX: DbTx> DatabaseStateRoot<'a, TX> for StateRoot<&'a TX, &'a TX> {
) -> Result<(B256, TrieUpdates), StateRootError> {
let prefix_sets = post_state.construct_prefix_sets().freeze();
let sorted = post_state.into_sorted();
Self::from_tx(tx)
.with_hashed_cursor_factory(HashedPostStateCursorFactory::new(tx, &sorted))
.with_prefix_sets(prefix_sets)
.root_with_updates()
StateRoot::new(
tx,
HashedPostStateCursorFactory::new(DatabaseHashedCursorFactory::new(tx), &sorted),
)
.with_prefix_sets(prefix_sets)
.root_with_updates()
}
}

View File

@ -9,7 +9,8 @@ use reth_provider::{
};
use reth_tasks::pool::BlockingTaskPool;
use reth_trie::{
hashed_cursor::HashedPostStateCursorFactory, HashedPostState, HashedStorage, StateRoot,
hashed_cursor::{DatabaseHashedCursorFactory, HashedPostStateCursorFactory},
HashedPostState, HashedStorage, StateRoot,
};
use reth_trie_db::DatabaseStateRoot;
use reth_trie_parallel::{async_root::AsyncStateRoot, parallel_root::ParallelStateRoot};
@ -47,11 +48,12 @@ pub fn calculate_state_root(c: &mut Criterion) {
(provider, sorted_state, prefix_sets)
},
|(provider, sorted_state, prefix_sets)| async move {
let hashed_cursor_factory = HashedPostStateCursorFactory::new(
DatabaseHashedCursorFactory::new(provider.tx_ref()),
&sorted_state,
);
StateRoot::from_tx(provider.tx_ref())
.with_hashed_cursor_factory(HashedPostStateCursorFactory::new(
provider.tx_ref(),
&sorted_state,
))
.with_hashed_cursor_factory(hashed_cursor_factory)
.with_prefix_sets(prefix_sets)
.root()
},

View File

@ -7,7 +7,9 @@ use reth_primitives::B256;
use reth_provider::{providers::ConsistentDbView, DatabaseProviderFactory, ProviderError};
use reth_tasks::pool::BlockingTaskPool;
use reth_trie::{
hashed_cursor::{HashedCursorFactory, HashedPostStateCursorFactory},
hashed_cursor::{
DatabaseHashedCursorFactory, HashedCursorFactory, HashedPostStateCursorFactory,
},
node_iter::{TrieElement, TrieNodeIter},
trie_cursor::TrieCursorFactory,
updates::TrieUpdates,
@ -107,9 +109,13 @@ where
let handle =
self.blocking_pool.spawn_fifo(move || -> Result<_, AsyncStateRootError> {
let provider = view.provider_ro()?;
let hashed_state = HashedPostStateCursorFactory::new(
DatabaseHashedCursorFactory::new(provider.tx_ref()),
&hashed_state_sorted,
);
Ok(StorageRoot::new_hashed(
provider.tx_ref(),
HashedPostStateCursorFactory::new(provider.tx_ref(), &hashed_state_sorted),
hashed_state,
hashed_address,
#[cfg(feature = "metrics")]
metrics,
@ -125,7 +131,10 @@ where
let provider_ro = self.view.provider_ro()?;
let tx = provider_ro.tx_ref();
let hashed_cursor_factory = HashedPostStateCursorFactory::new(tx, &hashed_state_sorted);
let hashed_cursor_factory = HashedPostStateCursorFactory::new(
DatabaseHashedCursorFactory::new(tx),
&hashed_state_sorted,
);
let trie_cursor_factory = tx;
let walker = TrieWalker::new(

View File

@ -6,7 +6,9 @@ use reth_execution_errors::StorageRootError;
use reth_primitives::B256;
use reth_provider::{providers::ConsistentDbView, DatabaseProviderFactory, ProviderError};
use reth_trie::{
hashed_cursor::{HashedCursorFactory, HashedPostStateCursorFactory},
hashed_cursor::{
DatabaseHashedCursorFactory, HashedCursorFactory, HashedPostStateCursorFactory,
},
node_iter::{TrieElement, TrieNodeIter},
trie_cursor::TrieCursorFactory,
updates::TrieUpdates,
@ -91,9 +93,13 @@ where
.into_par_iter()
.map(|(hashed_address, prefix_set)| {
let provider_ro = self.view.provider_ro()?;
let hashed_cursor_factory = HashedPostStateCursorFactory::new(
DatabaseHashedCursorFactory::new(provider_ro.tx_ref()),
&hashed_state_sorted,
);
let storage_root_result = StorageRoot::new_hashed(
provider_ro.tx_ref(),
HashedPostStateCursorFactory::new(provider_ro.tx_ref(), &hashed_state_sorted),
hashed_cursor_factory,
hashed_address,
#[cfg(feature = "metrics")]
self.metrics.storage_trie.clone(),
@ -108,8 +114,10 @@ where
let mut trie_updates = TrieUpdates::default();
let provider_ro = self.view.provider_ro()?;
let hashed_cursor_factory =
HashedPostStateCursorFactory::new(provider_ro.tx_ref(), &hashed_state_sorted);
let hashed_cursor_factory = HashedPostStateCursorFactory::new(
DatabaseHashedCursorFactory::new(provider_ro.tx_ref()),
&hashed_state_sorted,
);
let trie_cursor_factory = provider_ro.tx_ref();
let walker = TrieWalker::new(

View File

@ -6,13 +6,30 @@ use reth_db_api::{
};
use reth_primitives::{Account, B256, U256};
impl<'a, TX: DbTx> HashedCursorFactory for &'a TX {
type AccountCursor = <TX as DbTx>::Cursor<tables::HashedAccounts>;
/// A struct wrapping database transaction that implements [`HashedCursorFactory`].
#[derive(Debug)]
pub struct DatabaseHashedCursorFactory<'a, TX>(&'a TX);
impl<'a, TX> Clone for DatabaseHashedCursorFactory<'a, TX> {
fn clone(&self) -> Self {
Self(self.0)
}
}
impl<'a, TX> DatabaseHashedCursorFactory<'a, TX> {
/// Create new database hashed cursor factory.
pub const fn new(tx: &'a TX) -> Self {
Self(tx)
}
}
impl<'a, TX: DbTx> HashedCursorFactory for DatabaseHashedCursorFactory<'a, TX> {
type AccountCursor = DatabaseHashedAccountCursor<<TX as DbTx>::Cursor<tables::HashedAccounts>>;
type StorageCursor =
DatabaseHashedStorageCursor<<TX as DbTx>::DupCursor<tables::HashedStorages>>;
fn hashed_account_cursor(&self) -> Result<Self::AccountCursor, reth_db::DatabaseError> {
self.cursor_read::<tables::HashedAccounts>()
Ok(DatabaseHashedAccountCursor(self.0.cursor_read::<tables::HashedAccounts>()?))
}
fn hashed_storage_cursor(
@ -20,24 +37,36 @@ impl<'a, TX: DbTx> HashedCursorFactory for &'a TX {
hashed_address: B256,
) -> Result<Self::StorageCursor, reth_db::DatabaseError> {
Ok(DatabaseHashedStorageCursor::new(
self.cursor_dup_read::<tables::HashedStorages>()?,
self.0.cursor_dup_read::<tables::HashedStorages>()?,
hashed_address,
))
}
}
impl<C> HashedCursor for C
/// A struct wrapping database cursor over hashed accounts implementing [`HashedCursor`] for
/// iterating over accounts.
#[derive(Debug)]
pub struct DatabaseHashedAccountCursor<C>(C);
impl<C> DatabaseHashedAccountCursor<C> {
/// Create new database hashed account cursor.
pub const fn new(cursor: C) -> Self {
Self(cursor)
}
}
impl<C> HashedCursor for DatabaseHashedAccountCursor<C>
where
C: DbCursorRO<tables::HashedAccounts>,
{
type Value = Account;
fn seek(&mut self, key: B256) -> Result<Option<(B256, Self::Value)>, reth_db::DatabaseError> {
self.seek(key)
self.0.seek(key)
}
fn next(&mut self) -> Result<Option<(B256, Self::Value)>, reth_db::DatabaseError> {
self.next()
self.0.next()
}
}

View File

@ -2,7 +2,7 @@ use reth_primitives::{Account, B256, U256};
/// Default implementation of the hashed state cursor traits.
mod default;
pub use default::DatabaseHashedStorageCursor;
pub use default::*;
/// Implementation of hashed state cursor traits for the post state.
mod post_state;

View File

@ -8,7 +8,7 @@ use reth_primitives::{Account, B256, U256};
use std::collections::HashSet;
/// The hashed cursor factory for the post state.
#[derive(Debug, Clone)]
#[derive(Clone, Debug)]
pub struct HashedPostStateCursorFactory<'a, CF> {
cursor_factory: CF,
post_state: &'a HashedPostStateSorted,
@ -328,7 +328,7 @@ where
#[cfg(test)]
mod tests {
use super::*;
use crate::{HashedPostState, HashedStorage};
use crate::{hashed_cursor::DatabaseHashedCursorFactory, HashedPostState, HashedStorage};
use proptest::prelude::*;
use proptest_arbitrary_interop::arb;
use reth_db::{tables, test_utils::create_test_rw_db};
@ -387,7 +387,8 @@ mod tests {
let sorted = hashed_post_state.into_sorted();
let tx = db.tx().unwrap();
let factory = HashedPostStateCursorFactory::new(&tx, &sorted);
let factory =
HashedPostStateCursorFactory::new(DatabaseHashedCursorFactory::new(&tx), &sorted);
assert_account_cursor_order(&factory, accounts.into_iter());
}
@ -406,7 +407,10 @@ mod tests {
let sorted_post_state = HashedPostState::default().into_sorted();
let tx = db.tx().unwrap();
let factory = HashedPostStateCursorFactory::new(&tx, &sorted_post_state);
let factory = HashedPostStateCursorFactory::new(
DatabaseHashedCursorFactory::new(&tx),
&sorted_post_state,
);
assert_account_cursor_order(&factory, accounts.into_iter());
}
@ -431,7 +435,8 @@ mod tests {
let sorted = hashed_post_state.into_sorted();
let tx = db.tx().unwrap();
let factory = HashedPostStateCursorFactory::new(&tx, &sorted);
let factory =
HashedPostStateCursorFactory::new(DatabaseHashedCursorFactory::new(&tx), &sorted);
assert_account_cursor_order(&factory, accounts.into_iter());
}
@ -461,7 +466,8 @@ mod tests {
let sorted = hashed_post_state.into_sorted();
let tx = db.tx().unwrap();
let factory = HashedPostStateCursorFactory::new(&tx, &sorted);
let factory =
HashedPostStateCursorFactory::new(DatabaseHashedCursorFactory::new(&tx), &sorted);
let expected = accounts.into_iter().filter(|x| !removed_keys.contains(&x.0));
assert_account_cursor_order(&factory, expected);
}
@ -488,7 +494,8 @@ mod tests {
let sorted = hashed_post_state.into_sorted();
let tx = db.tx().unwrap();
let factory = HashedPostStateCursorFactory::new(&tx, &sorted);
let factory =
HashedPostStateCursorFactory::new(DatabaseHashedCursorFactory::new(&tx), &sorted);
assert_account_cursor_order(&factory, accounts.into_iter());
}
@ -520,7 +527,7 @@ mod tests {
let sorted = hashed_post_state.into_sorted();
let tx = db.tx().unwrap();
let factory = HashedPostStateCursorFactory::new(&tx, &sorted);
let factory = HashedPostStateCursorFactory::new(DatabaseHashedCursorFactory::new(&tx), &sorted);
assert_account_cursor_order(&factory, expected.into_iter());
}
);
@ -535,7 +542,8 @@ mod tests {
{
let sorted = HashedPostState::default().into_sorted();
let tx = db.tx().unwrap();
let factory = HashedPostStateCursorFactory::new(&tx, &sorted);
let factory =
HashedPostStateCursorFactory::new(DatabaseHashedCursorFactory::new(&tx), &sorted);
let mut cursor = factory.hashed_storage_cursor(address).unwrap();
assert!(cursor.is_storage_empty().unwrap());
}
@ -558,7 +566,8 @@ mod tests {
{
let sorted = HashedPostState::default().into_sorted();
let tx = db.tx().unwrap();
let factory = HashedPostStateCursorFactory::new(&tx, &sorted);
let factory =
HashedPostStateCursorFactory::new(DatabaseHashedCursorFactory::new(&tx), &sorted);
let mut cursor = factory.hashed_storage_cursor(address).unwrap();
assert!(!cursor.is_storage_empty().unwrap());
}
@ -573,7 +582,8 @@ mod tests {
let sorted = hashed_post_state.into_sorted();
let tx = db.tx().unwrap();
let factory = HashedPostStateCursorFactory::new(&tx, &sorted);
let factory =
HashedPostStateCursorFactory::new(DatabaseHashedCursorFactory::new(&tx), &sorted);
let mut cursor = factory.hashed_storage_cursor(address).unwrap();
assert!(cursor.is_storage_empty().unwrap());
}
@ -589,7 +599,8 @@ mod tests {
let sorted = hashed_post_state.into_sorted();
let tx = db.tx().unwrap();
let factory = HashedPostStateCursorFactory::new(&tx, &sorted);
let factory =
HashedPostStateCursorFactory::new(DatabaseHashedCursorFactory::new(&tx), &sorted);
let mut cursor = factory.hashed_storage_cursor(address).unwrap();
assert!(cursor.is_storage_empty().unwrap());
}
@ -605,7 +616,8 @@ mod tests {
let sorted = hashed_post_state.into_sorted();
let tx = db.tx().unwrap();
let factory = HashedPostStateCursorFactory::new(&tx, &sorted);
let factory =
HashedPostStateCursorFactory::new(DatabaseHashedCursorFactory::new(&tx), &sorted);
let mut cursor = factory.hashed_storage_cursor(address).unwrap();
assert!(!cursor.is_storage_empty().unwrap());
}
@ -643,7 +655,8 @@ mod tests {
let sorted = hashed_post_state.into_sorted();
let tx = db.tx().unwrap();
let factory = HashedPostStateCursorFactory::new(&tx, &sorted);
let factory =
HashedPostStateCursorFactory::new(DatabaseHashedCursorFactory::new(&tx), &sorted);
let expected =
std::iter::once((address, db_storage.into_iter().chain(post_state_storage).collect()));
assert_storage_cursor_order(&factory, expected);
@ -679,7 +692,8 @@ mod tests {
let sorted = hashed_post_state.into_sorted();
let tx = db.tx().unwrap();
let factory = HashedPostStateCursorFactory::new(&tx, &sorted);
let factory =
HashedPostStateCursorFactory::new(DatabaseHashedCursorFactory::new(&tx), &sorted);
let expected = std::iter::once((
address,
post_state_storage.into_iter().filter(|(_, value)| *value > U256::ZERO).collect(),
@ -716,7 +730,8 @@ mod tests {
let sorted = hashed_post_state.into_sorted();
let tx = db.tx().unwrap();
let factory = HashedPostStateCursorFactory::new(&tx, &sorted);
let factory =
HashedPostStateCursorFactory::new(DatabaseHashedCursorFactory::new(&tx), &sorted);
let expected = std::iter::once((address, post_state_storage));
assert_storage_cursor_order(&factory, expected);
}
@ -751,7 +766,8 @@ mod tests {
let sorted = hashed_post_state.into_sorted();
let tx = db.tx().unwrap();
let factory = HashedPostStateCursorFactory::new(&tx, &sorted);
let factory =
HashedPostStateCursorFactory::new(DatabaseHashedCursorFactory::new(&tx), &sorted);
let expected = std::iter::once((address, storage));
assert_storage_cursor_order(&factory, expected);
}
@ -798,7 +814,7 @@ mod tests {
let sorted = hashed_post_state.into_sorted();
let tx = db.tx().unwrap();
let factory = HashedPostStateCursorFactory::new(&tx, &sorted);
let factory = HashedPostStateCursorFactory::new(DatabaseHashedCursorFactory::new(&tx), &sorted);
assert_storage_cursor_order(&factory, expected.into_iter());
});
}

View File

@ -1,5 +1,5 @@
use crate::{
hashed_cursor::{HashedCursorFactory, HashedStorageCursor},
hashed_cursor::{DatabaseHashedCursorFactory, HashedCursorFactory, HashedStorageCursor},
node_iter::{TrieElement, TrieNodeIter},
prefix_set::TriePrefixSetsMut,
trie_cursor::{DatabaseAccountTrieCursor, DatabaseStorageTrieCursor},
@ -46,10 +46,10 @@ impl<'a, TX, H> Proof<'a, TX, H> {
}
}
impl<'a, TX> Proof<'a, TX, &'a TX> {
impl<'a, TX> Proof<'a, TX, DatabaseHashedCursorFactory<'a, TX>> {
/// Create a new [Proof] instance from database transaction.
pub fn from_tx(tx: &'a TX) -> Self {
Self::new(tx, tx)
Self::new(tx, DatabaseHashedCursorFactory::new(tx))
}
}

View File

@ -1,5 +1,5 @@
use crate::{
hashed_cursor::HashedPostStateCursorFactory,
hashed_cursor::{DatabaseHashedCursorFactory, HashedPostStateCursorFactory},
prefix_set::{PrefixSetMut, TriePrefixSetsMut},
proof::Proof,
Nibbles,
@ -203,8 +203,10 @@ impl HashedPostState {
) -> Result<AccountProof, StateRootError> {
let sorted = self.clone().into_sorted();
let prefix_sets = self.construct_prefix_sets();
let hashed_cursor_factory =
HashedPostStateCursorFactory::new(DatabaseHashedCursorFactory::new(tx), &sorted);
Proof::from_tx(tx)
.with_hashed_cursor_factory(HashedPostStateCursorFactory::new(tx, &sorted))
.with_hashed_cursor_factory(hashed_cursor_factory)
.with_prefix_sets_mut(prefix_sets)
.account_proof(address, slots)
}

View File

@ -1,5 +1,5 @@
use crate::{
hashed_cursor::{HashedCursorFactory, HashedStorageCursor},
hashed_cursor::{DatabaseHashedCursorFactory, HashedCursorFactory, HashedStorageCursor},
node_iter::{TrieElement, TrieNodeIter},
prefix_set::{PrefixSet, TriePrefixSets},
progress::{IntermediateStateRootState, StateRootProgress},
@ -363,12 +363,12 @@ impl<T, H> StorageRoot<T, H> {
}
}
impl<'a, TX: DbTx> StorageRoot<&'a TX, &'a TX> {
impl<'a, TX: DbTx> StorageRoot<&'a TX, DatabaseHashedCursorFactory<'a, TX>> {
/// Create a new storage root calculator from database transaction and raw address.
pub fn from_tx(tx: &'a TX, address: Address) -> Self {
Self::new(
tx,
tx,
DatabaseHashedCursorFactory::new(tx),
address,
#[cfg(feature = "metrics")]
TrieRootMetrics::new(TrieType::Storage),
@ -379,7 +379,7 @@ impl<'a, TX: DbTx> StorageRoot<&'a TX, &'a TX> {
pub fn from_tx_hashed(tx: &'a TX, hashed_address: B256) -> Self {
Self::new_hashed(
tx,
tx,
DatabaseHashedCursorFactory::new(tx),
hashed_address,
#[cfg(feature = "metrics")]
TrieRootMetrics::new(TrieType::Storage),