Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(trie): expose storage proofs #11550

Merged
merged 2 commits into from
Oct 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion crates/chain-state/src/in_memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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 {
Expand Down
17 changes: 16 additions & 1 deletion crates/chain-state/src/memory_overlay.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
12 changes: 11 additions & 1 deletion crates/revm/src/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand Down
9 changes: 9 additions & 0 deletions crates/rpc/rpc-eth-types/src/cache/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<'_> {
Expand Down
36 changes: 26 additions & 10 deletions crates/storage/provider/src/providers/bundle_state_provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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
Expand Down
20 changes: 17 additions & 3 deletions crates/storage/provider/src/providers/state/historical.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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)
}
Comment on lines +341 to +346
Copy link
Member Author

@rkrasiuk rkrasiuk Oct 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

naming sucks here (reth_trie::StorageProof and reth_trie::proof::StorageProof), ikik, open to suggestions

}

impl<TX: DbTx> StateProofProvider for HistoricalStateProviderRef<'_, TX> {
Expand Down
21 changes: 18 additions & 3 deletions crates/storage/provider/src/providers/state/latest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -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> {
Expand Down
3 changes: 2 additions & 1 deletion crates/storage/provider/src/providers/state/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>;
Expand Down
12 changes: 11 additions & 1 deletion crates/storage/provider/src/test_utils/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand Down Expand Up @@ -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 {
Expand Down
9 changes: 9 additions & 0 deletions crates/storage/provider/src/test_utils/noop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
12 changes: 11 additions & 1 deletion crates/storage/storage-api/src/trie.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion crates/trie/db/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand Down
50 changes: 48 additions & 2 deletions crates/trie/db/src/proof.rs
Original file line number Diff line number Diff line change
@@ -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;

Expand Down Expand Up @@ -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)
}
}
Loading
Loading