refactor(trie): initialize sparse trie with the provider (#15199)

This commit is contained in:
Alexey Shekhirin
2025-03-21 15:36:21 +00:00
committed by GitHub
parent 664250946f
commit 20a6a85148
9 changed files with 215 additions and 273 deletions

1
Cargo.lock generated
View File

@@ -10056,6 +10056,7 @@ dependencies = [
"alloy-rlp",
"arbitrary",
"assert_matches",
"auto_impl",
"codspeed-criterion-compat",
"itertools 0.14.0",
"metrics",

View File

@@ -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();

View File

@@ -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

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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>;

View File

@@ -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

View File

@@ -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(&current).unwrap().is_hash() {
if let Some(RevealedNode { node, tree_mask, hash_mask }) =
provider.blinded_node(&current)?
self.provider.blinded_node(&current)?
{
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 = "\

View File

@@ -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);