Skip to content

Commit

Permalink
feat(executor): Expose full revm Handler (#475)
Browse files Browse the repository at this point in the history
* feat(executor): Expose full `revm` Handler

Improves the API around the `revm` handler in the
`StatelessL2BlockExecutor` to allow for a custom `HandleRegister` to be
passed into the `StatelessL2BlockExecutorBuilder`.

* doc lint

lint
  • Loading branch information
clabby authored Sep 2, 2024
1 parent 25e19e5 commit 9e5e7d3
Show file tree
Hide file tree
Showing 11 changed files with 93 additions and 151 deletions.
File renamed without changes.
File renamed without changes.
49 changes: 49 additions & 0 deletions bin/client/src/fault/handler/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//! Contains the [KonaHandleRegister] function for registering the FPVM-accelerated precompiles.
//!
//! [KonaHandleRegister]: kona_executor::KonaHandleRegister

use alloc::sync::Arc;
use kona_mpt::{TrieDB, TrieDBFetcher, TrieDBHinter};
use revm::{
handler::register::EvmHandler, precompile::PrecompileSpecId, primitives::SpecId,
ContextPrecompiles, State,
};

mod bn128_pair;
mod ecrecover;
mod kzg_point_eval;

/// The [KonaHandleRegister] function for registering the FPVM-accelerated precompiles.
///
/// [KonaHandleRegister]: kona_executor::KonaHandleRegister
pub(crate) fn fpvm_handle_register<F, H>(
handler: &mut EvmHandler<'_, (), &mut State<&mut TrieDB<F, H>>>,
) where
F: TrieDBFetcher,
H: TrieDBHinter,
{
let spec_id = handler.cfg.spec_id;

handler.pre_execution.load_precompiles = Arc::new(move || {
let mut ctx_precompiles =
ContextPrecompiles::new(PrecompileSpecId::from_spec_id(spec_id)).clone();

// Extend with FPVM-accelerated precompiles
let override_precompiles = [
ecrecover::FPVM_ECRECOVER,
bn128_pair::FPVM_ECPAIRING,
kzg_point_eval::FPVM_KZG_POINT_EVAL,
];
ctx_precompiles.extend(override_precompiles);

// Ensure the secp256r1 P256verify precompile is enabled in the FJORD spec
if spec_id.is_enabled_in(SpecId::FJORD) {
ctx_precompiles.extend([
// EIP-7212: secp256r1 P256verify
revm::precompile::secp256r1::P256VERIFY,
]);
}

ctx_precompiles
});
}
4 changes: 2 additions & 2 deletions bin/client/src/fault/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
use kona_common::FileDescriptor;
use kona_preimage::{HintWriter, OracleReader, PipeHandle};

mod precompiles;
pub(crate) use precompiles::FPVMPrecompileOverride;
mod handler;
pub(crate) use handler::fpvm_handle_register;

/// The global preimage oracle reader pipe.
static ORACLE_READER_PIPE: PipeHandle =
Expand Down
65 changes: 0 additions & 65 deletions bin/client/src/fault/precompiles/mod.rs

This file was deleted.

9 changes: 2 additions & 7 deletions bin/client/src/kona.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,10 @@ use kona_client::{
};
use kona_common_proc::client_entry;
use kona_executor::StatelessL2BlockExecutor;
use kona_preimage::{HintWriter, OracleReader};
use kona_primitives::L2AttributesWithParent;

pub(crate) mod fault;
use fault::{FPVMPrecompileOverride, HINT_WRITER, ORACLE_READER};
use fault::{fpvm_handle_register, HINT_WRITER, ORACLE_READER};

/// The size of the LRU cache in the oracle.
const ORACLE_LRU_SIZE: usize = 1024;
Expand Down Expand Up @@ -61,15 +60,11 @@ fn main() -> Result<()> {
.await?;
let L2AttributesWithParent { attributes, .. } = driver.produce_disputed_payload().await?;

let precompile_overrides = FPVMPrecompileOverride::<
OracleL2ChainProvider<CachingOracle<OracleReader, HintWriter>>,
OracleL2ChainProvider<CachingOracle<OracleReader, HintWriter>>,
>::default();
let mut executor = StatelessL2BlockExecutor::builder(&boot.rollup_config)
.with_parent_header(driver.take_l2_safe_head_header())
.with_fetcher(l2_provider.clone())
.with_hinter(l2_provider)
.with_precompile_overrides(precompile_overrides)
.with_handle_register(fpvm_handle_register)
.build()?;
let Header { number, .. } = *executor.execute_payload(attributes)?;
let output_root = executor.compute_output_root()?;
Expand Down
3 changes: 1 addition & 2 deletions crates/executor/benches/execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use alloy_primitives::{address, b256, hex, Bytes, B256};
use alloy_rlp::Decodable;
use anyhow::{anyhow, Result};
use criterion::{criterion_group, criterion_main, Bencher, Criterion};
use kona_executor::{NoPrecompileOverride, StatelessL2BlockExecutor};
use kona_executor::StatelessL2BlockExecutor;
use kona_mpt::{NoopTrieDBHinter, TrieDBFetcher};
use kona_primitives::{
L2PayloadAttributes, RollupConfig, OP_BASE_FEE_PARAMS, OP_CANYON_BASE_FEE_PARAMS,
Expand Down Expand Up @@ -81,7 +81,6 @@ fn op_mainnet_exec_bench(
.with_parent_header(pre_state_header.clone().seal_slow())
.with_fetcher(TestdataTrieDBFetcher::new(data_folder))
.with_hinter(NoopTrieDBHinter)
.with_precompile_overrides(NoPrecompileOverride)
.build()
.unwrap();
l2_block_executor.execute_payload(payload_attrs.clone()).unwrap();
Expand Down
36 changes: 16 additions & 20 deletions crates/executor/src/builder.rs
Original file line number Diff line number Diff line change
@@ -1,46 +1,43 @@
//! Contains the builder pattern for the [StatelessL2BlockExecutor].

use crate::{PrecompileOverride, StatelessL2BlockExecutor};
use crate::StatelessL2BlockExecutor;
use alloy_consensus::{Header, Sealable, Sealed};
use anyhow::Result;
use kona_mpt::{TrieDB, TrieDBFetcher, TrieDBHinter};
use kona_primitives::RollupConfig;
use revm::{db::State, handler::register::EvmHandler};

/// A type alias for the [revm::handler::register::HandleRegister] for kona's block executor.
pub type KonaHandleRegister<F, H> =
for<'i> fn(&mut EvmHandler<'i, (), &mut State<&mut TrieDB<F, H>>>);

/// The builder pattern for the [StatelessL2BlockExecutor].
#[derive(Debug)]
pub struct StatelessL2BlockExecutorBuilder<'a, F, H, PO>
pub struct StatelessL2BlockExecutorBuilder<'a, F, H>
where
F: TrieDBFetcher,
H: TrieDBHinter,
PO: PrecompileOverride<F, H>,
{
/// The [RollupConfig].
config: &'a RollupConfig,
/// The parent [Header] to begin execution from.
parent_header: Option<Sealed<Header>>,
/// The precompile overrides to use during execution.
precompile_overrides: Option<PO>,
/// The [KonaHandleRegister] to use during execution.
handler_register: Option<KonaHandleRegister<F, H>>,
/// The [TrieDBFetcher] to fetch the state trie preimages.
fetcher: Option<F>,
/// The [TrieDBHinter] to hint the state trie preimages.
hinter: Option<H>,
}

impl<'a, F, H, PO> StatelessL2BlockExecutorBuilder<'a, F, H, PO>
impl<'a, F, H> StatelessL2BlockExecutorBuilder<'a, F, H>
where
F: TrieDBFetcher,
H: TrieDBHinter,
PO: PrecompileOverride<F, H>,
{
/// Instantiate a new builder with the given [RollupConfig].
pub fn with_config(config: &'a RollupConfig) -> Self {
Self {
config,
parent_header: None,
precompile_overrides: None,
fetcher: None,
hinter: None,
}
Self { config, parent_header: None, handler_register: None, fetcher: None, hinter: None }
}

/// Set the [Header] to begin execution from.
Expand All @@ -61,14 +58,14 @@ where
self
}

/// Set the precompile overrides to use during execution.
pub fn with_precompile_overrides(mut self, precompile_overrides: PO) -> Self {
self.precompile_overrides = Some(precompile_overrides);
/// Set the [KonaHandleRegister] for execution.
pub fn with_handle_register(mut self, handler_register: KonaHandleRegister<F, H>) -> Self {
self.handler_register = Some(handler_register);
self
}

/// Build the [StatelessL2BlockExecutor] from the builder configuration.
pub fn build(self) -> Result<StatelessL2BlockExecutor<'a, F, H, PO>> {
pub fn build(self) -> Result<StatelessL2BlockExecutor<'a, F, H>> {
let fetcher = self.fetcher.ok_or(anyhow::anyhow!("Fetcher not set"))?;
let hinter = self.hinter.ok_or(anyhow::anyhow!("Hinter not set"))?;
let parent_header = self.parent_header.unwrap_or_else(|| {
Expand All @@ -77,11 +74,10 @@ where
});

let trie_db = TrieDB::new(parent_header.state_root, parent_header, fetcher, hinter);

Ok(StatelessL2BlockExecutor {
config: self.config,
trie_db,
_phantom: core::marker::PhantomData::<PO>,
handler_register: self.handler_register,
})
}
}
50 changes: 23 additions & 27 deletions crates/executor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,7 @@ use revm::{
use tracing::{debug, info};

mod builder;
pub use builder::StatelessL2BlockExecutorBuilder;

mod precompile;
pub use precompile::{NoPrecompileOverride, PrecompileOverride};
pub use builder::{KonaHandleRegister, StatelessL2BlockExecutorBuilder};

mod eip4788;
use eip4788::pre_block_beacon_root_contract_call;
Expand All @@ -43,28 +40,26 @@ use util::{extract_tx_gas_limit, is_system_transaction, logs_bloom, receipt_enve
/// The block executor for the L2 client program. Operates off of a [TrieDB] backed [State],
/// allowing for stateless block execution of OP Stack blocks.
#[derive(Debug)]
pub struct StatelessL2BlockExecutor<'a, F, H, PO>
pub struct StatelessL2BlockExecutor<'a, F, H>
where
F: TrieDBFetcher,
H: TrieDBHinter,
PO: PrecompileOverride<F, H>,
{
/// The [RollupConfig].
config: &'a RollupConfig,
/// The inner state database component.
trie_db: TrieDB<F, H>,
/// Phantom data for the precompile overrides.
_phantom: core::marker::PhantomData<PO>,
/// The [KonaHandleRegister] to use during execution.
handler_register: Option<KonaHandleRegister<F, H>>,
}

impl<'a, F, H, PO> StatelessL2BlockExecutor<'a, F, H, PO>
impl<'a, F, H> StatelessL2BlockExecutor<'a, F, H>
where
F: TrieDBFetcher,
H: TrieDBHinter,
PO: PrecompileOverride<F, H>,
{
/// Constructs a new [StatelessL2BlockExecutorBuilder] with the given [RollupConfig].
pub fn builder(config: &'a RollupConfig) -> StatelessL2BlockExecutorBuilder<'a, F, H, PO> {
pub fn builder(config: &'a RollupConfig) -> StatelessL2BlockExecutorBuilder<'a, F, H> {
StatelessL2BlockExecutorBuilder::with_config(config)
}

Expand Down Expand Up @@ -128,15 +123,22 @@ where

// Construct the block-scoped EVM with the given configuration.
// The transaction environment is set within the loop for each transaction.
let mut evm = Evm::builder()
.with_db(&mut state)
.with_env_with_handler_cfg(EnvWithHandlerCfg::new_with_cfg_env(
initialized_cfg.clone(),
initialized_block_env.clone(),
Default::default(),
))
.append_handler_register(PO::set_precompiles)
.build();
let mut evm = {
let mut base = Evm::builder().with_db(&mut state).with_env_with_handler_cfg(
EnvWithHandlerCfg::new_with_cfg_env(
initialized_cfg.clone(),
initialized_block_env.clone(),
Default::default(),
),
);

// If a handler register is provided, append it to the base EVM.
if let Some(handler) = self.handler_register {
base = base.append_handler_register(handler);
}

base.build()
};

// Execute the transactions in the payload.
let transactions = payload
Expand Down Expand Up @@ -223,7 +225,7 @@ where
cumulative_gas_used = cumulative_gas_used
);

// Drop the EVM to rid the exclusive reference to the database.
// Drop the EVM to free the exclusive reference to the database.
drop(evm);

// Merge all state transitions into the cache state.
Expand Down Expand Up @@ -699,7 +701,6 @@ mod test {
.with_parent_header(header.seal_slow())
.with_fetcher(TestdataTrieDBFetcher::new("block_120794432_exec"))
.with_hinter(NoopTrieDBHinter)
.with_precompile_overrides(NoPrecompileOverride)
.build()
.unwrap();

Expand Down Expand Up @@ -753,7 +754,6 @@ mod test {
.with_parent_header(parent_header.seal_slow())
.with_fetcher(TestdataTrieDBFetcher::new("block_121049889_exec"))
.with_hinter(NoopTrieDBHinter)
.with_precompile_overrides(NoPrecompileOverride)
.build()
.unwrap();

Expand Down Expand Up @@ -811,7 +811,6 @@ mod test {
.with_parent_header(parent_header.seal_slow())
.with_fetcher(TestdataTrieDBFetcher::new("block_121003241_exec"))
.with_hinter(NoopTrieDBHinter)
.with_precompile_overrides(NoPrecompileOverride)
.build()
.unwrap();

Expand Down Expand Up @@ -876,7 +875,6 @@ mod test {
.with_parent_header(parent_header.seal_slow())
.with_fetcher(TestdataTrieDBFetcher::new("block_121057303_exec"))
.with_hinter(NoopTrieDBHinter)
.with_precompile_overrides(NoPrecompileOverride)
.build()
.unwrap();

Expand Down Expand Up @@ -935,7 +933,6 @@ mod test {
.with_parent_header(parent_header.seal_slow())
.with_fetcher(TestdataTrieDBFetcher::new("block_121065789_exec"))
.with_hinter(NoopTrieDBHinter)
.with_precompile_overrides(NoPrecompileOverride)
.build()
.unwrap();

Expand Down Expand Up @@ -1003,7 +1000,6 @@ mod test {
.with_parent_header(parent_header.seal_slow())
.with_fetcher(TestdataTrieDBFetcher::new("block_121135704_exec"))
.with_hinter(NoopTrieDBHinter)
.with_precompile_overrides(NoPrecompileOverride)
.build()
.unwrap();

Expand Down
Loading

0 comments on commit 9e5e7d3

Please sign in to comment.