bluealloy/revm

Allow `ContextStatefulPrecompile` trait to access broader `Context`

Opened this issue · 3 comments

Overview

At the moment, the ContextStatefulPrecompile can only access the InnerEvmContext. This is a bit limiting in that the external context within the broader Context cannot be accessed during precompile execution.

The generic external context is a useful place to store owned memory such as a channel sender, etc., that is intended to have a lifetime that matches the EVM. This would help out over in kona, where we replace a few precompiles with versions that reach out to the host program via a file channel for the result of execution to speed up proving when running natively.

I'd be glad to take this on or a different suggested approach to solve the issue if upstream is open to it.

I am working towards it in Evm Framework.

In this PR: #1865
Context is flattened and full of generics:

pub struct Context<BLOCK = BlockEnv, TX = TxEnv, SPEC = SpecId, DB: Database = EmptyDB, CHAIN = ()>
{
/// Transaction information.
pub tx: TX,
/// Block information.
pub block: BLOCK,
/// Configurations.
pub cfg: CfgEnv,
/// EVM State with journaling support and database.
pub journaled_state: JournaledState<DB>,
/// Inner context.
pub chain: CHAIN,
/// TODO include it inside CfgEnv.
pub spec: SPEC,
/// Error that happened during execution.
pub error: Result<(), <DB as Database>::Error>,
}

And precompiles is a trait you implement, that when called will give you all of the context:
pub trait PrecompileProvider: Clone {
type Context;
type Error;
fn new(ctx: &mut Self::Context) -> Self;
fn run(
&mut self,
ctx: &mut Self::Context,
address: &Address,
bytes: &Bytes,
gas_limit: u64,
) -> Result<Option<InterpreterResult>, Self::Error>;
fn warm_addresses(&self) -> impl Iterator<Item = Address>;
}

This is pretty neat @rakita. Is the intention here to treat what is currently EXT as CHAIN, or is that intended for something else? It looks like, for example, the revm-optimism crate is already using this for L1 block info caching.

/// Context for the Optimism chain.
#[derive(Clone, Default, Debug, PartialEq, Eq)]
pub struct Context {
l1_block_info: Option<L1BlockInfo>,
}
impl OptimismContextTrait for Context {
fn l1_block_info(&self) -> Option<&L1BlockInfo> {
self.l1_block_info.as_ref()
}
fn l1_block_info_mut(&mut self) -> &mut Option<L1BlockInfo> {
&mut self.l1_block_info
}
}

What I'd like to do is give the precompiles access to owned periphery context, unrelated to the chain context. In kona we need to do this with revm-optimism, so it looks like the optimal way to do this within the current setup would be to create a new OptimismContextTrait implementation, and then define a new OptimismEvmWiring that sets Self::ChainContext to my extended context structure?

impl<DB: Database, EXT> EvmWiring for OptimismEvmWiring<DB, EXT> {
type Block = BlockEnv;
type Database = DB;
type ChainContext = Context;
type ExternalContext = EXT;
type Hardfork = OptimismSpecId;
type HaltReason = OptimismHaltReason;
type Transaction = OpTransaction<TxEnv>;
}

This is pretty neat @rakita. Is the intention here to treat what is currently EXT as CHAIN, or is that intended for something else? It looks like, for example, the revm-optimism crate is already using this for L1 block info caching.

Yeah, you will have only a Context, that has one of generics a CHAIN so it is a lot easier to reason about.

OptimismEvmWiring is removed, check out the new setup and how it is used inside revm-optimism