Compare commits

...

1 Commits

Author SHA1 Message Date
Georgios Konstantopoulos
1570119301 perf(trie): reduce allocations in sparse trie hot paths
- Change update_leaf / update_account_leaf / update_storage_leaf to
  accept `&[u8]` instead of `Vec<u8>`, eliminating unnecessary clones
  at call sites (e.g. account_rlp_buf.clone()).
- Add `hashes_buf: Vec<B256>` to `RlpNodeBuffers` so branch node hash
  collection reuses the same buffer across iterations instead of
  allocating a new Vec per branch node in the RLP encoding hot loop.

Co-authored-by: yk <yongkangc@users.noreply.github.com>
Amp-Thread-ID: https://ampcode.com/threads/T-019c3632-da9f-724f-a496-5b3a46414107
Co-authored-by: Amp <amp@ampcode.com>
2026-02-07 04:05:43 +00:00
9 changed files with 106 additions and 97 deletions

View File

@@ -936,7 +936,7 @@ where
trace!(target: "engine::tree::payload_processor::sparse_trie", ?slot_nibbles, "Updating storage slot");
storage_trie.update_leaf(
slot_nibbles,
alloy_rlp::encode_fixed_size(&value).to_vec(),
&alloy_rlp::encode_fixed_size(&value),
&storage_provider,
)?;
}

View File

@@ -261,7 +261,7 @@ fn calculate_state_root(
} else {
storage_trie.update_leaf(
nibbles,
alloy_rlp::encode_fixed_size(&value).to_vec(),
&alloy_rlp::encode_fixed_size(&value),
&storage_provider,
)?;
}
@@ -300,7 +300,7 @@ fn calculate_state_root(
if let Some(account) = account {
account_rlp_buf.clear();
account.into_trie_account(storage_root).encode(&mut account_rlp_buf);
trie.update_account_leaf(nibbles, account_rlp_buf.clone(), &provider_factory)?;
trie.update_account_leaf(nibbles, &account_rlp_buf, &provider_factory)?;
} else {
trie.remove_account_leaf(&nibbles, &provider_factory)?;
}

View File

@@ -323,13 +323,13 @@ impl SparseTrie for ParallelSparseTrie {
fn update_leaf<P: TrieNodeProvider>(
&mut self,
full_path: Nibbles,
value: Vec<u8>,
value: &[u8],
provider: P,
) -> SparseTrieResult<()> {
// Check if the value already exists - if so, just update it (no structural changes needed)
if self.upper_subtrie.inner.values.contains_key(&full_path) {
self.prefix_set.insert(full_path);
self.upper_subtrie.inner.values.insert(full_path, value);
self.upper_subtrie.inner.values.insert(full_path, value.to_vec());
return Ok(());
}
// Also check lower subtries for existing value
@@ -341,7 +341,7 @@ impl SparseTrie for ParallelSparseTrie {
.expect("subtrie exists")
.inner
.values
.insert(full_path, value);
.insert(full_path, value.to_vec());
return Ok(());
}
@@ -349,7 +349,7 @@ impl SparseTrie for ParallelSparseTrie {
// Insert value into upper subtrie temporarily. We'll move it to the correct subtrie
// during traversal, or clean it up if we error.
self.upper_subtrie.inner.values.insert(full_path, value.clone());
self.upper_subtrie.inner.values.insert(full_path, value.to_vec());
// Start at the root, traversing until we find either the node to update or a subtrie to
// update.
@@ -1281,8 +1281,7 @@ impl SparseTrieExt for ParallelSparseTrie {
}
} else {
// Update/insert: update_leaf is atomic - cleans up on error.
if let Err(e) = self.update_leaf(full_path, value.clone(), NoRevealProvider)
{
if let Err(e) = self.update_leaf(full_path, &value, NoRevealProvider) {
if let Some(path) = Self::get_retriable_path(&e) {
let (target_key, min_len) =
Self::proof_target_for_path(key, &full_path, &path);
@@ -2414,7 +2413,7 @@ impl SparseSubtrie {
pub fn update_leaf(
&mut self,
full_path: Nibbles,
value: Vec<u8>,
value: &[u8],
provider: impl TrieNodeProvider,
retain_updates: bool,
) -> SparseTrieResult<Option<(Nibbles, BranchNodeMasks)>> {
@@ -2422,7 +2421,7 @@ impl SparseSubtrie {
// Check if value already exists - if so, just update it (no structural changes needed)
if let Entry::Occupied(mut e) = self.inner.values.entry(full_path) {
e.insert(value);
e.insert(value.to_vec());
return Ok(None)
}
@@ -2536,7 +2535,7 @@ impl SparseSubtrie {
}
// Only insert the value after all structural changes succeed
self.inner.values.insert(full_path, value);
self.inner.values.insert(full_path, value.to_vec());
Ok(revealed)
}
@@ -3693,7 +3692,7 @@ mod tests {
leaves: impl IntoIterator<Item = (Nibbles, Vec<u8>)>,
) {
for (path, value) in leaves {
trie.update_leaf(path, value, DefaultTrieNodeProvider).unwrap();
trie.update_leaf(path, &value, DefaultTrieNodeProvider).unwrap();
}
}
@@ -4419,7 +4418,7 @@ mod tests {
// Insert leaf_3 via update_leaf. This modifies the branch at [0x0] to add child
// 0x2 and creates a fresh leaf node with hash: None in the lower subtrie.
let provider = MockTrieNodeProvider::new();
trie.update_leaf(leaf_3_full_path, encode_account_value(3), provider).unwrap();
trie.update_leaf(leaf_3_full_path, &encode_account_value(3), provider).unwrap();
// Calculate subtrie indexes
let subtrie_1_index = SparseSubtrieType::from_path(&leaf_1_path).lower_index().unwrap();
@@ -5477,7 +5476,7 @@ mod tests {
let provider = DefaultTrieNodeProvider;
let mut sparse = ParallelSparseTrie::default().with_updates(true);
for path in &paths {
sparse.update_leaf(*path, value_encoded(), &provider).unwrap();
sparse.update_leaf(*path, &value_encoded(), &provider).unwrap();
}
let sparse_root = sparse.root();
let sparse_updates = sparse.take_updates();
@@ -5972,7 +5971,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, &default_provider).unwrap();
sparse.update_leaf(key, &account_rlp, &default_provider).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
@@ -6121,8 +6120,8 @@ mod tests {
let account = account.into_trie_account(EMPTY_ROOT_HASH);
let mut account_rlp = Vec::new();
account.encode(&mut account_rlp);
serial.update_leaf(key, account_rlp.clone(), &default_provider).unwrap();
parallel.update_leaf(key, account_rlp, &default_provider).unwrap();
serial.update_leaf(key, &account_rlp, &default_provider).unwrap();
parallel.update_leaf(key, &account_rlp, &default_provider).unwrap();
}
// Calculate roots and assert their equality
@@ -6221,11 +6220,11 @@ mod tests {
account.encode(&mut account_rlp);
// Add a leaf and calculate the root.
trie.update_leaf(key_50, account_rlp.clone(), &provider).unwrap();
trie.update_leaf(key_50, &account_rlp, &provider).unwrap();
trie.root();
// Add a second leaf and assert that the root is the expected value.
trie.update_leaf(key_51, account_rlp.clone(), &provider).unwrap();
trie.update_leaf(key_51, &account_rlp, &provider).unwrap();
let expected_root =
hex!("0xdaf0ef9f91a2f179bb74501209effdb5301db1697bcab041eca2234b126e25de");

View File

@@ -26,11 +26,7 @@ fn update_rlp_node_level(c: &mut Criterion) {
let mut sparse = SerialSparseTrie::default();
for (key, value) in &state {
sparse
.update_leaf(
Nibbles::unpack(key),
alloy_rlp::encode_fixed_size(value).to_vec(),
&provider,
)
.update_leaf(Nibbles::unpack(key), &alloy_rlp::encode_fixed_size(value), &provider)
.unwrap();
}
sparse.root();
@@ -43,7 +39,7 @@ fn update_rlp_node_level(c: &mut Criterion) {
sparse
.update_leaf(
Nibbles::unpack(key),
alloy_rlp::encode_fixed_size(&rng.random::<U256>()).to_vec(),
&alloy_rlp::encode_fixed_size(&rng.random::<U256>()),
&provider,
)
.unwrap();

View File

@@ -49,7 +49,7 @@ fn calculate_root_from_leaves(c: &mut Criterion) {
sparse
.update_leaf(
Nibbles::unpack(key),
alloy_rlp::encode_fixed_size(value).to_vec(),
&alloy_rlp::encode_fixed_size(value),
&provider,
)
.unwrap();
@@ -215,7 +215,7 @@ fn calculate_root_from_leaves_repeated(c: &mut Criterion) {
sparse
.update_leaf(
Nibbles::unpack(key),
alloy_rlp::encode_fixed_size(value).to_vec(),
&alloy_rlp::encode_fixed_size(value),
&provider,
)
.unwrap();
@@ -229,7 +229,7 @@ fn calculate_root_from_leaves_repeated(c: &mut Criterion) {
sparse
.update_leaf(
Nibbles::unpack(key),
alloy_rlp::encode_fixed_size(value).to_vec(),
&alloy_rlp::encode_fixed_size(value),
&provider,
)
.unwrap();

View File

@@ -943,7 +943,7 @@ where
pub fn update_account_leaf(
&mut self,
path: Nibbles,
value: Vec<u8>,
value: &[u8],
provider_factory: impl TrieNodeProviderFactory,
) -> SparseStateTrieResult<()> {
if !self.revealed_account_paths.contains(&path) {
@@ -960,7 +960,7 @@ where
&mut self,
address: B256,
slot: Nibbles,
value: Vec<u8>,
value: &[u8],
provider_factory: impl TrieNodeProviderFactory,
) -> SparseStateTrieResult<()> {
let provider = provider_factory.storage_node_provider(address);
@@ -1010,7 +1010,10 @@ where
let nibbles = Nibbles::unpack(address);
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)?;
let value = core::mem::take(&mut self.account_rlp_buf);
let result = self.update_account_leaf(nibbles, &value, provider_factory);
self.account_rlp_buf = value;
result?;
Ok(true)
}
@@ -1063,7 +1066,10 @@ where
let nibbles = Nibbles::unpack(address);
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)?;
let value = core::mem::take(&mut self.account_rlp_buf);
let result = self.update_account_leaf(nibbles, &value, provider_factory);
self.account_rlp_buf = value;
result?;
Ok(true)
}
@@ -2084,7 +2090,7 @@ mod tests {
sparse
.update_account_leaf(
address_path_3,
alloy_rlp::encode(trie_account_3),
&alloy_rlp::encode(trie_account_3),
&provider_factory,
)
.unwrap();
@@ -2093,7 +2099,7 @@ mod tests {
.update_storage_leaf(
address_1,
slot_path_3,
alloy_rlp::encode(value_3),
&alloy_rlp::encode(value_3),
&provider_factory,
)
.unwrap();
@@ -2101,7 +2107,7 @@ mod tests {
sparse
.update_account_leaf(
address_path_1,
alloy_rlp::encode(trie_account_1),
&alloy_rlp::encode(trie_account_1),
&provider_factory,
)
.unwrap();
@@ -2111,7 +2117,7 @@ mod tests {
sparse
.update_account_leaf(
address_path_2,
alloy_rlp::encode(trie_account_2),
&alloy_rlp::encode(trie_account_2),
&provider_factory,
)
.unwrap();

View File

@@ -155,7 +155,7 @@ pub trait SparseTrie: Sized + Debug + Send + Sync {
fn update_leaf<P: TrieNodeProvider>(
&mut self,
full_path: Nibbles,
value: Vec<u8>,
value: &[u8],
provider: P,
) -> SparseTrieResult<()>;

View File

@@ -241,7 +241,7 @@ impl<T: SparseTrieTrait> RevealableSparseTrie<T> {
pub fn update_leaf(
&mut self,
path: Nibbles,
value: Vec<u8>,
value: &[u8],
provider: impl TrieNodeProvider,
) -> SparseTrieResult<()> {
let revealed = self.as_revealed_mut().ok_or(SparseTrieErrorKind::Blind)?;
@@ -635,11 +635,11 @@ impl SparseTrieTrait for SerialSparseTrie {
fn update_leaf<P: TrieNodeProvider>(
&mut self,
full_path: Nibbles,
value: Vec<u8>,
value: &[u8],
provider: P,
) -> SparseTrieResult<()> {
self.prefix_set.insert(full_path);
let existing = self.values.insert(full_path, value);
let existing = self.values.insert(full_path, value.to_vec());
if existing.is_some() {
// trie structure unchanged, return immediately
return Ok(())
@@ -1670,7 +1670,7 @@ impl SerialSparseTrie {
let mut tree_mask = TrieMask::default();
let mut hash_mask = TrieMask::default();
let mut hashes = Vec::new();
buffers.hashes_buf.clear();
// Lazy lookup for branch node masks - shared across loop iterations
let mut path_masks_storage = None;
@@ -1721,7 +1721,7 @@ impl SerialSparseTrie {
});
if let Some(hash) = hash {
hash_mask.set_bit(last_child_nibble);
hashes.push(hash);
buffers.hashes_buf.push(hash);
}
}
@@ -1772,12 +1772,12 @@ impl SerialSparseTrie {
if store_in_db_trie {
// Store in DB trie if there are either any children that are stored in
// the DB trie, or any children represent hashed values
hashes.reverse();
buffers.hashes_buf.reverse();
let branch_node = BranchNodeCompact::new(
*state_mask,
tree_mask,
hash_mask,
hashes,
buffers.hashes_buf.clone(),
hash.filter(|_| path.is_empty()),
);
updates.updated_nodes.insert(path, branch_node);
@@ -2024,6 +2024,8 @@ pub struct RlpNodeBuffers {
branch_child_buf: Vec<Nibbles>,
/// Reusable branch value stack
branch_value_stack_buf: Vec<RlpNode>,
/// Reusable buffer for collecting branch node child hashes during updates
hashes_buf: Vec<B256>,
}
impl RlpNodeBuffers {
@@ -2038,6 +2040,7 @@ impl RlpNodeBuffers {
rlp_node_stack: Vec::new(),
branch_child_buf: Vec::new(),
branch_value_stack_buf: Vec::new(),
hashes_buf: Vec::new(),
}
}
}
@@ -2116,7 +2119,7 @@ mod find_leaf_tests {
let path = Nibbles::from_nibbles([0x1, 0x2, 0x3]);
let value = b"test_value".to_vec();
sparse.update_leaf(path, value.clone(), &provider).unwrap();
sparse.update_leaf(path, &value, &provider).unwrap();
// Check that the leaf exists
let result = sparse.find_leaf(&path, None);
@@ -2136,7 +2139,7 @@ mod find_leaf_tests {
let value = b"test_value".to_vec();
let wrong_value = b"wrong_value".to_vec();
sparse.update_leaf(path, value, &provider).unwrap();
sparse.update_leaf(path, &value, &provider).unwrap();
// Check with wrong expected value
let result = sparse.find_leaf(&path, Some(&wrong_value));
@@ -2171,7 +2174,7 @@ mod find_leaf_tests {
let provider = DefaultTrieNodeProvider;
let mut sparse = SerialSparseTrie::default();
let path = Nibbles::from_nibbles_unchecked([0x1, 0x2, 0x3, 0x4]);
sparse.update_leaf(path, VALUE_A(), &provider).unwrap();
sparse.update_leaf(path, &VALUE_A(), &provider).unwrap();
let result = sparse.find_leaf(&path, None);
assert_matches!(result, Ok(LeafLookup::Exists));
@@ -2183,7 +2186,7 @@ mod find_leaf_tests {
let mut sparse = SerialSparseTrie::default();
let path = Nibbles::from_nibbles_unchecked([0x1, 0x2, 0x3, 0x4]);
let value = VALUE_A();
sparse.update_leaf(path, value.clone(), &provider).unwrap();
sparse.update_leaf(path, &value, &provider).unwrap();
let result = sparse.find_leaf(&path, Some(&value));
assert_matches!(result, Ok(LeafLookup::Exists));
@@ -2197,8 +2200,8 @@ mod find_leaf_tests {
let path2 = Nibbles::from_nibbles_unchecked([0x1, 0x2, 0x5, 0x6]); // Belongs to same branch
let search_path = Nibbles::from_nibbles_unchecked([0x1, 0x2, 0x7, 0x8]); // Diverges at nibble 7
sparse.update_leaf(path1, VALUE_A(), &provider).unwrap();
sparse.update_leaf(path2, VALUE_B(), &provider).unwrap();
sparse.update_leaf(path1, &VALUE_A(), &provider).unwrap();
sparse.update_leaf(path2, &VALUE_B(), &provider).unwrap();
let result = sparse.find_leaf(&search_path, None);
assert_matches!(result, Ok(LeafLookup::NonExistent));
@@ -2213,7 +2216,7 @@ mod find_leaf_tests {
// This path diverges from the extension key
let search_path = Nibbles::from_nibbles_unchecked([0x1, 0x2, 0x7, 0x8]);
sparse.update_leaf(path1, VALUE_A(), &provider).unwrap();
sparse.update_leaf(path1, &VALUE_A(), &provider).unwrap();
let result = sparse.find_leaf(&search_path, None);
assert_matches!(result, Ok(LeafLookup::NonExistent));
@@ -2226,7 +2229,7 @@ mod find_leaf_tests {
let existing_leaf_path = Nibbles::from_nibbles_unchecked([0x1, 0x2, 0x3, 0x4]);
let search_path = Nibbles::from_nibbles_unchecked([0x1, 0x2, 0x3, 0x4, 0x5, 0x6]);
sparse.update_leaf(existing_leaf_path, VALUE_A(), &provider).unwrap();
sparse.update_leaf(existing_leaf_path, &VALUE_A(), &provider).unwrap();
let result = sparse.find_leaf(&search_path, None);
assert_matches!(result, Ok(LeafLookup::NonExistent));
@@ -2240,8 +2243,8 @@ mod find_leaf_tests {
let path2 = Nibbles::from_nibbles_unchecked([0x1, 0x2, 0x5, 0x6]);
let search_path = Nibbles::from_nibbles_unchecked([0x1, 0x2]); // Path of the branch itself
sparse.update_leaf(path1, VALUE_A(), &provider).unwrap();
sparse.update_leaf(path2, VALUE_B(), &provider).unwrap();
sparse.update_leaf(path1, &VALUE_A(), &provider).unwrap();
sparse.update_leaf(path2, &VALUE_B(), &provider).unwrap();
let result = sparse.find_leaf(&search_path, None);
assert_matches!(result, Ok(LeafLookup::NonExistent));
@@ -2574,7 +2577,7 @@ mod tests {
let provider = DefaultTrieNodeProvider;
let mut sparse = SerialSparseTrie::default().with_updates(true);
sparse.update_leaf(key, value_encoded(), &provider).unwrap();
sparse.update_leaf(key, &value_encoded(), &provider).unwrap();
let sparse_root = sparse.root();
let sparse_updates = sparse.take_updates();
@@ -2606,7 +2609,7 @@ mod tests {
let provider = DefaultTrieNodeProvider;
let mut sparse = SerialSparseTrie::default().with_updates(true);
for path in &paths {
sparse.update_leaf(*path, value_encoded(), &provider).unwrap();
sparse.update_leaf(*path, &value_encoded(), &provider).unwrap();
}
let sparse_root = sparse.root();
let sparse_updates = sparse.take_updates();
@@ -2637,7 +2640,7 @@ mod tests {
let provider = DefaultTrieNodeProvider;
let mut sparse = SerialSparseTrie::default().with_updates(true);
for path in &paths {
sparse.update_leaf(*path, value_encoded(), &provider).unwrap();
sparse.update_leaf(*path, &value_encoded(), &provider).unwrap();
}
let sparse_root = sparse.root();
let sparse_updates = sparse.take_updates();
@@ -2676,7 +2679,7 @@ mod tests {
let provider = DefaultTrieNodeProvider;
let mut sparse = SerialSparseTrie::default().with_updates(true);
for path in &paths {
sparse.update_leaf(*path, value_encoded(), &provider).unwrap();
sparse.update_leaf(*path, &value_encoded(), &provider).unwrap();
}
let sparse_root = sparse.root();
let sparse_updates = sparse.take_updates();
@@ -2716,7 +2719,7 @@ mod tests {
let provider = DefaultTrieNodeProvider;
let mut sparse = SerialSparseTrie::default().with_updates(true);
for path in &paths {
sparse.update_leaf(*path, old_value_encoded.clone(), &provider).unwrap();
sparse.update_leaf(*path, &old_value_encoded, &provider).unwrap();
}
let sparse_root = sparse.root();
let sparse_updates = sparse.updates_ref();
@@ -2734,7 +2737,7 @@ mod tests {
);
for path in &paths {
sparse.update_leaf(*path, new_value_encoded.clone(), &provider).unwrap();
sparse.update_leaf(*path, &new_value_encoded, &provider).unwrap();
}
let sparse_root = sparse.root();
let sparse_updates = sparse.take_updates();
@@ -2754,22 +2757,22 @@ mod tests {
let value = alloy_rlp::encode_fixed_size(&U256::ZERO).to_vec();
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, &provider)
.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, &provider)
.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, &provider)
.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, &provider)
.unwrap();
sparse
.update_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x0, 0x2]), value.clone(), &provider)
.update_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x0, 0x2]), &value, &provider)
.unwrap();
sparse
.update_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x2, 0x0]), value, &provider)
.update_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x2, 0x0]), &value, &provider)
.unwrap();
// Extension (Key = 5)
@@ -3105,7 +3108,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, &default_provider).unwrap();
sparse.update_leaf(key, &account_rlp, &default_provider).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
@@ -3296,7 +3299,7 @@ mod tests {
);
// Insert the leaf for the second key
sparse.update_leaf(key2(), value_encoded(), &provider).unwrap();
sparse.update_leaf(key2(), &value_encoded(), &provider).unwrap();
// Check that the branch node was updated and another nibble was set
assert_eq!(
@@ -3476,7 +3479,7 @@ mod tests {
);
// Insert the leaf with a different prefix
sparse.update_leaf(key3(), value_encoded(), &provider).unwrap();
sparse.update_leaf(key3(), &value_encoded(), &provider).unwrap();
// Check that the extension node was turned into a branch node
assert_matches!(
@@ -3526,22 +3529,22 @@ 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, &provider)
.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, &provider)
.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, &provider)
.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, &provider)
.unwrap();
sparse
.update_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x0, 0x2]), value.clone(), &provider)
.update_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x0, 0x2]), &value, &provider)
.unwrap();
sparse
.update_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x2, 0x0]), value, &provider)
.update_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x2, 0x0]), &value, &provider)
.unwrap();
assert_eq!(
@@ -3625,8 +3628,8 @@ mod tests {
let provider = DefaultTrieNodeProvider;
let mut sparse = SerialSparseTrie::default();
sparse.update_leaf(key1(), value_encoded(), &provider).unwrap();
sparse.update_leaf(key2(), value_encoded(), &provider).unwrap();
sparse.update_leaf(key1(), &value_encoded(), &provider).unwrap();
sparse.update_leaf(key2(), &value_encoded(), &provider).unwrap();
let sparse_root = sparse.root();
let sparse_updates = sparse.take_updates();
@@ -3654,22 +3657,22 @@ 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, &provider)
.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, &provider)
.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, &provider)
.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, &provider)
.unwrap();
sparse
.update_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x0, 0x2]), value.clone(), &provider)
.update_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x0, 0x2]), &value, &provider)
.unwrap();
sparse
.update_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x2, 0x0]), value, &provider)
.update_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x2, 0x0]), &value, &provider)
.unwrap();
sparse.wipe();
@@ -3690,16 +3693,16 @@ mod tests {
let mut sparse = SerialSparseTrie::default();
let value = alloy_rlp::encode_fixed_size(&U256::ZERO).to_vec();
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, &provider)
.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, &provider)
.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, &provider)
.unwrap();
sparse
.update_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x1, 0x0, 0x2]), value, &provider)
.update_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x1, 0x0, 0x2]), &value, &provider)
.unwrap();
sparse.clear();
@@ -3728,22 +3731,22 @@ 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, &provider)
.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, &provider)
.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, &provider)
.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, &provider)
.unwrap();
sparse
.update_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x0, 0x2]), value.clone(), &provider)
.update_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x0, 0x2]), &value, &provider)
.unwrap();
sparse
.update_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x2, 0x0]), value, &provider)
.update_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x2, 0x0]), &value, &provider)
.unwrap();
let normal_printed = format!("{sparse}");

View File

@@ -175,9 +175,14 @@ 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| {
SparseStateTrieErrorKind::SparseStorageTrie(hashed_address, err.into_kind())
})?;
storage_trie.update_leaf(storage_nibbles, &value, &provider).map_err(
|err| {
SparseStateTrieErrorKind::SparseStorageTrie(
hashed_address,
err.into_kind(),
)
},
)?;
} else {
storage_trie.remove_leaf(&storage_nibbles, &provider).map_err(|err| {
SparseStateTrieErrorKind::SparseStorageTrie(hashed_address, err.into_kind())