mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
fix(trie): reveal blinded node along with masks in sparse trie (#13827)
This commit is contained in:
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
use alloy_primitives::{Bytes, B256};
|
use alloy_primitives::{Bytes, B256};
|
||||||
use reth_execution_errors::SparseTrieError;
|
use reth_execution_errors::SparseTrieError;
|
||||||
use reth_trie_common::Nibbles;
|
use reth_trie_common::{Nibbles, TrieMask};
|
||||||
|
|
||||||
/// Factory for instantiating blinded node providers.
|
/// Factory for instantiating blinded node providers.
|
||||||
pub trait BlindedProviderFactory {
|
pub trait BlindedProviderFactory {
|
||||||
@ -18,10 +18,21 @@ pub trait BlindedProviderFactory {
|
|||||||
fn storage_node_provider(&self, account: B256) -> Self::StorageNodeProvider;
|
fn storage_node_provider(&self, account: B256) -> Self::StorageNodeProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Revealed blinded trie node.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct RevealedNode {
|
||||||
|
/// Raw trie node.
|
||||||
|
pub node: Bytes,
|
||||||
|
/// Branch node tree mask, if any.
|
||||||
|
pub tree_mask: Option<TrieMask>,
|
||||||
|
/// Branch node hash mask, if any.
|
||||||
|
pub hash_mask: Option<TrieMask>,
|
||||||
|
}
|
||||||
|
|
||||||
/// Trie node provider for retrieving blinded nodes.
|
/// Trie node provider for retrieving blinded nodes.
|
||||||
pub trait BlindedProvider {
|
pub trait BlindedProvider {
|
||||||
/// Retrieve blinded node by path.
|
/// Retrieve blinded node by path.
|
||||||
fn blinded_node(&mut self, path: &Nibbles) -> Result<Option<Bytes>, SparseTrieError>;
|
fn blinded_node(&mut self, path: &Nibbles) -> Result<Option<RevealedNode>, SparseTrieError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Default blinded node provider factory that creates [`DefaultBlindedProvider`].
|
/// Default blinded node provider factory that creates [`DefaultBlindedProvider`].
|
||||||
@ -46,7 +57,7 @@ impl BlindedProviderFactory for DefaultBlindedProviderFactory {
|
|||||||
pub struct DefaultBlindedProvider;
|
pub struct DefaultBlindedProvider;
|
||||||
|
|
||||||
impl BlindedProvider for DefaultBlindedProvider {
|
impl BlindedProvider for DefaultBlindedProvider {
|
||||||
fn blinded_node(&mut self, _path: &Nibbles) -> Result<Option<Bytes>, SparseTrieError> {
|
fn blinded_node(&mut self, _path: &Nibbles) -> Result<Option<RevealedNode>, SparseTrieError> {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
use crate::blinded::{BlindedProvider, DefaultBlindedProvider};
|
use crate::blinded::{BlindedProvider, DefaultBlindedProvider, RevealedNode};
|
||||||
use alloy_primitives::{
|
use alloy_primitives::{
|
||||||
hex, keccak256,
|
hex, keccak256,
|
||||||
map::{Entry, HashMap, HashSet},
|
map::{Entry, HashMap, HashSet},
|
||||||
@ -945,14 +945,24 @@ impl<P: BlindedProvider> RevealedSparseTrie<P> {
|
|||||||
if self.updates.is_some() {
|
if self.updates.is_some() {
|
||||||
// Check if the extension node child is a hash that needs to be revealed
|
// Check if the extension node child is a hash that needs to be revealed
|
||||||
if self.nodes.get(¤t).unwrap().is_hash() {
|
if self.nodes.get(¤t).unwrap().is_hash() {
|
||||||
if let Some(node) = self.provider.blinded_node(¤t)? {
|
if let Some(RevealedNode { node, tree_mask, hash_mask }) =
|
||||||
|
self.provider.blinded_node(¤t)?
|
||||||
|
{
|
||||||
let decoded = TrieNode::decode(&mut &node[..])?;
|
let decoded = TrieNode::decode(&mut &node[..])?;
|
||||||
trace!(target: "trie::sparse", ?current, ?decoded, "Revealing extension node child");
|
trace!(
|
||||||
// We'll never have to update the revealed child node, only
|
target: "trie::sparse",
|
||||||
// remove or do nothing, so
|
?current,
|
||||||
// we can safely ignore the hash mask here and
|
?decoded,
|
||||||
// pass `None`.
|
?tree_mask,
|
||||||
self.reveal_node(current.clone(), decoded, None, None)?;
|
?hash_mask,
|
||||||
|
"Revealing extension node child",
|
||||||
|
);
|
||||||
|
self.reveal_node(
|
||||||
|
current.clone(),
|
||||||
|
decoded,
|
||||||
|
tree_mask,
|
||||||
|
hash_mask,
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1000,6 +1010,7 @@ impl<P: BlindedProvider> RevealedSparseTrie<P> {
|
|||||||
return Err(SparseTrieErrorKind::BlindedNode { path: path.clone(), hash }.into())
|
return Err(SparseTrieErrorKind::BlindedNode { path: path.clone(), hash }.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trace!(target: "trie::sparse", ?path, "Leaf node is not present in the trie");
|
||||||
// Leaf is not present in the trie.
|
// Leaf is not present in the trie.
|
||||||
return Ok(())
|
return Ok(())
|
||||||
}
|
}
|
||||||
@ -1098,13 +1109,24 @@ impl<P: BlindedProvider> RevealedSparseTrie<P> {
|
|||||||
|
|
||||||
if self.nodes.get(&child_path).unwrap().is_hash() {
|
if self.nodes.get(&child_path).unwrap().is_hash() {
|
||||||
trace!(target: "trie::sparse", ?child_path, "Retrieving remaining blinded branch child");
|
trace!(target: "trie::sparse", ?child_path, "Retrieving remaining blinded branch child");
|
||||||
if let Some(node) = self.provider.blinded_node(&child_path)? {
|
if let Some(RevealedNode { node, tree_mask, hash_mask }) =
|
||||||
|
self.provider.blinded_node(&child_path)?
|
||||||
|
{
|
||||||
let decoded = TrieNode::decode(&mut &node[..])?;
|
let decoded = TrieNode::decode(&mut &node[..])?;
|
||||||
trace!(target: "trie::sparse", ?child_path, ?decoded, "Revealing remaining blinded branch child");
|
trace!(
|
||||||
// We'll never have to update the revealed branch node, only remove
|
target: "trie::sparse",
|
||||||
// or do nothing, so we can safely ignore the hash mask here and
|
?child_path,
|
||||||
// pass `None`.
|
?decoded,
|
||||||
self.reveal_node(child_path.clone(), decoded, None, None)?;
|
?tree_mask,
|
||||||
|
?hash_mask,
|
||||||
|
"Revealing remaining blinded branch child"
|
||||||
|
);
|
||||||
|
self.reveal_node(
|
||||||
|
child_path.clone(),
|
||||||
|
decoded,
|
||||||
|
tree_mask,
|
||||||
|
hash_mask,
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,11 +2,13 @@ use super::{Proof, StorageProof};
|
|||||||
use crate::{hashed_cursor::HashedCursorFactory, trie_cursor::TrieCursorFactory};
|
use crate::{hashed_cursor::HashedCursorFactory, trie_cursor::TrieCursorFactory};
|
||||||
use alloy_primitives::{
|
use alloy_primitives::{
|
||||||
map::{HashMap, HashSet},
|
map::{HashMap, HashSet},
|
||||||
Bytes, B256,
|
B256,
|
||||||
};
|
};
|
||||||
use reth_execution_errors::{SparseTrieError, SparseTrieErrorKind};
|
use reth_execution_errors::{SparseTrieError, SparseTrieErrorKind};
|
||||||
use reth_trie_common::{prefix_set::TriePrefixSetsMut, Nibbles};
|
use reth_trie_common::{prefix_set::TriePrefixSetsMut, Nibbles};
|
||||||
use reth_trie_sparse::blinded::{pad_path_to_key, BlindedProvider, BlindedProviderFactory};
|
use reth_trie_sparse::blinded::{
|
||||||
|
pad_path_to_key, BlindedProvider, BlindedProviderFactory, RevealedNode,
|
||||||
|
};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tracing::trace;
|
use tracing::trace;
|
||||||
|
|
||||||
@ -85,17 +87,20 @@ where
|
|||||||
T: TrieCursorFactory + Clone + Send + Sync,
|
T: TrieCursorFactory + Clone + Send + Sync,
|
||||||
H: HashedCursorFactory + Clone + Send + Sync,
|
H: HashedCursorFactory + Clone + Send + Sync,
|
||||||
{
|
{
|
||||||
fn blinded_node(&mut self, path: &Nibbles) -> Result<Option<Bytes>, SparseTrieError> {
|
fn blinded_node(&mut self, path: &Nibbles) -> Result<Option<RevealedNode>, SparseTrieError> {
|
||||||
let targets = HashMap::from_iter([(pad_path_to_key(path), HashSet::default())]);
|
let targets = HashMap::from_iter([(pad_path_to_key(path), HashSet::default())]);
|
||||||
let proof =
|
let mut proof =
|
||||||
Proof::new(self.trie_cursor_factory.clone(), self.hashed_cursor_factory.clone())
|
Proof::new(self.trie_cursor_factory.clone(), self.hashed_cursor_factory.clone())
|
||||||
.with_prefix_sets_mut(self.prefix_sets.as_ref().clone())
|
.with_prefix_sets_mut(self.prefix_sets.as_ref().clone())
|
||||||
|
.with_branch_node_masks(true)
|
||||||
.multiproof(targets)
|
.multiproof(targets)
|
||||||
.map_err(|error| SparseTrieErrorKind::Other(Box::new(error)))?;
|
.map_err(|error| SparseTrieErrorKind::Other(Box::new(error)))?;
|
||||||
let node = proof.account_subtree.into_inner().remove(path);
|
let node = proof.account_subtree.into_inner().remove(path);
|
||||||
|
let tree_mask = proof.branch_node_tree_masks.remove(path);
|
||||||
|
let hash_mask = proof.branch_node_hash_masks.remove(path);
|
||||||
trace!(target: "trie::proof::blinded", ?path, ?node, "Blinded node for account trie");
|
trace!(target: "trie::proof::blinded", ?path, ?node, "Blinded node for account trie");
|
||||||
Ok(node)
|
|
||||||
|
Ok(node.map(|node| RevealedNode { node, tree_mask, hash_mask }))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,21 +134,24 @@ where
|
|||||||
T: TrieCursorFactory + Clone + Send + Sync,
|
T: TrieCursorFactory + Clone + Send + Sync,
|
||||||
H: HashedCursorFactory + Clone + Send + Sync,
|
H: HashedCursorFactory + Clone + Send + Sync,
|
||||||
{
|
{
|
||||||
fn blinded_node(&mut self, path: &Nibbles) -> Result<Option<Bytes>, SparseTrieError> {
|
fn blinded_node(&mut self, path: &Nibbles) -> Result<Option<RevealedNode>, SparseTrieError> {
|
||||||
let targets = HashSet::from_iter([pad_path_to_key(path)]);
|
let targets = HashSet::from_iter([pad_path_to_key(path)]);
|
||||||
let storage_prefix_set =
|
let storage_prefix_set =
|
||||||
self.prefix_sets.storage_prefix_sets.get(&self.account).cloned().unwrap_or_default();
|
self.prefix_sets.storage_prefix_sets.get(&self.account).cloned().unwrap_or_default();
|
||||||
let proof = StorageProof::new_hashed(
|
let mut proof = StorageProof::new_hashed(
|
||||||
self.trie_cursor_factory.clone(),
|
self.trie_cursor_factory.clone(),
|
||||||
self.hashed_cursor_factory.clone(),
|
self.hashed_cursor_factory.clone(),
|
||||||
self.account,
|
self.account,
|
||||||
)
|
)
|
||||||
.with_prefix_set_mut(storage_prefix_set)
|
.with_prefix_set_mut(storage_prefix_set)
|
||||||
|
.with_branch_node_masks(true)
|
||||||
.storage_multiproof(targets)
|
.storage_multiproof(targets)
|
||||||
.map_err(|error| SparseTrieErrorKind::Other(Box::new(error)))?;
|
.map_err(|error| SparseTrieErrorKind::Other(Box::new(error)))?;
|
||||||
let node = proof.subtree.into_inner().remove(path);
|
let node = proof.subtree.into_inner().remove(path);
|
||||||
|
let tree_mask = proof.branch_node_tree_masks.remove(path);
|
||||||
|
let hash_mask = proof.branch_node_hash_masks.remove(path);
|
||||||
trace!(target: "trie::proof::blinded", account = ?self.account, ?path, ?node, "Blinded node for storage trie");
|
trace!(target: "trie::proof::blinded", account = ?self.account, ?path, ?node, "Blinded node for storage trie");
|
||||||
Ok(node)
|
|
||||||
|
Ok(node.map(|node| RevealedNode { node, tree_mask, hash_mask }))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,7 +17,7 @@ use reth_execution_errors::{
|
|||||||
};
|
};
|
||||||
use reth_trie_common::{MultiProofTargets, Nibbles};
|
use reth_trie_common::{MultiProofTargets, Nibbles};
|
||||||
use reth_trie_sparse::{
|
use reth_trie_sparse::{
|
||||||
blinded::{BlindedProvider, BlindedProviderFactory},
|
blinded::{BlindedProvider, BlindedProviderFactory, RevealedNode},
|
||||||
SparseStateTrie,
|
SparseStateTrie,
|
||||||
};
|
};
|
||||||
use std::sync::{mpsc, Arc};
|
use std::sync::{mpsc, Arc};
|
||||||
@ -244,11 +244,11 @@ impl<P> WitnessBlindedProvider<P> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<P: BlindedProvider> BlindedProvider for WitnessBlindedProvider<P> {
|
impl<P: BlindedProvider> BlindedProvider for WitnessBlindedProvider<P> {
|
||||||
fn blinded_node(&mut self, path: &Nibbles) -> Result<Option<Bytes>, SparseTrieError> {
|
fn blinded_node(&mut self, path: &Nibbles) -> Result<Option<RevealedNode>, SparseTrieError> {
|
||||||
let maybe_node = self.provider.blinded_node(path)?;
|
let maybe_node = self.provider.blinded_node(path)?;
|
||||||
if let Some(node) = &maybe_node {
|
if let Some(node) = &maybe_node {
|
||||||
self.tx
|
self.tx
|
||||||
.send(node.clone())
|
.send(node.node.clone())
|
||||||
.map_err(|error| SparseTrieErrorKind::Other(Box::new(error)))?;
|
.map_err(|error| SparseTrieErrorKind::Other(Box::new(error)))?;
|
||||||
}
|
}
|
||||||
Ok(maybe_node)
|
Ok(maybe_node)
|
||||||
|
|||||||
Reference in New Issue
Block a user