revm_handler/
instructions.rs

1use auto_impl::auto_impl;
2use interpreter::{
3    instructions::{instruction_table_gas_changes_spec, InstructionTable},
4    Host, Instruction, InterpreterTypes,
5};
6use primitives::hardfork::SpecId;
7use std::boxed::Box;
8
9/// Stores instructions for EVM.
10#[auto_impl(&mut, Box)]
11pub trait InstructionProvider {
12    /// Context type.
13    type Context;
14    /// Interpreter types.
15    type InterpreterTypes: InterpreterTypes;
16
17    /// Returns the instruction table that is used by EvmTr to execute instructions.
18    fn instruction_table(&self) -> &InstructionTable<Self::InterpreterTypes, Self::Context>;
19}
20
21/// Ethereum instruction contains list of mainnet instructions that is used for Interpreter execution.
22#[derive(Debug)]
23pub struct EthInstructions<WIRE: InterpreterTypes, HOST: ?Sized> {
24    /// Table containing instruction implementations indexed by opcode.
25    pub instruction_table: Box<InstructionTable<WIRE, HOST>>,
26    /// Spec that is used to set gas costs for instructions.
27    pub spec: SpecId,
28}
29
30impl<WIRE, HOST: Host + ?Sized> Clone for EthInstructions<WIRE, HOST>
31where
32    WIRE: InterpreterTypes,
33{
34    fn clone(&self) -> Self {
35        Self {
36            instruction_table: self.instruction_table.clone(),
37            spec: self.spec,
38        }
39    }
40}
41
42impl<WIRE, HOST> EthInstructions<WIRE, HOST>
43where
44    WIRE: InterpreterTypes,
45    HOST: Host,
46{
47    /// Returns `EthInstructions` with mainnet spec.
48    pub fn new_mainnet() -> Self {
49        let spec = SpecId::default();
50        Self::new(instruction_table_gas_changes_spec(spec), spec)
51    }
52
53    /// Returns `EthInstructions` with mainnet spec.
54    pub fn new_mainnet_with_spec(spec: SpecId) -> Self {
55        Self::new(instruction_table_gas_changes_spec(spec), spec)
56    }
57
58    /// Returns a new instance of `EthInstructions` with custom instruction table.
59    #[inline]
60    pub fn new(base_table: InstructionTable<WIRE, HOST>, spec: SpecId) -> Self {
61        Self {
62            instruction_table: Box::new(base_table),
63            spec,
64        }
65    }
66
67    /// Inserts a new instruction into the instruction table.
68    #[inline]
69    pub fn insert_instruction(&mut self, opcode: u8, instruction: Instruction<WIRE, HOST>) {
70        self.instruction_table[opcode as usize] = instruction;
71    }
72}
73
74impl<IT, CTX> InstructionProvider for EthInstructions<IT, CTX>
75where
76    IT: InterpreterTypes,
77    CTX: Host,
78{
79    type InterpreterTypes = IT;
80    type Context = CTX;
81
82    fn instruction_table(&self) -> &InstructionTable<Self::InterpreterTypes, Self::Context> {
83        &self.instruction_table
84    }
85}
86
87impl<WIRE, HOST> Default for EthInstructions<WIRE, HOST>
88where
89    WIRE: InterpreterTypes,
90    HOST: Host,
91{
92    fn default() -> Self {
93        Self::new_mainnet()
94    }
95}