mirror of
https://github.com/paradigmxyz/reth.git
synced 2026-01-10 07:48:19 -05:00
refactor(trie): initialize sparse trie with the provider (#15199)
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -10056,6 +10056,7 @@ dependencies = [
|
||||
"alloy-rlp",
|
||||
"arbitrary",
|
||||
"assert_matches",
|
||||
"auto_impl",
|
||||
"codspeed-criterion-compat",
|
||||
"itertools 0.14.0",
|
||||
"metrics",
|
||||
|
||||
@@ -62,7 +62,7 @@ where
|
||||
let now = Instant::now();
|
||||
|
||||
let mut num_iterations = 0;
|
||||
let mut trie = SparseStateTrie::default().with_updates(true);
|
||||
let mut trie = SparseStateTrie::new(&self.blinded_provider_factory).with_updates(true);
|
||||
|
||||
while let Ok(mut update) = self.updates.recv() {
|
||||
num_iterations += 1;
|
||||
@@ -80,10 +80,9 @@ where
|
||||
"Updating sparse trie"
|
||||
);
|
||||
|
||||
let elapsed = update_sparse_trie(&mut trie, update, &self.blinded_provider_factory)
|
||||
.map_err(|e| {
|
||||
ParallelStateRootError::Other(format!("could not calculate state root: {e:?}"))
|
||||
})?;
|
||||
let elapsed = update_sparse_trie(&mut trie, update).map_err(|e| {
|
||||
ParallelStateRootError::Other(format!("could not calculate state root: {e:?}"))
|
||||
})?;
|
||||
self.metrics.sparse_trie_update_duration_histogram.record(elapsed);
|
||||
trace!(target: "engine::root", ?elapsed, num_iterations, "Root calculation completed");
|
||||
}
|
||||
@@ -91,10 +90,9 @@ where
|
||||
debug!(target: "engine::root", num_iterations, "All proofs processed, ending calculation");
|
||||
|
||||
let start = Instant::now();
|
||||
let (state_root, trie_updates) =
|
||||
trie.root_with_updates(&self.blinded_provider_factory).map_err(|e| {
|
||||
ParallelStateRootError::Other(format!("could not calculate state root: {e:?}"))
|
||||
})?;
|
||||
let (state_root, trie_updates) = trie.root_with_updates().map_err(|e| {
|
||||
ParallelStateRootError::Other(format!("could not calculate state root: {e:?}"))
|
||||
})?;
|
||||
|
||||
self.metrics.sparse_trie_final_update_duration_histogram.record(start.elapsed());
|
||||
self.metrics.sparse_trie_total_duration_histogram.record(now.elapsed());
|
||||
@@ -115,9 +113,8 @@ pub struct StateRootComputeOutcome {
|
||||
|
||||
/// Updates the sparse trie with the given proofs and state, and returns the elapsed time.
|
||||
pub(crate) fn update_sparse_trie<BPF>(
|
||||
trie: &mut SparseStateTrie,
|
||||
trie: &mut SparseStateTrie<BPF>,
|
||||
SparseTrieUpdate { mut state, multiproof }: SparseTrieUpdate,
|
||||
blinded_provider_factory: &BPF,
|
||||
) -> SparseStateTrieResult<Duration>
|
||||
where
|
||||
BPF: BlindedProviderFactory + Send + Sync,
|
||||
@@ -148,7 +145,6 @@ where
|
||||
let _enter = span.enter();
|
||||
trace!(target: "engine::root::sparse", "Updating storage");
|
||||
let mut storage_trie = storage_trie.ok_or(SparseTrieErrorKind::Blind)?;
|
||||
let provider = blinded_provider_factory.storage_node_provider(address);
|
||||
|
||||
if storage.wiped {
|
||||
trace!(target: "engine::root::sparse", "Wiping storage");
|
||||
@@ -158,14 +154,11 @@ where
|
||||
let slot_nibbles = Nibbles::unpack(slot);
|
||||
if value.is_zero() {
|
||||
trace!(target: "engine::root::sparse", ?slot, "Removing storage slot");
|
||||
storage_trie.remove_leaf(&slot_nibbles, &provider)?;
|
||||
storage_trie.remove_leaf(&slot_nibbles)?;
|
||||
} else {
|
||||
trace!(target: "engine::root::sparse", ?slot, "Updating storage slot");
|
||||
storage_trie.update_leaf(
|
||||
slot_nibbles,
|
||||
alloy_rlp::encode_fixed_size(&value).to_vec(),
|
||||
&provider,
|
||||
)?;
|
||||
storage_trie
|
||||
.update_leaf(slot_nibbles, alloy_rlp::encode_fixed_size(&value).to_vec())?;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,18 +178,18 @@ where
|
||||
// If the account itself has an update, remove it from the state update and update in
|
||||
// one go instead of doing it down below.
|
||||
trace!(target: "engine::root::sparse", ?address, "Updating account and its storage root");
|
||||
trie.update_account(address, account.unwrap_or_default(), blinded_provider_factory)?;
|
||||
trie.update_account(address, account.unwrap_or_default())?;
|
||||
} else if trie.is_account_revealed(address) {
|
||||
// Otherwise, if the account is revealed, only update its storage root.
|
||||
trace!(target: "engine::root::sparse", ?address, "Updating account storage root");
|
||||
trie.update_account_storage_root(address, blinded_provider_factory)?;
|
||||
trie.update_account_storage_root(address)?;
|
||||
}
|
||||
}
|
||||
|
||||
// Update accounts
|
||||
for (address, account) in state.accounts {
|
||||
trace!(target: "engine::root::sparse", ?address, "Updating account");
|
||||
trie.update_account(address, account.unwrap_or_default(), blinded_provider_factory)?;
|
||||
trie.update_account(address, account.unwrap_or_default())?;
|
||||
}
|
||||
|
||||
let elapsed_before = started_at.elapsed();
|
||||
|
||||
@@ -23,6 +23,7 @@ alloy-primitives.workspace = true
|
||||
alloy-rlp.workspace = true
|
||||
|
||||
# misc
|
||||
auto_impl.workspace = true
|
||||
smallvec = { workspace = true, features = ["const_new"] }
|
||||
thiserror.workspace = true
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ use proptest::{prelude::*, test_runner::TestRunner};
|
||||
use rand::seq::IteratorRandom;
|
||||
use reth_testing_utils::generators;
|
||||
use reth_trie::Nibbles;
|
||||
use reth_trie_sparse::{blinded::DefaultBlindedProvider, RevealedSparseTrie};
|
||||
use reth_trie_sparse::RevealedSparseTrie;
|
||||
|
||||
fn update_rlp_node_level(c: &mut Criterion) {
|
||||
let mut rng = generators::rng();
|
||||
@@ -25,11 +25,7 @@ fn update_rlp_node_level(c: &mut Criterion) {
|
||||
let mut sparse = RevealedSparseTrie::default();
|
||||
for (key, value) in &state {
|
||||
sparse
|
||||
.update_leaf(
|
||||
Nibbles::unpack(key),
|
||||
alloy_rlp::encode_fixed_size(value).to_vec(),
|
||||
&DefaultBlindedProvider,
|
||||
)
|
||||
.update_leaf(Nibbles::unpack(key), alloy_rlp::encode_fixed_size(value).to_vec())
|
||||
.unwrap();
|
||||
}
|
||||
sparse.root();
|
||||
@@ -43,7 +39,6 @@ fn update_rlp_node_level(c: &mut Criterion) {
|
||||
.update_leaf(
|
||||
Nibbles::unpack(key),
|
||||
alloy_rlp::encode_fixed_size(&rng.gen::<U256>()).to_vec(),
|
||||
&DefaultBlindedProvider,
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ use reth_trie::{
|
||||
HashedStorage,
|
||||
};
|
||||
use reth_trie_common::{HashBuilder, Nibbles};
|
||||
use reth_trie_sparse::{blinded::DefaultBlindedProvider, SparseTrie};
|
||||
use reth_trie_sparse::SparseTrie;
|
||||
|
||||
fn calculate_root_from_leaves(c: &mut Criterion) {
|
||||
let mut group = c.benchmark_group("calculate root from leaves");
|
||||
@@ -47,7 +47,6 @@ fn calculate_root_from_leaves(c: &mut Criterion) {
|
||||
.update_leaf(
|
||||
Nibbles::unpack(key),
|
||||
alloy_rlp::encode_fixed_size(value).to_vec(),
|
||||
&DefaultBlindedProvider,
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
@@ -189,7 +188,6 @@ fn calculate_root_from_leaves_repeated(c: &mut Criterion) {
|
||||
.update_leaf(
|
||||
Nibbles::unpack(key),
|
||||
alloy_rlp::encode_fixed_size(value).to_vec(),
|
||||
&DefaultBlindedProvider,
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
@@ -203,7 +201,6 @@ fn calculate_root_from_leaves_repeated(c: &mut Criterion) {
|
||||
.update_leaf(
|
||||
Nibbles::unpack(key),
|
||||
alloy_rlp::encode_fixed_size(value).to_vec(),
|
||||
&DefaultBlindedProvider,
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ use reth_execution_errors::SparseTrieError;
|
||||
use reth_trie_common::{Nibbles, TrieMask};
|
||||
|
||||
/// Factory for instantiating blinded node providers.
|
||||
#[auto_impl::auto_impl(&)]
|
||||
pub trait BlindedProviderFactory {
|
||||
/// Type capable of fetching blinded account nodes.
|
||||
type AccountNodeProvider: BlindedProvider;
|
||||
@@ -30,6 +31,7 @@ pub struct RevealedNode {
|
||||
}
|
||||
|
||||
/// Trie node provider for retrieving blinded nodes.
|
||||
#[auto_impl::auto_impl(&)]
|
||||
pub trait BlindedProvider {
|
||||
/// Retrieve blinded node by path.
|
||||
fn blinded_node(&self, path: &Nibbles) -> Result<Option<RevealedNode>, SparseTrieError>;
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
use crate::{
|
||||
blinded::{BlindedProvider, BlindedProviderFactory},
|
||||
blinded::{BlindedProvider, BlindedProviderFactory, DefaultBlindedProviderFactory},
|
||||
metrics::SparseStateTrieMetrics,
|
||||
RevealedSparseTrie, SparseTrie, TrieMasks,
|
||||
};
|
||||
use alloy_primitives::{
|
||||
hex,
|
||||
map::{B256Map, HashMap, HashSet},
|
||||
Bytes, B256,
|
||||
};
|
||||
use alloy_rlp::{Decodable, Encodable};
|
||||
use core::fmt;
|
||||
use reth_execution_errors::{SparseStateTrieErrorKind, SparseStateTrieResult, SparseTrieErrorKind};
|
||||
use reth_primitives_traits::Account;
|
||||
use reth_tracing::tracing::trace;
|
||||
@@ -20,12 +22,13 @@ use reth_trie_common::{
|
||||
use std::{collections::VecDeque, iter::Peekable};
|
||||
|
||||
/// Sparse state trie representing lazy-loaded Ethereum state trie.
|
||||
#[derive(Debug)]
|
||||
pub struct SparseStateTrie {
|
||||
pub struct SparseStateTrie<F: BlindedProviderFactory = DefaultBlindedProviderFactory> {
|
||||
/// Blinded node provider factory.
|
||||
provider_factory: F,
|
||||
/// Sparse account trie.
|
||||
state: SparseTrie,
|
||||
state: SparseTrie<F::AccountNodeProvider>,
|
||||
/// Sparse storage tries.
|
||||
storages: B256Map<SparseTrie>,
|
||||
storages: B256Map<SparseTrie<F::StorageNodeProvider>>,
|
||||
/// Collection of revealed account trie paths.
|
||||
revealed_account_paths: HashSet<Nibbles>,
|
||||
/// Collection of revealed storage trie paths, per account.
|
||||
@@ -38,9 +41,11 @@ pub struct SparseStateTrie {
|
||||
metrics: SparseStateTrieMetrics,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl Default for SparseStateTrie {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
provider_factory: DefaultBlindedProviderFactory,
|
||||
state: Default::default(),
|
||||
storages: Default::default(),
|
||||
revealed_account_paths: Default::default(),
|
||||
@@ -52,6 +57,20 @@ impl Default for SparseStateTrie {
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: BlindedProviderFactory> fmt::Debug for SparseStateTrie<P> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("SparseStateTrie")
|
||||
.field("state", &self.state)
|
||||
.field("storages", &self.storages)
|
||||
.field("revealed_account_paths", &self.revealed_account_paths)
|
||||
.field("revealed_storage_paths", &self.revealed_storage_paths)
|
||||
.field("retain_updates", &self.retain_updates)
|
||||
.field("account_rlp_buf", &hex::encode(&self.account_rlp_buf))
|
||||
.finish_non_exhaustive()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl SparseStateTrie {
|
||||
/// Create state trie from state trie.
|
||||
pub fn from_state(state: SparseTrie) -> Self {
|
||||
@@ -59,7 +78,21 @@ impl SparseStateTrie {
|
||||
}
|
||||
}
|
||||
|
||||
impl SparseStateTrie {
|
||||
impl<F: BlindedProviderFactory> SparseStateTrie<F> {
|
||||
/// Create new [`SparseStateTrie`] with blinded node provider factory.
|
||||
pub fn new(provider_factory: F) -> Self {
|
||||
Self {
|
||||
provider_factory,
|
||||
state: Default::default(),
|
||||
storages: Default::default(),
|
||||
revealed_account_paths: Default::default(),
|
||||
revealed_storage_paths: Default::default(),
|
||||
retain_updates: false,
|
||||
account_rlp_buf: Vec::with_capacity(TRIE_ACCOUNT_RLP_MAX_SIZE),
|
||||
metrics: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the retention of branch node updates and deletions.
|
||||
pub const fn with_updates(mut self, retain_updates: bool) -> Self {
|
||||
self.retain_updates = retain_updates;
|
||||
@@ -89,27 +122,40 @@ impl SparseStateTrie {
|
||||
}
|
||||
|
||||
/// Returns reference to state trie if it was revealed.
|
||||
pub const fn state_trie_ref(&self) -> Option<&RevealedSparseTrie> {
|
||||
pub const fn state_trie_ref(&self) -> Option<&RevealedSparseTrie<F::AccountNodeProvider>> {
|
||||
self.state.as_revealed_ref()
|
||||
}
|
||||
|
||||
/// Returns reference to storage trie if it was revealed.
|
||||
pub fn storage_trie_ref(&self, address: &B256) -> Option<&RevealedSparseTrie> {
|
||||
pub fn storage_trie_ref(
|
||||
&self,
|
||||
address: &B256,
|
||||
) -> Option<&RevealedSparseTrie<F::StorageNodeProvider>> {
|
||||
self.storages.get(address).and_then(|e| e.as_revealed_ref())
|
||||
}
|
||||
|
||||
/// Returns mutable reference to storage sparse trie if it was revealed.
|
||||
pub fn storage_trie_mut(&mut self, address: &B256) -> Option<&mut RevealedSparseTrie> {
|
||||
pub fn storage_trie_mut(
|
||||
&mut self,
|
||||
address: &B256,
|
||||
) -> Option<&mut RevealedSparseTrie<F::StorageNodeProvider>> {
|
||||
self.storages.get_mut(address).and_then(|e| e.as_revealed_mut())
|
||||
}
|
||||
|
||||
/// Takes the storage trie for the provided address.
|
||||
pub fn take_storage_trie(&mut self, address: &B256) -> Option<SparseTrie> {
|
||||
pub fn take_storage_trie(
|
||||
&mut self,
|
||||
address: &B256,
|
||||
) -> Option<SparseTrie<F::StorageNodeProvider>> {
|
||||
self.storages.remove(address)
|
||||
}
|
||||
|
||||
/// Inserts storage trie for the provided address.
|
||||
pub fn insert_storage_trie(&mut self, address: B256, storage_trie: SparseTrie) {
|
||||
pub fn insert_storage_trie(
|
||||
&mut self,
|
||||
address: B256,
|
||||
storage_trie: SparseTrie<F::StorageNodeProvider>,
|
||||
) {
|
||||
self.storages.insert(address, storage_trie);
|
||||
}
|
||||
|
||||
@@ -135,6 +181,7 @@ impl SparseStateTrie {
|
||||
|
||||
// Reveal root node if it wasn't already.
|
||||
let trie = self.state.reveal_root_with_provider(
|
||||
self.provider_factory.account_node_provider(),
|
||||
root_node,
|
||||
TrieMasks::none(),
|
||||
self.retain_updates,
|
||||
@@ -178,6 +225,7 @@ impl SparseStateTrie {
|
||||
|
||||
// Reveal root node if it wasn't already.
|
||||
let trie = self.storages.entry(account).or_default().reveal_root_with_provider(
|
||||
self.provider_factory.storage_node_provider(account),
|
||||
root_node,
|
||||
TrieMasks::none(),
|
||||
self.retain_updates,
|
||||
@@ -239,6 +287,7 @@ impl SparseStateTrie {
|
||||
if let Some(root_node) = self.validate_root_node(&mut account_nodes)? {
|
||||
// Reveal root node if it wasn't already.
|
||||
let trie = self.state.reveal_root_with_provider(
|
||||
self.provider_factory.account_node_provider(),
|
||||
root_node,
|
||||
TrieMasks {
|
||||
hash_mask: branch_node_hash_masks.get(&Nibbles::default()).copied(),
|
||||
@@ -288,6 +337,7 @@ impl SparseStateTrie {
|
||||
if let Some(root_node) = self.validate_root_node(&mut nodes)? {
|
||||
// Reveal root node if it wasn't already.
|
||||
let trie = self.storages.entry(account).or_default().reveal_root_with_provider(
|
||||
self.provider_factory.storage_node_provider(account),
|
||||
root_node,
|
||||
TrieMasks {
|
||||
hash_mask: storage_subtree
|
||||
@@ -397,6 +447,7 @@ impl SparseStateTrie {
|
||||
if path.is_empty() {
|
||||
// Handle special storage state root node case.
|
||||
storage_trie_entry.reveal_root_with_provider(
|
||||
self.provider_factory.storage_node_provider(account),
|
||||
trie_node,
|
||||
TrieMasks::none(),
|
||||
self.retain_updates,
|
||||
@@ -418,6 +469,7 @@ impl SparseStateTrie {
|
||||
if path.is_empty() {
|
||||
// Handle special state root node case.
|
||||
self.state.reveal_root_with_provider(
|
||||
self.provider_factory.account_node_provider(),
|
||||
trie_node,
|
||||
TrieMasks::none(),
|
||||
self.retain_updates,
|
||||
@@ -488,11 +540,11 @@ impl SparseStateTrie {
|
||||
/// If the trie is not revealed yet, its root will be revealed using the blinded node provider.
|
||||
fn revealed_trie_mut(
|
||||
&mut self,
|
||||
provider_factory: &impl BlindedProviderFactory,
|
||||
) -> SparseStateTrieResult<&mut RevealedSparseTrie> {
|
||||
) -> SparseStateTrieResult<&mut RevealedSparseTrie<F::AccountNodeProvider>> {
|
||||
match self.state {
|
||||
SparseTrie::Blind => {
|
||||
let (root_node, hash_mask, tree_mask) = provider_factory
|
||||
let (root_node, hash_mask, tree_mask) = self
|
||||
.provider_factory
|
||||
.account_node_provider()
|
||||
.blinded_node(&Nibbles::default())?
|
||||
.map(|node| {
|
||||
@@ -503,6 +555,7 @@ impl SparseStateTrie {
|
||||
.unwrap_or((TrieNode::EmptyRoot, None, None));
|
||||
self.state
|
||||
.reveal_root_with_provider(
|
||||
self.provider_factory.account_node_provider(),
|
||||
root_node,
|
||||
TrieMasks { hash_mask, tree_mask },
|
||||
self.retain_updates,
|
||||
@@ -516,26 +569,20 @@ impl SparseStateTrie {
|
||||
/// Returns sparse trie root.
|
||||
///
|
||||
/// If the trie has not been revealed, this function reveals the root node and returns its hash.
|
||||
pub fn root(
|
||||
&mut self,
|
||||
provider_factory: &impl BlindedProviderFactory,
|
||||
) -> SparseStateTrieResult<B256> {
|
||||
pub fn root(&mut self) -> SparseStateTrieResult<B256> {
|
||||
// record revealed node metrics
|
||||
self.metrics.record();
|
||||
|
||||
Ok(self.revealed_trie_mut(provider_factory)?.root())
|
||||
Ok(self.revealed_trie_mut()?.root())
|
||||
}
|
||||
|
||||
/// Returns sparse trie root and trie updates if the trie has been revealed.
|
||||
pub fn root_with_updates(
|
||||
&mut self,
|
||||
provider_factory: &impl BlindedProviderFactory,
|
||||
) -> SparseStateTrieResult<(B256, TrieUpdates)> {
|
||||
pub fn root_with_updates(&mut self) -> SparseStateTrieResult<(B256, TrieUpdates)> {
|
||||
// record revealed node metrics
|
||||
self.metrics.record();
|
||||
|
||||
let storage_tries = self.storage_trie_updates();
|
||||
let revealed = self.revealed_trie_mut(provider_factory)?;
|
||||
let revealed = self.revealed_trie_mut()?;
|
||||
|
||||
let (root, updates) = (revealed.root(), revealed.take_updates());
|
||||
let updates = TrieUpdates {
|
||||
@@ -586,13 +633,12 @@ impl SparseStateTrie {
|
||||
&mut self,
|
||||
path: Nibbles,
|
||||
value: Vec<u8>,
|
||||
provider_factory: &impl BlindedProviderFactory,
|
||||
) -> SparseStateTrieResult<()> {
|
||||
if !self.revealed_account_paths.contains(&path) {
|
||||
self.revealed_account_paths.insert(path.clone());
|
||||
}
|
||||
|
||||
self.state.update_leaf(path, value, &provider_factory.account_node_provider())?;
|
||||
self.state.update_leaf(path, value)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -602,14 +648,13 @@ impl SparseStateTrie {
|
||||
address: B256,
|
||||
slot: Nibbles,
|
||||
value: Vec<u8>,
|
||||
provider_factory: &impl BlindedProviderFactory,
|
||||
) -> SparseStateTrieResult<()> {
|
||||
if !self.revealed_storage_paths.get(&address).is_some_and(|slots| slots.contains(&slot)) {
|
||||
self.revealed_storage_paths.entry(address).or_default().insert(slot.clone());
|
||||
}
|
||||
|
||||
let storage_trie = self.storages.get_mut(&address).ok_or(SparseTrieErrorKind::Blind)?;
|
||||
storage_trie.update_leaf(slot, value, &provider_factory.storage_node_provider(address))?;
|
||||
storage_trie.update_leaf(slot, value)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -617,12 +662,7 @@ impl SparseStateTrie {
|
||||
/// the storage root based on update storage trie or look it up from existing leaf value.
|
||||
///
|
||||
/// If the new account info and storage trie are empty, the account leaf will be removed.
|
||||
pub fn update_account(
|
||||
&mut self,
|
||||
address: B256,
|
||||
account: Account,
|
||||
provider_factory: &impl BlindedProviderFactory,
|
||||
) -> SparseStateTrieResult<()> {
|
||||
pub fn update_account(&mut self, address: B256, account: Account) -> SparseStateTrieResult<()> {
|
||||
let nibbles = Nibbles::unpack(address);
|
||||
|
||||
let storage_root = if let Some(storage_trie) = self.storages.get_mut(&address) {
|
||||
@@ -644,12 +684,12 @@ impl SparseStateTrie {
|
||||
|
||||
if account.is_empty() && storage_root == EMPTY_ROOT_HASH {
|
||||
trace!(target: "trie::sparse", ?address, "Removing account");
|
||||
self.remove_account_leaf(&nibbles, provider_factory)
|
||||
self.remove_account_leaf(&nibbles)
|
||||
} else {
|
||||
trace!(target: "trie::sparse", ?address, "Updating account");
|
||||
self.account_rlp_buf.clear();
|
||||
account.into_trie_account(storage_root).encode(&mut self.account_rlp_buf);
|
||||
self.update_account_leaf(nibbles, self.account_rlp_buf.clone(), provider_factory)
|
||||
self.update_account_leaf(nibbles, self.account_rlp_buf.clone())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -659,11 +699,7 @@ impl SparseStateTrie {
|
||||
///
|
||||
/// If the new storage root is empty, and the account info was already empty, the account leaf
|
||||
/// will be removed.
|
||||
pub fn update_account_storage_root(
|
||||
&mut self,
|
||||
address: B256,
|
||||
provider_factory: &impl BlindedProviderFactory,
|
||||
) -> SparseStateTrieResult<()> {
|
||||
pub fn update_account_storage_root(&mut self, address: B256) -> SparseStateTrieResult<()> {
|
||||
if !self.is_account_revealed(address) {
|
||||
return Err(SparseTrieErrorKind::Blind.into())
|
||||
}
|
||||
@@ -694,25 +730,21 @@ impl SparseStateTrie {
|
||||
if trie_account == TrieAccount::default() {
|
||||
// If the account is empty, remove it.
|
||||
trace!(target: "trie::sparse", ?address, "Removing account because the storage root is empty");
|
||||
self.remove_account_leaf(&nibbles, provider_factory)?;
|
||||
self.remove_account_leaf(&nibbles)?;
|
||||
} else {
|
||||
// Otherwise, update the account leaf.
|
||||
trace!(target: "trie::sparse", ?address, "Updating account with the new storage root");
|
||||
self.account_rlp_buf.clear();
|
||||
trie_account.encode(&mut self.account_rlp_buf);
|
||||
self.update_account_leaf(nibbles, self.account_rlp_buf.clone(), provider_factory)?;
|
||||
self.update_account_leaf(nibbles, self.account_rlp_buf.clone())?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Remove the account leaf node.
|
||||
pub fn remove_account_leaf(
|
||||
&mut self,
|
||||
path: &Nibbles,
|
||||
provider_factory: &impl BlindedProviderFactory,
|
||||
) -> SparseStateTrieResult<()> {
|
||||
self.state.remove_leaf(path, &provider_factory.account_node_provider())?;
|
||||
pub fn remove_account_leaf(&mut self, path: &Nibbles) -> SparseStateTrieResult<()> {
|
||||
self.state.remove_leaf(path)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -721,18 +753,15 @@ impl SparseStateTrie {
|
||||
&mut self,
|
||||
address: B256,
|
||||
slot: &Nibbles,
|
||||
provider_factory: &impl BlindedProviderFactory,
|
||||
) -> SparseStateTrieResult<()> {
|
||||
let storage_trie = self.storages.get_mut(&address).ok_or(SparseTrieErrorKind::Blind)?;
|
||||
storage_trie.remove_leaf(slot, &provider_factory.account_node_provider())?;
|
||||
storage_trie.remove_leaf(slot)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::blinded::DefaultBlindedProviderFactory;
|
||||
|
||||
use super::*;
|
||||
use alloy_primitives::{
|
||||
b256,
|
||||
@@ -852,9 +881,7 @@ mod tests {
|
||||
|
||||
// Remove the leaf node and check that the state trie does not contain the leaf node and
|
||||
// value
|
||||
sparse
|
||||
.remove_account_leaf(&Nibbles::from_nibbles([0x0]), &DefaultBlindedProviderFactory)
|
||||
.unwrap();
|
||||
sparse.remove_account_leaf(&Nibbles::from_nibbles([0x0])).unwrap();
|
||||
assert!(!sparse
|
||||
.state_trie_ref()
|
||||
.unwrap()
|
||||
@@ -936,13 +963,7 @@ mod tests {
|
||||
|
||||
// Remove the leaf node and check that the storage trie does not contain the leaf node and
|
||||
// value
|
||||
sparse
|
||||
.remove_storage_leaf(
|
||||
B256::ZERO,
|
||||
&Nibbles::from_nibbles([0x0]),
|
||||
&DefaultBlindedProviderFactory,
|
||||
)
|
||||
.unwrap();
|
||||
sparse.remove_storage_leaf(B256::ZERO, &Nibbles::from_nibbles([0x0])).unwrap();
|
||||
assert!(!sparse
|
||||
.storage_trie_ref(&B256::ZERO)
|
||||
.unwrap()
|
||||
@@ -1056,49 +1077,24 @@ mod tests {
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(sparse.root(&DefaultBlindedProviderFactory).unwrap(), root);
|
||||
assert_eq!(sparse.root().unwrap(), root);
|
||||
|
||||
let address_3 = b256!("0x2000000000000000000000000000000000000000000000000000000000000000");
|
||||
let address_path_3 = Nibbles::unpack(address_3);
|
||||
let account_3 = Account { nonce: account_1.nonce + 1, ..account_1 };
|
||||
let trie_account_3 = account_3.into_trie_account(EMPTY_ROOT_HASH);
|
||||
|
||||
sparse
|
||||
.update_account_leaf(
|
||||
address_path_3,
|
||||
alloy_rlp::encode(trie_account_3),
|
||||
&DefaultBlindedProviderFactory,
|
||||
)
|
||||
.unwrap();
|
||||
sparse.update_account_leaf(address_path_3, alloy_rlp::encode(trie_account_3)).unwrap();
|
||||
|
||||
sparse
|
||||
.update_storage_leaf(
|
||||
address_1,
|
||||
slot_path_3,
|
||||
alloy_rlp::encode(value_3),
|
||||
&DefaultBlindedProviderFactory,
|
||||
)
|
||||
.unwrap();
|
||||
sparse.update_storage_leaf(address_1, slot_path_3, alloy_rlp::encode(value_3)).unwrap();
|
||||
trie_account_1.storage_root = sparse.storage_root(address_1).unwrap();
|
||||
sparse
|
||||
.update_account_leaf(
|
||||
address_path_1,
|
||||
alloy_rlp::encode(trie_account_1),
|
||||
&DefaultBlindedProviderFactory,
|
||||
)
|
||||
.unwrap();
|
||||
sparse.update_account_leaf(address_path_1, alloy_rlp::encode(trie_account_1)).unwrap();
|
||||
|
||||
sparse.wipe_storage(address_2).unwrap();
|
||||
trie_account_2.storage_root = sparse.storage_root(address_2).unwrap();
|
||||
sparse
|
||||
.update_account_leaf(
|
||||
address_path_2,
|
||||
alloy_rlp::encode(trie_account_2),
|
||||
&DefaultBlindedProviderFactory,
|
||||
)
|
||||
.unwrap();
|
||||
sparse.update_account_leaf(address_path_2, alloy_rlp::encode(trie_account_2)).unwrap();
|
||||
|
||||
sparse.root(&DefaultBlindedProviderFactory).unwrap();
|
||||
sparse.root().unwrap();
|
||||
|
||||
let sparse_updates = sparse.take_trie_updates().unwrap();
|
||||
// TODO(alexey): assert against real state root calculation updates
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::blinded::{BlindedProvider, RevealedNode};
|
||||
use crate::blinded::{BlindedProvider, DefaultBlindedProvider, RevealedNode};
|
||||
use alloy_primitives::{
|
||||
hex, keccak256,
|
||||
map::{Entry, HashMap, HashSet},
|
||||
@@ -34,14 +34,14 @@ impl TrieMasks {
|
||||
/// Inner representation of the sparse trie.
|
||||
/// Sparse trie is blind by default until nodes are revealed.
|
||||
#[derive(PartialEq, Eq)]
|
||||
pub enum SparseTrie {
|
||||
pub enum SparseTrie<P = DefaultBlindedProvider> {
|
||||
/// None of the trie nodes are known.
|
||||
Blind,
|
||||
/// The trie nodes have been revealed.
|
||||
Revealed(Box<RevealedSparseTrie>),
|
||||
Revealed(Box<RevealedSparseTrie<P>>),
|
||||
}
|
||||
|
||||
impl fmt::Debug for SparseTrie {
|
||||
impl<P> fmt::Debug for SparseTrie<P> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::Blind => write!(f, "Blind"),
|
||||
@@ -50,7 +50,7 @@ impl fmt::Debug for SparseTrie {
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for SparseTrie {
|
||||
impl<P> Default for SparseTrie<P> {
|
||||
fn default() -> Self {
|
||||
Self::Blind
|
||||
}
|
||||
@@ -78,18 +78,18 @@ impl SparseTrie {
|
||||
masks: TrieMasks,
|
||||
retain_updates: bool,
|
||||
) -> SparseTrieResult<&mut RevealedSparseTrie> {
|
||||
self.reveal_root_with_provider(root, masks, retain_updates)
|
||||
self.reveal_root_with_provider(Default::default(), root, masks, retain_updates)
|
||||
}
|
||||
}
|
||||
|
||||
impl SparseTrie {
|
||||
impl<P> SparseTrie<P> {
|
||||
/// Returns `true` if the sparse trie has no revealed nodes.
|
||||
pub const fn is_blind(&self) -> bool {
|
||||
matches!(self, Self::Blind)
|
||||
}
|
||||
|
||||
/// Returns reference to revealed sparse trie if the trie is not blind.
|
||||
pub const fn as_revealed_ref(&self) -> Option<&RevealedSparseTrie> {
|
||||
pub const fn as_revealed_ref(&self) -> Option<&RevealedSparseTrie<P>> {
|
||||
if let Self::Revealed(revealed) = self {
|
||||
Some(revealed)
|
||||
} else {
|
||||
@@ -98,7 +98,7 @@ impl SparseTrie {
|
||||
}
|
||||
|
||||
/// Returns mutable reference to revealed sparse trie if the trie is not blind.
|
||||
pub fn as_revealed_mut(&mut self) -> Option<&mut RevealedSparseTrie> {
|
||||
pub fn as_revealed_mut(&mut self) -> Option<&mut RevealedSparseTrie<P>> {
|
||||
if let Self::Revealed(revealed) = self {
|
||||
Some(revealed)
|
||||
} else {
|
||||
@@ -113,12 +113,14 @@ impl SparseTrie {
|
||||
/// Mutable reference to [`RevealedSparseTrie`].
|
||||
pub fn reveal_root_with_provider(
|
||||
&mut self,
|
||||
provider: P,
|
||||
root: TrieNode,
|
||||
masks: TrieMasks,
|
||||
retain_updates: bool,
|
||||
) -> SparseTrieResult<&mut RevealedSparseTrie> {
|
||||
) -> SparseTrieResult<&mut RevealedSparseTrie<P>> {
|
||||
if self.is_blind() {
|
||||
*self = Self::Revealed(Box::new(RevealedSparseTrie::from_root_node(
|
||||
*self = Self::Revealed(Box::new(RevealedSparseTrie::from_provider_and_root(
|
||||
provider,
|
||||
root,
|
||||
masks,
|
||||
retain_updates,
|
||||
@@ -146,27 +148,18 @@ impl SparseTrie {
|
||||
}
|
||||
}
|
||||
|
||||
impl SparseTrie {
|
||||
impl<P: BlindedProvider> SparseTrie<P> {
|
||||
/// Update the leaf node.
|
||||
pub fn update_leaf<P: BlindedProvider>(
|
||||
&mut self,
|
||||
path: Nibbles,
|
||||
value: Vec<u8>,
|
||||
provider: &P,
|
||||
) -> SparseTrieResult<()> {
|
||||
pub fn update_leaf(&mut self, path: Nibbles, value: Vec<u8>) -> SparseTrieResult<()> {
|
||||
let revealed = self.as_revealed_mut().ok_or(SparseTrieErrorKind::Blind)?;
|
||||
revealed.update_leaf(path, value, provider)?;
|
||||
revealed.update_leaf(path, value)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Remove the leaf node.
|
||||
pub fn remove_leaf<P: BlindedProvider>(
|
||||
&mut self,
|
||||
path: &Nibbles,
|
||||
provider: &P,
|
||||
) -> SparseTrieResult<()> {
|
||||
pub fn remove_leaf(&mut self, path: &Nibbles) -> SparseTrieResult<()> {
|
||||
let revealed = self.as_revealed_mut().ok_or(SparseTrieErrorKind::Blind)?;
|
||||
revealed.remove_leaf(path, provider)?;
|
||||
revealed.remove_leaf(path)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -180,7 +173,9 @@ impl SparseTrie {
|
||||
/// The opposite is also true.
|
||||
/// - All keys in `values` collection are full leaf paths.
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub struct RevealedSparseTrie {
|
||||
pub struct RevealedSparseTrie<P = DefaultBlindedProvider> {
|
||||
/// Blinded node provider.
|
||||
provider: P,
|
||||
/// All trie nodes.
|
||||
nodes: HashMap<Nibbles, SparseNode>,
|
||||
/// All branch node tree masks.
|
||||
@@ -197,7 +192,7 @@ pub struct RevealedSparseTrie {
|
||||
rlp_buf: Vec<u8>,
|
||||
}
|
||||
|
||||
impl fmt::Debug for RevealedSparseTrie {
|
||||
impl<P> fmt::Debug for RevealedSparseTrie<P> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("RevealedSparseTrie")
|
||||
.field("nodes", &self.nodes)
|
||||
@@ -217,7 +212,7 @@ fn encode_nibbles(nibbles: &Nibbles) -> String {
|
||||
encoded[..nibbles.len()].to_string()
|
||||
}
|
||||
|
||||
impl fmt::Display for RevealedSparseTrie {
|
||||
impl<P: BlindedProvider> fmt::Display for RevealedSparseTrie<P> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
// This prints the trie in preorder traversal, using a stack
|
||||
let mut stack = Vec::new();
|
||||
@@ -286,6 +281,7 @@ impl fmt::Display for RevealedSparseTrie {
|
||||
impl Default for RevealedSparseTrie {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
provider: Default::default(),
|
||||
nodes: HashMap::from_iter([(Nibbles::default(), SparseNode::Empty)]),
|
||||
branch_node_tree_masks: HashMap::default(),
|
||||
branch_node_hash_masks: HashMap::default(),
|
||||
@@ -305,6 +301,7 @@ impl RevealedSparseTrie {
|
||||
retain_updates: bool,
|
||||
) -> SparseTrieResult<Self> {
|
||||
let mut this = Self {
|
||||
provider: Default::default(),
|
||||
nodes: HashMap::default(),
|
||||
branch_node_tree_masks: HashMap::default(),
|
||||
branch_node_hash_masks: HashMap::default(),
|
||||
@@ -319,14 +316,16 @@ impl RevealedSparseTrie {
|
||||
}
|
||||
}
|
||||
|
||||
impl RevealedSparseTrie {
|
||||
impl<P> RevealedSparseTrie<P> {
|
||||
/// Create new revealed sparse trie from the given root node.
|
||||
pub fn from_root_node(
|
||||
pub fn from_provider_and_root(
|
||||
provider: P,
|
||||
node: TrieNode,
|
||||
masks: TrieMasks,
|
||||
retain_updates: bool,
|
||||
) -> SparseTrieResult<Self> {
|
||||
let mut this = Self {
|
||||
provider,
|
||||
nodes: HashMap::default(),
|
||||
branch_node_tree_masks: HashMap::default(),
|
||||
branch_node_hash_masks: HashMap::default(),
|
||||
@@ -341,8 +340,17 @@ impl RevealedSparseTrie {
|
||||
}
|
||||
|
||||
/// Set new blinded node provider on sparse trie.
|
||||
pub fn with_provider(self) -> Self {
|
||||
self
|
||||
pub fn with_provider<BP>(self, provider: BP) -> RevealedSparseTrie<BP> {
|
||||
RevealedSparseTrie {
|
||||
provider,
|
||||
nodes: self.nodes,
|
||||
branch_node_tree_masks: self.branch_node_tree_masks,
|
||||
branch_node_hash_masks: self.branch_node_hash_masks,
|
||||
values: self.values,
|
||||
prefix_set: self.prefix_set,
|
||||
updates: self.updates,
|
||||
rlp_buf: self.rlp_buf,
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the retention of branch node updates and deletions.
|
||||
@@ -668,26 +676,10 @@ impl RevealedSparseTrie {
|
||||
path,
|
||||
is_in_prefix_set: Some(true),
|
||||
});
|
||||
|
||||
self.rlp_node_using_buf(&mut prefix_set, &mut buffers);
|
||||
self.rlp_node(&mut prefix_set, &mut buffers);
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper function to take out the rlp buffer while calling the `rlp_node` function.
|
||||
fn rlp_node_using_buf(
|
||||
&mut self,
|
||||
prefix_set: &mut PrefixSet,
|
||||
buffers: &mut RlpNodeBuffers,
|
||||
) -> RlpNode {
|
||||
// take rlp_buf out, so we can pass it to the function
|
||||
let mut rlp_buf = std::mem::take(&mut self.rlp_buf);
|
||||
let rlp_node = self.rlp_node(prefix_set, buffers, &mut rlp_buf);
|
||||
|
||||
// put the buf back
|
||||
self.rlp_buf = rlp_buf;
|
||||
rlp_node
|
||||
}
|
||||
|
||||
/// Returns a list of levels and paths to the nodes that were changed according to the prefix
|
||||
/// set and are located at the provided depth when counting from the root node. If there's a
|
||||
/// leaf at a depth less than the provided depth, it will be included in the result.
|
||||
@@ -752,15 +744,14 @@ impl RevealedSparseTrie {
|
||||
(targets, unchanged_prefix_set)
|
||||
}
|
||||
|
||||
/// Look up or calculate the RLP of the node at the root path. Allocates a new
|
||||
/// [`RlpNodeBuffers`] for the computation.
|
||||
/// Look up or calculate the RLP of the node at the root path.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// If the node at provided path does not exist.
|
||||
pub fn rlp_node_allocate(&mut self, prefix_set: &mut PrefixSet) -> RlpNode {
|
||||
let mut buffers = RlpNodeBuffers::new_with_root_path();
|
||||
self.rlp_node_using_buf(prefix_set, &mut buffers)
|
||||
self.rlp_node(prefix_set, &mut buffers)
|
||||
}
|
||||
|
||||
/// Look up or calculate the RLP of the node at the given path specified in [`RlpNodeBuffers`].
|
||||
@@ -772,7 +763,6 @@ impl RevealedSparseTrie {
|
||||
&mut self,
|
||||
prefix_set: &mut PrefixSet,
|
||||
buffers: &mut RlpNodeBuffers,
|
||||
rlp_buf: &mut Vec<u8>,
|
||||
) -> RlpNode {
|
||||
let starting_path = buffers.path_stack.last().map(|item| item.path.clone());
|
||||
|
||||
@@ -806,8 +796,8 @@ impl RevealedSparseTrie {
|
||||
(RlpNode::word_rlp(&hash), SparseNodeType::Leaf)
|
||||
} else {
|
||||
let value = self.values.get(&path).unwrap();
|
||||
rlp_buf.clear();
|
||||
let rlp_node = LeafNodeRef { key, value }.rlp(rlp_buf);
|
||||
self.rlp_buf.clear();
|
||||
let rlp_node = LeafNodeRef { key, value }.rlp(&mut self.rlp_buf);
|
||||
*hash = rlp_node.as_hash();
|
||||
(rlp_node, SparseNodeType::Leaf)
|
||||
}
|
||||
@@ -828,8 +818,8 @@ impl RevealedSparseTrie {
|
||||
rlp_node: child,
|
||||
node_type: child_node_type,
|
||||
} = buffers.rlp_node_stack.pop().unwrap();
|
||||
rlp_buf.clear();
|
||||
let rlp_node = ExtensionNodeRef::new(key, &child).rlp(rlp_buf);
|
||||
self.rlp_buf.clear();
|
||||
let rlp_node = ExtensionNodeRef::new(key, &child).rlp(&mut self.rlp_buf);
|
||||
*hash = rlp_node.as_hash();
|
||||
|
||||
let store_in_db_trie_value = child_node_type.store_in_db_trie();
|
||||
@@ -980,10 +970,10 @@ impl RevealedSparseTrie {
|
||||
"Branch node masks"
|
||||
);
|
||||
|
||||
rlp_buf.clear();
|
||||
self.rlp_buf.clear();
|
||||
let branch_node_ref =
|
||||
BranchNodeRef::new(&buffers.branch_value_stack_buf, *state_mask);
|
||||
let rlp_node = branch_node_ref.rlp(rlp_buf);
|
||||
let rlp_node = branch_node_ref.rlp(&mut self.rlp_buf);
|
||||
*hash = rlp_node.as_hash();
|
||||
|
||||
// Save a branch node update only if it's not a root node, and we need to
|
||||
@@ -1062,14 +1052,9 @@ impl RevealedSparseTrie {
|
||||
}
|
||||
}
|
||||
|
||||
impl RevealedSparseTrie {
|
||||
impl<P: BlindedProvider> RevealedSparseTrie<P> {
|
||||
/// Update the leaf node with provided value.
|
||||
pub fn update_leaf<P: BlindedProvider>(
|
||||
&mut self,
|
||||
path: Nibbles,
|
||||
value: Vec<u8>,
|
||||
provider: &P,
|
||||
) -> SparseTrieResult<()> {
|
||||
pub fn update_leaf(&mut self, path: Nibbles, value: Vec<u8>) -> SparseTrieResult<()> {
|
||||
self.prefix_set.insert(path.clone());
|
||||
let existing = self.values.insert(path.clone(), value);
|
||||
if existing.is_some() {
|
||||
@@ -1134,7 +1119,7 @@ impl RevealedSparseTrie {
|
||||
// Check if the extension node child is a hash that needs to be revealed
|
||||
if self.nodes.get(¤t).unwrap().is_hash() {
|
||||
if let Some(RevealedNode { node, tree_mask, hash_mask }) =
|
||||
provider.blinded_node(¤t)?
|
||||
self.provider.blinded_node(¤t)?
|
||||
{
|
||||
let decoded = TrieNode::decode(&mut &node[..])?;
|
||||
trace!(
|
||||
@@ -1190,11 +1175,7 @@ impl RevealedSparseTrie {
|
||||
}
|
||||
|
||||
/// Remove leaf node from the trie.
|
||||
pub fn remove_leaf<P: BlindedProvider>(
|
||||
&mut self,
|
||||
path: &Nibbles,
|
||||
provider: &P,
|
||||
) -> SparseTrieResult<()> {
|
||||
pub fn remove_leaf(&mut self, path: &Nibbles) -> SparseTrieResult<()> {
|
||||
if self.values.remove(path).is_none() {
|
||||
if let Some(&SparseNode::Hash(hash)) = self.nodes.get(path) {
|
||||
// Leaf is present in the trie, but it's blinded.
|
||||
@@ -1301,7 +1282,7 @@ impl RevealedSparseTrie {
|
||||
if self.nodes.get(&child_path).unwrap().is_hash() {
|
||||
trace!(target: "trie::sparse", ?child_path, "Retrieving remaining blinded branch child");
|
||||
if let Some(RevealedNode { node, tree_mask, hash_mask }) =
|
||||
provider.blinded_node(&child_path)?
|
||||
self.provider.blinded_node(&child_path)?
|
||||
{
|
||||
let decoded = TrieNode::decode(&mut &node[..])?;
|
||||
trace!(
|
||||
@@ -1594,8 +1575,6 @@ impl SparseTrieUpdates {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::blinded::DefaultBlindedProvider;
|
||||
|
||||
use super::*;
|
||||
use alloy_primitives::{map::B256Set, U256};
|
||||
use alloy_rlp::Encodable;
|
||||
@@ -1781,8 +1760,7 @@ mod tests {
|
||||
);
|
||||
|
||||
let mut sparse = RevealedSparseTrie::default().with_updates(true);
|
||||
let provider = DefaultBlindedProvider;
|
||||
sparse.update_leaf(key, value_encoded(), &provider).unwrap();
|
||||
sparse.update_leaf(key, value_encoded()).unwrap();
|
||||
let sparse_root = sparse.root();
|
||||
let sparse_updates = sparse.take_updates();
|
||||
|
||||
@@ -1812,9 +1790,8 @@ mod tests {
|
||||
);
|
||||
|
||||
let mut sparse = RevealedSparseTrie::default().with_updates(true);
|
||||
let provider = DefaultBlindedProvider;
|
||||
for path in &paths {
|
||||
sparse.update_leaf(path.clone(), value_encoded(), &provider).unwrap();
|
||||
sparse.update_leaf(path.clone(), value_encoded()).unwrap();
|
||||
}
|
||||
let sparse_root = sparse.root();
|
||||
let sparse_updates = sparse.take_updates();
|
||||
@@ -1843,9 +1820,8 @@ mod tests {
|
||||
);
|
||||
|
||||
let mut sparse = RevealedSparseTrie::default().with_updates(true);
|
||||
let provider = DefaultBlindedProvider;
|
||||
for path in &paths {
|
||||
sparse.update_leaf(path.clone(), value_encoded(), &provider).unwrap();
|
||||
sparse.update_leaf(path.clone(), value_encoded()).unwrap();
|
||||
}
|
||||
let sparse_root = sparse.root();
|
||||
let sparse_updates = sparse.take_updates();
|
||||
@@ -1882,9 +1858,8 @@ mod tests {
|
||||
);
|
||||
|
||||
let mut sparse = RevealedSparseTrie::default().with_updates(true);
|
||||
let provider = DefaultBlindedProvider;
|
||||
for path in &paths {
|
||||
sparse.update_leaf(path.clone(), value_encoded(), &provider).unwrap();
|
||||
sparse.update_leaf(path.clone(), value_encoded()).unwrap();
|
||||
}
|
||||
let sparse_root = sparse.root();
|
||||
let sparse_updates = sparse.take_updates();
|
||||
@@ -1922,9 +1897,8 @@ mod tests {
|
||||
);
|
||||
|
||||
let mut sparse = RevealedSparseTrie::default().with_updates(true);
|
||||
let provider = DefaultBlindedProvider;
|
||||
for path in &paths {
|
||||
sparse.update_leaf(path.clone(), old_value_encoded.clone(), &provider).unwrap();
|
||||
sparse.update_leaf(path.clone(), old_value_encoded.clone()).unwrap();
|
||||
}
|
||||
let sparse_root = sparse.root();
|
||||
let sparse_updates = sparse.updates_ref();
|
||||
@@ -1940,9 +1914,9 @@ mod tests {
|
||||
Default::default(),
|
||||
paths.clone(),
|
||||
);
|
||||
let provider = DefaultBlindedProvider;
|
||||
|
||||
for path in &paths {
|
||||
sparse.update_leaf(path.clone(), new_value_encoded.clone(), &provider).unwrap();
|
||||
sparse.update_leaf(path.clone(), new_value_encoded.clone()).unwrap();
|
||||
}
|
||||
let sparse_root = sparse.root();
|
||||
let sparse_updates = sparse.take_updates();
|
||||
@@ -1959,26 +1933,23 @@ mod tests {
|
||||
let mut sparse = RevealedSparseTrie::default();
|
||||
|
||||
let value = alloy_rlp::encode_fixed_size(&U256::ZERO).to_vec();
|
||||
let provider = DefaultBlindedProvider;
|
||||
|
||||
sparse
|
||||
.update_leaf(Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x1]), value.clone(), &provider)
|
||||
.update_leaf(Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x1]), value.clone())
|
||||
.unwrap();
|
||||
sparse
|
||||
.update_leaf(Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x3]), value.clone(), &provider)
|
||||
.update_leaf(Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x3]), value.clone())
|
||||
.unwrap();
|
||||
sparse
|
||||
.update_leaf(Nibbles::from_nibbles([0x5, 0x2, 0x0, 0x1, 0x3]), value.clone(), &provider)
|
||||
.update_leaf(Nibbles::from_nibbles([0x5, 0x2, 0x0, 0x1, 0x3]), value.clone())
|
||||
.unwrap();
|
||||
sparse
|
||||
.update_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x1, 0x0, 0x2]), value.clone(), &provider)
|
||||
.update_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x1, 0x0, 0x2]), value.clone())
|
||||
.unwrap();
|
||||
sparse
|
||||
.update_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x0, 0x2]), value.clone(), &provider)
|
||||
.unwrap();
|
||||
sparse
|
||||
.update_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x2, 0x0]), value, &provider)
|
||||
.update_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x0, 0x2]), value.clone())
|
||||
.unwrap();
|
||||
sparse.update_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x2, 0x0]), value).unwrap();
|
||||
|
||||
// Extension (Key = 5)
|
||||
// └── Branch (Mask = 1011)
|
||||
@@ -2034,7 +2005,7 @@ mod tests {
|
||||
])
|
||||
);
|
||||
|
||||
sparse.remove_leaf(&Nibbles::from_nibbles([0x5, 0x2, 0x0, 0x1, 0x3]), &provider).unwrap();
|
||||
sparse.remove_leaf(&Nibbles::from_nibbles([0x5, 0x2, 0x0, 0x1, 0x3])).unwrap();
|
||||
|
||||
// Extension (Key = 5)
|
||||
// └── Branch (Mask = 1001)
|
||||
@@ -2085,7 +2056,7 @@ mod tests {
|
||||
])
|
||||
);
|
||||
|
||||
sparse.remove_leaf(&Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x1]), &provider).unwrap();
|
||||
sparse.remove_leaf(&Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x1])).unwrap();
|
||||
|
||||
// Extension (Key = 5)
|
||||
// └── Branch (Mask = 1001)
|
||||
@@ -2121,7 +2092,7 @@ mod tests {
|
||||
])
|
||||
);
|
||||
|
||||
sparse.remove_leaf(&Nibbles::from_nibbles([0x5, 0x3, 0x1, 0x0, 0x2]), &provider).unwrap();
|
||||
sparse.remove_leaf(&Nibbles::from_nibbles([0x5, 0x3, 0x1, 0x0, 0x2])).unwrap();
|
||||
|
||||
// Extension (Key = 5)
|
||||
// └── Branch (Mask = 1001)
|
||||
@@ -2154,7 +2125,7 @@ mod tests {
|
||||
])
|
||||
);
|
||||
|
||||
sparse.remove_leaf(&Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x2, 0x0]), &provider).unwrap();
|
||||
sparse.remove_leaf(&Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x2, 0x0])).unwrap();
|
||||
|
||||
// Extension (Key = 5)
|
||||
// └── Branch (Mask = 1001)
|
||||
@@ -2176,7 +2147,7 @@ mod tests {
|
||||
])
|
||||
);
|
||||
|
||||
sparse.remove_leaf(&Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x3]), &provider).unwrap();
|
||||
sparse.remove_leaf(&Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x3])).unwrap();
|
||||
|
||||
// Leaf (Key = 53302)
|
||||
pretty_assertions::assert_eq!(
|
||||
@@ -2187,7 +2158,7 @@ mod tests {
|
||||
),])
|
||||
);
|
||||
|
||||
sparse.remove_leaf(&Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x0, 0x2]), &provider).unwrap();
|
||||
sparse.remove_leaf(&Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x0, 0x2])).unwrap();
|
||||
|
||||
// Empty
|
||||
pretty_assertions::assert_eq!(
|
||||
@@ -2235,7 +2206,7 @@ mod tests {
|
||||
|
||||
// Removing a blinded leaf should result in an error
|
||||
assert_matches!(
|
||||
sparse.remove_leaf(&Nibbles::from_nibbles([0x0]), &DefaultBlindedProvider).map_err(|e| e.into_kind()),
|
||||
sparse.remove_leaf(&Nibbles::from_nibbles([0x0])).map_err(|e| e.into_kind()),
|
||||
Err(SparseTrieErrorKind::BlindedNode { path, hash }) if path == Nibbles::from_nibbles([0x0]) && hash == B256::repeat_byte(1)
|
||||
);
|
||||
}
|
||||
@@ -2279,10 +2250,7 @@ mod tests {
|
||||
|
||||
// Removing a non-existent leaf should be a noop
|
||||
let sparse_old = sparse.clone();
|
||||
assert_matches!(
|
||||
sparse.remove_leaf(&Nibbles::from_nibbles([0x2]), &DefaultBlindedProvider),
|
||||
Ok(())
|
||||
);
|
||||
assert_matches!(sparse.remove_leaf(&Nibbles::from_nibbles([0x2])), Ok(()));
|
||||
assert_eq!(sparse, sparse_old);
|
||||
}
|
||||
|
||||
@@ -2306,7 +2274,7 @@ mod tests {
|
||||
let account = account.into_trie_account(EMPTY_ROOT_HASH);
|
||||
let mut account_rlp = Vec::new();
|
||||
account.encode(&mut account_rlp);
|
||||
sparse.update_leaf(key, account_rlp, &DefaultBlindedProvider).unwrap();
|
||||
sparse.update_leaf(key, account_rlp).unwrap();
|
||||
}
|
||||
// We need to clone the sparse trie, so that all updated branch nodes are
|
||||
// preserved, and not only those that were changed after the last call to
|
||||
@@ -2346,7 +2314,7 @@ mod tests {
|
||||
// that the sparse trie root still matches the hash builder root
|
||||
for key in &keys_to_delete {
|
||||
state.remove(key).unwrap();
|
||||
sparse.remove_leaf(key, &DefaultBlindedProvider).unwrap();
|
||||
sparse.remove_leaf(key).unwrap();
|
||||
}
|
||||
|
||||
// We need to clone the sparse trie, so that all updated branch nodes are
|
||||
@@ -2492,7 +2460,7 @@ mod tests {
|
||||
);
|
||||
|
||||
// Insert the leaf for the second key
|
||||
sparse.update_leaf(key2(), value_encoded(), &DefaultBlindedProvider).unwrap();
|
||||
sparse.update_leaf(key2(), value_encoded()).unwrap();
|
||||
|
||||
// Check that the branch node was updated and another nibble was set
|
||||
assert_eq!(
|
||||
@@ -2601,7 +2569,7 @@ mod tests {
|
||||
);
|
||||
|
||||
// Remove the leaf for the first key
|
||||
sparse.remove_leaf(&key1(), &DefaultBlindedProvider).unwrap();
|
||||
sparse.remove_leaf(&key1()).unwrap();
|
||||
|
||||
// Check that the branch node was turned into an extension node
|
||||
assert_eq!(
|
||||
@@ -2681,7 +2649,7 @@ mod tests {
|
||||
);
|
||||
|
||||
// Insert the leaf with a different prefix
|
||||
sparse.update_leaf(key3(), value_encoded(), &DefaultBlindedProvider).unwrap();
|
||||
sparse.update_leaf(key3(), value_encoded()).unwrap();
|
||||
|
||||
// Check that the extension node was turned into a branch node
|
||||
assert_matches!(
|
||||
@@ -2721,7 +2689,6 @@ mod tests {
|
||||
let mut sparse = RevealedSparseTrie::default();
|
||||
|
||||
let value = alloy_rlp::encode_fixed_size(&U256::ZERO).to_vec();
|
||||
let provider = DefaultBlindedProvider;
|
||||
|
||||
// Extension (Key = 5) – Level 0
|
||||
// └── Branch (Mask = 1011) – Level 1
|
||||
@@ -2736,23 +2703,21 @@ mod tests {
|
||||
// ├── 0 -> Leaf (Key = 3302, Path = 53302) – Level 4
|
||||
// └── 2 -> Leaf (Key = 3320, Path = 53320) – Level 4
|
||||
sparse
|
||||
.update_leaf(Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x1]), value.clone(), &provider)
|
||||
.update_leaf(Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x1]), value.clone())
|
||||
.unwrap();
|
||||
sparse
|
||||
.update_leaf(Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x3]), value.clone(), &provider)
|
||||
.update_leaf(Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x3]), value.clone())
|
||||
.unwrap();
|
||||
sparse
|
||||
.update_leaf(Nibbles::from_nibbles([0x5, 0x2, 0x0, 0x1, 0x3]), value.clone(), &provider)
|
||||
.update_leaf(Nibbles::from_nibbles([0x5, 0x2, 0x0, 0x1, 0x3]), value.clone())
|
||||
.unwrap();
|
||||
sparse
|
||||
.update_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x1, 0x0, 0x2]), value.clone(), &provider)
|
||||
.update_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x1, 0x0, 0x2]), value.clone())
|
||||
.unwrap();
|
||||
sparse
|
||||
.update_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x0, 0x2]), value.clone(), &provider)
|
||||
.unwrap();
|
||||
sparse
|
||||
.update_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x2, 0x0]), value, &provider)
|
||||
.update_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x0, 0x2]), value.clone())
|
||||
.unwrap();
|
||||
sparse.update_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x2, 0x0]), value).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
sparse.get_changed_nodes_at_depth(&mut PrefixSet::default(), 0),
|
||||
@@ -2833,9 +2798,8 @@ mod tests {
|
||||
[Nibbles::default()],
|
||||
);
|
||||
let mut sparse = RevealedSparseTrie::default();
|
||||
let provider = DefaultBlindedProvider;
|
||||
sparse.update_leaf(key1(), value_encoded(), &provider).unwrap();
|
||||
sparse.update_leaf(key2(), value_encoded(), &provider).unwrap();
|
||||
sparse.update_leaf(key1(), value_encoded()).unwrap();
|
||||
sparse.update_leaf(key2(), value_encoded()).unwrap();
|
||||
let sparse_root = sparse.root();
|
||||
let sparse_updates = sparse.take_updates();
|
||||
|
||||
@@ -2848,7 +2812,6 @@ mod tests {
|
||||
let mut sparse = RevealedSparseTrie::default().with_updates(true);
|
||||
|
||||
let value = alloy_rlp::encode_fixed_size(&U256::ZERO).to_vec();
|
||||
let provider = DefaultBlindedProvider;
|
||||
|
||||
// Extension (Key = 5) – Level 0
|
||||
// └── Branch (Mask = 1011) – Level 1
|
||||
@@ -2863,23 +2826,21 @@ mod tests {
|
||||
// ├── 0 -> Leaf (Key = 3302, Path = 53302) – Level 4
|
||||
// └── 2 -> Leaf (Key = 3320, Path = 53320) – Level 4
|
||||
sparse
|
||||
.update_leaf(Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x1]), value.clone(), &provider)
|
||||
.update_leaf(Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x1]), value.clone())
|
||||
.unwrap();
|
||||
sparse
|
||||
.update_leaf(Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x3]), value.clone(), &provider)
|
||||
.update_leaf(Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x3]), value.clone())
|
||||
.unwrap();
|
||||
sparse
|
||||
.update_leaf(Nibbles::from_nibbles([0x5, 0x2, 0x0, 0x1, 0x3]), value.clone(), &provider)
|
||||
.update_leaf(Nibbles::from_nibbles([0x5, 0x2, 0x0, 0x1, 0x3]), value.clone())
|
||||
.unwrap();
|
||||
sparse
|
||||
.update_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x1, 0x0, 0x2]), value.clone(), &provider)
|
||||
.update_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x1, 0x0, 0x2]), value.clone())
|
||||
.unwrap();
|
||||
sparse
|
||||
.update_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x0, 0x2]), value.clone(), &provider)
|
||||
.unwrap();
|
||||
sparse
|
||||
.update_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x2, 0x0]), value, &provider)
|
||||
.update_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x0, 0x2]), value.clone())
|
||||
.unwrap();
|
||||
sparse.update_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x2, 0x0]), value).unwrap();
|
||||
|
||||
sparse.wipe();
|
||||
|
||||
@@ -2891,7 +2852,6 @@ mod tests {
|
||||
let mut sparse = RevealedSparseTrie::default();
|
||||
|
||||
let value = alloy_rlp::encode_fixed_size(&U256::ZERO).to_vec();
|
||||
let provider = DefaultBlindedProvider;
|
||||
|
||||
// Extension (Key = 5) – Level 0
|
||||
// └── Branch (Mask = 1011) – Level 1
|
||||
@@ -2906,23 +2866,21 @@ mod tests {
|
||||
// ├── 0 -> Leaf (Key = 3302, Path = 53302) – Level 4
|
||||
// └── 2 -> Leaf (Key = 3320, Path = 53320) – Level 4
|
||||
sparse
|
||||
.update_leaf(Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x1]), value.clone(), &provider)
|
||||
.update_leaf(Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x1]), value.clone())
|
||||
.unwrap();
|
||||
sparse
|
||||
.update_leaf(Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x3]), value.clone(), &provider)
|
||||
.update_leaf(Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x3]), value.clone())
|
||||
.unwrap();
|
||||
sparse
|
||||
.update_leaf(Nibbles::from_nibbles([0x5, 0x2, 0x0, 0x1, 0x3]), value.clone(), &provider)
|
||||
.update_leaf(Nibbles::from_nibbles([0x5, 0x2, 0x0, 0x1, 0x3]), value.clone())
|
||||
.unwrap();
|
||||
sparse
|
||||
.update_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x1, 0x0, 0x2]), value.clone(), &provider)
|
||||
.update_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x1, 0x0, 0x2]), value.clone())
|
||||
.unwrap();
|
||||
sparse
|
||||
.update_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x0, 0x2]), value.clone(), &provider)
|
||||
.unwrap();
|
||||
sparse
|
||||
.update_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x2, 0x0]), value, &provider)
|
||||
.update_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x0, 0x2]), value.clone())
|
||||
.unwrap();
|
||||
sparse.update_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x2, 0x0]), value).unwrap();
|
||||
|
||||
let normal_printed = format!("{sparse}");
|
||||
let expected = "\
|
||||
|
||||
@@ -117,7 +117,7 @@ where
|
||||
),
|
||||
tx,
|
||||
);
|
||||
let mut sparse_trie = SparseStateTrie::default();
|
||||
let mut sparse_trie = SparseStateTrie::new(blinded_provider_factory);
|
||||
sparse_trie.reveal_multiproof(multiproof)?;
|
||||
|
||||
// Attempt to update state trie to gather additional information for the witness.
|
||||
@@ -132,7 +132,6 @@ where
|
||||
SparseTrieErrorKind::Blind,
|
||||
),
|
||||
)?;
|
||||
let provider = blinded_provider_factory.storage_node_provider(hashed_address);
|
||||
for hashed_slot in hashed_slots.into_iter().sorted_unstable() {
|
||||
let storage_nibbles = Nibbles::unpack(hashed_slot);
|
||||
let maybe_leaf_value = storage
|
||||
@@ -141,11 +140,11 @@ where
|
||||
.map(|v| alloy_rlp::encode_fixed_size(v).to_vec());
|
||||
|
||||
if let Some(value) = maybe_leaf_value {
|
||||
storage_trie.update_leaf(storage_nibbles, value, &provider).map_err(|err| {
|
||||
storage_trie.update_leaf(storage_nibbles, value).map_err(|err| {
|
||||
SparseStateTrieErrorKind::SparseStorageTrie(hashed_address, err.into_kind())
|
||||
})?;
|
||||
} else {
|
||||
storage_trie.remove_leaf(&storage_nibbles, &provider).map_err(|err| {
|
||||
storage_trie.remove_leaf(&storage_nibbles).map_err(|err| {
|
||||
SparseStateTrieErrorKind::SparseStorageTrie(hashed_address, err.into_kind())
|
||||
})?;
|
||||
}
|
||||
@@ -159,7 +158,7 @@ where
|
||||
.get(&hashed_address)
|
||||
.ok_or(TrieWitnessError::MissingAccount(hashed_address))?
|
||||
.unwrap_or_default();
|
||||
sparse_trie.update_account(hashed_address, account, &blinded_provider_factory)?;
|
||||
sparse_trie.update_account(hashed_address, account)?;
|
||||
|
||||
while let Ok(node) = rx.try_recv() {
|
||||
self.witness.insert(keccak256(&node), node);
|
||||
|
||||
Reference in New Issue
Block a user