evm_disassembler/
types.rs

1//! Output types for Operation and Opcode
2use eyre::{eyre, Result};
3use std::fmt;
4
5/// A single EVM operation
6///
7/// For additional information on each operation see: https://www.evm.codes/
8#[derive(Clone, Copy, Debug, PartialEq, Eq)]
9#[allow(missing_docs)]
10pub enum Opcode {
11    STOP,
12    ADD,
13    MUL,
14    SUB,
15    DIV,
16    SDIV,
17    MOD,
18    SMOD,
19    ADDMOD,
20    MULMOD,
21    EXP,
22    SIGNEXTEND,
23    LT,
24    GT,
25    SLT,
26    SGT,
27    EQ,
28    ISZERO,
29    AND,
30    OR,
31    XOR,
32    NOT,
33    BYTE,
34    SHL,
35    SHR,
36    SAR,
37    SHA3,
38    ADDRESS,
39    BALANCE,
40    ORIGIN,
41    CALLER,
42    CALLVALUE,
43    CALLDATALOAD,
44    CALLDATASIZE,
45    CALLDATACOPY,
46    CODESIZE,
47    CODECOPY,
48    GASPRICE,
49    EXTCODESIZE,
50    EXTCODECOPY,
51    RETURNDATASIZE,
52    RETURNDATACOPY,
53    EXTCODEHASH,
54    BLOCKHASH,
55    COINBASE,
56    TIMESTAMP,
57    NUMBER,
58    DIFFICULTY,
59    GASLIMIT,
60    CHAINID,
61    SELFBALANCE,
62    BASEFEE,
63    POP,
64    MLOAD,
65    MSTORE,
66    MSTORE8,
67    SLOAD,
68    SSTORE,
69    JUMP,
70    JUMPI,
71    PC,
72    MSIZE,
73    GAS,
74    JUMPDEST,
75    MCOPY,
76    TLOAD,
77    TSTORE,
78    PUSH0,
79    PUSH1,
80    PUSH2,
81    PUSH3,
82    PUSH4,
83    PUSH5,
84    PUSH6,
85    PUSH7,
86    PUSH8,
87    PUSH9,
88    PUSH10,
89    PUSH11,
90    PUSH12,
91    PUSH13,
92    PUSH14,
93    PUSH15,
94    PUSH16,
95    PUSH17,
96    PUSH18,
97    PUSH19,
98    PUSH20,
99    PUSH21,
100    PUSH22,
101    PUSH23,
102    PUSH24,
103    PUSH25,
104    PUSH26,
105    PUSH27,
106    PUSH28,
107    PUSH29,
108    PUSH30,
109    PUSH31,
110    PUSH32,
111    DUP1,
112    DUP2,
113    DUP3,
114    DUP4,
115    DUP5,
116    DUP6,
117    DUP7,
118    DUP8,
119    DUP9,
120    DUP10,
121    DUP11,
122    DUP12,
123    DUP13,
124    DUP14,
125    DUP15,
126    DUP16,
127    SWAP1,
128    SWAP2,
129    SWAP3,
130    SWAP4,
131    SWAP5,
132    SWAP6,
133    SWAP7,
134    SWAP8,
135    SWAP9,
136    SWAP10,
137    SWAP11,
138    SWAP12,
139    SWAP13,
140    SWAP14,
141    SWAP15,
142    SWAP16,
143    LOG0,
144    LOG1,
145    LOG2,
146    LOG3,
147    LOG4,
148    CREATE,
149    CALL,
150    CALLCODE,
151    RETURN,
152    DELEGATECALL,
153    CREATE2,
154    STATICCALL,
155    REVERT,
156    INVALID,
157    SELFDESTRUCT,
158    BLOBBASEFEE,
159    BLOBHASH,
160}
161
162impl Opcode {
163    /// Convert a byte into an Opcode
164    pub fn from_byte(byte: u8) -> Opcode {
165        match byte {
166            0x00 => Opcode::STOP,
167            0x01 => Opcode::ADD,
168            0x02 => Opcode::MUL,
169            0x03 => Opcode::SUB,
170            0x04 => Opcode::DIV,
171            0x05 => Opcode::SDIV,
172            0x06 => Opcode::MOD,
173            0x07 => Opcode::SMOD,
174            0x08 => Opcode::ADDMOD,
175            0x09 => Opcode::MULMOD,
176            0x0A => Opcode::EXP,
177            0x0B => Opcode::SIGNEXTEND,
178            0x10 => Opcode::LT,
179            0x11 => Opcode::GT,
180            0x12 => Opcode::SLT,
181            0x13 => Opcode::SGT,
182            0x14 => Opcode::EQ,
183            0x15 => Opcode::ISZERO,
184            0x16 => Opcode::AND,
185            0x17 => Opcode::OR,
186            0x18 => Opcode::XOR,
187            0x19 => Opcode::NOT,
188            0x1a => Opcode::BYTE,
189            0x1b => Opcode::SHL,
190            0x1c => Opcode::SHR,
191            0x1d => Opcode::SAR,
192            0x20 => Opcode::SHA3,
193            0x30 => Opcode::ADDRESS,
194            0x31 => Opcode::BALANCE,
195            0x32 => Opcode::ORIGIN,
196            0x33 => Opcode::CALLER,
197            0x34 => Opcode::CALLVALUE,
198            0x35 => Opcode::CALLDATALOAD,
199            0x36 => Opcode::CALLDATASIZE,
200            0x37 => Opcode::CALLDATACOPY,
201            0x38 => Opcode::CODESIZE,
202            0x39 => Opcode::CODECOPY,
203            0x3a => Opcode::GASPRICE,
204            0x3b => Opcode::EXTCODESIZE,
205            0x3c => Opcode::EXTCODECOPY,
206            0x3d => Opcode::RETURNDATASIZE,
207            0x3e => Opcode::RETURNDATACOPY,
208            0x3f => Opcode::EXTCODEHASH,
209            0x40 => Opcode::BLOCKHASH,
210            0x41 => Opcode::COINBASE,
211            0x42 => Opcode::TIMESTAMP,
212            0x43 => Opcode::NUMBER,
213            0x44 => Opcode::DIFFICULTY,
214            0x45 => Opcode::GASLIMIT,
215            0x46 => Opcode::CHAINID,
216            0x47 => Opcode::SELFBALANCE,
217            0x48 => Opcode::BASEFEE,
218            0x49 => Opcode::BLOBHASH,
219            0x4a => Opcode::BLOBBASEFEE,
220            0x50 => Opcode::POP,
221            0x51 => Opcode::MLOAD,
222            0x52 => Opcode::MSTORE,
223            0x53 => Opcode::MSTORE8,
224            0x54 => Opcode::SLOAD,
225            0x55 => Opcode::SSTORE,
226            0x56 => Opcode::JUMP,
227            0x57 => Opcode::JUMPI,
228            0x58 => Opcode::PC,
229            0x59 => Opcode::MSIZE,
230            0x5a => Opcode::GAS,
231            0x5b => Opcode::JUMPDEST,
232            0x5c => Opcode::TLOAD,
233            0x5d => Opcode::TSTORE,
234            0x5e => Opcode::MCOPY,
235            0x5F => Opcode::PUSH0,
236            0x60 => Opcode::PUSH1,
237            0x61 => Opcode::PUSH2,
238            0x62 => Opcode::PUSH3,
239            0x63 => Opcode::PUSH4,
240            0x64 => Opcode::PUSH5,
241            0x65 => Opcode::PUSH6,
242            0x66 => Opcode::PUSH7,
243            0x67 => Opcode::PUSH8,
244            0x68 => Opcode::PUSH9,
245            0x69 => Opcode::PUSH10,
246            0x6a => Opcode::PUSH11,
247            0x6b => Opcode::PUSH12,
248            0x6c => Opcode::PUSH13,
249            0x6d => Opcode::PUSH14,
250            0x6e => Opcode::PUSH15,
251            0x6f => Opcode::PUSH16,
252            0x70 => Opcode::PUSH17,
253            0x71 => Opcode::PUSH18,
254            0x72 => Opcode::PUSH19,
255            0x73 => Opcode::PUSH20,
256            0x74 => Opcode::PUSH21,
257            0x75 => Opcode::PUSH22,
258            0x76 => Opcode::PUSH23,
259            0x77 => Opcode::PUSH24,
260            0x78 => Opcode::PUSH25,
261            0x79 => Opcode::PUSH26,
262            0x7a => Opcode::PUSH27,
263            0x7b => Opcode::PUSH28,
264            0x7c => Opcode::PUSH29,
265            0x7d => Opcode::PUSH30,
266            0x7e => Opcode::PUSH31,
267            0x7f => Opcode::PUSH32,
268            0x80 => Opcode::DUP1,
269            0x81 => Opcode::DUP2,
270            0x82 => Opcode::DUP3,
271            0x83 => Opcode::DUP4,
272            0x84 => Opcode::DUP5,
273            0x85 => Opcode::DUP6,
274            0x86 => Opcode::DUP7,
275            0x87 => Opcode::DUP8,
276            0x88 => Opcode::DUP9,
277            0x89 => Opcode::DUP10,
278            0x8a => Opcode::DUP11,
279            0x8b => Opcode::DUP12,
280            0x8c => Opcode::DUP13,
281            0x8d => Opcode::DUP14,
282            0x8e => Opcode::DUP15,
283            0x8f => Opcode::DUP16,
284            0x90 => Opcode::SWAP1,
285            0x91 => Opcode::SWAP2,
286            0x92 => Opcode::SWAP3,
287            0x93 => Opcode::SWAP4,
288            0x94 => Opcode::SWAP5,
289            0x95 => Opcode::SWAP6,
290            0x96 => Opcode::SWAP7,
291            0x97 => Opcode::SWAP8,
292            0x98 => Opcode::SWAP9,
293            0x99 => Opcode::SWAP10,
294            0x9a => Opcode::SWAP11,
295            0x9b => Opcode::SWAP12,
296            0x9c => Opcode::SWAP13,
297            0x9d => Opcode::SWAP14,
298            0x9e => Opcode::SWAP15,
299            0x9f => Opcode::SWAP16,
300            0xa0 => Opcode::LOG0,
301            0xa1 => Opcode::LOG1,
302            0xa2 => Opcode::LOG2,
303            0xa3 => Opcode::LOG3,
304            0xa4 => Opcode::LOG4,
305            0xf0 => Opcode::CREATE,
306            0xf1 => Opcode::CALL,
307            0xf2 => Opcode::CALLCODE,
308            0xf3 => Opcode::RETURN,
309            0xf4 => Opcode::DELEGATECALL,
310            0xf5 => Opcode::CREATE2,
311            0xfa => Opcode::STATICCALL,
312            0xfd => Opcode::REVERT,
313            0xff => Opcode::SELFDESTRUCT,
314            _ => Opcode::INVALID,
315        }
316    }
317}
318
319/// A decoded operation
320///
321/// An operation is represented by the combination of an opcode, the offset in the bytecode and any
322/// additional bytes that are part of the operation (only for PUSH operations).
323#[derive(PartialEq, Eq)]
324pub struct Operation {
325    /// The opcode
326    pub opcode: Opcode,
327    /// Additional bytes that are part of the Operation (only for PUSH)
328    pub input: Vec<u8>,
329    /// The offset in the bytecode
330    pub offset: u32,
331}
332
333impl fmt::Debug for Operation {
334    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
335        let mut formatted = format!(
336            "{:0>8}: {:?}",
337            format!("{:#x}", self.offset).trim_start_matches("0x"),
338            self.opcode
339        );
340        if !self.input.is_empty() {
341            let encoded_bytes = hex::encode(&self.input);
342            let mut formatted_bytes = encoded_bytes.trim_start_matches('0');
343            if formatted_bytes.is_empty() {
344                formatted_bytes = "0";
345            }
346            formatted = format!("{} {}", formatted, "0x".to_owned() + formatted_bytes);
347        }
348        write!(f, "{formatted}")
349    }
350}
351
352impl Operation {
353    /// Creates a new operation with empty `input` bytes
354    pub fn new(opcode: Opcode, offset: u32) -> Self {
355        Operation {
356            opcode,
357            offset,
358            input: Vec::new(),
359        }
360    }
361
362    /// Adds additional bytes to the operation (for PUSH instructions)
363    pub fn with_bytes(
364        self,
365        num_bytes: u8,
366        bytes: &mut dyn ExactSizeIterator<Item = u8>,
367    ) -> Result<Self> {
368        if num_bytes == 0 {
369            return Ok(self);
370        }
371        if num_bytes as usize > bytes.len() {
372            return Err(eyre!(
373                "Not enough bytes to read - expected {} but only {} left",
374                num_bytes,
375                bytes.len()
376            ));
377        }
378        Ok(Operation {
379            opcode: self.opcode,
380            offset: self.offset,
381            input: bytes.take(num_bytes as usize).collect(),
382        })
383    }
384}