Skip to content

Commit

Permalink
feat: introduce HashedPostStateProvider
Browse files Browse the repository at this point in the history
  • Loading branch information
frisitano committed Oct 18, 2024
1 parent cb77bce commit d3db641
Show file tree
Hide file tree
Showing 38 changed files with 372 additions and 116 deletions.
4 changes: 0 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions bin/reth/src/commands/debug_cmd/build_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ use reth_primitives::{
};
use reth_provider::{
providers::BlockchainProvider, BlockHashReader, BlockReader, BlockWriter, ChainSpecProvider,
ProviderFactory, StageCheckpointReader, StateProviderFactory,
HashedPostStateProvider, ProviderFactory, StageCheckpointReader, StateProviderFactory,
};
use reth_revm::{database::StateProviderDatabase, primitives::EnvKzgSettings};
use reth_stages::StageId;
Expand Down Expand Up @@ -266,7 +266,8 @@ impl<C: ChainSpecParser<ChainSpec = ChainSpec>> Command<C> {
ExecutionOutcome::from((block_execution_output, block.number));
debug!(target: "reth::cli", ?execution_outcome, "Executed block");

let hashed_post_state = execution_outcome.hash_state_slow();
let hashed_post_state =
provider_factory.hashed_post_state_from_bundle_state(execution_outcome.state());
let (state_root, trie_updates) = StateRoot::overlay_root_with_updates(
provider_factory.provider()?.tx_ref(),
hashed_post_state.clone(),
Expand Down
8 changes: 4 additions & 4 deletions bin/reth/src/commands/debug_cmd/in_memory_merkle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ use reth_node_api::{NodeTypesWithDB, NodeTypesWithEngine};
use reth_node_ethereum::EthExecutorProvider;
use reth_primitives::BlockHashOrNumber;
use reth_provider::{
writer::UnifiedStorageWriter, AccountExtReader, ChainSpecProvider, HashingWriter,
HeaderProvider, OriginalValuesKnown, ProviderFactory, StageCheckpointReader, StateWriter,
StorageReader, ToLatestStateProviderRef,
writer::UnifiedStorageWriter, AccountExtReader, ChainSpecProvider, HashedPostStateProvider,
HashingWriter, HeaderProvider, OriginalValuesKnown, ProviderFactory, StageCheckpointReader,
StateWriter, StorageReader, ToLatestStateProviderRef,
};
use reth_revm::database::StateProviderDatabase;
use reth_stages::StageId;
Expand Down Expand Up @@ -153,7 +153,7 @@ impl<C: ChainSpecParser<ChainSpec = ChainSpec>> Command<C> {
// Unpacked `BundleState::state_root_slow` function
let (in_memory_state_root, in_memory_updates) = StateRoot::overlay_root_with_updates(
provider.tx_ref(),
execution_outcome.hash_state_slow(),
provider.hashed_post_state_from_bundle_state(execution_outcome.state()),
)?;

if in_memory_state_root == block.state_root {
Expand Down
14 changes: 10 additions & 4 deletions crates/blockchain-tree/src/blockchain_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ use reth_primitives::{
use reth_provider::{
providers::ProviderNodeTypes, BlockExecutionWriter, BlockNumReader, BlockWriter,
CanonStateNotification, CanonStateNotificationSender, CanonStateNotifications,
ChainSpecProvider, ChainSplit, ChainSplitTarget, DisplayBlocksChain, HeaderProvider,
ProviderError, StaticFileProviderFactory,
ChainSpecProvider, ChainSplit, ChainSplitTarget, DisplayBlocksChain, HashedPostStateProvider,
HeaderProvider, ProviderError, StaticFileProviderFactory,
};
use reth_stages_api::{MetricEvent, MetricEventsSender};
use reth_storage_errors::provider::{ProviderResult, RootMismatch};
Expand Down Expand Up @@ -1216,7 +1216,8 @@ where
recorder: &mut MakeCanonicalDurationsRecorder,
) -> Result<(), CanonicalError> {
let (blocks, state, chain_trie_updates) = chain.into_inner();
let hashed_state = state.hash_state_slow();
let hashed_state =
self.externals.provider_factory.hashed_post_state_from_bundle_state(state.state());
let prefix_sets = hashed_state.construct_prefix_sets().freeze();
let hashed_state_sorted = hashed_state.into_sorted();

Expand Down Expand Up @@ -1875,7 +1876,12 @@ mod tests {
);

let provider = tree.externals.provider_factory.provider().unwrap();
let prefix_sets = exec5.hash_state_slow().construct_prefix_sets().freeze();
let prefix_sets = tree
.externals
.provider_factory
.hashed_post_state_from_bundle_state(exec5.state())
.construct_prefix_sets()
.freeze();
let state_root =
StateRoot::from_tx(provider.tx_ref()).with_prefix_sets(prefix_sets).root().unwrap();
assert_eq!(state_root, block5.state_root);
Expand Down
16 changes: 11 additions & 5 deletions crates/blockchain-tree/src/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@ use reth_execution_types::{Chain, ExecutionOutcome};
use reth_primitives::{GotExpected, SealedBlockWithSenders, SealedHeader};
use reth_provider::{
providers::{BundleStateProvider, ConsistentDbView, ProviderNodeTypes},
FullExecutionDataProvider, ProviderError, StateRootProvider, TryIntoHistoricalStateProvider,
FullExecutionDataProvider, HashedPostStateProvider, ProviderError, StateRootProvider,
TryIntoHistoricalStateProvider,
};
use reth_revm::database::StateProviderDatabase;
use reth_trie::{updates::TrieUpdates, HashedPostState, TrieInput};
use reth_trie::{updates::TrieUpdates, TrieInput};
use reth_trie_parallel::parallel_root::ParallelStateRoot;
use std::{
collections::BTreeMap,
Expand Down Expand Up @@ -227,14 +228,19 @@ impl AppendableChain {
execution_outcome.extend(initial_execution_outcome.clone());
ParallelStateRoot::new(
consistent_view,
TrieInput::from_state(execution_outcome.hash_state_slow()),
TrieInput::from_state(
externals
.provider_factory
.hashed_post_state_from_bundle_state(execution_outcome.state()),
),
)
.incremental_root_with_updates()
.map(|(root, updates)| (root, Some(updates)))
.map_err(ProviderError::from)?
} else {
let hashed_state =
HashedPostState::from_bundle_state(&initial_execution_outcome.state().state);
let hashed_state = externals
.provider_factory
.hashed_post_state_from_bundle_state(initial_execution_outcome.state());
let state_root = provider.state_root(hashed_state)?;
(state_root, None)
};
Expand Down
20 changes: 18 additions & 2 deletions crates/chain-state/src/in_memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -870,8 +870,8 @@ mod tests {
use reth_errors::ProviderResult;
use reth_primitives::{Account, Bytecode, Receipt, Requests};
use reth_storage_api::{
AccountReader, BlockHashReader, StateProofProvider, StateProvider, StateRootProvider,
StorageRootProvider,
AccountReader, BlockHashReader, HashedPostStateProvider, StateProofProvider, StateProvider,
StateRootProvider, StorageRootProvider,
};
use reth_trie::{AccountProof, HashedStorage, MultiProof, StorageProof, TrieInput};

Expand Down Expand Up @@ -1012,6 +1012,22 @@ mod tests {
}
}

impl HashedPostStateProvider for MockStateProvider {
fn hashed_post_state_from_bundle_state(
&self,
_bundle_state: &reth_execution_types::BundleState,
) -> HashedPostState {
HashedPostState::default()
}

fn hashed_post_state_from_reverts(
&self,
_block_number: BlockNumber,
) -> ProviderResult<HashedPostState> {
Ok(HashedPostState::default())
}
}

#[test]
fn test_in_memory_state_impl_state_by_hash() {
let mut state_by_hash = HashMap::default();
Expand Down
20 changes: 18 additions & 2 deletions crates/chain-state/src/memory_overlay.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ use alloy_primitives::{
use reth_errors::ProviderResult;
use reth_primitives::{Account, Bytecode};
use reth_storage_api::{
AccountReader, BlockHashReader, StateProofProvider, StateProvider, StateProviderBox,
StateRootProvider, StorageRootProvider,
AccountReader, BlockHashReader, HashedPostStateProvider, StateProofProvider, StateProvider,
StateProviderBox, StateRootProvider, StorageRootProvider,
};
use reth_trie::{
updates::TrieUpdates, AccountProof, HashedPostState, HashedStorage, MultiProof, TrieInput,
Expand Down Expand Up @@ -188,6 +188,22 @@ impl StateProofProvider for MemoryOverlayStateProvider {
}
}

impl HashedPostStateProvider for MemoryOverlayStateProvider {
fn hashed_post_state_from_bundle_state(
&self,
bundle_state: &reth_execution_types::BundleState,
) -> HashedPostState {
self.historical.hashed_post_state_from_bundle_state(bundle_state)
}

fn hashed_post_state_from_reverts(
&self,
block_number: BlockNumber,
) -> ProviderResult<HashedPostState> {
self.historical.hashed_post_state_from_reverts(block_number)
}
}

impl StateProvider for MemoryOverlayStateProvider {
fn storage(
&self,
Expand Down
1 change: 0 additions & 1 deletion crates/consensus/auto-seal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ reth-engine-primitives.workspace = true
reth-consensus.workspace = true
reth-network-peers.workspace = true
reth-tokio-util.workspace = true
reth-trie.workspace = true

# ethereum
alloy-primitives.workspace = true
Expand Down
3 changes: 1 addition & 2 deletions crates/consensus/auto-seal/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ use reth_primitives::{
use reth_provider::{BlockReaderIdExt, StateProviderFactory, StateRootProvider};
use reth_revm::database::StateProviderDatabase;
use reth_transaction_pool::TransactionPool;
use reth_trie::HashedPostState;
use revm_primitives::calc_excess_blob_gas;
use std::{
collections::HashMap,
Expand Down Expand Up @@ -383,7 +382,7 @@ impl StorageInner {
executor.executor(&mut db).execute((&block, U256::ZERO).into())?;
let gas_used = block_execution_output.gas_used;
let execution_outcome = ExecutionOutcome::from((block_execution_output, block.number));
let hashed_state = HashedPostState::from_bundle_state(&execution_outcome.state().state);
let hashed_state = db.0.hashed_post_state_from_bundle_state(execution_outcome.state());

// todo(onbjerg): we should not pass requests around as this is building a block, which
// means we need to extract the requests from the execution output and compute the requests
Expand Down
4 changes: 2 additions & 2 deletions crates/engine/invalid-block-hooks/src/witness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use reth_revm::{
};
use reth_rpc_api::DebugApiClient;
use reth_tracing::tracing::warn;
use reth_trie::{updates::TrieUpdates, HashedPostState, HashedStorage};
use reth_trie::{updates::TrieUpdates, HashedStorage};
use serde::Serialize;

/// Generates a witness for the given block and saves it to a file.
Expand Down Expand Up @@ -128,7 +128,7 @@ where
//
// Note: We grab *all* accounts in the cache here, as the `BundleState` prunes
// referenced accounts + storage slots.
let mut hashed_state = HashedPostState::from_bundle_state(&bundle_state.state);
let mut hashed_state = db.database.hashed_post_state_from_bundle_state(&bundle_state);
for (address, account) in db.cache.accounts {
let hashed_address = keccak256(address);
hashed_state
Expand Down
19 changes: 13 additions & 6 deletions crates/engine/tree/src/tree/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ use reth_primitives::{
};
use reth_provider::{
providers::ConsistentDbView, BlockReader, DatabaseProviderFactory, ExecutionOutcome,
ProviderError, StateProviderBox, StateProviderFactory, StateReader, StateRootProvider,
TransactionVariant,
HashedPostStateProvider, ProviderError, StateProviderBox, StateProviderFactory, StateReader,
StateRootProvider, TransactionVariant,
};
use reth_revm::database::StateProviderDatabase;
use reth_stages_api::ControlFlow;
Expand Down Expand Up @@ -531,8 +531,14 @@ impl<P: Debug, E: Debug, T: EngineTypes + Debug, Spec: Debug> std::fmt::Debug

impl<P, E, T, Spec> EngineApiTreeHandler<P, E, T, Spec>
where
P: DatabaseProviderFactory + BlockReader + StateProviderFactory + StateReader + Clone + 'static,
<P as DatabaseProviderFactory>::Provider: BlockReader,
P: DatabaseProviderFactory
+ BlockReader
+ StateProviderFactory
+ StateReader
+ HashedPostStateProvider
+ Clone
+ 'static,
<P as DatabaseProviderFactory>::Provider: BlockReader + HashedPostStateProvider,
E: BlockExecutorProvider,
T: EngineTypes,
Spec: Send + Sync + EthereumHardforks + 'static,
Expand Down Expand Up @@ -1530,7 +1536,8 @@ where
.provider
.get_state(block.number)?
.ok_or_else(|| ProviderError::StateForNumberNotFound(block.number))?;
let hashed_state = execution_output.hash_state_slow();
let hashed_state =
self.provider.hashed_post_state_from_bundle_state(execution_output.state());

Ok(Some(ExecutedBlock {
block: Arc::new(block),
Expand Down Expand Up @@ -2194,7 +2201,7 @@ where
return Err(err.into())
}

let hashed_state = HashedPostState::from_bundle_state(&output.state.state);
let hashed_state = self.provider.hashed_post_state_from_bundle_state(&output.state);

trace!(target: "engine::tree", block=?BlockNumHash::new(block_number, block_hash), "Calculating block state root");
let root_time = Instant::now();
Expand Down
3 changes: 1 addition & 2 deletions crates/engine/util/src/reorg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ use reth_revm::{
DatabaseCommit,
};
use reth_rpc_types_compat::engine::payload::block_to_payload;
use reth_trie::HashedPostState;
use revm_primitives::{
calc_excess_blob_gas, BlockEnv, CfgEnvWithHandlerCfg, EVMError, EnvWithHandlerCfg,
};
Expand Down Expand Up @@ -365,7 +364,7 @@ where
reorg_target.number,
Default::default(),
);
let hashed_state = HashedPostState::from_bundle_state(&outcome.state().state);
let hashed_state = state_provider.hashed_post_state_from_bundle_state(outcome.state());

let (blob_gas_used, excess_blob_gas) =
if chain_spec.is_cancun_active_at_timestamp(reorg_target.timestamp) {
Expand Down
1 change: 0 additions & 1 deletion crates/ethereum/payload/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ reth-basic-payload-builder.workspace = true
reth-evm.workspace = true
reth-evm-ethereum.workspace = true
reth-errors.workspace = true
reth-trie.workspace = true
reth-chain-state.workspace = true
reth-chainspec.workspace = true

Expand Down
23 changes: 13 additions & 10 deletions crates/ethereum/payload/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ use reth_revm::database::StateProviderDatabase;
use reth_transaction_pool::{
noop::NoopTransactionPool, BestTransactionsAttributes, TransactionPool,
};
use reth_trie::HashedPostState;
use revm::{
db::{states::bundle_state::BundleRetention, State},
primitives::{EVMError, EnvWithHandlerCfg, InvalidTransaction, ResultAndState},
Expand Down Expand Up @@ -353,16 +352,20 @@ where
let logs_bloom = execution_outcome.block_logs_bloom(block_number).expect("Number is in range");

// calculate the state root
let hashed_state = HashedPostState::from_bundle_state(&execution_outcome.state().state);
let (state_root, trie_output) = {

let (state_root, trie_output, hashed_state) = {
let state_provider = db.database.0.inner.borrow_mut();
state_provider.db.state_root_with_updates(hashed_state.clone()).inspect_err(|err| {
warn!(target: "payload_builder",
parent_hash=%parent_block.hash(),
%err,
"failed to calculate state root for payload"
);
})?
let hashed_state =
state_provider.db.hashed_post_state_from_bundle_state(execution_outcome.state());
let (state_root, trie_output) =
state_provider.db.state_root_with_updates(hashed_state.clone()).inspect_err(|err| {
warn!(target: "payload_builder",
parent_hash=%parent_block.hash(),
%err,
"failed to calculate state root for payload"
);
})?;
(state_root, trie_output, hashed_state)
};

// create the block header
Expand Down
6 changes: 3 additions & 3 deletions crates/evm/execution-types/src/execution_outcome.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::BlockExecutionOutput;
use alloy_primitives::{Address, BlockNumber, Bloom, Log, B256, U256};
use reth_primitives::{logs_bloom, Account, Bytecode, Receipt, Receipts, Requests, StorageEntry};
use reth_trie::HashedPostState;
use reth_trie::{HashedPostState, KeyHasher};
use revm::{
db::{states::BundleState, BundleAccount},
primitives::AccountInfo,
Expand Down Expand Up @@ -162,8 +162,8 @@ impl ExecutionOutcome {

/// Returns [`HashedPostState`] for this execution outcome.
/// See [`HashedPostState::from_bundle_state`] for more info.
pub fn hash_state_slow(&self) -> HashedPostState {
HashedPostState::from_bundle_state(&self.bundle.state)
pub fn hash_state_slow<KH: KeyHasher>(&self) -> HashedPostState {
HashedPostState::from_bundle_state::<KH>(&self.bundle.state)
}

/// Transform block number to the index of block.
Expand Down
3 changes: 3 additions & 0 deletions crates/evm/execution-types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ pub use execute::*;
mod execution_outcome;
pub use execution_outcome::*;

// Re-export commonly used execution types from `revm`.
pub use revm::db::{BundleAccount, BundleState};

/// Bincode-compatible serde implementations for commonly used types for (EVM) block execution.
///
/// `bincode` crate doesn't work with optionally serializable serde fields, but some of the
Expand Down
Loading

0 comments on commit d3db641

Please sign in to comment.