example_custom_opcodes/
main.rs

1//! Custom opcodes example
2#![cfg_attr(not(test), warn(unused_crate_dependencies))]
3
4use revm::{
5    bytecode::opcode,
6    context::{Evm, TxEnv},
7    database::{BenchmarkDB, BENCH_TARGET},
8    handler::{instructions::EthInstructions, EthPrecompiles},
9    inspector::inspectors::TracerEip3155,
10    interpreter::{
11        interpreter::EthInterpreter,
12        interpreter_types::{Immediates, Jumps},
13        Instruction, InstructionContext,
14    },
15    primitives::TxKind,
16    state::Bytecode,
17    Context, InspectEvm, MainContext,
18};
19
20/// Opcode hex value
21const MY_STATIC_JUMP: u8 = 0x0C;
22
23/// Demonstrates how to implement and use custom opcodes in REVM.
24/// This example shows how to create a custom static jump opcode that reads
25/// a 16-bit offset from the bytecode and performs a relative jump.
26pub fn main() {
27    let ctx = Context::mainnet().with_db(BenchmarkDB::new_bytecode(Bytecode::new_raw(
28        [
29            MY_STATIC_JUMP,
30            0x00,
31            0x03,
32            opcode::STOP,
33            opcode::JUMPDEST,
34            opcode::STOP,
35        ]
36        .into(),
37    )));
38
39    // Create a new instruction set with our mainnet opcodes.
40    let mut instructions = EthInstructions::new_mainnet();
41    // insert our custom opcode
42    instructions.insert_instruction(
43        MY_STATIC_JUMP,
44        Instruction::new(
45            |ctx: InstructionContext<'_, _, EthInterpreter>| {
46                let offset = ctx.interpreter.bytecode.read_i16();
47                ctx.interpreter.bytecode.relative_jump(offset as isize);
48            },
49            0,
50        ),
51    );
52
53    // Create a new EVM instance.
54    let mut evm = Evm::new(ctx, instructions, EthPrecompiles::default())
55        .with_inspector(TracerEip3155::new_stdout().without_summary());
56
57    // inspect the transaction.
58    let _ = evm.inspect_one_tx(
59        TxEnv::builder()
60            .kind(TxKind::Call(BENCH_TARGET))
61            .build()
62            .unwrap(),
63    );
64
65    // Expected output where we can see that JUMPDEST is called.
66    /*
67    "{"pc":0,"op":12,"gas":"0x1c97178","gasCost":"0x0","stack":[],"depth":1,"returnData":"0x","refund":"0x0","memSize":"0x0"}
68    {"pc":4,"op":91,"gas":"0x1c97178","gasCost":"0x1","stack":[],"depth":1,"returnData":"0x","refund":"0x0","memSize":"0x0","opName":"JUMPDEST"}
69    {"pc":5,"op":0,"gas":"0x1c97177","gasCost":"0x0","stack":[],"depth":1,"returnData":"0x","refund":"0x0","memSize":"0x0","opName":"STOP"}
70    */
71}