Skip to main content

yevm_core/ops/
mod.rs

1use crate::{
2    Call,
3    evm::{Context, Evm, EvmResult, EvmYield, HaltReason},
4    state::State,
5};
6
7pub mod basic;
8pub mod calls;
9pub mod chain;
10pub mod logs;
11pub mod stack;
12pub mod store;
13
14fn invalid(evm: &mut Evm, _: &Context, _: &Call, _: &mut dyn State) -> EvmResult<()> {
15    let op = evm.code.get(evm.pc).copied().unwrap_or_default();
16    Err(EvmYield::Halt(HaltReason::BadOpcode(op)))
17}
18
19pub fn text(code: &[u8]) -> Vec<String> {
20    let mut ret = Vec::with_capacity(code.len());
21    let mut pc = 0;
22    while pc < code.len() {
23        let op = code[pc];
24        let name = OPS[op as usize];
25        let data = match op {
26            0x60..0x80 => {
27                let len = op as usize - 0x60 + 1; // PUSH{1..32}
28                let lo = (pc + 1).min(code.len());
29                let hi = (pc + 1 + len).min(code.len());
30                pc += len;
31                Some(hex::encode(&code[lo..hi]))
32            }
33            _ => None,
34        };
35        let data = data.map(|d| format!(" [{d}]")).unwrap_or_default();
36        ret.push(format!("{pc:04x}: {name:16}{data}"));
37        pc += 1;
38    }
39    ret
40}
41
42pub fn dispatch<S: State>(
43    op: u8,
44    evm: &mut Evm,
45    ctx: &Context,
46    call: &Call,
47    state: &mut S,
48) -> EvmResult<()> {
49    match op {
50        0x00 => basic::stop(evm),
51        0x01 => basic::add(evm),
52        0x02 => basic::mul(evm),
53        0x03 => basic::sub(evm),
54        0x04 => basic::div(evm),
55        0x05 => basic::sdiv(evm),
56        0x06 => basic::r#mod(evm),
57        0x07 => basic::smod(evm),
58        0x08 => basic::addmod(evm),
59        0x09 => basic::mulmod(evm),
60        0x0A => basic::exp(evm),
61        0x0B => basic::signextend(evm),
62        0x10 => basic::lt(evm),
63        0x11 => basic::gt(evm),
64        0x12 => basic::slt(evm),
65        0x13 => basic::sgt(evm),
66        0x14 => basic::eq(evm),
67        0x15 => basic::iszero(evm),
68        0x16 => basic::and(evm),
69        0x17 => basic::or(evm),
70        0x18 => basic::xor(evm),
71        0x19 => basic::not(evm),
72        0x1A => basic::byte(evm),
73        0x1B => basic::shl(evm),
74        0x1C => basic::shr(evm),
75        0x1D => basic::sar(evm),
76        0x1E => basic::clz(evm),
77        0x20 => basic::hash(evm, state),
78        0x30 => chain::address(evm, ctx, call, state),
79        0x31 => chain::balance(evm, ctx, call, state),
80        0x32 => chain::origin(evm, ctx, call, state),
81        0x33 => chain::caller(evm, ctx, call, state),
82        0x34 => chain::callvalue(evm, ctx, call, state),
83        0x35 => chain::calldataload(evm, ctx, call, state),
84        0x36 => chain::calldatasize(evm, ctx, call, state),
85        0x37 => chain::calldatacopy(evm, ctx, call, state),
86        0x38 => chain::codesize(evm, ctx, call, state),
87        0x39 => chain::codecopy(evm, ctx, call, state),
88        0x3A => chain::gasprice(evm, ctx, call, state),
89        0x3B => chain::extcodesize(evm, ctx, call, state),
90        0x3C => chain::extcodecopy(evm, ctx, call, state),
91        0x3D => chain::returndatasize(evm, ctx, call, state),
92        0x3E => chain::returndatacopy(evm, ctx, call, state),
93        0x3F => chain::extcodehash(evm, ctx, call, state),
94        0x40 => chain::blockhash(evm, ctx, call, state),
95        0x41 => chain::coinbase(evm, ctx, call, state),
96        0x42 => chain::timestamp(evm, ctx, call, state),
97        0x43 => chain::number(evm, ctx, call, state),
98        0x44 => chain::prevrandao(evm, ctx, call, state),
99        0x45 => chain::gaslimit(evm, ctx, call, state),
100        0x46 => chain::chainid(evm, ctx, call, state),
101        0x47 => chain::selfbalance(evm, ctx, call, state),
102        0x48 => chain::basefee(evm, ctx, call, state),
103        0x49 => chain::blobhash(evm, ctx, call, state),
104        0x4A => chain::blobbasefee(evm, ctx, call, state),
105        0x50 => store::pop(evm, ctx, call, state),
106        0x51 => store::mload(evm, ctx, call, state),
107        0x52 => store::mstore(evm, ctx, call, state),
108        0x53 => store::mstore8(evm, ctx, call, state),
109        0x54 => store::sload(evm, ctx, call, state),
110        0x55 => store::sstore(evm, ctx, call, state),
111        0x56 => store::jump(evm, ctx, call, state),
112        0x57 => store::jumpi(evm, ctx, call, state),
113        0x58 => store::pc(evm, ctx, call, state),
114        0x59 => store::msize(evm, ctx, call, state),
115        0x5A => store::gas(evm, ctx, call, state),
116        0x5B => store::jumpdest(evm, ctx, call, state),
117        0x5C => store::tload(evm, ctx, call, state),
118        0x5D => store::tstore(evm, ctx, call, state),
119        0x5E => store::mcopy(evm, ctx, call, state),
120        0x5F..=0x7F => stack::push(evm, ctx, call, state),
121        0x80..=0x8F => stack::dup(evm, ctx, call, state),
122        0x90..=0x9F => stack::swap(evm, ctx, call, state),
123        0xA0..=0xA4 => logs::log(evm, ctx, call, state),
124        0xF0 => calls::create(evm, ctx, call, state),
125        0xF1 => calls::call(evm, ctx, call, state),
126        0xF2 => calls::callcode(evm, ctx, call, state),
127        0xF3 => calls::r#return(evm, ctx, call, state),
128        0xF4 => calls::delegatecall(evm, ctx, call, state),
129        0xF5 => calls::create2(evm, ctx, call, state),
130        0xFA => calls::staticcall(evm, ctx, call, state),
131        0xFD => calls::revert(evm, ctx, call, state),
132        0xFF => calls::selfdestruct(evm, ctx, call, state),
133        _ => invalid(evm, ctx, call, state),
134    }
135}
136
137pub const OPS: [&str; 256] = [
138    // 0x00
139    "STOP",
140    "ADD",
141    "MUL",
142    "SUB",
143    "DIV",
144    "SDIV",
145    "MOD",
146    "SMOD",
147    "ADDMOD",
148    "MULMOD",
149    "EXP",
150    "SIGNEXTEND",
151    "INVALID/0x0C",
152    "INVALID/0x0D",
153    "INVALID/0x0E",
154    "INVALID/0x0F",
155    // 0x10
156    "LT",
157    "GT",
158    "SLT",
159    "SGT",
160    "EQ",
161    "ISZERO",
162    "AND",
163    "OR",
164    "XOR",
165    "NOT",
166    "BYTE",
167    "SHL",
168    "SHR",
169    "SAR",
170    "CLZ",
171    // "INVALID/0x1E", // CLZ is not in the Cancun spec
172    "INVALID/0x1F",
173    // 0x20
174    "KECCAK256",
175    "INVALID/0x21",
176    "INVALID/0x22",
177    "INVALID/0x23",
178    "INVALID/0x24",
179    "INVALID/0x25",
180    "INVALID/0x26",
181    "INVALID/0x27",
182    "INVALID/0x28",
183    "INVALID/0x29",
184    "INVALID/0x2A",
185    "INVALID/0x2B",
186    "INVALID/0x2C",
187    "INVALID/0x2D",
188    "INVALID/0x2E",
189    "INVALID/0x2F",
190    // 0x30
191    "ADDRESS",
192    "BALANCE",
193    "ORIGIN",
194    "CALLER",
195    "CALLVALUE",
196    "CALLDATALOAD",
197    "CALLDATASIZE",
198    "CALLDATACOPY",
199    "CODESIZE",
200    "CODECOPY",
201    "GASPRICE",
202    "EXTCODESIZE",
203    "EXTCODECOPY",
204    "RETURNDATASIZE",
205    "RETURNDATACOPY",
206    "EXTCODEHASH",
207    // 0x40
208    "BLOCKHASH",
209    "COINBASE",
210    "TIMESTAMP",
211    "NUMBER",
212    /* "PREVRANDAO", */ "DIFFICULTY",
213    "GASLIMIT",
214    "CHAINID",
215    "SELFBALANCE",
216    "BASEFEE",
217    "BLOBHASH",
218    "BLOBBASEFEE",
219    "INVALID/0x4B",
220    "INVALID/0x4C",
221    "INVALID/0x4D",
222    "INVALID/0x4E",
223    "INVALID/0x4F",
224    // 0x50
225    "POP",
226    "MLOAD",
227    "MSTORE",
228    "MSTORE8",
229    "SLOAD",
230    "SSTORE",
231    "JUMP",
232    "JUMPI",
233    "PC",
234    "MSIZE",
235    "GAS",
236    "JUMPDEST",
237    "TLOAD",
238    "TSTORE",
239    "MCOPY",
240    "PUSH0",
241    // 0x60
242    "PUSH1",
243    "PUSH2",
244    "PUSH3",
245    "PUSH4",
246    "PUSH5",
247    "PUSH6",
248    "PUSH7",
249    "PUSH8",
250    "PUSH9",
251    "PUSH10",
252    "PUSH11",
253    "PUSH12",
254    "PUSH13",
255    "PUSH14",
256    "PUSH15",
257    "PUSH16",
258    // 0x70
259    "PUSH17",
260    "PUSH18",
261    "PUSH19",
262    "PUSH20",
263    "PUSH21",
264    "PUSH22",
265    "PUSH23",
266    "PUSH24",
267    "PUSH25",
268    "PUSH26",
269    "PUSH27",
270    "PUSH28",
271    "PUSH29",
272    "PUSH30",
273    "PUSH31",
274    "PUSH32",
275    // 0x80
276    "DUP1",
277    "DUP2",
278    "DUP3",
279    "DUP4",
280    "DUP5",
281    "DUP6",
282    "DUP7",
283    "DUP8",
284    "DUP9",
285    "DUP10",
286    "DUP11",
287    "DUP12",
288    "DUP13",
289    "DUP14",
290    "DUP15",
291    "DUP16",
292    // 0x90
293    "SWAP1",
294    "SWAP2",
295    "SWAP3",
296    "SWAP4",
297    "SWAP5",
298    "SWAP6",
299    "SWAP7",
300    "SWAP8",
301    "SWAP9",
302    "SWAP10",
303    "SWAP11",
304    "SWAP12",
305    "SWAP13",
306    "SWAP14",
307    "SWAP15",
308    "SWAP16",
309    // 0xA0
310    "LOG0",
311    "LOG1",
312    "LOG2",
313    "LOG3",
314    "LOG4",
315    "INVALID/0xA5",
316    "INVALID/0xA6",
317    "INVALID/0xA7",
318    "INVALID/0xA8",
319    "INVALID/0xA9",
320    "INVALID/0xAA",
321    "INVALID/0xAB",
322    "INVALID/0xAC",
323    "INVALID/0xAD",
324    "INVALID/0xAE",
325    "INVALID/0xAF",
326    // 0xB0
327    "INVALID/0xB0",
328    "INVALID/0xB1",
329    "INVALID/0xB2",
330    "INVALID/0xB3",
331    "INVALID/0xB4",
332    "INVALID/0xB5",
333    "INVALID/0xB6",
334    "INVALID/0xB7",
335    "INVALID/0xB8",
336    "INVALID/0xB9",
337    "INVALID/0xBA",
338    "INVALID/0xBB",
339    "INVALID/0xBC",
340    "INVALID/0xBD",
341    "INVALID/0xBE",
342    "INVALID/0xBF",
343    // 0xC0
344    "INVALID/0xC0",
345    "INVALID/0xC1",
346    "INVALID/0xC2",
347    "INVALID/0xC3",
348    "INVALID/0xC4",
349    "INVALID/0xC5",
350    "INVALID/0xC6",
351    "INVALID/0xC7",
352    "INVALID/0xC8",
353    "INVALID/0xC9",
354    "INVALID/0xCA",
355    "INVALID/0xCB",
356    "INVALID/0xCC",
357    "INVALID/0xCD",
358    "INVALID/0xCE",
359    "INVALID/0xCF",
360    // 0xD0
361    "INVALID/0xD0",
362    "INVALID/0xD1",
363    "INVALID/0xD2",
364    "INVALID/0xD3",
365    "INVALID/0xD4",
366    "INVALID/0xD5",
367    "INVALID/0xD6",
368    "INVALID/0xD7",
369    "INVALID/0xD8",
370    "INVALID/0xD9",
371    "INVALID/0xDA",
372    "INVALID/0xDB",
373    "INVALID/0xDC",
374    "INVALID/0xDD",
375    "INVALID/0xDE",
376    "INVALID/0xDF",
377    // 0xE0
378    "INVALID/0xE0",
379    "INVALID/0xE1",
380    "INVALID/0xE2",
381    "INVALID/0xE3",
382    "INVALID/0xE4",
383    "INVALID/0xE5",
384    "INVALID/0xE6",
385    "INVALID/0xE7",
386    "INVALID/0xE8",
387    "INVALID/0xE9",
388    "INVALID/0xEA",
389    "INVALID/0xEB",
390    "INVALID/0xEC",
391    "INVALID/0xED",
392    "INVALID/0xEE",
393    "INVALID/0xEF",
394    // 0xF0
395    "CREATE",
396    "CALL",
397    "CALLCODE",
398    "RETURN",
399    "DELEGATECALL",
400    "CREATE2",
401    "INVALID/0xF6",
402    "INVALID/0xF7",
403    "INVALID/0xF8",
404    "INVALID/0xF9",
405    "STATICCALL",
406    "INVALID/0xFB",
407    "INVALID/0xFC",
408    "REVERT",
409    "INVALID/0xFE",
410    "SELFDESTRUCT",
411];
412
413#[cfg(test)]
414pub mod tests {
415    use yevm_misc::buf::Buf;
416
417    use crate::{
418        Acc, Call, Head, Int,
419        evm::Context,
420        state::{Account, State},
421        trace::Event,
422    };
423
424    pub fn ctx() -> Context {
425        Context {
426            origin: Acc::ZERO,
427            is_static: false,
428            depth: 0,
429            this: Acc::ZERO,
430        }
431    }
432
433    pub fn call() -> Call {
434        Call {
435            by: Acc::ZERO,
436            to: Some(Acc::ONE),
437            gas: 0,
438            eth: Int::ZERO,
439            data: vec![].into(),
440        }
441    }
442
443    pub fn state() -> Empty {
444        Empty
445    }
446
447    #[derive(Default)]
448    pub struct Empty;
449
450    impl State for Empty {
451        fn get(&mut self, _: &Acc, _: &Int) -> Option<(Int, Int)> {
452            None
453        }
454        fn put(&mut self, _: &Acc, _: &Int, _: Int) -> Option<Int> {
455            None
456        }
457        fn init(&mut self, _: &Acc, _: &Int, _: Int) {}
458        fn tget(&mut self, _: &Acc, _: &Int) -> Option<Int> {
459            None
460        }
461        fn tput(&mut self, _: Acc, _: Int, _: Int) -> Option<Int> {
462            None
463        }
464        fn inc_nonce(&mut self, _: &Acc, _: Int) -> Int {
465            Int::ZERO
466        }
467        fn set_value(&mut self, _: &Acc, _: Int) -> Int {
468            Int::ZERO
469        }
470        fn set_code(&mut self, _: &Acc, _: Buf, _: Int) -> Int {
471            Int::ZERO
472        }
473        fn balance(&mut self, _: &Acc) -> Option<Int> {
474            None
475        }
476        fn nonce(&mut self, _: &Acc) -> Option<Int> {
477            None
478        }
479        fn code(&mut self, _: &Acc) -> Option<(Buf, Int)> {
480            None
481        }
482        fn acc(&mut self, _: &Acc) -> Option<Account> {
483            None
484        }
485        fn merge(&mut self, _: &Acc, _: Account) {}
486        fn is_cold_acc(&self, _: &Acc) -> bool {
487            true
488        }
489        fn is_cold_key(&self, _: &Acc, _: &Int) -> bool {
490            true
491        }
492        fn warm_acc(&mut self, _: &Acc) -> bool {
493            false
494        }
495        fn warm_key(&mut self, _: &Acc, _: &Int) -> bool {
496            false
497        }
498        fn create(&mut self, _: Acc, _: Account) {}
499        fn destroy(&mut self, _: &Acc) {}
500        fn created(&self) -> Vec<Acc> {
501            vec![]
502        }
503        fn destroyed(&self) -> Vec<Acc> {
504            vec![]
505        }
506        fn head(&self, _: u64) -> Option<Head> {
507            None
508        }
509        fn hash(&mut self, _: u64, _: Int) {}
510        fn auth(&self, _: &Acc) -> Option<Acc> {
511            None
512        }
513        fn log(&mut self, _: Buf, _: Vec<Int>) {}
514        fn emit(&mut self, _: Event) -> usize {
515            0
516        }
517        fn set_auth(&mut self, _: &Acc, _: &Acc) {}
518        fn apply(&mut self) {}
519    }
520}