feat(trie): StorageRootProvider::storage_multiproof (#12879)

This commit is contained in:
Roman Krasiuk
2024-11-26 15:01:31 +01:00
committed by GitHub
parent b6d6bf5eed
commit a0f99df21b
12 changed files with 149 additions and 11 deletions

View File

@ -944,7 +944,9 @@ mod tests {
AccountReader, BlockHashReader, StateProofProvider, StateProvider, StateRootProvider, AccountReader, BlockHashReader, StateProofProvider, StateProvider, StateRootProvider,
StorageRootProvider, StorageRootProvider,
}; };
use reth_trie::{AccountProof, HashedStorage, MultiProof, StorageProof, TrieInput}; use reth_trie::{
AccountProof, HashedStorage, MultiProof, StorageMultiProof, StorageProof, TrieInput,
};
fn create_mock_state( fn create_mock_state(
test_block_builder: &mut TestBlockBuilder<EthPrimitives>, test_block_builder: &mut TestBlockBuilder<EthPrimitives>,
@ -1054,6 +1056,15 @@ mod tests {
) -> ProviderResult<StorageProof> { ) -> ProviderResult<StorageProof> {
Ok(StorageProof::new(slot)) Ok(StorageProof::new(slot))
} }
fn storage_multiproof(
&self,
_address: Address,
_slots: &[B256],
_hashed_storage: HashedStorage,
) -> ProviderResult<StorageMultiProof> {
Ok(StorageMultiProof::empty())
}
} }
impl StateProofProvider for MockStateProvider { impl StateProofProvider for MockStateProvider {

View File

@ -11,7 +11,8 @@ use reth_storage_api::{
StorageRootProvider, StorageRootProvider,
}; };
use reth_trie::{ use reth_trie::{
updates::TrieUpdates, AccountProof, HashedPostState, HashedStorage, MultiProof, TrieInput, updates::TrieUpdates, AccountProof, HashedPostState, HashedStorage, MultiProof,
StorageMultiProof, TrieInput,
}; };
use std::sync::OnceLock; use std::sync::OnceLock;
@ -167,6 +168,20 @@ macro_rules! impl_state_provider {
hashed_storage.extend(&storage); hashed_storage.extend(&storage);
self.historical.storage_proof(address, slot, hashed_storage) self.historical.storage_proof(address, slot, hashed_storage)
} }
// TODO: Currently this does not reuse available in-memory trie nodes.
fn storage_multiproof(
&self,
address: Address,
slots: &[B256],
storage: HashedStorage,
) -> ProviderResult<StorageMultiProof> {
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_multiproof(address, slots, hashed_storage)
}
} }
impl $($tokens)* StateProofProvider for $type { impl $($tokens)* StateProofProvider for $type {

View File

@ -11,8 +11,8 @@ use reth_storage_api::{
}; };
use reth_storage_errors::provider::ProviderResult; use reth_storage_errors::provider::ProviderResult;
use reth_trie::{ use reth_trie::{
updates::TrieUpdates, AccountProof, HashedPostState, HashedStorage, MultiProof, StorageProof, updates::TrieUpdates, AccountProof, HashedPostState, HashedStorage, MultiProof,
TrieInput, StorageMultiProof, StorageProof, TrieInput,
}; };
/// Mock state for testing /// Mock state for testing
@ -112,6 +112,15 @@ impl StorageRootProvider for StateProviderTest {
) -> ProviderResult<StorageProof> { ) -> ProviderResult<StorageProof> {
unimplemented!("proof generation is not supported") unimplemented!("proof generation is not supported")
} }
fn storage_multiproof(
&self,
_address: Address,
_slots: &[B256],
_hashed_storage: HashedStorage,
) -> ProviderResult<StorageMultiProof> {
unimplemented!("proof generation is not supported")
}
} }
impl StateProofProvider for StateProviderTest { impl StateProofProvider for StateProviderTest {

View File

@ -67,6 +67,15 @@ impl reth_storage_api::StorageRootProvider for StateProviderTraitObjWrapper<'_>
) -> ProviderResult<reth_trie::StorageProof> { ) -> ProviderResult<reth_trie::StorageProof> {
self.0.storage_proof(address, slot, hashed_storage) self.0.storage_proof(address, slot, hashed_storage)
} }
fn storage_multiproof(
&self,
address: Address,
slots: &[B256],
hashed_storage: HashedStorage,
) -> ProviderResult<reth_trie::StorageMultiProof> {
self.0.storage_multiproof(address, slots, hashed_storage)
}
} }
impl reth_storage_api::StateProofProvider for StateProviderTraitObjWrapper<'_> { impl reth_storage_api::StateProofProvider for StateProviderTraitObjWrapper<'_> {

View File

@ -9,7 +9,8 @@ use reth_primitives::{Account, Bytecode};
use reth_storage_api::{StateProofProvider, StorageRootProvider}; use reth_storage_api::{StateProofProvider, StorageRootProvider};
use reth_storage_errors::provider::ProviderResult; use reth_storage_errors::provider::ProviderResult;
use reth_trie::{ use reth_trie::{
updates::TrieUpdates, AccountProof, HashedPostState, HashedStorage, MultiProof, TrieInput, updates::TrieUpdates, AccountProof, HashedPostState, HashedStorage, MultiProof,
StorageMultiProof, TrieInput,
}; };
/// A state provider that resolves to data from either a wrapped [`crate::ExecutionOutcome`] /// A state provider that resolves to data from either a wrapped [`crate::ExecutionOutcome`]
@ -138,6 +139,17 @@ impl<SP: StateProvider, EDP: ExecutionDataProvider> StorageRootProvider
storage.extend(&hashed_storage); storage.extend(&hashed_storage);
self.state_provider.storage_proof(address, slot, storage) self.state_provider.storage_proof(address, slot, storage)
} }
fn storage_multiproof(
&self,
address: Address,
slots: &[B256],
hashed_storage: HashedStorage,
) -> ProviderResult<StorageMultiProof> {
let mut storage = self.get_hashed_storage(address);
storage.extend(&hashed_storage);
self.state_provider.storage_multiproof(address, slots, storage)
}
} }
impl<SP: StateProvider, EDP: ExecutionDataProvider> StateProofProvider impl<SP: StateProvider, EDP: ExecutionDataProvider> StateProofProvider

View File

@ -21,7 +21,8 @@ use reth_trie::{
proof::{Proof, StorageProof}, proof::{Proof, StorageProof},
updates::TrieUpdates, updates::TrieUpdates,
witness::TrieWitness, witness::TrieWitness,
AccountProof, HashedPostState, HashedStorage, MultiProof, StateRoot, StorageRoot, TrieInput, AccountProof, HashedPostState, HashedStorage, MultiProof, StateRoot, StorageMultiProof,
StorageRoot, TrieInput,
}; };
use reth_trie_db::{ use reth_trie_db::{
DatabaseHashedPostState, DatabaseHashedStorage, DatabaseProof, DatabaseStateRoot, DatabaseHashedPostState, DatabaseHashedStorage, DatabaseProof, DatabaseStateRoot,
@ -341,6 +342,18 @@ impl<Provider: DBProvider + BlockNumReader> StorageRootProvider
StorageProof::overlay_storage_proof(self.tx(), address, slot, revert_storage) StorageProof::overlay_storage_proof(self.tx(), address, slot, revert_storage)
.map_err(Into::<ProviderError>::into) .map_err(Into::<ProviderError>::into)
} }
fn storage_multiproof(
&self,
address: Address,
slots: &[B256],
hashed_storage: HashedStorage,
) -> ProviderResult<StorageMultiProof> {
let mut revert_storage = self.revert_storage(address)?;
revert_storage.extend(&hashed_storage);
StorageProof::overlay_storage_multiproof(self.tx(), address, slots, revert_storage)
.map_err(Into::<ProviderError>::into)
}
} }
impl<Provider: DBProvider + BlockNumReader> StateProofProvider impl<Provider: DBProvider + BlockNumReader> StateProofProvider

View File

@ -15,7 +15,8 @@ use reth_trie::{
proof::{Proof, StorageProof}, proof::{Proof, StorageProof},
updates::TrieUpdates, updates::TrieUpdates,
witness::TrieWitness, witness::TrieWitness,
AccountProof, HashedPostState, HashedStorage, MultiProof, StateRoot, StorageRoot, TrieInput, AccountProof, HashedPostState, HashedStorage, MultiProof, StateRoot, StorageMultiProof,
StorageRoot, TrieInput,
}; };
use reth_trie_db::{ use reth_trie_db::{
DatabaseProof, DatabaseStateRoot, DatabaseStorageProof, DatabaseStorageRoot, DatabaseProof, DatabaseStateRoot, DatabaseStorageProof, DatabaseStorageRoot,
@ -108,6 +109,16 @@ impl<Provider: DBProvider> StorageRootProvider for LatestStateProviderRef<'_, Pr
StorageProof::overlay_storage_proof(self.tx(), address, slot, hashed_storage) StorageProof::overlay_storage_proof(self.tx(), address, slot, hashed_storage)
.map_err(Into::<ProviderError>::into) .map_err(Into::<ProviderError>::into)
} }
fn storage_multiproof(
&self,
address: Address,
slots: &[B256],
hashed_storage: HashedStorage,
) -> ProviderResult<StorageMultiProof> {
StorageProof::overlay_storage_multiproof(self.tx(), address, slots, hashed_storage)
.map_err(Into::<ProviderError>::into)
}
} }
impl<Provider: DBProvider> StateProofProvider for LatestStateProviderRef<'_, Provider> { impl<Provider: DBProvider> StateProofProvider for LatestStateProviderRef<'_, Provider> {

View File

@ -50,6 +50,7 @@ macro_rules! delegate_provider_impls {
StorageRootProvider $(where [$($generics)*])? { 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>; fn storage_proof(&self, address: alloy_primitives::Address, slot: alloy_primitives::B256, storage: reth_trie::HashedStorage) -> reth_storage_errors::provider::ProviderResult<reth_trie::StorageProof>;
fn storage_multiproof(&self, address: alloy_primitives::Address, slots: &[alloy_primitives::B256], storage: reth_trie::HashedStorage) -> reth_storage_errors::provider::ProviderResult<reth_trie::StorageMultiProof>;
} }
StateProofProvider $(where [$($generics)*])? { 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>; fn proof(&self, input: reth_trie::TrieInput, address: alloy_primitives::Address, slots: &[alloy_primitives::B256]) -> reth_storage_errors::provider::ProviderResult<reth_trie::AccountProof>;

View File

@ -32,8 +32,8 @@ use reth_storage_api::{
}; };
use reth_storage_errors::provider::{ConsistentViewError, ProviderError, ProviderResult}; use reth_storage_errors::provider::{ConsistentViewError, ProviderError, ProviderResult};
use reth_trie::{ use reth_trie::{
updates::TrieUpdates, AccountProof, HashedPostState, HashedStorage, MultiProof, StorageProof, updates::TrieUpdates, AccountProof, HashedPostState, HashedStorage, MultiProof,
TrieInput, StorageMultiProof, StorageProof, TrieInput,
}; };
use reth_trie_db::MerklePatriciaTrie; use reth_trie_db::MerklePatriciaTrie;
use revm::primitives::{BlockEnv, CfgEnvWithHandlerCfg}; use revm::primitives::{BlockEnv, CfgEnvWithHandlerCfg};
@ -639,6 +639,15 @@ impl StorageRootProvider for MockEthProvider {
) -> ProviderResult<reth_trie::StorageProof> { ) -> ProviderResult<reth_trie::StorageProof> {
Ok(StorageProof::new(slot)) Ok(StorageProof::new(slot))
} }
fn storage_multiproof(
&self,
_address: Address,
_slots: &[B256],
_hashed_storage: HashedStorage,
) -> ProviderResult<StorageMultiProof> {
Ok(StorageMultiProof::empty())
}
} }
impl StateProofProvider for MockEthProvider { impl StateProofProvider for MockEthProvider {

View File

@ -372,6 +372,15 @@ impl StorageRootProvider for NoopProvider {
) -> ProviderResult<reth_trie::StorageProof> { ) -> ProviderResult<reth_trie::StorageProof> {
Ok(reth_trie::StorageProof::new(slot)) Ok(reth_trie::StorageProof::new(slot))
} }
fn storage_multiproof(
&self,
_address: Address,
_slots: &[B256],
_hashed_storage: HashedStorage,
) -> ProviderResult<reth_trie::StorageMultiProof> {
Ok(reth_trie::StorageMultiProof::empty())
}
} }
impl StateProofProvider for NoopProvider { impl StateProofProvider for NoopProvider {

View File

@ -5,7 +5,8 @@ use alloy_primitives::{
use reth_storage_errors::provider::ProviderResult; use reth_storage_errors::provider::ProviderResult;
use reth_trie::{ use reth_trie::{
updates::{StorageTrieUpdates, TrieUpdates}, updates::{StorageTrieUpdates, TrieUpdates},
AccountProof, HashedPostState, HashedStorage, MultiProof, StorageProof, TrieInput, AccountProof, HashedPostState, HashedStorage, MultiProof, StorageMultiProof, StorageProof,
TrieInput,
}; };
/// A type that can compute the state root of a given post state. /// A type that can compute the state root of a given post state.
@ -56,6 +57,14 @@ pub trait StorageRootProvider: Send + Sync {
slot: B256, slot: B256,
hashed_storage: HashedStorage, hashed_storage: HashedStorage,
) -> ProviderResult<StorageProof>; ) -> ProviderResult<StorageProof>;
/// Returns the storage multiproof for target slots.
fn storage_multiproof(
&self,
address: Address,
slots: &[B256],
hashed_storage: HashedStorage,
) -> ProviderResult<StorageMultiProof>;
} }
/// A type that can generate state proof on top of a given post state. /// A type that can generate state proof on top of a given post state.

View File

@ -10,7 +10,7 @@ use reth_trie::{
hashed_cursor::HashedPostStateCursorFactory, hashed_cursor::HashedPostStateCursorFactory,
proof::{Proof, StorageProof}, proof::{Proof, StorageProof},
trie_cursor::InMemoryTrieCursorFactory, trie_cursor::InMemoryTrieCursorFactory,
AccountProof, HashedPostStateSorted, HashedStorage, MultiProof, TrieInput, AccountProof, HashedPostStateSorted, HashedStorage, MultiProof, StorageMultiProof, TrieInput,
}; };
/// Extends [`Proof`] with operations specific for working with a database transaction. /// Extends [`Proof`] with operations specific for working with a database transaction.
@ -96,6 +96,14 @@ pub trait DatabaseStorageProof<'a, TX> {
slot: B256, slot: B256,
storage: HashedStorage, storage: HashedStorage,
) -> Result<reth_trie::StorageProof, StateProofError>; ) -> Result<reth_trie::StorageProof, StateProofError>;
/// Generates the storage multiproof for target slots based on [`TrieInput`].
fn overlay_storage_multiproof(
tx: &'a TX,
address: Address,
slots: &[B256],
storage: HashedStorage,
) -> Result<StorageMultiProof, StateProofError>;
} }
impl<'a, TX: DbTx> DatabaseStorageProof<'a, TX> impl<'a, TX: DbTx> DatabaseStorageProof<'a, TX>
@ -125,4 +133,26 @@ impl<'a, TX: DbTx> DatabaseStorageProof<'a, TX>
.with_prefix_set_mut(prefix_set) .with_prefix_set_mut(prefix_set)
.storage_proof(slot) .storage_proof(slot)
} }
fn overlay_storage_multiproof(
tx: &'a TX,
address: Address,
slots: &[B256],
storage: HashedStorage,
) -> Result<StorageMultiProof, StateProofError> {
let hashed_address = keccak256(address);
let targets = slots.iter().map(keccak256).collect();
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_multiproof(targets)
}
} }