mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
feat(trie): trie cursor abstraction (#5643)
This commit is contained in:
@ -181,7 +181,7 @@ impl Command {
|
|||||||
let (account_prefix_set, storage_prefix_set) = hashed_post_state.construct_prefix_sets();
|
let (account_prefix_set, storage_prefix_set) = hashed_post_state.construct_prefix_sets();
|
||||||
let tx = provider.tx_ref();
|
let tx = provider.tx_ref();
|
||||||
let hashed_cursor_factory = HashedPostStateCursorFactory::new(tx, &hashed_post_state);
|
let hashed_cursor_factory = HashedPostStateCursorFactory::new(tx, &hashed_post_state);
|
||||||
let (in_memory_state_root, in_memory_updates) = StateRoot::new(tx)
|
let (in_memory_state_root, in_memory_updates) = StateRoot::from_tx(tx)
|
||||||
.with_hashed_cursor_factory(hashed_cursor_factory)
|
.with_hashed_cursor_factory(hashed_cursor_factory)
|
||||||
.with_changed_account_prefixes(account_prefix_set)
|
.with_changed_account_prefixes(account_prefix_set)
|
||||||
.with_changed_storage_prefixes(storage_prefix_set)
|
.with_changed_storage_prefixes(storage_prefix_set)
|
||||||
|
|||||||
@ -76,7 +76,7 @@ impl Command {
|
|||||||
entry = storage_trie_cursor.next()?;
|
entry = storage_trie_cursor.next()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let state_root = StateRoot::new(tx_mut).root()?;
|
let state_root = StateRoot::from_tx(tx_mut).root()?;
|
||||||
if state_root != best_header.state_root {
|
if state_root != best_header.state_root {
|
||||||
eyre::bail!(
|
eyre::bail!(
|
||||||
"Recovery failed. Incorrect state root. Expected: {:?}. Received: {:?}",
|
"Recovery failed. Incorrect state root. Expected: {:?}. Received: {:?}",
|
||||||
|
|||||||
@ -126,8 +126,9 @@ pub(crate) fn txs_testdata(num_blocks: u64) -> PathBuf {
|
|||||||
db.insert_accounts_and_storages(start_state.clone()).unwrap();
|
db.insert_accounts_and_storages(start_state.clone()).unwrap();
|
||||||
|
|
||||||
// make first block after genesis have valid state root
|
// make first block after genesis have valid state root
|
||||||
let (root, updates) =
|
let (root, updates) = StateRoot::from_tx(db.factory.provider_rw().unwrap().tx_ref())
|
||||||
StateRoot::new(db.factory.provider_rw().unwrap().tx_ref()).root_with_updates().unwrap();
|
.root_with_updates()
|
||||||
|
.unwrap();
|
||||||
let second_block = blocks.get_mut(1).unwrap();
|
let second_block = blocks.get_mut(1).unwrap();
|
||||||
let cloned_second = second_block.clone();
|
let cloned_second = second_block.clone();
|
||||||
let mut updated_header = cloned_second.header.unseal();
|
let mut updated_header = cloned_second.header.unseal();
|
||||||
@ -154,7 +155,7 @@ pub(crate) fn txs_testdata(num_blocks: u64) -> PathBuf {
|
|||||||
// make last block have valid state root
|
// make last block have valid state root
|
||||||
let root = {
|
let root = {
|
||||||
let tx_mut = db.factory.provider_rw().unwrap();
|
let tx_mut = db.factory.provider_rw().unwrap();
|
||||||
let root = StateRoot::new(tx_mut.tx_ref()).root().unwrap();
|
let root = StateRoot::from_tx(tx_mut.tx_ref()).root().unwrap();
|
||||||
tx_mut.commit().unwrap();
|
tx_mut.commit().unwrap();
|
||||||
root
|
root
|
||||||
};
|
};
|
||||||
|
|||||||
@ -191,7 +191,7 @@ impl<DB: Database> Stage<DB> for MerkleStage {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let tx = provider.tx_ref();
|
let tx = provider.tx_ref();
|
||||||
let progress = StateRoot::new(tx)
|
let progress = StateRoot::from_tx(tx)
|
||||||
.with_intermediate_state(checkpoint.map(IntermediateStateRootState::from))
|
.with_intermediate_state(checkpoint.map(IntermediateStateRootState::from))
|
||||||
.root_with_progress()
|
.root_with_progress()
|
||||||
.map_err(|e| StageError::Fatal(Box::new(e)))?;
|
.map_err(|e| StageError::Fatal(Box::new(e)))?;
|
||||||
|
|||||||
@ -159,10 +159,10 @@ impl BundleStateWithReceipts {
|
|||||||
&self,
|
&self,
|
||||||
tx: &'a TX,
|
tx: &'a TX,
|
||||||
hashed_post_state: &'b HashedPostState,
|
hashed_post_state: &'b HashedPostState,
|
||||||
) -> StateRoot<'a, TX, HashedPostStateCursorFactory<'a, 'b, TX>> {
|
) -> StateRoot<&'a TX, HashedPostStateCursorFactory<'a, 'b, TX>> {
|
||||||
let (account_prefix_set, storage_prefix_set) = hashed_post_state.construct_prefix_sets();
|
let (account_prefix_set, storage_prefix_set) = hashed_post_state.construct_prefix_sets();
|
||||||
let hashed_cursor_factory = HashedPostStateCursorFactory::new(tx, hashed_post_state);
|
let hashed_cursor_factory = HashedPostStateCursorFactory::new(tx, hashed_post_state);
|
||||||
StateRoot::new(tx)
|
StateRoot::from_tx(tx)
|
||||||
.with_hashed_cursor_factory(hashed_cursor_factory)
|
.with_hashed_cursor_factory(hashed_cursor_factory)
|
||||||
.with_changed_account_prefixes(account_prefix_set)
|
.with_changed_account_prefixes(account_prefix_set)
|
||||||
.with_changed_storage_prefixes(storage_prefix_set)
|
.with_changed_storage_prefixes(storage_prefix_set)
|
||||||
@ -1236,7 +1236,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let (_, updates) = StateRoot::new(tx).root_with_updates().unwrap();
|
let (_, updates) = StateRoot::from_tx(tx).root_with_updates().unwrap();
|
||||||
updates.flush(tx).unwrap();
|
updates.flush(tx).unwrap();
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|||||||
@ -2077,7 +2077,7 @@ impl<TX: DbTxMut + DbTx> HashingWriter for DatabaseProvider<TX> {
|
|||||||
{
|
{
|
||||||
// This is the same as `StateRoot::incremental_root_with_updates`, only the prefix sets
|
// This is the same as `StateRoot::incremental_root_with_updates`, only the prefix sets
|
||||||
// are pre-loaded.
|
// are pre-loaded.
|
||||||
let (state_root, trie_updates) = StateRoot::new(&self.tx)
|
let (state_root, trie_updates) = StateRoot::from_tx(&self.tx)
|
||||||
.with_changed_account_prefixes(account_prefix_set.freeze())
|
.with_changed_account_prefixes(account_prefix_set.freeze())
|
||||||
.with_changed_storage_prefixes(
|
.with_changed_storage_prefixes(
|
||||||
storage_prefix_set.into_iter().map(|(k, v)| (k, v.freeze())).collect(),
|
storage_prefix_set.into_iter().map(|(k, v)| (k, v.freeze())).collect(),
|
||||||
@ -2261,7 +2261,7 @@ impl<TX: DbTxMut + DbTx> BlockExecutionWriter for DatabaseProvider<TX> {
|
|||||||
// Calculate the reverted merkle root.
|
// Calculate the reverted merkle root.
|
||||||
// This is the same as `StateRoot::incremental_root_with_updates`, only the prefix sets
|
// This is the same as `StateRoot::incremental_root_with_updates`, only the prefix sets
|
||||||
// are pre-loaded.
|
// are pre-loaded.
|
||||||
let (new_state_root, trie_updates) = StateRoot::new(&self.tx)
|
let (new_state_root, trie_updates) = StateRoot::from_tx(&self.tx)
|
||||||
.with_changed_account_prefixes(account_prefix_set.freeze())
|
.with_changed_account_prefixes(account_prefix_set.freeze())
|
||||||
.with_changed_storage_prefixes(
|
.with_changed_storage_prefixes(
|
||||||
storage_prefix_set.into_iter().map(|(k, v)| (k, v.freeze())).collect(),
|
storage_prefix_set.into_iter().map(|(k, v)| (k, v.freeze())).collect(),
|
||||||
|
|||||||
@ -2,7 +2,7 @@ use crate::{
|
|||||||
hashed_cursor::{HashedCursorFactory, HashedStorageCursor},
|
hashed_cursor::{HashedCursorFactory, HashedStorageCursor},
|
||||||
node_iter::{AccountNode, AccountNodeIter, StorageNode, StorageNodeIter},
|
node_iter::{AccountNode, AccountNodeIter, StorageNode, StorageNodeIter},
|
||||||
prefix_set::PrefixSetMut,
|
prefix_set::PrefixSetMut,
|
||||||
trie_cursor::{AccountTrieCursor, StorageTrieCursor},
|
trie_cursor::{DatabaseAccountTrieCursor, DatabaseStorageTrieCursor},
|
||||||
walker::TrieWalker,
|
walker::TrieWalker,
|
||||||
StateRootError, StorageRootError,
|
StateRootError, StorageRootError,
|
||||||
};
|
};
|
||||||
@ -51,7 +51,8 @@ where
|
|||||||
let mut account_proof = AccountProof::new(address);
|
let mut account_proof = AccountProof::new(address);
|
||||||
|
|
||||||
let hashed_account_cursor = self.hashed_cursor_factory.hashed_account_cursor()?;
|
let hashed_account_cursor = self.hashed_cursor_factory.hashed_account_cursor()?;
|
||||||
let trie_cursor = AccountTrieCursor::new(self.tx.cursor_read::<tables::AccountsTrie>()?);
|
let trie_cursor =
|
||||||
|
DatabaseAccountTrieCursor::new(self.tx.cursor_read::<tables::AccountsTrie>()?);
|
||||||
|
|
||||||
// Create the walker.
|
// Create the walker.
|
||||||
let mut prefix_set = PrefixSetMut::default();
|
let mut prefix_set = PrefixSetMut::default();
|
||||||
@ -119,7 +120,7 @@ where
|
|||||||
|
|
||||||
let target_nibbles = proofs.iter().map(|p| p.nibbles.clone()).collect::<Vec<_>>();
|
let target_nibbles = proofs.iter().map(|p| p.nibbles.clone()).collect::<Vec<_>>();
|
||||||
let prefix_set = PrefixSetMut::from(target_nibbles.clone()).freeze();
|
let prefix_set = PrefixSetMut::from(target_nibbles.clone()).freeze();
|
||||||
let trie_cursor = StorageTrieCursor::new(
|
let trie_cursor = DatabaseStorageTrieCursor::new(
|
||||||
self.tx.cursor_dup_read::<tables::StoragesTrie>()?,
|
self.tx.cursor_dup_read::<tables::StoragesTrie>()?,
|
||||||
hashed_address,
|
hashed_address,
|
||||||
);
|
);
|
||||||
@ -221,7 +222,7 @@ mod tests {
|
|||||||
});
|
});
|
||||||
provider.insert_storage_for_hashing(alloc_storage)?;
|
provider.insert_storage_for_hashing(alloc_storage)?;
|
||||||
|
|
||||||
let (_, updates) = StateRoot::new(provider.tx_ref())
|
let (_, updates) = StateRoot::from_tx(provider.tx_ref())
|
||||||
.root_with_updates()
|
.root_with_updates()
|
||||||
.map_err(Into::<reth_db::DatabaseError>::into)?;
|
.map_err(Into::<reth_db::DatabaseError>::into)?;
|
||||||
updates.flush(provider.tx_mut())?;
|
updates.flush(provider.tx_mut())?;
|
||||||
|
|||||||
@ -3,13 +3,13 @@ use crate::{
|
|||||||
node_iter::{AccountNode, AccountNodeIter, StorageNode, StorageNodeIter},
|
node_iter::{AccountNode, AccountNodeIter, StorageNode, StorageNodeIter},
|
||||||
prefix_set::{PrefixSet, PrefixSetLoader, PrefixSetMut},
|
prefix_set::{PrefixSet, PrefixSetLoader, PrefixSetMut},
|
||||||
progress::{IntermediateStateRootState, StateRootProgress},
|
progress::{IntermediateStateRootState, StateRootProgress},
|
||||||
trie_cursor::{AccountTrieCursor, StorageTrieCursor},
|
trie_cursor::TrieCursorFactory,
|
||||||
updates::{TrieKey, TrieOp, TrieUpdates},
|
updates::{TrieKey, TrieOp, TrieUpdates},
|
||||||
walker::TrieWalker,
|
walker::TrieWalker,
|
||||||
StateRootError, StorageRootError,
|
StateRootError, StorageRootError,
|
||||||
};
|
};
|
||||||
use alloy_rlp::{BufMut, Encodable};
|
use alloy_rlp::{BufMut, Encodable};
|
||||||
use reth_db::{tables, transaction::DbTx};
|
use reth_db::transaction::DbTx;
|
||||||
use reth_primitives::{
|
use reth_primitives::{
|
||||||
constants::EMPTY_ROOT_HASH,
|
constants::EMPTY_ROOT_HASH,
|
||||||
keccak256,
|
keccak256,
|
||||||
@ -24,9 +24,9 @@ use tracing::{debug, trace};
|
|||||||
|
|
||||||
/// StateRoot is used to compute the root node of a state trie.
|
/// StateRoot is used to compute the root node of a state trie.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct StateRoot<'a, TX, H> {
|
pub struct StateRoot<T, H> {
|
||||||
/// A reference to the database transaction.
|
/// The factory for trie cursors.
|
||||||
pub tx: &'a TX,
|
pub trie_cursor_factory: T,
|
||||||
/// The factory for hashed cursors.
|
/// The factory for hashed cursors.
|
||||||
pub hashed_cursor_factory: H,
|
pub hashed_cursor_factory: H,
|
||||||
/// A set of account prefixes that have changed.
|
/// A set of account prefixes that have changed.
|
||||||
@ -42,7 +42,7 @@ pub struct StateRoot<'a, TX, H> {
|
|||||||
threshold: u64,
|
threshold: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, TX, H> StateRoot<'a, TX, H> {
|
impl<T, H> StateRoot<T, H> {
|
||||||
/// Set the changed account prefixes.
|
/// Set the changed account prefixes.
|
||||||
pub fn with_changed_account_prefixes(mut self, prefixes: PrefixSet) -> Self {
|
pub fn with_changed_account_prefixes(mut self, prefixes: PrefixSet) -> Self {
|
||||||
self.changed_account_prefixes = prefixes;
|
self.changed_account_prefixes = prefixes;
|
||||||
@ -80,33 +80,43 @@ impl<'a, TX, H> StateRoot<'a, TX, H> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Set the hashed cursor factory.
|
/// Set the hashed cursor factory.
|
||||||
pub fn with_hashed_cursor_factory<HF>(
|
pub fn with_hashed_cursor_factory<HF>(self, hashed_cursor_factory: HF) -> StateRoot<T, HF> {
|
||||||
self,
|
|
||||||
hashed_cursor_factory: HF,
|
|
||||||
) -> StateRoot<'a, TX, HF> {
|
|
||||||
StateRoot {
|
StateRoot {
|
||||||
tx: self.tx,
|
trie_cursor_factory: self.trie_cursor_factory,
|
||||||
|
hashed_cursor_factory,
|
||||||
|
changed_account_prefixes: self.changed_account_prefixes,
|
||||||
|
changed_storage_prefixes: self.changed_storage_prefixes,
|
||||||
|
destroyed_accounts: self.destroyed_accounts,
|
||||||
|
threshold: self.threshold,
|
||||||
|
previous_state: self.previous_state,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the trie cursor factory.
|
||||||
|
pub fn with_trie_cursor_factory<TF>(self, trie_cursor_factory: TF) -> StateRoot<TF, H> {
|
||||||
|
StateRoot {
|
||||||
|
trie_cursor_factory,
|
||||||
|
hashed_cursor_factory: self.hashed_cursor_factory,
|
||||||
changed_account_prefixes: self.changed_account_prefixes,
|
changed_account_prefixes: self.changed_account_prefixes,
|
||||||
changed_storage_prefixes: self.changed_storage_prefixes,
|
changed_storage_prefixes: self.changed_storage_prefixes,
|
||||||
destroyed_accounts: self.destroyed_accounts,
|
destroyed_accounts: self.destroyed_accounts,
|
||||||
threshold: self.threshold,
|
threshold: self.threshold,
|
||||||
previous_state: self.previous_state,
|
previous_state: self.previous_state,
|
||||||
hashed_cursor_factory,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, TX: DbTx> StateRoot<'a, TX, &'a TX> {
|
impl<'a, TX: DbTx> StateRoot<&'a TX, &'a TX> {
|
||||||
/// Create a new [StateRoot] instance.
|
/// Create a new [StateRoot] instance.
|
||||||
pub fn new(tx: &'a TX) -> Self {
|
pub fn from_tx(tx: &'a TX) -> Self {
|
||||||
Self {
|
Self {
|
||||||
tx,
|
trie_cursor_factory: tx,
|
||||||
|
hashed_cursor_factory: tx,
|
||||||
changed_account_prefixes: PrefixSetMut::default().freeze(),
|
changed_account_prefixes: PrefixSetMut::default().freeze(),
|
||||||
changed_storage_prefixes: HashMap::default(),
|
changed_storage_prefixes: HashMap::default(),
|
||||||
destroyed_accounts: HashSet::default(),
|
destroyed_accounts: HashSet::default(),
|
||||||
previous_state: None,
|
previous_state: None,
|
||||||
threshold: 100_000,
|
threshold: 100_000,
|
||||||
hashed_cursor_factory: tx,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,7 +131,7 @@ impl<'a, TX: DbTx> StateRoot<'a, TX, &'a TX> {
|
|||||||
range: RangeInclusive<BlockNumber>,
|
range: RangeInclusive<BlockNumber>,
|
||||||
) -> Result<Self, StateRootError> {
|
) -> Result<Self, StateRootError> {
|
||||||
let loaded_prefix_sets = PrefixSetLoader::new(tx).load(range)?;
|
let loaded_prefix_sets = PrefixSetLoader::new(tx).load(range)?;
|
||||||
Ok(Self::new(tx)
|
Ok(Self::from_tx(tx)
|
||||||
.with_changed_account_prefixes(loaded_prefix_sets.account_prefix_set.freeze())
|
.with_changed_account_prefixes(loaded_prefix_sets.account_prefix_set.freeze())
|
||||||
.with_changed_storage_prefixes(
|
.with_changed_storage_prefixes(
|
||||||
loaded_prefix_sets
|
loaded_prefix_sets
|
||||||
@ -178,9 +188,9 @@ impl<'a, TX: DbTx> StateRoot<'a, TX, &'a TX> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, TX, H> StateRoot<'a, TX, H>
|
impl<T, H> StateRoot<T, H>
|
||||||
where
|
where
|
||||||
TX: DbTx,
|
T: TrieCursorFactory + Clone,
|
||||||
H: HashedCursorFactory + Clone,
|
H: HashedCursorFactory + Clone,
|
||||||
{
|
{
|
||||||
/// Walks the intermediate nodes of existing state trie (if any) and hashed entries. Feeds the
|
/// Walks the intermediate nodes of existing state trie (if any) and hashed entries. Feeds the
|
||||||
@ -226,7 +236,7 @@ where
|
|||||||
let mut trie_updates = TrieUpdates::default();
|
let mut trie_updates = TrieUpdates::default();
|
||||||
|
|
||||||
let hashed_account_cursor = self.hashed_cursor_factory.hashed_account_cursor()?;
|
let hashed_account_cursor = self.hashed_cursor_factory.hashed_account_cursor()?;
|
||||||
let trie_cursor = AccountTrieCursor::new(self.tx.cursor_read::<tables::AccountsTrie>()?);
|
let trie_cursor = self.trie_cursor_factory.account_trie_cursor()?;
|
||||||
|
|
||||||
let (mut hash_builder, mut account_node_iter) = match self.previous_state {
|
let (mut hash_builder, mut account_node_iter) = match self.previous_state {
|
||||||
Some(state) => {
|
Some(state) => {
|
||||||
@ -267,14 +277,17 @@ where
|
|||||||
// progress.
|
// progress.
|
||||||
// TODO: We can consider introducing the TrieProgress::Progress/Complete
|
// TODO: We can consider introducing the TrieProgress::Progress/Complete
|
||||||
// abstraction inside StorageRoot, but let's give it a try as-is for now.
|
// abstraction inside StorageRoot, but let's give it a try as-is for now.
|
||||||
let storage_root_calculator = StorageRoot::new_hashed(self.tx, hashed_address)
|
let storage_root_calculator = StorageRoot::new_hashed(
|
||||||
.with_hashed_cursor_factory(self.hashed_cursor_factory.clone())
|
self.trie_cursor_factory.clone(),
|
||||||
.with_changed_prefixes(
|
self.hashed_cursor_factory.clone(),
|
||||||
self.changed_storage_prefixes
|
hashed_address,
|
||||||
.get(&hashed_address)
|
)
|
||||||
.cloned()
|
.with_changed_prefixes(
|
||||||
.unwrap_or_default(),
|
self.changed_storage_prefixes
|
||||||
);
|
.get(&hashed_address)
|
||||||
|
.cloned()
|
||||||
|
.unwrap_or_default(),
|
||||||
|
);
|
||||||
|
|
||||||
let storage_root = if retain_updates {
|
let storage_root = if retain_updates {
|
||||||
let (root, storage_slots_walked, updates) =
|
let (root, storage_slots_walked, updates) =
|
||||||
@ -336,9 +349,9 @@ where
|
|||||||
|
|
||||||
/// StorageRoot is used to compute the root node of an account storage trie.
|
/// StorageRoot is used to compute the root node of an account storage trie.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct StorageRoot<'a, TX, H> {
|
pub struct StorageRoot<T, H> {
|
||||||
/// A reference to the database transaction.
|
/// A reference to the database transaction.
|
||||||
pub tx: &'a TX,
|
pub trie_cursor_factory: T,
|
||||||
/// The factory for hashed cursors.
|
/// The factory for hashed cursors.
|
||||||
pub hashed_cursor_factory: H,
|
pub hashed_cursor_factory: H,
|
||||||
/// The hashed address of an account.
|
/// The hashed address of an account.
|
||||||
@ -347,40 +360,23 @@ pub struct StorageRoot<'a, TX, H> {
|
|||||||
pub changed_prefixes: PrefixSet,
|
pub changed_prefixes: PrefixSet,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, TX: DbTx> StorageRoot<'a, TX, &'a TX> {
|
impl<T, H> StorageRoot<T, H> {
|
||||||
/// Creates a new storage root calculator given an raw address.
|
/// Creates a new storage root calculator given a raw address.
|
||||||
pub fn new(tx: &'a TX, address: Address) -> Self {
|
pub fn new(trie_cursor_factory: T, hashed_cursor_factory: H, address: Address) -> Self {
|
||||||
Self::new_hashed(tx, keccak256(address))
|
Self::new_hashed(trie_cursor_factory, hashed_cursor_factory, keccak256(address))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new storage root calculator given a hashed address.
|
/// Creates a new storage root calculator given a hashed address.
|
||||||
pub fn new_hashed(tx: &'a TX, hashed_address: B256) -> Self {
|
pub fn new_hashed(
|
||||||
Self {
|
trie_cursor_factory: T,
|
||||||
tx,
|
|
||||||
hashed_address,
|
|
||||||
changed_prefixes: PrefixSetMut::default().freeze(),
|
|
||||||
hashed_cursor_factory: tx,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, TX, H> StorageRoot<'a, TX, H> {
|
|
||||||
/// Creates a new storage root calculator given an raw address.
|
|
||||||
pub fn new_with_factory(tx: &'a TX, hashed_cursor_factory: H, address: Address) -> Self {
|
|
||||||
Self::new_hashed_with_factory(tx, hashed_cursor_factory, keccak256(address))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a new storage root calculator given a hashed address.
|
|
||||||
pub fn new_hashed_with_factory(
|
|
||||||
tx: &'a TX,
|
|
||||||
hashed_cursor_factory: H,
|
hashed_cursor_factory: H,
|
||||||
hashed_address: B256,
|
hashed_address: B256,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
tx,
|
trie_cursor_factory,
|
||||||
|
hashed_cursor_factory,
|
||||||
hashed_address,
|
hashed_address,
|
||||||
changed_prefixes: PrefixSetMut::default().freeze(),
|
changed_prefixes: PrefixSetMut::default().freeze(),
|
||||||
hashed_cursor_factory,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -391,22 +387,41 @@ impl<'a, TX, H> StorageRoot<'a, TX, H> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Set the hashed cursor factory.
|
/// Set the hashed cursor factory.
|
||||||
pub fn with_hashed_cursor_factory<HF>(
|
pub fn with_hashed_cursor_factory<HF>(self, hashed_cursor_factory: HF) -> StorageRoot<T, HF> {
|
||||||
self,
|
|
||||||
hashed_cursor_factory: HF,
|
|
||||||
) -> StorageRoot<'a, TX, HF> {
|
|
||||||
StorageRoot {
|
StorageRoot {
|
||||||
tx: self.tx,
|
trie_cursor_factory: self.trie_cursor_factory,
|
||||||
|
hashed_cursor_factory,
|
||||||
|
hashed_address: self.hashed_address,
|
||||||
|
changed_prefixes: self.changed_prefixes,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the trie cursor factory.
|
||||||
|
pub fn with_trie_cursor_factory<TF>(self, trie_cursor_factory: TF) -> StorageRoot<TF, H> {
|
||||||
|
StorageRoot {
|
||||||
|
trie_cursor_factory,
|
||||||
|
hashed_cursor_factory: self.hashed_cursor_factory,
|
||||||
hashed_address: self.hashed_address,
|
hashed_address: self.hashed_address,
|
||||||
changed_prefixes: self.changed_prefixes,
|
changed_prefixes: self.changed_prefixes,
|
||||||
hashed_cursor_factory,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, TX, H> StorageRoot<'a, TX, H>
|
impl<'a, TX: DbTx> StorageRoot<&'a TX, &'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, address)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new storage root calculator from database transaction and hashed address.
|
||||||
|
pub fn from_tx_hashed(tx: &'a TX, hashed_address: B256) -> Self {
|
||||||
|
Self::new_hashed(tx, tx, hashed_address)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, H> StorageRoot<T, H>
|
||||||
where
|
where
|
||||||
TX: DbTx,
|
T: TrieCursorFactory,
|
||||||
H: HashedCursorFactory,
|
H: HashedCursorFactory,
|
||||||
{
|
{
|
||||||
/// Walks the hashed storage table entries for a given address and calculates the storage root.
|
/// Walks the hashed storage table entries for a given address and calculates the storage root.
|
||||||
@ -444,10 +459,7 @@ where
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
let trie_cursor = StorageTrieCursor::new(
|
let trie_cursor = self.trie_cursor_factory.storage_tries_cursor(self.hashed_address)?;
|
||||||
self.tx.cursor_dup_read::<tables::StoragesTrie>()?,
|
|
||||||
self.hashed_address,
|
|
||||||
);
|
|
||||||
let walker = TrieWalker::new(trie_cursor, self.changed_prefixes.clone())
|
let walker = TrieWalker::new(trie_cursor, self.changed_prefixes.clone())
|
||||||
.with_updates(retain_updates);
|
.with_updates(retain_updates);
|
||||||
|
|
||||||
@ -545,7 +557,7 @@ mod tests {
|
|||||||
|
|
||||||
// Generate the intermediate nodes on the receiving end of the channel
|
// Generate the intermediate nodes on the receiving end of the channel
|
||||||
let (_, _, trie_updates) =
|
let (_, _, trie_updates) =
|
||||||
StorageRoot::new_hashed(tx.tx_ref(), hashed_address).root_with_updates().unwrap();
|
StorageRoot::from_tx_hashed(tx.tx_ref(), hashed_address).root_with_updates().unwrap();
|
||||||
|
|
||||||
// 1. Some state transition happens, update the hashed storage to the new value
|
// 1. Some state transition happens, update the hashed storage to the new value
|
||||||
let modified_key = B256::from_str(modified).unwrap();
|
let modified_key = B256::from_str(modified).unwrap();
|
||||||
@ -559,7 +571,7 @@ mod tests {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// 2. Calculate full merkle root
|
// 2. Calculate full merkle root
|
||||||
let loader = StorageRoot::new_hashed(tx.tx_ref(), hashed_address);
|
let loader = StorageRoot::from_tx_hashed(tx.tx_ref(), hashed_address);
|
||||||
let modified_root = loader.root().unwrap();
|
let modified_root = loader.root().unwrap();
|
||||||
|
|
||||||
// Update the intermediate roots table so that we can run the incremental verification
|
// Update the intermediate roots table so that we can run the incremental verification
|
||||||
@ -568,7 +580,7 @@ mod tests {
|
|||||||
// 3. Calculate the incremental root
|
// 3. Calculate the incremental root
|
||||||
let mut storage_changes = PrefixSetMut::default();
|
let mut storage_changes = PrefixSetMut::default();
|
||||||
storage_changes.insert(Nibbles::unpack(modified_key));
|
storage_changes.insert(Nibbles::unpack(modified_key));
|
||||||
let loader = StorageRoot::new_hashed(tx.tx_ref(), hashed_address)
|
let loader = StorageRoot::from_tx_hashed(tx.tx_ref(), hashed_address)
|
||||||
.with_changed_prefixes(storage_changes.freeze());
|
.with_changed_prefixes(storage_changes.freeze());
|
||||||
let incremental_root = loader.root().unwrap();
|
let incremental_root = loader.root().unwrap();
|
||||||
|
|
||||||
@ -608,7 +620,7 @@ mod tests {
|
|||||||
tx.commit().unwrap();
|
tx.commit().unwrap();
|
||||||
|
|
||||||
let tx = factory.provider_rw().unwrap();
|
let tx = factory.provider_rw().unwrap();
|
||||||
let got = StorageRoot::new(tx.tx_ref(), address).root().unwrap();
|
let got = StorageRoot::from_tx(tx.tx_ref(), address).root().unwrap();
|
||||||
let expected = storage_root(storage.into_iter());
|
let expected = storage_root(storage.into_iter());
|
||||||
assert_eq!(expected, got);
|
assert_eq!(expected, got);
|
||||||
});
|
});
|
||||||
@ -667,7 +679,7 @@ mod tests {
|
|||||||
tx.commit().unwrap();
|
tx.commit().unwrap();
|
||||||
|
|
||||||
let tx = factory.provider_rw().unwrap();
|
let tx = factory.provider_rw().unwrap();
|
||||||
let got = StorageRoot::new(tx.tx_ref(), address).root().unwrap();
|
let got = StorageRoot::from_tx(tx.tx_ref(), address).root().unwrap();
|
||||||
assert_eq!(got, EMPTY_ROOT_HASH);
|
assert_eq!(got, EMPTY_ROOT_HASH);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -692,7 +704,7 @@ mod tests {
|
|||||||
tx.commit().unwrap();
|
tx.commit().unwrap();
|
||||||
|
|
||||||
let tx = factory.provider_rw().unwrap();
|
let tx = factory.provider_rw().unwrap();
|
||||||
let got = StorageRoot::new(tx.tx_ref(), address).root().unwrap();
|
let got = StorageRoot::from_tx(tx.tx_ref(), address).root().unwrap();
|
||||||
|
|
||||||
assert_eq!(storage_root(storage.into_iter()), got);
|
assert_eq!(storage_root(storage.into_iter()), got);
|
||||||
}
|
}
|
||||||
@ -732,7 +744,7 @@ mod tests {
|
|||||||
|
|
||||||
let mut intermediate_state: Option<Box<IntermediateStateRootState>> = None;
|
let mut intermediate_state: Option<Box<IntermediateStateRootState>> = None;
|
||||||
while got.is_none() {
|
while got.is_none() {
|
||||||
let calculator = StateRoot::new(tx.tx_ref())
|
let calculator = StateRoot::from_tx(tx.tx_ref())
|
||||||
.with_threshold(threshold)
|
.with_threshold(threshold)
|
||||||
.with_intermediate_state(intermediate_state.take().map(|state| *state));
|
.with_intermediate_state(intermediate_state.take().map(|state| *state));
|
||||||
match calculator.root_with_progress().unwrap() {
|
match calculator.root_with_progress().unwrap() {
|
||||||
@ -763,7 +775,7 @@ mod tests {
|
|||||||
let expected = state_root(state.into_iter());
|
let expected = state_root(state.into_iter());
|
||||||
|
|
||||||
let tx = factory.provider_rw().unwrap();
|
let tx = factory.provider_rw().unwrap();
|
||||||
let got = StateRoot::new(tx.tx_ref()).root().unwrap();
|
let got = StateRoot::from_tx(tx.tx_ref()).root().unwrap();
|
||||||
assert_eq!(expected, got);
|
assert_eq!(expected, got);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -802,7 +814,7 @@ mod tests {
|
|||||||
tx.commit().unwrap();
|
tx.commit().unwrap();
|
||||||
let tx = factory.provider_rw().unwrap();
|
let tx = factory.provider_rw().unwrap();
|
||||||
|
|
||||||
let account3_storage_root = StorageRoot::new(tx.tx_ref(), address3).root().unwrap();
|
let account3_storage_root = StorageRoot::from_tx(tx.tx_ref(), address3).root().unwrap();
|
||||||
let expected_root = storage_root_prehashed(storage.into_iter());
|
let expected_root = storage_root_prehashed(storage.into_iter());
|
||||||
assert_eq!(expected_root, account3_storage_root);
|
assert_eq!(expected_root, account3_storage_root);
|
||||||
}
|
}
|
||||||
@ -869,7 +881,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
hashed_storage_cursor.upsert(key3, StorageEntry { key: hashed_slot, value }).unwrap();
|
hashed_storage_cursor.upsert(key3, StorageEntry { key: hashed_slot, value }).unwrap();
|
||||||
}
|
}
|
||||||
let account3_storage_root = StorageRoot::new(tx.tx_ref(), address3).root().unwrap();
|
let account3_storage_root = StorageRoot::from_tx(tx.tx_ref(), address3).root().unwrap();
|
||||||
hash_builder.add_leaf(
|
hash_builder.add_leaf(
|
||||||
Nibbles::unpack(key3),
|
Nibbles::unpack(key3),
|
||||||
&encode_account(account3, Some(account3_storage_root)),
|
&encode_account(account3, Some(account3_storage_root)),
|
||||||
@ -918,7 +930,7 @@ mod tests {
|
|||||||
assert_eq!(hash_builder.root(), computed_expected_root);
|
assert_eq!(hash_builder.root(), computed_expected_root);
|
||||||
|
|
||||||
// Check state root calculation from scratch
|
// Check state root calculation from scratch
|
||||||
let (root, trie_updates) = StateRoot::new(tx.tx_ref()).root_with_updates().unwrap();
|
let (root, trie_updates) = StateRoot::from_tx(tx.tx_ref()).root_with_updates().unwrap();
|
||||||
assert_eq!(root, computed_expected_root);
|
assert_eq!(root, computed_expected_root);
|
||||||
|
|
||||||
// Check account trie
|
// Check account trie
|
||||||
@ -983,7 +995,7 @@ mod tests {
|
|||||||
B256::from_str("8e263cd4eefb0c3cbbb14e5541a66a755cad25bcfab1e10dd9d706263e811b28")
|
B256::from_str("8e263cd4eefb0c3cbbb14e5541a66a755cad25bcfab1e10dd9d706263e811b28")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let (root, trie_updates) = StateRoot::new(tx.tx_ref())
|
let (root, trie_updates) = StateRoot::from_tx(tx.tx_ref())
|
||||||
.with_changed_account_prefixes(prefix_set.freeze())
|
.with_changed_account_prefixes(prefix_set.freeze())
|
||||||
.root_with_updates()
|
.root_with_updates()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -1035,7 +1047,7 @@ mod tests {
|
|||||||
(key6, encode_account(account6, None)),
|
(key6, encode_account(account6, None)),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
let (root, trie_updates) = StateRoot::new(tx.tx_ref())
|
let (root, trie_updates) = StateRoot::from_tx(tx.tx_ref())
|
||||||
.with_changed_account_prefixes(account_prefix_set.freeze())
|
.with_changed_account_prefixes(account_prefix_set.freeze())
|
||||||
.root_with_updates()
|
.root_with_updates()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -1092,7 +1104,7 @@ mod tests {
|
|||||||
(key6, encode_account(account6, None)),
|
(key6, encode_account(account6, None)),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
let (root, trie_updates) = StateRoot::new(tx.tx_ref())
|
let (root, trie_updates) = StateRoot::from_tx(tx.tx_ref())
|
||||||
.with_changed_account_prefixes(account_prefix_set.freeze())
|
.with_changed_account_prefixes(account_prefix_set.freeze())
|
||||||
.root_with_updates()
|
.root_with_updates()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -1131,7 +1143,7 @@ mod tests {
|
|||||||
|
|
||||||
let expected = extension_node_trie(&tx);
|
let expected = extension_node_trie(&tx);
|
||||||
|
|
||||||
let (got, updates) = StateRoot::new(tx.tx_ref()).root_with_updates().unwrap();
|
let (got, updates) = StateRoot::from_tx(tx.tx_ref()).root_with_updates().unwrap();
|
||||||
assert_eq!(expected, got);
|
assert_eq!(expected, got);
|
||||||
|
|
||||||
// Check account trie
|
// Check account trie
|
||||||
@ -1156,7 +1168,7 @@ mod tests {
|
|||||||
|
|
||||||
let expected = extension_node_trie(&tx);
|
let expected = extension_node_trie(&tx);
|
||||||
|
|
||||||
let (got, updates) = StateRoot::new(tx.tx_ref()).root_with_updates().unwrap();
|
let (got, updates) = StateRoot::from_tx(tx.tx_ref()).root_with_updates().unwrap();
|
||||||
assert_eq!(expected, got);
|
assert_eq!(expected, got);
|
||||||
updates.flush(tx.tx_ref()).unwrap();
|
updates.flush(tx.tx_ref()).unwrap();
|
||||||
|
|
||||||
@ -1195,7 +1207,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let (state_root, trie_updates) = StateRoot::new(tx.tx_ref())
|
let (state_root, trie_updates) = StateRoot::from_tx(tx.tx_ref())
|
||||||
.with_changed_account_prefixes(changes.freeze())
|
.with_changed_account_prefixes(changes.freeze())
|
||||||
.root_with_updates()
|
.root_with_updates()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -1220,7 +1232,7 @@ mod tests {
|
|||||||
let (expected_root, expected_updates) = extension_node_storage_trie(&tx, hashed_address);
|
let (expected_root, expected_updates) = extension_node_storage_trie(&tx, hashed_address);
|
||||||
|
|
||||||
let (got, _, updates) =
|
let (got, _, updates) =
|
||||||
StorageRoot::new_hashed(tx.tx_ref(), hashed_address).root_with_updates().unwrap();
|
StorageRoot::from_tx_hashed(tx.tx_ref(), hashed_address).root_with_updates().unwrap();
|
||||||
assert_eq!(expected_root, got);
|
assert_eq!(expected_root, got);
|
||||||
|
|
||||||
// Check account trie
|
// Check account trie
|
||||||
|
|||||||
@ -1,92 +0,0 @@
|
|||||||
use super::TrieCursor;
|
|
||||||
use crate::updates::TrieKey;
|
|
||||||
use reth_db::{cursor::DbCursorRO, tables, DatabaseError};
|
|
||||||
use reth_primitives::trie::{BranchNodeCompact, StoredNibbles};
|
|
||||||
|
|
||||||
/// A cursor over the account trie.
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct AccountTrieCursor<C>(C);
|
|
||||||
|
|
||||||
impl<C> AccountTrieCursor<C> {
|
|
||||||
/// Create a new account trie cursor.
|
|
||||||
pub fn new(cursor: C) -> Self {
|
|
||||||
Self(cursor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<C> TrieCursor for AccountTrieCursor<C>
|
|
||||||
where
|
|
||||||
C: DbCursorRO<tables::AccountsTrie>,
|
|
||||||
{
|
|
||||||
type Key = StoredNibbles;
|
|
||||||
|
|
||||||
fn seek_exact(
|
|
||||||
&mut self,
|
|
||||||
key: Self::Key,
|
|
||||||
) -> Result<Option<(Vec<u8>, BranchNodeCompact)>, DatabaseError> {
|
|
||||||
Ok(self.0.seek_exact(key)?.map(|value| (value.0 .0.to_vec(), value.1)))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn seek(
|
|
||||||
&mut self,
|
|
||||||
key: Self::Key,
|
|
||||||
) -> Result<Option<(Vec<u8>, BranchNodeCompact)>, DatabaseError> {
|
|
||||||
Ok(self.0.seek(key)?.map(|value| (value.0 .0.to_vec(), value.1)))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn current(&mut self) -> Result<Option<TrieKey>, DatabaseError> {
|
|
||||||
Ok(self.0.current()?.map(|(k, _)| TrieKey::AccountNode(k)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
use reth_db::{
|
|
||||||
cursor::{DbCursorRO, DbCursorRW},
|
|
||||||
tables,
|
|
||||||
transaction::DbTxMut,
|
|
||||||
};
|
|
||||||
use reth_primitives::hex_literal::hex;
|
|
||||||
use reth_provider::test_utils::create_test_provider_factory;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_account_trie_order() {
|
|
||||||
let factory = create_test_provider_factory();
|
|
||||||
let provider = factory.provider_rw().unwrap();
|
|
||||||
let mut cursor = provider.tx_ref().cursor_write::<tables::AccountsTrie>().unwrap();
|
|
||||||
|
|
||||||
let data = vec![
|
|
||||||
hex!("0303040e").to_vec(),
|
|
||||||
hex!("030305").to_vec(),
|
|
||||||
hex!("03030500").to_vec(),
|
|
||||||
hex!("0303050a").to_vec(),
|
|
||||||
];
|
|
||||||
|
|
||||||
for key in data.clone() {
|
|
||||||
cursor
|
|
||||||
.upsert(
|
|
||||||
key.into(),
|
|
||||||
BranchNodeCompact::new(
|
|
||||||
0b0000_0010_0000_0001,
|
|
||||||
0b0000_0010_0000_0001,
|
|
||||||
0,
|
|
||||||
Vec::default(),
|
|
||||||
None,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
let db_data = cursor.walk_range(..).unwrap().collect::<Result<Vec<_>, _>>().unwrap();
|
|
||||||
assert_eq!(db_data[0].0 .0.to_vec(), data[0]);
|
|
||||||
assert_eq!(db_data[1].0 .0.to_vec(), data[1]);
|
|
||||||
assert_eq!(db_data[2].0 .0.to_vec(), data[2]);
|
|
||||||
assert_eq!(db_data[3].0 .0.to_vec(), data[3]);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
cursor.seek(hex!("0303040f").to_vec().into()).unwrap().map(|(k, _)| k.0.to_vec()),
|
|
||||||
Some(data[1].clone())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
191
crates/trie/src/trie_cursor/database_cursors.rs
Normal file
191
crates/trie/src/trie_cursor/database_cursors.rs
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
use super::{TrieCursor, TrieCursorFactory};
|
||||||
|
use crate::updates::TrieKey;
|
||||||
|
use reth_db::{
|
||||||
|
cursor::{DbCursorRO, DbDupCursorRO},
|
||||||
|
tables,
|
||||||
|
transaction::DbTx,
|
||||||
|
DatabaseError,
|
||||||
|
};
|
||||||
|
use reth_primitives::{
|
||||||
|
trie::{BranchNodeCompact, StoredNibbles, StoredNibblesSubKey},
|
||||||
|
B256,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Implementation of the trie cursor factory for a database transaction.
|
||||||
|
impl<'a, TX: DbTx> TrieCursorFactory for &'a TX {
|
||||||
|
fn account_trie_cursor(
|
||||||
|
&self,
|
||||||
|
) -> Result<Box<dyn TrieCursor<Key = StoredNibbles> + '_>, DatabaseError> {
|
||||||
|
Ok(Box::new(DatabaseAccountTrieCursor::new(self.cursor_read::<tables::AccountsTrie>()?)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn storage_tries_cursor(
|
||||||
|
&self,
|
||||||
|
hashed_address: B256,
|
||||||
|
) -> Result<Box<dyn TrieCursor<Key = StoredNibblesSubKey> + '_>, DatabaseError> {
|
||||||
|
Ok(Box::new(DatabaseStorageTrieCursor::new(
|
||||||
|
self.cursor_dup_read::<tables::StoragesTrie>()?,
|
||||||
|
hashed_address,
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A cursor over the account trie.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct DatabaseAccountTrieCursor<C>(C);
|
||||||
|
|
||||||
|
impl<C> DatabaseAccountTrieCursor<C> {
|
||||||
|
/// Create a new account trie cursor.
|
||||||
|
pub fn new(cursor: C) -> Self {
|
||||||
|
Self(cursor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C> TrieCursor for DatabaseAccountTrieCursor<C>
|
||||||
|
where
|
||||||
|
C: DbCursorRO<tables::AccountsTrie>,
|
||||||
|
{
|
||||||
|
type Key = StoredNibbles;
|
||||||
|
|
||||||
|
fn seek_exact(
|
||||||
|
&mut self,
|
||||||
|
key: Self::Key,
|
||||||
|
) -> Result<Option<(Vec<u8>, BranchNodeCompact)>, DatabaseError> {
|
||||||
|
Ok(self.0.seek_exact(key)?.map(|value| (value.0 .0.to_vec(), value.1)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn seek(
|
||||||
|
&mut self,
|
||||||
|
key: Self::Key,
|
||||||
|
) -> Result<Option<(Vec<u8>, BranchNodeCompact)>, DatabaseError> {
|
||||||
|
Ok(self.0.seek(key)?.map(|value| (value.0 .0.to_vec(), value.1)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn current(&mut self) -> Result<Option<TrieKey>, DatabaseError> {
|
||||||
|
Ok(self.0.current()?.map(|(k, _)| TrieKey::AccountNode(k)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A cursor over the storage tries stored in the database.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct DatabaseStorageTrieCursor<C> {
|
||||||
|
/// The underlying cursor.
|
||||||
|
pub cursor: C,
|
||||||
|
hashed_address: B256,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C> DatabaseStorageTrieCursor<C> {
|
||||||
|
/// Create a new storage trie cursor.
|
||||||
|
pub fn new(cursor: C, hashed_address: B256) -> Self {
|
||||||
|
Self { cursor, hashed_address }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C> TrieCursor for DatabaseStorageTrieCursor<C>
|
||||||
|
where
|
||||||
|
C: DbDupCursorRO<tables::StoragesTrie> + DbCursorRO<tables::StoragesTrie>,
|
||||||
|
{
|
||||||
|
type Key = StoredNibblesSubKey;
|
||||||
|
|
||||||
|
fn seek_exact(
|
||||||
|
&mut self,
|
||||||
|
key: Self::Key,
|
||||||
|
) -> Result<Option<(Vec<u8>, BranchNodeCompact)>, DatabaseError> {
|
||||||
|
Ok(self
|
||||||
|
.cursor
|
||||||
|
.seek_by_key_subkey(self.hashed_address, key.clone())?
|
||||||
|
.filter(|e| e.nibbles == key)
|
||||||
|
.map(|value| (value.nibbles.to_vec(), value.node)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn seek(
|
||||||
|
&mut self,
|
||||||
|
key: Self::Key,
|
||||||
|
) -> Result<Option<(Vec<u8>, BranchNodeCompact)>, DatabaseError> {
|
||||||
|
Ok(self
|
||||||
|
.cursor
|
||||||
|
.seek_by_key_subkey(self.hashed_address, key)?
|
||||||
|
.map(|value| (value.nibbles.to_vec(), value.node)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn current(&mut self) -> Result<Option<TrieKey>, DatabaseError> {
|
||||||
|
Ok(self.cursor.current()?.map(|(k, v)| TrieKey::StorageNode(k, v.nibbles)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use reth_db::{
|
||||||
|
cursor::{DbCursorRO, DbCursorRW},
|
||||||
|
tables,
|
||||||
|
transaction::DbTxMut,
|
||||||
|
};
|
||||||
|
use reth_primitives::{
|
||||||
|
hex_literal::hex,
|
||||||
|
trie::{BranchNodeCompact, StorageTrieEntry},
|
||||||
|
};
|
||||||
|
use reth_provider::test_utils::create_test_provider_factory;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_account_trie_order() {
|
||||||
|
let factory = create_test_provider_factory();
|
||||||
|
let provider = factory.provider_rw().unwrap();
|
||||||
|
let mut cursor = provider.tx_ref().cursor_write::<tables::AccountsTrie>().unwrap();
|
||||||
|
|
||||||
|
let data = vec![
|
||||||
|
hex!("0303040e").to_vec(),
|
||||||
|
hex!("030305").to_vec(),
|
||||||
|
hex!("03030500").to_vec(),
|
||||||
|
hex!("0303050a").to_vec(),
|
||||||
|
];
|
||||||
|
|
||||||
|
for key in data.clone() {
|
||||||
|
cursor
|
||||||
|
.upsert(
|
||||||
|
key.into(),
|
||||||
|
BranchNodeCompact::new(
|
||||||
|
0b0000_0010_0000_0001,
|
||||||
|
0b0000_0010_0000_0001,
|
||||||
|
0,
|
||||||
|
Vec::default(),
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let db_data = cursor.walk_range(..).unwrap().collect::<Result<Vec<_>, _>>().unwrap();
|
||||||
|
assert_eq!(db_data[0].0 .0.to_vec(), data[0]);
|
||||||
|
assert_eq!(db_data[1].0 .0.to_vec(), data[1]);
|
||||||
|
assert_eq!(db_data[2].0 .0.to_vec(), data[2]);
|
||||||
|
assert_eq!(db_data[3].0 .0.to_vec(), data[3]);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
cursor.seek(hex!("0303040f").to_vec().into()).unwrap().map(|(k, _)| k.0.to_vec()),
|
||||||
|
Some(data[1].clone())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// tests that upsert and seek match on the storage trie cursor
|
||||||
|
#[test]
|
||||||
|
fn test_storage_cursor_abstraction() {
|
||||||
|
let factory = create_test_provider_factory();
|
||||||
|
let provider = factory.provider_rw().unwrap();
|
||||||
|
let mut cursor = provider.tx_ref().cursor_dup_write::<tables::StoragesTrie>().unwrap();
|
||||||
|
|
||||||
|
let hashed_address = B256::random();
|
||||||
|
let key = vec![0x2, 0x3];
|
||||||
|
let value = BranchNodeCompact::new(1, 1, 1, vec![B256::random()], None);
|
||||||
|
|
||||||
|
cursor
|
||||||
|
.upsert(
|
||||||
|
hashed_address,
|
||||||
|
StorageTrieEntry { nibbles: key.clone().into(), node: value.clone() },
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let mut cursor = DatabaseStorageTrieCursor::new(cursor, hashed_address);
|
||||||
|
assert_eq!(cursor.seek(key.into()).unwrap().unwrap().1, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,17 +1,37 @@
|
|||||||
use crate::updates::TrieKey;
|
use crate::updates::TrieKey;
|
||||||
use reth_db::DatabaseError;
|
use reth_db::DatabaseError;
|
||||||
use reth_primitives::trie::BranchNodeCompact;
|
use reth_primitives::{
|
||||||
|
trie::{BranchNodeCompact, StoredNibbles, StoredNibblesSubKey},
|
||||||
mod account_cursor;
|
B256,
|
||||||
mod storage_cursor;
|
|
||||||
mod subnode;
|
|
||||||
|
|
||||||
pub use self::{
|
|
||||||
account_cursor::AccountTrieCursor, storage_cursor::StorageTrieCursor, subnode::CursorSubNode,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
mod database_cursors;
|
||||||
|
mod subnode;
|
||||||
|
|
||||||
|
/// Noop trie cursor implementations.
|
||||||
|
pub mod noop;
|
||||||
|
|
||||||
|
pub use self::{
|
||||||
|
database_cursors::{DatabaseAccountTrieCursor, DatabaseStorageTrieCursor},
|
||||||
|
subnode::CursorSubNode,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Factory for creating trie cursors.
|
||||||
|
pub trait TrieCursorFactory {
|
||||||
|
/// Create an account trie cursor.
|
||||||
|
fn account_trie_cursor(
|
||||||
|
&self,
|
||||||
|
) -> Result<Box<dyn TrieCursor<Key = StoredNibbles> + '_>, DatabaseError>;
|
||||||
|
|
||||||
|
/// Create a storage tries cursor.
|
||||||
|
fn storage_tries_cursor(
|
||||||
|
&self,
|
||||||
|
hashed_address: B256,
|
||||||
|
) -> Result<Box<dyn TrieCursor<Key = StoredNibblesSubKey> + '_>, DatabaseError>;
|
||||||
|
}
|
||||||
|
|
||||||
/// A cursor for navigating a trie that works with both Tables and DupSort tables.
|
/// A cursor for navigating a trie that works with both Tables and DupSort tables.
|
||||||
#[auto_impl::auto_impl(&mut)]
|
#[auto_impl::auto_impl(&mut, Box)]
|
||||||
pub trait TrieCursor {
|
pub trait TrieCursor {
|
||||||
/// The key type of the cursor.
|
/// The key type of the cursor.
|
||||||
type Key: From<Vec<u8>>;
|
type Key: From<Vec<u8>>;
|
||||||
|
|||||||
80
crates/trie/src/trie_cursor/noop.rs
Normal file
80
crates/trie/src/trie_cursor/noop.rs
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
use reth_db::DatabaseError;
|
||||||
|
use reth_primitives::trie::{BranchNodeCompact, StoredNibbles, StoredNibblesSubKey};
|
||||||
|
|
||||||
|
use crate::updates::TrieKey;
|
||||||
|
|
||||||
|
use super::{TrieCursor, TrieCursorFactory};
|
||||||
|
|
||||||
|
/// Noop trie cursor factory.
|
||||||
|
#[derive(Default, Debug)]
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub struct NoopTrieCursorFactory;
|
||||||
|
|
||||||
|
impl TrieCursorFactory for NoopTrieCursorFactory {
|
||||||
|
fn account_trie_cursor(
|
||||||
|
&self,
|
||||||
|
) -> Result<Box<dyn TrieCursor<Key = StoredNibbles> + '_>, DatabaseError> {
|
||||||
|
Ok(Box::<NoopAccountTrieCursor>::default())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn storage_tries_cursor(
|
||||||
|
&self,
|
||||||
|
_hashed_address: reth_primitives::B256,
|
||||||
|
) -> Result<Box<dyn TrieCursor<Key = StoredNibblesSubKey> + '_>, DatabaseError> {
|
||||||
|
Ok(Box::<NoopStorageTrieCursor>::default())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Noop account trie cursor.
|
||||||
|
#[derive(Default, Debug)]
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub struct NoopAccountTrieCursor;
|
||||||
|
|
||||||
|
impl TrieCursor for NoopAccountTrieCursor {
|
||||||
|
type Key = StoredNibbles;
|
||||||
|
|
||||||
|
fn seek(
|
||||||
|
&mut self,
|
||||||
|
_key: Self::Key,
|
||||||
|
) -> Result<Option<(Vec<u8>, BranchNodeCompact)>, DatabaseError> {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn seek_exact(
|
||||||
|
&mut self,
|
||||||
|
_key: Self::Key,
|
||||||
|
) -> Result<Option<(Vec<u8>, BranchNodeCompact)>, DatabaseError> {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn current(&mut self) -> Result<Option<TrieKey>, DatabaseError> {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Noop account trie cursor.
|
||||||
|
#[derive(Default, Debug)]
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub struct NoopStorageTrieCursor;
|
||||||
|
|
||||||
|
impl TrieCursor for NoopStorageTrieCursor {
|
||||||
|
type Key = StoredNibblesSubKey;
|
||||||
|
|
||||||
|
fn seek(
|
||||||
|
&mut self,
|
||||||
|
_key: Self::Key,
|
||||||
|
) -> Result<Option<(Vec<u8>, BranchNodeCompact)>, DatabaseError> {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn seek_exact(
|
||||||
|
&mut self,
|
||||||
|
_key: Self::Key,
|
||||||
|
) -> Result<Option<(Vec<u8>, BranchNodeCompact)>, DatabaseError> {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn current(&mut self) -> Result<Option<TrieKey>, DatabaseError> {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,88 +0,0 @@
|
|||||||
use super::TrieCursor;
|
|
||||||
use crate::updates::TrieKey;
|
|
||||||
use reth_db::{
|
|
||||||
cursor::{DbCursorRO, DbDupCursorRO},
|
|
||||||
tables, DatabaseError,
|
|
||||||
};
|
|
||||||
use reth_primitives::{
|
|
||||||
trie::{BranchNodeCompact, StoredNibblesSubKey},
|
|
||||||
B256,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// A cursor over the storage trie.
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct StorageTrieCursor<C> {
|
|
||||||
/// The underlying cursor.
|
|
||||||
pub cursor: C,
|
|
||||||
hashed_address: B256,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<C> StorageTrieCursor<C> {
|
|
||||||
/// Create a new storage trie cursor.
|
|
||||||
pub fn new(cursor: C, hashed_address: B256) -> Self {
|
|
||||||
Self { cursor, hashed_address }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<C> TrieCursor for StorageTrieCursor<C>
|
|
||||||
where
|
|
||||||
C: DbDupCursorRO<tables::StoragesTrie> + DbCursorRO<tables::StoragesTrie>,
|
|
||||||
{
|
|
||||||
type Key = StoredNibblesSubKey;
|
|
||||||
|
|
||||||
fn seek_exact(
|
|
||||||
&mut self,
|
|
||||||
key: Self::Key,
|
|
||||||
) -> Result<Option<(Vec<u8>, BranchNodeCompact)>, DatabaseError> {
|
|
||||||
Ok(self
|
|
||||||
.cursor
|
|
||||||
.seek_by_key_subkey(self.hashed_address, key.clone())?
|
|
||||||
.filter(|e| e.nibbles == key)
|
|
||||||
.map(|value| (value.nibbles.to_vec(), value.node)))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn seek(
|
|
||||||
&mut self,
|
|
||||||
key: Self::Key,
|
|
||||||
) -> Result<Option<(Vec<u8>, BranchNodeCompact)>, DatabaseError> {
|
|
||||||
Ok(self
|
|
||||||
.cursor
|
|
||||||
.seek_by_key_subkey(self.hashed_address, key)?
|
|
||||||
.map(|value| (value.nibbles.to_vec(), value.node)))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn current(&mut self) -> Result<Option<TrieKey>, DatabaseError> {
|
|
||||||
Ok(self.cursor.current()?.map(|(k, v)| TrieKey::StorageNode(k, v.nibbles)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
use reth_db::{cursor::DbCursorRW, tables, transaction::DbTxMut};
|
|
||||||
use reth_primitives::trie::{BranchNodeCompact, StorageTrieEntry};
|
|
||||||
use reth_provider::test_utils::create_test_provider_factory;
|
|
||||||
|
|
||||||
// tests that upsert and seek match on the storagetrie cursor
|
|
||||||
#[test]
|
|
||||||
fn test_storage_cursor_abstraction() {
|
|
||||||
let factory = create_test_provider_factory();
|
|
||||||
let provider = factory.provider_rw().unwrap();
|
|
||||||
let mut cursor = provider.tx_ref().cursor_dup_write::<tables::StoragesTrie>().unwrap();
|
|
||||||
|
|
||||||
let hashed_address = B256::random();
|
|
||||||
let key = vec![0x2, 0x3];
|
|
||||||
let value = BranchNodeCompact::new(1, 1, 1, vec![B256::random()], None);
|
|
||||||
|
|
||||||
cursor
|
|
||||||
.upsert(
|
|
||||||
hashed_address,
|
|
||||||
StorageTrieEntry { nibbles: key.clone().into(), node: value.clone() },
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let mut cursor = StorageTrieCursor::new(cursor, hashed_address);
|
|
||||||
assert_eq!(cursor.seek(key.into()).unwrap().unwrap().1, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -250,7 +250,7 @@ mod tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
prefix_set::PrefixSetMut,
|
prefix_set::PrefixSetMut,
|
||||||
trie_cursor::{AccountTrieCursor, StorageTrieCursor},
|
trie_cursor::{DatabaseAccountTrieCursor, DatabaseStorageTrieCursor},
|
||||||
};
|
};
|
||||||
use reth_db::{cursor::DbCursorRW, tables, transaction::DbTxMut};
|
use reth_db::{cursor::DbCursorRW, tables, transaction::DbTxMut};
|
||||||
use reth_primitives::trie::StorageTrieEntry;
|
use reth_primitives::trie::StorageTrieEntry;
|
||||||
@ -286,7 +286,7 @@ mod tests {
|
|||||||
for (k, v) in &inputs {
|
for (k, v) in &inputs {
|
||||||
account_cursor.upsert(k.clone().into(), v.clone()).unwrap();
|
account_cursor.upsert(k.clone().into(), v.clone()).unwrap();
|
||||||
}
|
}
|
||||||
let account_trie = AccountTrieCursor::new(account_cursor);
|
let account_trie = DatabaseAccountTrieCursor::new(account_cursor);
|
||||||
test_cursor(account_trie, &expected);
|
test_cursor(account_trie, &expected);
|
||||||
|
|
||||||
let hashed_address = B256::random();
|
let hashed_address = B256::random();
|
||||||
@ -299,7 +299,7 @@ mod tests {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
let storage_trie = StorageTrieCursor::new(storage_cursor, hashed_address);
|
let storage_trie = DatabaseStorageTrieCursor::new(storage_cursor, hashed_address);
|
||||||
test_cursor(storage_trie, &expected);
|
test_cursor(storage_trie, &expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -357,7 +357,7 @@ mod tests {
|
|||||||
cursor.upsert(hashed_address, StorageTrieEntry { nibbles: k.into(), node: v }).unwrap();
|
cursor.upsert(hashed_address, StorageTrieEntry { nibbles: k.into(), node: v }).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut trie = StorageTrieCursor::new(cursor, hashed_address);
|
let mut trie = DatabaseStorageTrieCursor::new(cursor, hashed_address);
|
||||||
|
|
||||||
// No changes
|
// No changes
|
||||||
let mut cursor = TrieWalker::new(&mut trie, Default::default());
|
let mut cursor = TrieWalker::new(&mut trie, Default::default());
|
||||||
|
|||||||
Reference in New Issue
Block a user