Skip to content

Commit 2e1ead2

Browse files
prestwichEvalir
andauthored
feat: disable prevrandao (#106)
* feat: disable prevrandao * doc: more of em * refactor: generalize * fix: forbid handler * feat: set precompiles * Update src/helpers.rs Co-authored-by: evalir <[email protected]> --------- Co-authored-by: evalir <[email protected]>
1 parent 873b506 commit 2e1ead2

File tree

3 files changed

+102
-13
lines changed

3 files changed

+102
-13
lines changed

src/evm.rs

Lines changed: 79 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::{
22
db::{StateAcc, TryStateAcc},
33
driver::DriveBlockResult,
4-
helpers::{Ctx, Evm},
4+
helpers::{Ctx, Evm, Instruction},
55
Block, BlockDriver, BundleDriver, Cfg, ChainDriver, DriveBundleResult, DriveChainResult,
66
ErroredState, EvmErrored, EvmExtUnchecked, EvmNeedsBlock, EvmNeedsCfg, EvmNeedsTx, EvmReady,
77
EvmTransacted, HasBlock, HasCfg, HasTx, NeedsCfg, NeedsTx, TransactedState, Tx,
@@ -12,13 +12,15 @@ use alloy::{
1212
};
1313
use core::{convert::Infallible, fmt};
1414
use revm::{
15+
bytecode::opcode::DIFFICULTY,
1516
context::{
1617
result::{EVMError, ExecutionResult, InvalidTransaction, ResultAndState},
1718
Block as _, BlockEnv, Cfg as _, ContextSetters, ContextTr, Transaction as _, TxEnv,
1819
},
1920
database::{states::bundle_state::BundleRetention, BundleState, TryDatabaseCommit},
21+
handler::EthPrecompiles,
2022
inspector::NoOpInspector,
21-
interpreter::gas::calculate_initial_tx_gas_for_tx,
23+
interpreter::{gas::calculate_initial_tx_gas_for_tx, instructions::block_info},
2224
primitives::{hardfork::SpecId, TxKind},
2325
state::{AccountInfo, Bytecode, EvmState},
2426
Database, DatabaseCommit, DatabaseRef, InspectEvm, Inspector,
@@ -183,6 +185,81 @@ where
183185
Ok(self)
184186
}
185187
}
188+
189+
/// Overide an opcode with a custom handler. Returns the previous
190+
/// instruction handler for the opcode.
191+
pub fn override_opcode(&mut self, opcode: u8, handler: Instruction<Db>) -> Instruction<Db> {
192+
std::mem::replace(&mut self.inner.instruction.instruction_table[opcode as usize], handler)
193+
}
194+
195+
/// Disable an opcode by replacing it with unknown opcode behavior. This is
196+
/// a shortcut for [`Self::override_opcode`] with [`crate::helpers::forbidden`].
197+
pub fn disable_opcode(&mut self, opcode: u8) -> Instruction<Db> {
198+
self.override_opcode(opcode, crate::helpers::forbidden)
199+
}
200+
201+
/// Run some closure with an opcode override, then restore the previous
202+
/// setting.
203+
pub fn with_opcode_override<F, NewState>(
204+
mut self,
205+
opcode: u8,
206+
handler: Instruction<Db>,
207+
f: F,
208+
) -> Trevm<Db, Insp, NewState>
209+
where
210+
F: FnOnce(Self) -> Trevm<Db, Insp, NewState>,
211+
{
212+
let old = self.override_opcode(opcode, handler);
213+
self.inner.instruction.insert_instruction(opcode, handler);
214+
let mut this = f(self);
215+
this.override_opcode(opcode, old);
216+
this
217+
}
218+
219+
/// Disable the prevrandao opcode, by replacing it with unknown opcode
220+
/// behavior. This is useful for block simulation, where the prevrandao
221+
/// opcode may produce incorrect results.
222+
pub fn disable_prevrandao(&mut self) -> Instruction<Db> {
223+
self.disable_opcode(DIFFICULTY)
224+
}
225+
226+
/// Enable the prevrandao opcode. If the prevrandao opcode was not
227+
/// previously disabled or replaced, this will have no effect on behavior.
228+
pub fn enable_prevrandao(&mut self) -> Instruction<Db> {
229+
self.override_opcode(DIFFICULTY, block_info::difficulty)
230+
}
231+
232+
/// Run some code with the prevrandao opcode disabled, then restore the
233+
/// previous setting. This is useful for block simulation, where the
234+
/// prevrandao opcode may produce incorrect results.
235+
pub fn without_prevrandao<F, NewState>(self, f: F) -> Trevm<Db, Insp, NewState>
236+
where
237+
F: FnOnce(Self) -> Trevm<Db, Insp, NewState>,
238+
{
239+
self.with_opcode_override(DIFFICULTY, crate::helpers::forbidden, f)
240+
}
241+
242+
/// Set the precompiles for the EVM. This will replace the current
243+
/// precompiles with the provided ones.
244+
pub fn override_precompiles(&mut self, precompiles: EthPrecompiles) -> EthPrecompiles {
245+
std::mem::replace(&mut self.inner.precompiles, precompiles)
246+
}
247+
248+
/// Run a closure with a different set of precompiles, then restore the
249+
/// previous setting.
250+
pub fn with_precompiles<F, NewState>(
251+
mut self,
252+
precompiles: EthPrecompiles,
253+
f: F,
254+
) -> Trevm<Db, Insp, NewState>
255+
where
256+
F: FnOnce(Self) -> Trevm<Db, Insp, NewState>,
257+
{
258+
let old = self.override_precompiles(precompiles);
259+
let mut this = f(self);
260+
this.override_precompiles(old);
261+
this
262+
}
186263
}
187264

188265
// Fallible DB Reads with &mut self

src/helpers.rs

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,30 @@
11
use revm::{
22
context::{BlockEnv, CfgEnv, TxEnv},
3+
context_interface::context::ContextError,
34
handler::{instructions::EthInstructions, EthPrecompiles},
45
inspector::NoOpInspector,
5-
interpreter::interpreter::EthInterpreter,
6-
Context, Journal,
6+
interpreter::{interpreter::EthInterpreter, Interpreter, InterpreterTypes},
7+
Context, Database, Journal,
78
};
89

910
/// [`revm::Context`] with default env types and adjustable DB
1011
pub type Ctx<Db, J = Journal<Db>, C = ()> = Context<BlockEnv, TxEnv, CfgEnv, Db, J, C>;
1112

1213
/// EVM with default env types and adjustable DB.
13-
pub type Evm<
14-
Db,
15-
Insp = NoOpInspector,
16-
Inst = EthInstructions<EthInterpreter, Ctx<Db>>,
17-
Prec = EthPrecompiles,
18-
> = revm::context::Evm<Ctx<Db>, Insp, Inst, Prec>;
14+
pub type Evm<Db, Insp = NoOpInspector, Inst = Instructions<Db>, Prec = EthPrecompiles> =
15+
revm::context::Evm<Ctx<Db>, Insp, Inst, Prec>;
16+
17+
/// Handler table for EVM opcodes.
18+
pub type Instructions<Db> = EthInstructions<EthInterpreter, Ctx<Db>>;
19+
20+
/// The handler type for an EVM opcode.
21+
pub type Instruction<Db> = revm::interpreter::Instruction<EthInterpreter, Ctx<Db>>;
22+
23+
/// An [`Instruction`] that sets a [`ContextError`] in the [`Ctx`] whenever it
24+
/// is executed.
25+
pub fn forbidden<Db: Database, Int: InterpreterTypes>(
26+
_interpreter: &mut Interpreter<Int>,
27+
ctx: &mut Ctx<Db>,
28+
) {
29+
ctx.error = Err(ContextError::Custom("forbidden opcode".to_string()));
30+
}

src/inspectors/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
mod layer;
2+
pub use layer::Layered;
3+
14
mod timeout;
25
pub use timeout::TimeLimit;
36

@@ -7,9 +10,6 @@ pub use set::InspectorSet;
710
mod spanning;
811
pub use spanning::SpanningInspector;
912

10-
mod layer;
11-
pub use layer::Layered;
12-
1313
#[cfg(test)]
1414
mod test {
1515
use super::*;

0 commit comments

Comments
 (0)