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

Abstract block executor output #11314

Closed
wants to merge 10 commits into from
256 changes: 146 additions & 110 deletions Cargo.lock

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ fmt:
cargo +nightly fmt

lint-reth:
cargo +nightly clippy \
cargo clippy \
--workspace \
--bin "reth" \
--lib \
Expand All @@ -336,7 +336,7 @@ lint-reth:
-- -D warnings

lint-op-reth:
cargo +nightly clippy \
cargo clippy \
--workspace \
--bin "op-reth" \
--lib \
Expand All @@ -347,7 +347,7 @@ lint-op-reth:
-- -D warnings

lint-other-targets:
cargo +nightly clippy \
cargo clippy \
--workspace \
--lib \
--examples \
Expand Down
31 changes: 10 additions & 21 deletions crates/consensus/auto-seal/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,9 @@ impl StorageInner {
let block_execution_output =
executor.executor(&mut db).execute((&block, U256::ZERO).into())?;
let gas_used = block_execution_output.gas_used;
// calculate the receipts root of the block
header.receipts_root = block_execution_output.receipts_root_slow();

let execution_outcome = ExecutionOutcome::from((block_execution_output, block.number));
let hashed_state = HashedPostState::from_bundle_state(&execution_outcome.state().state);

Expand All @@ -404,6 +407,13 @@ impl StorageInner {

// now we need to update certain header fields with the results of the execution
header.state_root = db.state_root(hashed_state)?;

trace!(target: "consensus::auto",
state_root=?header.state_root,
?body,
"calculated state root"
);

header.gas_used = gas_used;

let receipts = execution_outcome.receipts_by_block(header.number);
Expand All @@ -413,27 +423,6 @@ impl StorageInner {
receipts.iter().map(|r| r.as_ref().unwrap().bloom_slow()).collect::<Vec<Bloom>>();
header.logs_bloom = receipts_with_bloom.iter().fold(Bloom::ZERO, |bloom, r| bloom | *r);

// update receipts root
header.receipts_root = {
#[cfg(feature = "optimism")]
let receipts_root = execution_outcome
.generic_receipts_root_slow(header.number, |receipts| {
reth_optimism_consensus::calculate_receipt_root_no_memo_optimism(
receipts,
&chain_spec,
header.timestamp,
)
})
.expect("Receipts is present");

#[cfg(not(feature = "optimism"))]
let receipts_root =
execution_outcome.receipts_root_slow(header.number).expect("Receipts is present");

receipts_root
};
trace!(target: "consensus::auto", root=?header.state_root, ?body, "calculated root");

// finally insert into storage
self.insert_new_block(header.clone(), body);

Expand Down
12 changes: 6 additions & 6 deletions crates/engine/invalid-block-hooks/src/witness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use reth_chainspec::{EthChainSpec, EthereumHardforks};
use reth_engine_primitives::InvalidBlockHook;
use reth_evm::{system_calls::SystemCaller, ConfigureEvm};
use reth_primitives::{Header, Receipt, SealedBlockWithSenders, SealedHeader};
use reth_provider::{BlockExecutionOutput, ChainSpecProvider, StateProviderFactory};
use reth_provider::{BlockExecOutput, ChainSpecProvider, StateProviderFactory};
use reth_revm::{
database::StateProviderDatabase,
db::states::bundle_state::BundleRetention,
Expand Down Expand Up @@ -60,7 +60,7 @@ where
&self,
parent_header: &SealedHeader,
block: &SealedBlockWithSenders,
output: &BlockExecutionOutput<Receipt>,
output: impl BlockExecOutput,
trie_updates: Option<(&TrieUpdates, B256)>,
) -> eyre::Result<()> {
// TODO(alexey): unify with `DebugApi::debug_execution_witness`
Expand Down Expand Up @@ -209,18 +209,18 @@ where
reverts.sort_by(|left, right| left.0.cmp(&right.0));
}

if bundle_state != output.state {
if bundle_state != *output.state() {
let original_path = self.save_file(
format!("{}_{}.bundle_state.original.json", block.number, block.hash()),
&output.state,
output.state(),
)?;
let re_executed_path = self.save_file(
format!("{}_{}.bundle_state.re_executed.json", block.number, block.hash()),
&bundle_state,
)?;

let filename = format!("{}_{}.bundle_state.diff", block.number, block.hash());
let diff_path = self.save_diff(filename, &bundle_state, &output.state)?;
let diff_path = self.save_diff(filename, &bundle_state, output.state())?;

warn!(
target: "engine::invalid_block_hooks::witness",
Expand Down Expand Up @@ -306,7 +306,7 @@ where
&self,
parent_header: &SealedHeader,
block: &SealedBlockWithSenders,
output: &BlockExecutionOutput<Receipt>,
output: impl BlockExecOutput,
trie_updates: Option<(&TrieUpdates, B256)>,
) {
if let Err(err) = self.on_invalid_block(parent_header, block, output, trie_updates) {
Expand Down
21 changes: 8 additions & 13 deletions crates/engine/primitives/src/invalid_block_hook.rs
Original file line number Diff line number Diff line change
@@ -1,35 +1,30 @@
use alloy_primitives::B256;
use reth_execution_types::BlockExecutionOutput;
use reth_primitives::{Receipt, SealedBlockWithSenders, SealedHeader};
use reth_execution_types::BlockExecOutput;
use reth_primitives::{SealedBlockWithSenders, SealedHeader};
use reth_trie::updates::TrieUpdates;

/// An invalid block hook.
pub trait InvalidBlockHook: Send + Sync {
pub trait InvalidBlockHook<O>: Send + Sync {
/// Invoked when an invalid block is encountered.
fn on_invalid_block(
&self,
parent_header: &SealedHeader,
block: &SealedBlockWithSenders,
output: &BlockExecutionOutput<Receipt>,
output: &O,
trie_updates: Option<(&TrieUpdates, B256)>,
);
}

impl<F> InvalidBlockHook for F
impl<F, O> InvalidBlockHook<O> for F
where
F: Fn(
&SealedHeader,
&SealedBlockWithSenders,
&BlockExecutionOutput<Receipt>,
Option<(&TrieUpdates, B256)>,
) + Send
+ Sync,
F: Fn(&SealedHeader, &SealedBlockWithSenders, &O, Option<(&TrieUpdates, B256)>) + Send + Sync,
O: BlockExecOutput,
{
fn on_invalid_block(
&self,
parent_header: &SealedHeader,
block: &SealedBlockWithSenders,
output: &BlockExecutionOutput<Receipt>,
output: &O,
trie_updates: Option<(&TrieUpdates, B256)>,
) {
self(parent_header, block, output, trie_updates)
Expand Down
6 changes: 3 additions & 3 deletions crates/engine/tree/src/tree/invalid_block_hook.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use alloy_primitives::B256;
use reth_engine_primitives::InvalidBlockHook;
use reth_primitives::{Receipt, SealedBlockWithSenders, SealedHeader};
use reth_provider::BlockExecutionOutput;
use reth_provider::BlockExecOutput;
use reth_trie::updates::TrieUpdates;

/// A no-op [`InvalidBlockHook`] that does nothing.
Expand All @@ -14,7 +14,7 @@ impl InvalidBlockHook for NoopInvalidBlockHook {
&self,
_parent_header: &SealedHeader,
_block: &SealedBlockWithSenders,
_output: &BlockExecutionOutput<Receipt>,
_output: impl BlockExecOutput,
_trie_updates: Option<(&TrieUpdates, B256)>,
) {
}
Expand All @@ -34,7 +34,7 @@ impl InvalidBlockHook for InvalidBlockHooks {
&self,
parent_header: &SealedHeader,
block: &SealedBlockWithSenders,
output: &BlockExecutionOutput<Receipt>,
output: impl BlockExecOutput,
trie_updates: Option<(&TrieUpdates, B256)>,
) {
for hook in &self.0 {
Expand Down
12 changes: 6 additions & 6 deletions crates/ethereum/evm/src/execute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use reth_chainspec::{ChainSpec, EthereumHardforks, MAINNET};
use reth_ethereum_consensus::validate_block_post_execution;
use reth_evm::{
execute::{
BatchExecutor, BlockExecutionError, BlockExecutionInput, BlockExecutionOutput,
BatchExecutor, BlockExecOutput, BlockExecutionError, BlockExecutionInput,
BlockExecutorProvider, BlockValidationError, Executor, ProviderError,
},
system_calls::{NoopHook, OnStateHook, SystemCaller},
Expand Down Expand Up @@ -83,7 +83,7 @@ where
type BatchExecutor<DB: Database<Error: Into<ProviderError> + Display>> =
EthBatchExecutor<EvmConfig, DB>;

fn executor<DB>(&self, db: DB) -> Self::Executor<DB>
fn executor<DB>(&self, db: DB) -> Self::Executor<DB, impl>
where
DB: Database<Error: Into<ProviderError> + Display>,
{
Expand Down Expand Up @@ -353,7 +353,7 @@ where
DB: Database<Error: Into<ProviderError> + Display>,
{
type Input<'a> = BlockExecutionInput<'a, BlockWithSenders>;
type Output = BlockExecutionOutput<Receipt>;
type Output = EthBlockExecOutput;
type Error = BlockExecutionError;

/// Executes the block and commits the changes to the internal state.
Expand All @@ -369,7 +369,7 @@ where
// NOTE: we need to merge keep the reverts for the bundle retention
self.state.merge_transitions(BundleRetention::Reverts);

Ok(BlockExecutionOutput { state: self.state.take_bundle(), receipts, requests, gas_used })
Ok(BlockExecOutput { state: self.state.take_bundle(), receipts, requests, gas_used })
}

fn execute_with_state_witness<F>(
Expand All @@ -387,7 +387,7 @@ where
// NOTE: we need to merge keep the reverts for the bundle retention
self.state.merge_transitions(BundleRetention::Reverts);
witness(&self.state);
Ok(BlockExecutionOutput { state: self.state.take_bundle(), receipts, requests, gas_used })
Ok(BlockExecOutput { state: self.state.take_bundle(), receipts, requests, gas_used })
}

fn execute_with_state_hook<F>(
Expand Down Expand Up @@ -1282,7 +1282,7 @@ mod tests {

let executor = provider.executor(StateProviderDatabase::new(&db));

let BlockExecutionOutput { receipts, requests, .. } = executor
let BlockExecOutput { receipts, requests, .. } = executor
.execute(
(
&Block {
Expand Down
65 changes: 61 additions & 4 deletions crates/evm/execution-types/src/execute.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use alloy_primitives::U256;
use reth_primitives::Request;
use alloy_primitives::{B256, U256};
use reth_primitives::{proofs, Receipt, Request};
use revm::db::BundleState;

/// A helper type for ethereum block inputs that consists of a block and the total difficulty.
Expand All @@ -24,17 +24,74 @@ impl<'a, Block> From<(&'a Block, U256)> for BlockExecutionInput<'a, Block> {
}
}

/// Output from executing a block.
pub trait BlockExecOutput {
/// Receipt of block execution.
type Receipt;

/// Returns a reference to state post-execution.
fn state(&self) -> &BundleState;

/// Returns slice of receipts generated by block execution.
fn receipts(&self) -> &[Self::Receipt];

/// Returns slice of EIP-7685 requests of transactions in block.
fn requests(&self) -> &[Request];

/// Accumulated gas used to execute transactions in block.
fn gas_used(&self) -> u64;

/// Calculates the receipts root of the block.
fn receipts_root_slow(&self) -> Option<B256>;

/// Consumes instance and returns non-trivially state, receipts and requests.
fn deconstruct(self) -> (BundleState, Vec<Self::Receipt>, Vec<Request>);
}

/// The output of an ethereum block.
///
/// Contains the state changes, transaction receipts, and total gas used in the block.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct BlockExecutionOutput<T> {
pub struct EthBlockExecOutput {
/// The changed state of the block after execution.
pub state: BundleState,
/// All the receipts of the transactions in the block.
pub receipts: Vec<T>,
pub receipts: Vec<Receipt>,
/// All the EIP-7685 requests of the transactions in the block.
pub requests: Vec<Request>,
/// The total gas used by the block.
pub gas_used: u64,
}

impl BlockExecOutput for EthBlockExecOutput {
type Receipt = Receipt;

fn state(&self) -> &BundleState {
&self.state
}

fn receipts(&self) -> &[Self::Receipt] {
&self.receipts
}

fn requests(&self) -> &[Request] {
&self.requests
}

fn gas_used(&self) -> u64 {
self.gas_used
}

/// Returns the receipt root for all recorded receipts.
/// Note: this function calculated Bloom filters for every receipt and created merkle trees
/// of receipt. This is a expensive operation.
fn receipts_root_slow(&self) -> Option<B256> {
Some(proofs::calculate_receipt_root_no_memo(&self.receipts))
}

fn deconstruct(self) -> (BundleState, Vec<Self::Receipt>, Vec<Request>) {
let Self { state, receipts, requests, .. } = self;

(state, receipts, requests)
}
}
Loading
Loading