From 2032b747cf1934144e8cad58fc7ff2494ac6f236 Mon Sep 17 00:00:00 2001 From: James Date: Thu, 22 May 2025 11:11:11 -0400 Subject: [PATCH 1/6] feat: disable prevrandao --- src/evm.rs | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/src/evm.rs b/src/evm.rs index 50a7ebd..5e9ae56 100644 --- a/src/evm.rs +++ b/src/evm.rs @@ -12,13 +12,17 @@ use alloy::{ }; use core::{convert::Infallible, fmt}; use revm::{ + bytecode::opcode::DIFFICULTY, context::{ result::{EVMError, ExecutionResult, InvalidTransaction, ResultAndState}, Block as _, BlockEnv, Cfg as _, ContextSetters, ContextTr, Transaction as _, TxEnv, }, database::{states::bundle_state::BundleRetention, BundleState, TryDatabaseCommit}, inspector::NoOpInspector, - interpreter::gas::calculate_initial_tx_gas_for_tx, + interpreter::{ + gas::calculate_initial_tx_gas_for_tx, + instructions::{block_info, control}, + }, primitives::{hardfork::SpecId, TxKind}, state::{AccountInfo, Bytecode, EvmState}, Database, DatabaseCommit, DatabaseRef, InspectEvm, Inspector, @@ -183,6 +187,33 @@ where Ok(self) } } + + /// Disable the prevrandao opcode, by replacing it with unknown opcode + /// behavior. This is useful for block simulation, where the prevrandao + /// opcode may produce incorrect results. + pub fn disable_prevrandao(&mut self) { + self.inner.instruction.insert_instruction(DIFFICULTY, control::unknown); + } + + /// Enable the prevrandao opcode. + pub fn enable_prevrandao(&mut self) { + self.inner.instruction.insert_instruction(DIFFICULTY, block_info::difficulty); + } + + /// Run some code with the prevrandao opcode disabled, then restore the + /// previous setting. + pub fn without_prevrandao(mut self, f: F) -> Trevm + where + F: FnOnce(Self) -> Trevm, + { + let handler = std::mem::replace( + &mut self.inner.instruction.instruction_table[DIFFICULTY as usize], + control::unknown, + ); + let mut new = f(self); + new.inner.instruction.insert_instruction(DIFFICULTY, handler); + new + } } // Fallible DB Reads with &mut self From 9ec8518c3f0b2171686a24d044697e6b21c401ba Mon Sep 17 00:00:00 2001 From: James Date: Thu, 22 May 2025 11:12:26 -0400 Subject: [PATCH 2/6] doc: more of em --- src/evm.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/evm.rs b/src/evm.rs index 5e9ae56..09a4690 100644 --- a/src/evm.rs +++ b/src/evm.rs @@ -195,13 +195,15 @@ where self.inner.instruction.insert_instruction(DIFFICULTY, control::unknown); } - /// Enable the prevrandao opcode. + /// Enable the prevrandao opcode. If the prevrandao opcode was not + /// previously disabled or replaced, this will have no effect on behavior. pub fn enable_prevrandao(&mut self) { self.inner.instruction.insert_instruction(DIFFICULTY, block_info::difficulty); } /// Run some code with the prevrandao opcode disabled, then restore the - /// previous setting. + /// previous setting. This is useful for block simulation, where the + /// prevrandao opcode may produce incorrect results. pub fn without_prevrandao(mut self, f: F) -> Trevm where F: FnOnce(Self) -> Trevm, From 2a47599fe5b68ec7a9e0e6342fac98ec451732e0 Mon Sep 17 00:00:00 2001 From: James Date: Thu, 22 May 2025 11:21:08 -0400 Subject: [PATCH 3/6] refactor: generalize --- src/evm.rs | 50 +++++++++++++++++++++++++++++++++++++------------- src/helpers.rs | 14 ++++++++------ 2 files changed, 45 insertions(+), 19 deletions(-) diff --git a/src/evm.rs b/src/evm.rs index 09a4690..04c0b43 100644 --- a/src/evm.rs +++ b/src/evm.rs @@ -1,7 +1,7 @@ use crate::{ db::{StateAcc, TryStateAcc}, driver::DriveBlockResult, - helpers::{Ctx, Evm}, + helpers::{Ctx, Evm, Instruction}, Block, BlockDriver, BundleDriver, Cfg, ChainDriver, DriveBundleResult, DriveChainResult, ErroredState, EvmErrored, EvmExtUnchecked, EvmNeedsBlock, EvmNeedsCfg, EvmNeedsTx, EvmReady, EvmTransacted, HasBlock, HasCfg, HasTx, NeedsCfg, NeedsTx, TransactedState, Tx, @@ -188,33 +188,57 @@ where } } + /// Overide an opcode with a custom handler. Returns the previous + /// instruction handler for the opcode. + pub fn override_opcode(&mut self, opcode: u8, handler: Instruction) -> Instruction { + std::mem::replace(&mut self.inner.instruction.instruction_table[opcode as usize], handler) + } + + /// Disable an opcode by replacing it with unknown opcode behavior. This is + /// a shortcut for [`Self::override_opcode`] with [`control::unknown`]. + pub fn disable_opcode(&mut self, opcode: u8) -> Instruction { + self.override_opcode(opcode, control::unknown) + } + + /// Run some closure with an opcode override, then restore the previous + /// setting. + pub fn with_opcode_override( + mut self, + opcode: u8, + handler: Instruction, + f: F, + ) -> Trevm + where + F: FnOnce(Self) -> Trevm, + { + let old = self.override_opcode(opcode, handler); + self.inner.instruction.insert_instruction(opcode, handler); + let mut this = f(self); + this.override_opcode(opcode, old); + this + } + /// Disable the prevrandao opcode, by replacing it with unknown opcode /// behavior. This is useful for block simulation, where the prevrandao /// opcode may produce incorrect results. - pub fn disable_prevrandao(&mut self) { - self.inner.instruction.insert_instruction(DIFFICULTY, control::unknown); + pub fn disable_prevrandao(&mut self) -> Instruction { + self.disable_opcode(DIFFICULTY) } /// Enable the prevrandao opcode. If the prevrandao opcode was not /// previously disabled or replaced, this will have no effect on behavior. - pub fn enable_prevrandao(&mut self) { - self.inner.instruction.insert_instruction(DIFFICULTY, block_info::difficulty); + pub fn enable_prevrandao(&mut self) -> Instruction { + self.override_opcode(DIFFICULTY, block_info::difficulty) } /// Run some code with the prevrandao opcode disabled, then restore the /// previous setting. This is useful for block simulation, where the /// prevrandao opcode may produce incorrect results. - pub fn without_prevrandao(mut self, f: F) -> Trevm + pub fn without_prevrandao(self, f: F) -> Trevm where F: FnOnce(Self) -> Trevm, { - let handler = std::mem::replace( - &mut self.inner.instruction.instruction_table[DIFFICULTY as usize], - control::unknown, - ); - let mut new = f(self); - new.inner.instruction.insert_instruction(DIFFICULTY, handler); - new + self.with_opcode_override(DIFFICULTY, control::unknown, f) } } diff --git a/src/helpers.rs b/src/helpers.rs index 3e60947..048a039 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -10,9 +10,11 @@ use revm::{ pub type Ctx, C = ()> = Context; /// EVM with default env types and adjustable DB. -pub type Evm< - Db, - Insp = NoOpInspector, - Inst = EthInstructions>, - Prec = EthPrecompiles, -> = revm::context::Evm, Insp, Inst, Prec>; +pub type Evm, Prec = EthPrecompiles> = + revm::context::Evm, Insp, Inst, Prec>; + +/// Handler table for EVM opcodes. +pub type Instructions = EthInstructions>; + +/// The handler type for an EVM opcode. +pub type Instruction = revm::interpreter::Instruction>; From bcad5602f3d6241d0472153889e0c5b4b85e6169 Mon Sep 17 00:00:00 2001 From: James Date: Thu, 22 May 2025 13:09:15 -0400 Subject: [PATCH 4/6] fix: forbid handler --- src/evm.rs | 11 ++++------- src/helpers.rs | 14 ++++++++++++-- src/inspectors/mod.rs | 6 +++--- 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/src/evm.rs b/src/evm.rs index 04c0b43..b6ffe30 100644 --- a/src/evm.rs +++ b/src/evm.rs @@ -19,10 +19,7 @@ use revm::{ }, database::{states::bundle_state::BundleRetention, BundleState, TryDatabaseCommit}, inspector::NoOpInspector, - interpreter::{ - gas::calculate_initial_tx_gas_for_tx, - instructions::{block_info, control}, - }, + interpreter::{gas::calculate_initial_tx_gas_for_tx, instructions::block_info}, primitives::{hardfork::SpecId, TxKind}, state::{AccountInfo, Bytecode, EvmState}, Database, DatabaseCommit, DatabaseRef, InspectEvm, Inspector, @@ -195,9 +192,9 @@ where } /// Disable an opcode by replacing it with unknown opcode behavior. This is - /// a shortcut for [`Self::override_opcode`] with [`control::unknown`]. + /// a shortcut for [`Self::override_opcode`] with [`crate::helpers::forbidden`]. pub fn disable_opcode(&mut self, opcode: u8) -> Instruction { - self.override_opcode(opcode, control::unknown) + self.override_opcode(opcode, crate::helpers::forbidden) } /// Run some closure with an opcode override, then restore the previous @@ -238,7 +235,7 @@ where where F: FnOnce(Self) -> Trevm, { - self.with_opcode_override(DIFFICULTY, control::unknown, f) + self.with_opcode_override(DIFFICULTY, crate::helpers::forbidden, f) } } diff --git a/src/helpers.rs b/src/helpers.rs index 048a039..da09404 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,9 +1,10 @@ use revm::{ context::{BlockEnv, CfgEnv, TxEnv}, + context_interface::context::ContextError, handler::{instructions::EthInstructions, EthPrecompiles}, inspector::NoOpInspector, - interpreter::interpreter::EthInterpreter, - Context, Journal, + interpreter::{interpreter::EthInterpreter, Interpreter, InterpreterTypes}, + Context, Database, Journal, }; /// [`revm::Context`] with default env types and adjustable DB @@ -18,3 +19,12 @@ pub type Instructions = EthInstructions>; /// The handler type for an EVM opcode. pub type Instruction = revm::interpreter::Instruction>; + +/// An [`Instruction`] that sets a [`ContextError`] in the [`Ctx`]. whenever it +/// is executed. +pub fn forbidden( + _interpreter: &mut Interpreter, + ctx: &mut Ctx, +) { + ctx.error = Err(ContextError::Custom("forbidden opcode".to_string())); +} diff --git a/src/inspectors/mod.rs b/src/inspectors/mod.rs index 7ee9cf1..8ac5efe 100644 --- a/src/inspectors/mod.rs +++ b/src/inspectors/mod.rs @@ -1,3 +1,6 @@ +mod layer; +pub use layer::Layered; + mod timeout; pub use timeout::TimeLimit; @@ -7,9 +10,6 @@ pub use set::InspectorSet; mod spanning; pub use spanning::SpanningInspector; -mod layer; -pub use layer::Layered; - #[cfg(test)] mod test { use super::*; From 609371035057dab04ac715087f443a0e78151792 Mon Sep 17 00:00:00 2001 From: James Date: Thu, 22 May 2025 13:20:18 -0400 Subject: [PATCH 5/6] feat: set precompiles --- src/evm.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/evm.rs b/src/evm.rs index b6ffe30..f5c06ae 100644 --- a/src/evm.rs +++ b/src/evm.rs @@ -18,6 +18,7 @@ use revm::{ Block as _, BlockEnv, Cfg as _, ContextSetters, ContextTr, Transaction as _, TxEnv, }, database::{states::bundle_state::BundleRetention, BundleState, TryDatabaseCommit}, + handler::EthPrecompiles, inspector::NoOpInspector, interpreter::{gas::calculate_initial_tx_gas_for_tx, instructions::block_info}, primitives::{hardfork::SpecId, TxKind}, @@ -237,6 +238,28 @@ where { self.with_opcode_override(DIFFICULTY, crate::helpers::forbidden, f) } + + /// Set the precompiles for the EVM. This will replace the current + /// precompiles with the provided ones. + pub fn override_precompiles(&mut self, precompiles: EthPrecompiles) -> EthPrecompiles { + std::mem::replace(&mut self.inner.precompiles, precompiles) + } + + /// Run a closure with a different set of precompiles, then restore the + /// previous setting. + pub fn with_precompiles( + mut self, + precompiles: EthPrecompiles, + f: F, + ) -> Trevm + where + F: FnOnce(Self) -> Trevm, + { + let old = self.override_precompiles(precompiles); + let mut this = f(self); + this.override_precompiles(old); + this + } } // Fallible DB Reads with &mut self From 4f258f2325b866954b15fd49824399a13c0496f0 Mon Sep 17 00:00:00 2001 From: James Prestwich Date: Thu, 22 May 2025 14:07:19 -0400 Subject: [PATCH 6/6] Update src/helpers.rs Co-authored-by: evalir --- src/helpers.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/helpers.rs b/src/helpers.rs index da09404..7ae4db6 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -20,7 +20,7 @@ pub type Instructions = EthInstructions>; /// The handler type for an EVM opcode. pub type Instruction = revm::interpreter::Instruction>; -/// An [`Instruction`] that sets a [`ContextError`] in the [`Ctx`]. whenever it +/// An [`Instruction`] that sets a [`ContextError`] in the [`Ctx`] whenever it /// is executed. pub fn forbidden( _interpreter: &mut Interpreter,