mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
feat(trie): expose storage proofs (#11550)
This commit is contained in:
@ -872,7 +872,7 @@ mod tests {
|
||||
AccountReader, BlockHashReader, StateProofProvider, StateProvider, StateRootProvider,
|
||||
StorageRootProvider,
|
||||
};
|
||||
use reth_trie::{AccountProof, HashedStorage, MultiProof, TrieInput};
|
||||
use reth_trie::{AccountProof, HashedStorage, MultiProof, StorageProof, TrieInput};
|
||||
|
||||
fn create_mock_state(
|
||||
test_block_builder: &mut TestBlockBuilder,
|
||||
@ -973,6 +973,15 @@ mod tests {
|
||||
) -> ProviderResult<B256> {
|
||||
Ok(B256::random())
|
||||
}
|
||||
|
||||
fn storage_proof(
|
||||
&self,
|
||||
_address: Address,
|
||||
slot: B256,
|
||||
_hashed_storage: HashedStorage,
|
||||
) -> ProviderResult<StorageProof> {
|
||||
Ok(StorageProof::new(slot))
|
||||
}
|
||||
}
|
||||
|
||||
impl StateProofProvider for MockStateProvider {
|
||||
|
||||
@ -133,11 +133,26 @@ impl StateRootProvider for MemoryOverlayStateProvider {
|
||||
impl StorageRootProvider for MemoryOverlayStateProvider {
|
||||
// TODO: Currently this does not reuse available in-memory trie nodes.
|
||||
fn storage_root(&self, address: Address, storage: HashedStorage) -> ProviderResult<B256> {
|
||||
let state = &self.trie_state().state;
|
||||
let mut hashed_storage =
|
||||
self.trie_state().state.storages.get(&keccak256(address)).cloned().unwrap_or_default();
|
||||
state.storages.get(&keccak256(address)).cloned().unwrap_or_default();
|
||||
hashed_storage.extend(&storage);
|
||||
self.historical.storage_root(address, hashed_storage)
|
||||
}
|
||||
|
||||
// TODO: Currently this does not reuse available in-memory trie nodes.
|
||||
fn storage_proof(
|
||||
&self,
|
||||
address: Address,
|
||||
slot: B256,
|
||||
storage: HashedStorage,
|
||||
) -> ProviderResult<reth_trie::StorageProof> {
|
||||
let state = &self.trie_state().state;
|
||||
let mut hashed_storage =
|
||||
state.storages.get(&keccak256(address)).cloned().unwrap_or_default();
|
||||
hashed_storage.extend(&storage);
|
||||
self.historical.storage_proof(address, slot, hashed_storage)
|
||||
}
|
||||
}
|
||||
|
||||
impl StateProofProvider for MemoryOverlayStateProvider {
|
||||
|
||||
@ -11,7 +11,8 @@ use reth_storage_api::{
|
||||
};
|
||||
use reth_storage_errors::provider::ProviderResult;
|
||||
use reth_trie::{
|
||||
updates::TrieUpdates, AccountProof, HashedPostState, HashedStorage, MultiProof, TrieInput,
|
||||
updates::TrieUpdates, AccountProof, HashedPostState, HashedStorage, MultiProof, StorageProof,
|
||||
TrieInput,
|
||||
};
|
||||
|
||||
/// Mock state for testing
|
||||
@ -102,6 +103,15 @@ impl StorageRootProvider for StateProviderTest {
|
||||
) -> ProviderResult<B256> {
|
||||
unimplemented!("storage root is not supported")
|
||||
}
|
||||
|
||||
fn storage_proof(
|
||||
&self,
|
||||
_address: Address,
|
||||
_slot: B256,
|
||||
_hashed_storage: HashedStorage,
|
||||
) -> ProviderResult<StorageProof> {
|
||||
unimplemented!("proof generation is not supported")
|
||||
}
|
||||
}
|
||||
|
||||
impl StateProofProvider for StateProviderTest {
|
||||
|
||||
9
crates/rpc/rpc-eth-types/src/cache/db.rs
vendored
9
crates/rpc/rpc-eth-types/src/cache/db.rs
vendored
@ -58,6 +58,15 @@ impl reth_storage_api::StorageRootProvider for StateProviderTraitObjWrapper<'_>
|
||||
) -> ProviderResult<B256> {
|
||||
self.0.storage_root(address, hashed_storage)
|
||||
}
|
||||
|
||||
fn storage_proof(
|
||||
&self,
|
||||
address: Address,
|
||||
slot: B256,
|
||||
hashed_storage: HashedStorage,
|
||||
) -> ProviderResult<reth_trie::StorageProof> {
|
||||
self.0.storage_proof(address, slot, hashed_storage)
|
||||
}
|
||||
}
|
||||
|
||||
impl reth_storage_api::StateProofProvider for StateProviderTraitObjWrapper<'_> {
|
||||
|
||||
@ -31,6 +31,20 @@ impl<SP: StateProvider, EDP: ExecutionDataProvider> BundleStateProvider<SP, EDP>
|
||||
pub const fn new(state_provider: SP, block_execution_data_provider: EDP) -> Self {
|
||||
Self { state_provider, block_execution_data_provider }
|
||||
}
|
||||
|
||||
/// Retrieve hashed storage for target address.
|
||||
fn get_hashed_storage(&self, address: Address) -> HashedStorage {
|
||||
let bundle_state = self.block_execution_data_provider.execution_outcome().state();
|
||||
bundle_state
|
||||
.account(&address)
|
||||
.map(|account| {
|
||||
HashedStorage::from_plain_storage(
|
||||
account.status,
|
||||
account.storage.iter().map(|(slot, value)| (slot, &value.present_value)),
|
||||
)
|
||||
})
|
||||
.unwrap_or_else(|| HashedStorage::new(false))
|
||||
}
|
||||
}
|
||||
|
||||
/* Implement StateProvider traits */
|
||||
@ -109,19 +123,21 @@ impl<SP: StateProvider, EDP: ExecutionDataProvider> StorageRootProvider
|
||||
address: Address,
|
||||
hashed_storage: HashedStorage,
|
||||
) -> ProviderResult<B256> {
|
||||
let bundle_state = self.block_execution_data_provider.execution_outcome().state();
|
||||
let mut storage = bundle_state
|
||||
.account(&address)
|
||||
.map(|account| {
|
||||
HashedStorage::from_plain_storage(
|
||||
account.status,
|
||||
account.storage.iter().map(|(slot, value)| (slot, &value.present_value)),
|
||||
)
|
||||
})
|
||||
.unwrap_or_else(|| HashedStorage::new(false));
|
||||
let mut storage = self.get_hashed_storage(address);
|
||||
storage.extend(&hashed_storage);
|
||||
self.state_provider.storage_root(address, storage)
|
||||
}
|
||||
|
||||
fn storage_proof(
|
||||
&self,
|
||||
address: Address,
|
||||
slot: B256,
|
||||
hashed_storage: HashedStorage,
|
||||
) -> ProviderResult<reth_trie::StorageProof> {
|
||||
let mut storage = self.get_hashed_storage(address);
|
||||
storage.extend(&hashed_storage);
|
||||
self.state_provider.storage_proof(address, slot, storage)
|
||||
}
|
||||
}
|
||||
|
||||
impl<SP: StateProvider, EDP: ExecutionDataProvider> StateProofProvider
|
||||
|
||||
@ -17,12 +17,14 @@ use reth_primitives::{constants::EPOCH_SLOTS, Account, Bytecode, StaticFileSegme
|
||||
use reth_storage_api::{StateProofProvider, StorageRootProvider};
|
||||
use reth_storage_errors::provider::ProviderResult;
|
||||
use reth_trie::{
|
||||
proof::Proof, updates::TrieUpdates, witness::TrieWitness, AccountProof, HashedPostState,
|
||||
HashedStorage, MultiProof, StateRoot, StorageRoot, TrieInput,
|
||||
proof::{Proof, StorageProof},
|
||||
updates::TrieUpdates,
|
||||
witness::TrieWitness,
|
||||
AccountProof, HashedPostState, HashedStorage, MultiProof, StateRoot, StorageRoot, TrieInput,
|
||||
};
|
||||
use reth_trie_db::{
|
||||
DatabaseHashedPostState, DatabaseHashedStorage, DatabaseProof, DatabaseStateRoot,
|
||||
DatabaseStorageRoot, DatabaseTrieWitness,
|
||||
DatabaseStorageProof, DatabaseStorageRoot, DatabaseTrieWitness,
|
||||
};
|
||||
use std::fmt::Debug;
|
||||
|
||||
@ -330,6 +332,18 @@ impl<TX: DbTx> StorageRootProvider for HistoricalStateProviderRef<'_, TX> {
|
||||
StorageRoot::overlay_root(self.tx, address, revert_storage)
|
||||
.map_err(|err| ProviderError::Database(err.into()))
|
||||
}
|
||||
|
||||
fn storage_proof(
|
||||
&self,
|
||||
address: Address,
|
||||
slot: B256,
|
||||
hashed_storage: HashedStorage,
|
||||
) -> ProviderResult<reth_trie::StorageProof> {
|
||||
let mut revert_storage = self.revert_storage(address)?;
|
||||
revert_storage.extend(&hashed_storage);
|
||||
StorageProof::overlay_storage_proof(self.tx, address, slot, revert_storage)
|
||||
.map_err(Into::<ProviderError>::into)
|
||||
}
|
||||
}
|
||||
|
||||
impl<TX: DbTx> StateProofProvider for HistoricalStateProviderRef<'_, TX> {
|
||||
|
||||
@ -15,10 +15,15 @@ use reth_primitives::{Account, Bytecode, StaticFileSegment};
|
||||
use reth_storage_api::{StateProofProvider, StorageRootProvider};
|
||||
use reth_storage_errors::provider::{ProviderError, ProviderResult};
|
||||
use reth_trie::{
|
||||
proof::Proof, updates::TrieUpdates, witness::TrieWitness, AccountProof, HashedPostState,
|
||||
HashedStorage, MultiProof, StateRoot, StorageRoot, TrieInput,
|
||||
proof::{Proof, StorageProof},
|
||||
updates::TrieUpdates,
|
||||
witness::TrieWitness,
|
||||
AccountProof, HashedPostState, HashedStorage, MultiProof, StateRoot, StorageRoot, TrieInput,
|
||||
};
|
||||
use reth_trie_db::{
|
||||
DatabaseProof, DatabaseStateRoot, DatabaseStorageProof, DatabaseStorageRoot,
|
||||
DatabaseTrieWitness,
|
||||
};
|
||||
use reth_trie_db::{DatabaseProof, DatabaseStateRoot, DatabaseStorageRoot, DatabaseTrieWitness};
|
||||
|
||||
/// State provider over latest state that takes tx reference.
|
||||
#[derive(Debug)]
|
||||
@ -116,6 +121,16 @@ impl<TX: DbTx> StorageRootProvider for LatestStateProviderRef<'_, TX> {
|
||||
StorageRoot::overlay_root(self.tx, address, hashed_storage)
|
||||
.map_err(|err| ProviderError::Database(err.into()))
|
||||
}
|
||||
|
||||
fn storage_proof(
|
||||
&self,
|
||||
address: Address,
|
||||
slot: B256,
|
||||
hashed_storage: HashedStorage,
|
||||
) -> ProviderResult<reth_trie::StorageProof> {
|
||||
StorageProof::overlay_storage_proof(self.tx, address, slot, hashed_storage)
|
||||
.map_err(Into::<ProviderError>::into)
|
||||
}
|
||||
}
|
||||
|
||||
impl<TX: DbTx> StateProofProvider for LatestStateProviderRef<'_, TX> {
|
||||
|
||||
@ -48,7 +48,8 @@ macro_rules! delegate_provider_impls {
|
||||
fn state_root_from_nodes_with_updates(&self, input: reth_trie::TrieInput) -> reth_storage_errors::provider::ProviderResult<(alloy_primitives::B256, reth_trie::updates::TrieUpdates)>;
|
||||
}
|
||||
StorageRootProvider $(where [$($generics)*])? {
|
||||
fn storage_root(&self, address: alloy_primitives::Address, storage: reth_trie::HashedStorage) -> reth_storage_errors::provider::ProviderResult<alloy_primitives::B256>;
|
||||
fn storage_root(&self, address: alloy_primitives::Address, storage: reth_trie::HashedStorage) -> reth_storage_errors::provider::ProviderResult<alloy_primitives::B256>;
|
||||
fn storage_proof(&self, address: alloy_primitives::Address, slot: alloy_primitives::B256, storage: reth_trie::HashedStorage) -> reth_storage_errors::provider::ProviderResult<reth_trie::StorageProof>;
|
||||
}
|
||||
StateProofProvider $(where [$($generics)*])? {
|
||||
fn proof(&self, input: reth_trie::TrieInput, address: alloy_primitives::Address, slots: &[alloy_primitives::B256]) -> reth_storage_errors::provider::ProviderResult<reth_trie::AccountProof>;
|
||||
|
||||
@ -31,7 +31,8 @@ use reth_storage_api::{
|
||||
};
|
||||
use reth_storage_errors::provider::{ConsistentViewError, ProviderError, ProviderResult};
|
||||
use reth_trie::{
|
||||
updates::TrieUpdates, AccountProof, HashedPostState, HashedStorage, MultiProof, TrieInput,
|
||||
updates::TrieUpdates, AccountProof, HashedPostState, HashedStorage, MultiProof, StorageProof,
|
||||
TrieInput,
|
||||
};
|
||||
use revm::primitives::{BlockEnv, CfgEnvWithHandlerCfg};
|
||||
use std::{
|
||||
@ -639,6 +640,15 @@ impl StorageRootProvider for MockEthProvider {
|
||||
) -> ProviderResult<B256> {
|
||||
Ok(EMPTY_ROOT_HASH)
|
||||
}
|
||||
|
||||
fn storage_proof(
|
||||
&self,
|
||||
_address: Address,
|
||||
slot: B256,
|
||||
_hashed_storage: HashedStorage,
|
||||
) -> ProviderResult<reth_trie::StorageProof> {
|
||||
Ok(StorageProof::new(slot))
|
||||
}
|
||||
}
|
||||
|
||||
impl StateProofProvider for MockEthProvider {
|
||||
|
||||
@ -356,6 +356,15 @@ impl StorageRootProvider for NoopProvider {
|
||||
) -> ProviderResult<B256> {
|
||||
Ok(B256::default())
|
||||
}
|
||||
|
||||
fn storage_proof(
|
||||
&self,
|
||||
_address: Address,
|
||||
slot: B256,
|
||||
_hashed_storage: HashedStorage,
|
||||
) -> ProviderResult<reth_trie::StorageProof> {
|
||||
Ok(reth_trie::StorageProof::new(slot))
|
||||
}
|
||||
}
|
||||
|
||||
impl StateProofProvider for NoopProvider {
|
||||
|
||||
@ -4,7 +4,8 @@ use alloy_primitives::{
|
||||
};
|
||||
use reth_storage_errors::provider::ProviderResult;
|
||||
use reth_trie::{
|
||||
updates::TrieUpdates, AccountProof, HashedPostState, HashedStorage, MultiProof, TrieInput,
|
||||
updates::TrieUpdates, AccountProof, HashedPostState, HashedStorage, MultiProof, StorageProof,
|
||||
TrieInput,
|
||||
};
|
||||
|
||||
/// A type that can compute the state root of a given post state.
|
||||
@ -46,6 +47,15 @@ pub trait StorageRootProvider: Send + Sync {
|
||||
/// state.
|
||||
fn storage_root(&self, address: Address, hashed_storage: HashedStorage)
|
||||
-> ProviderResult<B256>;
|
||||
|
||||
/// Returns the storage proof of the `HashedStorage` for target slot on top of the current
|
||||
/// state.
|
||||
fn storage_proof(
|
||||
&self,
|
||||
address: Address,
|
||||
slot: B256,
|
||||
hashed_storage: HashedStorage,
|
||||
) -> ProviderResult<StorageProof>;
|
||||
}
|
||||
|
||||
/// A type that can generate state proof on top of a given post state.
|
||||
|
||||
@ -12,7 +12,7 @@ pub use hashed_cursor::{
|
||||
DatabaseHashedAccountCursor, DatabaseHashedCursorFactory, DatabaseHashedStorageCursor,
|
||||
};
|
||||
pub use prefix_set::PrefixSetLoader;
|
||||
pub use proof::DatabaseProof;
|
||||
pub use proof::{DatabaseProof, DatabaseStorageProof};
|
||||
pub use state::{DatabaseHashedPostState, DatabaseStateRoot};
|
||||
pub use storage::{DatabaseHashedStorage, DatabaseStorageRoot};
|
||||
pub use trie_cursor::{
|
||||
|
||||
@ -1,13 +1,16 @@
|
||||
use crate::{DatabaseHashedCursorFactory, DatabaseTrieCursorFactory};
|
||||
use alloy_primitives::{
|
||||
keccak256,
|
||||
map::{HashMap, HashSet},
|
||||
Address, B256,
|
||||
};
|
||||
use reth_db_api::transaction::DbTx;
|
||||
use reth_execution_errors::StateProofError;
|
||||
use reth_trie::{
|
||||
hashed_cursor::HashedPostStateCursorFactory, proof::Proof,
|
||||
trie_cursor::InMemoryTrieCursorFactory, MultiProof, TrieInput,
|
||||
hashed_cursor::HashedPostStateCursorFactory,
|
||||
proof::{Proof, StorageProof},
|
||||
trie_cursor::InMemoryTrieCursorFactory,
|
||||
HashedPostStateSorted, HashedStorage, MultiProof, TrieInput,
|
||||
};
|
||||
use reth_trie_common::AccountProof;
|
||||
|
||||
@ -81,3 +84,46 @@ impl<'a, TX: DbTx> DatabaseProof<'a, TX>
|
||||
.multiproof(targets)
|
||||
}
|
||||
}
|
||||
|
||||
/// Extends [`StorageProof`] with operations specific for working with a database transaction.
|
||||
pub trait DatabaseStorageProof<'a, TX> {
|
||||
/// Create a new [`StorageProof`] from database transaction and account address.
|
||||
fn from_tx(tx: &'a TX, address: Address) -> Self;
|
||||
|
||||
/// Generates the storage proof for target slot based on [`TrieInput`].
|
||||
fn overlay_storage_proof(
|
||||
tx: &'a TX,
|
||||
address: Address,
|
||||
slot: B256,
|
||||
storage: HashedStorage,
|
||||
) -> Result<reth_trie_common::StorageProof, StateProofError>;
|
||||
}
|
||||
|
||||
impl<'a, TX: DbTx> DatabaseStorageProof<'a, TX>
|
||||
for StorageProof<DatabaseTrieCursorFactory<'a, TX>, DatabaseHashedCursorFactory<'a, TX>>
|
||||
{
|
||||
fn from_tx(tx: &'a TX, address: Address) -> Self {
|
||||
Self::new(DatabaseTrieCursorFactory::new(tx), DatabaseHashedCursorFactory::new(tx), address)
|
||||
}
|
||||
|
||||
fn overlay_storage_proof(
|
||||
tx: &'a TX,
|
||||
address: Address,
|
||||
slot: B256,
|
||||
storage: HashedStorage,
|
||||
) -> Result<reth_trie_common::StorageProof, StateProofError> {
|
||||
let hashed_address = keccak256(address);
|
||||
let prefix_set = storage.construct_prefix_set();
|
||||
let state_sorted = HashedPostStateSorted::new(
|
||||
Default::default(),
|
||||
HashMap::from([(hashed_address, storage.into_sorted())]),
|
||||
);
|
||||
Self::from_tx(tx, address)
|
||||
.with_hashed_cursor_factory(HashedPostStateCursorFactory::new(
|
||||
DatabaseHashedCursorFactory::new(tx),
|
||||
&state_sorted,
|
||||
))
|
||||
.with_prefix_set_mut(prefix_set)
|
||||
.storage_proof(slot)
|
||||
}
|
||||
}
|
||||
|
||||
@ -124,7 +124,7 @@ where
|
||||
hashed_address,
|
||||
)
|
||||
.with_prefix_set_mut(storage_prefix_set)
|
||||
.storage_proof(proof_targets)?;
|
||||
.storage_multiproof(proof_targets)?;
|
||||
|
||||
// Encode account
|
||||
account_rlp.clear();
|
||||
@ -170,6 +170,26 @@ impl<T, H> StorageProof<T, H> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the trie cursor factory.
|
||||
pub fn with_trie_cursor_factory<TF>(self, trie_cursor_factory: TF) -> StorageProof<TF, H> {
|
||||
StorageProof {
|
||||
trie_cursor_factory,
|
||||
hashed_cursor_factory: self.hashed_cursor_factory,
|
||||
hashed_address: self.hashed_address,
|
||||
prefix_set: self.prefix_set,
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the hashed cursor factory.
|
||||
pub fn with_hashed_cursor_factory<HF>(self, hashed_cursor_factory: HF) -> StorageProof<T, HF> {
|
||||
StorageProof {
|
||||
trie_cursor_factory: self.trie_cursor_factory,
|
||||
hashed_cursor_factory,
|
||||
hashed_address: self.hashed_address,
|
||||
prefix_set: self.prefix_set,
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the changed prefixes.
|
||||
pub fn with_prefix_set_mut(mut self, prefix_set: PrefixSetMut) -> Self {
|
||||
self.prefix_set = prefix_set;
|
||||
@ -182,8 +202,17 @@ where
|
||||
T: TrieCursorFactory,
|
||||
H: HashedCursorFactory,
|
||||
{
|
||||
/// Generate storage proof.
|
||||
/// Generate an account proof from intermediate nodes.
|
||||
pub fn storage_proof(
|
||||
self,
|
||||
slot: B256,
|
||||
) -> Result<reth_trie_common::StorageProof, StateProofError> {
|
||||
let targets = HashSet::from_iter([keccak256(slot)]);
|
||||
Ok(self.storage_multiproof(targets)?.storage_proof(slot)?)
|
||||
}
|
||||
|
||||
/// Generate storage proof.
|
||||
pub fn storage_multiproof(
|
||||
mut self,
|
||||
targets: HashSet<B256>,
|
||||
) -> Result<StorageMultiProof, StateProofError> {
|
||||
|
||||
@ -178,7 +178,7 @@ where
|
||||
hashed_address,
|
||||
)
|
||||
.with_prefix_set_mut(storage_prefix_set)
|
||||
.storage_proof(HashSet::from_iter([target_key]))?;
|
||||
.storage_multiproof(HashSet::from_iter([target_key]))?;
|
||||
|
||||
// The subtree only contains the proof for a single target.
|
||||
let node =
|
||||
|
||||
Reference in New Issue
Block a user