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 CLZ,
161 DATALOAD,
163 DATALOADN,
164 DATASIZE,
165 DATACOPY,
166 RJUMP,
168 RJUMPI,
169 RJUMPV,
170 CALLF,
172 RETF,
173 JUMPF,
174 DUPN,
176 SWAPN,
177 EXCHANGE,
178 EXTCODETYPE,
180 EOFCREATE,
182 TXCREATE,
183 RETURNCONTRACT,
184 RETURNDATALOAD,
186 EXTCALL,
187 EXTDELEGATECALL,
188 EXTSTATICCALL,
189 PAY,
191}
192
193impl Opcode {
194 pub fn from_byte(byte: u8) -> Opcode {
196 match byte {
197 0x00 => Opcode::STOP,
198 0x01 => Opcode::ADD,
199 0x02 => Opcode::MUL,
200 0x03 => Opcode::SUB,
201 0x04 => Opcode::DIV,
202 0x05 => Opcode::SDIV,
203 0x06 => Opcode::MOD,
204 0x07 => Opcode::SMOD,
205 0x08 => Opcode::ADDMOD,
206 0x09 => Opcode::MULMOD,
207 0x0A => Opcode::EXP,
208 0x0B => Opcode::SIGNEXTEND,
209 0x10 => Opcode::LT,
210 0x11 => Opcode::GT,
211 0x12 => Opcode::SLT,
212 0x13 => Opcode::SGT,
213 0x14 => Opcode::EQ,
214 0x15 => Opcode::ISZERO,
215 0x16 => Opcode::AND,
216 0x17 => Opcode::OR,
217 0x18 => Opcode::XOR,
218 0x19 => Opcode::NOT,
219 0x1a => Opcode::BYTE,
220 0x1b => Opcode::SHL,
221 0x1c => Opcode::SHR,
222 0x1d => Opcode::SAR,
223 0x1e => Opcode::CLZ,
224 0x20 => Opcode::SHA3,
225 0x30 => Opcode::ADDRESS,
226 0x31 => Opcode::BALANCE,
227 0x32 => Opcode::ORIGIN,
228 0x33 => Opcode::CALLER,
229 0x34 => Opcode::CALLVALUE,
230 0x35 => Opcode::CALLDATALOAD,
231 0x36 => Opcode::CALLDATASIZE,
232 0x37 => Opcode::CALLDATACOPY,
233 0x38 => Opcode::CODESIZE,
234 0x39 => Opcode::CODECOPY,
235 0x3a => Opcode::GASPRICE,
236 0x3b => Opcode::EXTCODESIZE,
237 0x3c => Opcode::EXTCODECOPY,
238 0x3d => Opcode::RETURNDATASIZE,
239 0x3e => Opcode::RETURNDATACOPY,
240 0x3f => Opcode::EXTCODEHASH,
241 0x40 => Opcode::BLOCKHASH,
242 0x41 => Opcode::COINBASE,
243 0x42 => Opcode::TIMESTAMP,
244 0x43 => Opcode::NUMBER,
245 0x44 => Opcode::DIFFICULTY,
246 0x45 => Opcode::GASLIMIT,
247 0x46 => Opcode::CHAINID,
248 0x47 => Opcode::SELFBALANCE,
249 0x48 => Opcode::BASEFEE,
250 0x49 => Opcode::BLOBHASH,
251 0x4a => Opcode::BLOBBASEFEE,
252 0x50 => Opcode::POP,
253 0x51 => Opcode::MLOAD,
254 0x52 => Opcode::MSTORE,
255 0x53 => Opcode::MSTORE8,
256 0x54 => Opcode::SLOAD,
257 0x55 => Opcode::SSTORE,
258 0x56 => Opcode::JUMP,
259 0x57 => Opcode::JUMPI,
260 0x58 => Opcode::PC,
261 0x59 => Opcode::MSIZE,
262 0x5a => Opcode::GAS,
263 0x5b => Opcode::JUMPDEST,
264 0x5c => Opcode::TLOAD,
265 0x5d => Opcode::TSTORE,
266 0x5e => Opcode::MCOPY,
267 0x5F => Opcode::PUSH0,
268 0x60 => Opcode::PUSH1,
269 0x61 => Opcode::PUSH2,
270 0x62 => Opcode::PUSH3,
271 0x63 => Opcode::PUSH4,
272 0x64 => Opcode::PUSH5,
273 0x65 => Opcode::PUSH6,
274 0x66 => Opcode::PUSH7,
275 0x67 => Opcode::PUSH8,
276 0x68 => Opcode::PUSH9,
277 0x69 => Opcode::PUSH10,
278 0x6a => Opcode::PUSH11,
279 0x6b => Opcode::PUSH12,
280 0x6c => Opcode::PUSH13,
281 0x6d => Opcode::PUSH14,
282 0x6e => Opcode::PUSH15,
283 0x6f => Opcode::PUSH16,
284 0x70 => Opcode::PUSH17,
285 0x71 => Opcode::PUSH18,
286 0x72 => Opcode::PUSH19,
287 0x73 => Opcode::PUSH20,
288 0x74 => Opcode::PUSH21,
289 0x75 => Opcode::PUSH22,
290 0x76 => Opcode::PUSH23,
291 0x77 => Opcode::PUSH24,
292 0x78 => Opcode::PUSH25,
293 0x79 => Opcode::PUSH26,
294 0x7a => Opcode::PUSH27,
295 0x7b => Opcode::PUSH28,
296 0x7c => Opcode::PUSH29,
297 0x7d => Opcode::PUSH30,
298 0x7e => Opcode::PUSH31,
299 0x7f => Opcode::PUSH32,
300 0x80 => Opcode::DUP1,
301 0x81 => Opcode::DUP2,
302 0x82 => Opcode::DUP3,
303 0x83 => Opcode::DUP4,
304 0x84 => Opcode::DUP5,
305 0x85 => Opcode::DUP6,
306 0x86 => Opcode::DUP7,
307 0x87 => Opcode::DUP8,
308 0x88 => Opcode::DUP9,
309 0x89 => Opcode::DUP10,
310 0x8a => Opcode::DUP11,
311 0x8b => Opcode::DUP12,
312 0x8c => Opcode::DUP13,
313 0x8d => Opcode::DUP14,
314 0x8e => Opcode::DUP15,
315 0x8f => Opcode::DUP16,
316 0x90 => Opcode::SWAP1,
317 0x91 => Opcode::SWAP2,
318 0x92 => Opcode::SWAP3,
319 0x93 => Opcode::SWAP4,
320 0x94 => Opcode::SWAP5,
321 0x95 => Opcode::SWAP6,
322 0x96 => Opcode::SWAP7,
323 0x97 => Opcode::SWAP8,
324 0x98 => Opcode::SWAP9,
325 0x99 => Opcode::SWAP10,
326 0x9a => Opcode::SWAP11,
327 0x9b => Opcode::SWAP12,
328 0x9c => Opcode::SWAP13,
329 0x9d => Opcode::SWAP14,
330 0x9e => Opcode::SWAP15,
331 0x9f => Opcode::SWAP16,
332 0xa0 => Opcode::LOG0,
333 0xa1 => Opcode::LOG1,
334 0xa2 => Opcode::LOG2,
335 0xa3 => Opcode::LOG3,
336 0xa4 => Opcode::LOG4,
337 0xf0 => Opcode::CREATE,
338 0xf1 => Opcode::CALL,
339 0xf2 => Opcode::CALLCODE,
340 0xf3 => Opcode::RETURN,
341 0xf4 => Opcode::DELEGATECALL,
342 0xf5 => Opcode::CREATE2,
343 0xfa => Opcode::STATICCALL,
344 0xfd => Opcode::REVERT,
345 0xff => Opcode::SELFDESTRUCT,
346 _ => Opcode::INVALID,
347 }
348 }
349
350 pub fn from_byte_eof(byte: u8) -> Opcode {
354 match byte {
355 0xd0 => Opcode::DATALOAD,
357 0xd1 => Opcode::DATALOADN,
358 0xd2 => Opcode::DATASIZE,
359 0xd3 => Opcode::DATACOPY,
360 0xe0 => Opcode::RJUMP,
362 0xe1 => Opcode::RJUMPI,
363 0xe2 => Opcode::RJUMPV,
364 0xe3 => Opcode::CALLF,
366 0xe4 => Opcode::RETF,
367 0xe5 => Opcode::JUMPF,
368 0xe6 => Opcode::DUPN,
370 0xe7 => Opcode::SWAPN,
371 0xe8 => Opcode::EXCHANGE,
372 0xe9 => Opcode::EXTCODETYPE,
374 0xec => Opcode::EOFCREATE,
376 0xed => Opcode::TXCREATE,
377 0xee => Opcode::RETURNCONTRACT,
378 0xf7 => Opcode::RETURNDATALOAD,
380 0xf8 => Opcode::EXTCALL,
381 0xf9 => Opcode::EXTDELEGATECALL,
382 0xfb => Opcode::EXTSTATICCALL,
383 0xfc => Opcode::PAY,
385 _ => Self::from_byte(byte),
387 }
388 }
389}
390
391#[derive(PartialEq, Eq)]
396pub struct Operation {
397 pub opcode: Opcode,
399 pub input: Vec<u8>,
401 pub offset: u32,
403}
404
405impl fmt::Debug for Operation {
406 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
407 let mut formatted = format!(
408 "{:0>8}: {:?}",
409 format!("{:#x}", self.offset).trim_start_matches("0x"),
410 self.opcode
411 );
412 if !self.input.is_empty() {
413 let encoded_bytes = hex::encode(&self.input);
414 let mut formatted_bytes = encoded_bytes.trim_start_matches('0');
415 if formatted_bytes.is_empty() {
416 formatted_bytes = "0";
417 }
418 formatted = format!("{} {}", formatted, "0x".to_owned() + formatted_bytes);
419 }
420 write!(f, "{formatted}")
421 }
422}
423
424impl Operation {
425 pub fn new(opcode: Opcode, offset: u32) -> Self {
427 Operation {
428 opcode,
429 offset,
430 input: Vec::new(),
431 }
432 }
433
434 pub fn with_bytes(
436 self,
437 num_bytes: u8,
438 bytes: &mut dyn ExactSizeIterator<Item = u8>,
439 ) -> Result<Self> {
440 if num_bytes == 0 {
441 return Ok(self);
442 }
443 if num_bytes as usize > bytes.len() {
444 return Err(eyre!(
445 "Not enough bytes to read - expected {} but only {} left",
446 num_bytes,
447 bytes.len()
448 ));
449 }
450 Ok(Operation {
451 opcode: self.opcode,
452 offset: self.offset,
453 input: bytes.take(num_bytes as usize).collect(),
454 })
455 }
456}