1use eyre::{eyre, Result};
3use std::fmt;
4
5#[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 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#[derive(PartialEq, Eq)]
324pub struct Operation {
325 pub opcode: Opcode,
327 pub input: Vec<u8>,
329 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 pub fn new(opcode: Opcode, offset: u32) -> Self {
355 Operation {
356 opcode,
357 offset,
358 input: Vec::new(),
359 }
360 }
361
362 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}