Skip to content
This repository was archived by the owner on Jan 12, 2026. It is now read-only.
Draft
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
1 change: 1 addition & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions crates/op-rbuilder/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ async-trait = { workspace = true }
clap_builder = { workspace = true }
clap.workspace = true
derive_more.workspace = true
derive-where = { version = "1.6.0", default-features = false }
either.workspace = true
metrics.workspace = true
serde_json.workspace = true
Expand Down
3 changes: 2 additions & 1 deletion crates/op-rbuilder/src/block_stm/evm/custom_evm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@
//! This is based on the reference `op_revm::OpEvm` but lives in this crate
//! to allow customization of the execution process.

use super::EthFrame;
use op_revm::precompiles::OpPrecompiles;
use revm::{
Database, Inspector,
context::{ContextError, ContextSetters, Evm, FrameStack},
context_interface::ContextTr,
handler::{
EthFrame, EvmTr, FrameInitOrResult, ItemOrResult, PrecompileProvider,
EvmTr, FrameInitOrResult, ItemOrResult, PrecompileProvider,
evm::FrameTr,
instructions::{EthInstructions, InstructionProvider},
},
Expand Down
146 changes: 146 additions & 0 deletions crates/op-rbuilder/src/block_stm/evm/custom_precompiles.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
//! Custom precompile provider that extends OP Stack precompiles with WETH precompile.

use super::weth_precompile::{WETH_ADDRESS, run_weth_precompile};
use alloy_primitives::Address;
use op_revm::{OpSpecId, precompiles::OpPrecompiles};
use revm::{
context_interface::{Cfg, ContextTr, JournalTr, LocalContextTr, Transaction},
handler::PrecompileProvider,
interpreter::{CallInputs, Gas, InstructionResult, InterpreterResult},
primitives::Bytes,
};
use std::{boxed::Box, string::String};

/// Custom precompile provider that includes WETH precompile alongside OP Stack precompiles.
#[derive(Debug, Clone)]
pub struct OpCustomPrecompiles {
inner: OpPrecompiles,
spec: OpSpecId,
}

impl OpCustomPrecompiles {
pub fn new_with_spec(spec: OpSpecId) -> Self {
Self {
inner: OpPrecompiles::new_with_spec(spec),
spec,
}
}
}

impl Default for OpCustomPrecompiles {
fn default() -> Self {
Self::new_with_spec(OpSpecId::REGOLITH)
}
}

impl<CTX> PrecompileProvider<CTX> for OpCustomPrecompiles
where
CTX: ContextTr<Cfg: Cfg<Spec = OpSpecId>>,
{
type Output = InterpreterResult;

fn set_spec(&mut self, spec: <CTX::Cfg as Cfg>::Spec) -> bool {
if spec == self.spec {
return false;
}
self.spec = spec;
// Update inner precompiles with new spec
self.inner = OpPrecompiles::new_with_spec(spec);
true
}

fn run(
&mut self,
context: &mut CTX,
inputs: &CallInputs,
) -> Result<Option<Self::Output>, String> {
// Check if this is the WETH precompile
if inputs.bytecode_address == WETH_ADDRESS {
return Ok(Some(run_weth_precompile_adapter(context, inputs)?));
}

// Otherwise, delegate to standard OP precompiles
PrecompileProvider::<CTX>::run(&mut self.inner, context, inputs)
}

fn warm_addresses(&self) -> Box<impl Iterator<Item = Address>> {
// Include WETH address along with standard precompiles
let inner_addresses: Vec<Address> =
PrecompileProvider::<CTX>::warm_addresses(&self.inner).collect();
let mut addresses = vec![WETH_ADDRESS];
addresses.extend(inner_addresses);
Box::new(addresses.into_iter())
}

fn contains(&self, address: &Address) -> bool {
*address == WETH_ADDRESS || PrecompileProvider::<CTX>::contains(&self.inner, address)
}
}

/// Adapter function to convert between CallInputs and our WETH precompile interface
fn run_weth_precompile_adapter<CTX: ContextTr>(
context: &mut CTX,
inputs: &CallInputs,
) -> Result<InterpreterResult, String> {
// Extract input bytes from CallInputs
let input_bytes = match &inputs.input {
revm::interpreter::CallInput::SharedBuffer(range) => {
if let Some(slice) = context.local().shared_memory_buffer_slice(range.clone()) {
slice.to_vec()
} else {
vec![]
}
}
revm::interpreter::CallInput::Bytes(bytes) => bytes.0.to_vec(),
};

// Get caller and value
let caller = context.tx().caller();
let value = inputs.call_value();

// Check if this is a static call
let is_static = inputs.is_static;

// Run the WETH precompile
let result = run_weth_precompile(
context,
&input_bytes,
inputs.gas_limit,
value,
caller,
is_static,
);

// Convert PrecompileResult to InterpreterResult
match result {
Ok(output) => {
let mut interpreter_result = InterpreterResult {
result: InstructionResult::Return,
gas: Gas::new(inputs.gas_limit),
output: output.bytes,
};
let underflow = interpreter_result.gas.record_cost(output.gas_used);
if !underflow {
interpreter_result.result = InstructionResult::PrecompileOOG;
}
Ok(interpreter_result)
}
Err(e) => {
// If this is a top-level precompile call and error is non-OOG, record the message
if !e.is_oog() && context.journal().depth() == 1 {
context
.local_mut()
.set_precompile_error_context(e.to_string());
}
Ok(InterpreterResult {
result: if e.is_oog() {
InstructionResult::PrecompileOOG
} else {
InstructionResult::PrecompileError
},
gas: Gas::new(inputs.gas_limit),
output: Bytes::new(),
})
}
}
}
4 changes: 2 additions & 2 deletions crates/op-rbuilder/src/block_stm/evm/exec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

use crate::block_stm::evm::handler::LazyOpContextTr;

use super::{custom_evm::OpLazyEvmInner, handler::LazyRevmHandler};
use super::{custom_evm::OpLazyEvmInner, handler::LazyRevmHandler, EthFrame};
use op_revm::{OpHaltReason, transaction::OpTransactionError};
use revm::{
DatabaseCommit, ExecuteCommitEvm, ExecuteEvm,
Expand All @@ -15,7 +15,7 @@ use revm::{
result::{EVMError, ExecutionResult},
},
handler::{
EthFrame, Handler, PrecompileProvider, SystemCallTx, instructions::EthInstructions,
Handler, PrecompileProvider, SystemCallTx, instructions::EthInstructions,
system_call::SystemCallEvm,
},
inspector::{
Expand Down
Loading
Loading