1use crate::{
2 gas,
3 interpreter::Interpreter,
4 interpreter_types::{
5 EofCodeInfo, Immediates, InterpreterTypes, Jumps, LoopControl, MemoryTr, RuntimeFlag,
6 StackTr, SubRoutineStack,
7 },
8 InstructionResult, InterpreterAction,
9};
10use primitives::{Bytes, U256};
11
12use crate::InstructionContext;
13
14pub fn rjump<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
15 require_eof!(context.interpreter);
16 gas!(context.interpreter, gas::BASE);
17 let offset = context.interpreter.bytecode.read_i16() as isize;
18 context.interpreter.bytecode.relative_jump(offset + 2);
21}
22
23pub fn rjumpi<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
24 require_eof!(context.interpreter);
25 gas!(context.interpreter, gas::CONDITION_JUMP_GAS);
26 popn!([condition], context.interpreter);
27 let mut offset = 2;
30 if !condition.is_zero() {
31 offset += context.interpreter.bytecode.read_i16() as isize;
32 }
33
34 context.interpreter.bytecode.relative_jump(offset);
35}
36
37pub fn rjumpv<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
38 require_eof!(context.interpreter);
39 gas!(context.interpreter, gas::CONDITION_JUMP_GAS);
40 popn!([case], context.interpreter);
41 let case = as_isize_saturated!(case);
42
43 let max_index = context.interpreter.bytecode.read_u8() as isize;
44 let mut offset = (max_index + 1) * 2 + 1;
47
48 if case <= max_index {
49 offset += context.interpreter.bytecode.read_offset_i16(1 + case * 2) as isize;
50 }
51 context.interpreter.bytecode.relative_jump(offset);
52}
53
54pub fn jump<ITy: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, ITy>) {
55 gas!(context.interpreter, gas::MID);
56 popn!([target], context.interpreter);
57 jump_inner(context.interpreter, target);
58}
59
60pub fn jumpi<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
61 gas!(context.interpreter, gas::HIGH);
62 popn!([target, cond], context.interpreter);
63
64 if !cond.is_zero() {
65 jump_inner(context.interpreter, target);
66 }
67}
68
69#[inline]
70fn jump_inner<WIRE: InterpreterTypes>(interpreter: &mut Interpreter<WIRE>, target: U256) {
71 let target = as_usize_or_fail!(interpreter, target, InstructionResult::InvalidJump);
72 if !interpreter.bytecode.is_valid_legacy_jump(target) {
73 interpreter.halt(InstructionResult::InvalidJump);
74 return;
75 }
76 interpreter.bytecode.absolute_jump(target);
78}
79
80pub fn jumpdest_or_nop<WIRE: InterpreterTypes, H: ?Sized>(
81 context: InstructionContext<'_, H, WIRE>,
82) {
83 gas!(context.interpreter, gas::JUMPDEST);
84}
85
86pub fn callf<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
87 require_eof!(context.interpreter);
88 gas!(context.interpreter, gas::LOW);
89
90 let idx = context.interpreter.bytecode.read_u16() as usize;
91 let Some(types) = context.interpreter.bytecode.code_info(idx) else {
93 panic!("Invalid EOF in execution, expecting correct intermediate in callf")
94 };
95
96 if context.interpreter.stack.len() + types.max_stack_increase as usize > 1024 {
99 context.interpreter.halt(InstructionResult::StackOverflow);
100 return;
101 }
102
103 if !(context
106 .interpreter
107 .sub_routine
108 .push(context.interpreter.bytecode.pc() + 2, idx))
109 {
110 context
111 .interpreter
112 .halt(InstructionResult::SubRoutineStackOverflow);
113 return;
114 };
115 let pc = context
116 .interpreter
117 .bytecode
118 .code_section_pc(idx)
119 .expect("Invalid code section index");
120 context.interpreter.bytecode.absolute_jump(pc);
121}
122
123pub fn retf<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
124 require_eof!(context.interpreter);
125 gas!(context.interpreter, gas::RETF_GAS);
126
127 let Some(jump) = context.interpreter.sub_routine.pop() else {
128 panic!("Expected function frame")
129 };
130
131 context.interpreter.bytecode.absolute_jump(jump);
132}
133
134pub fn jumpf<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
135 require_eof!(context.interpreter);
136 gas!(context.interpreter, gas::LOW);
137
138 let idx = context.interpreter.bytecode.read_u16() as usize;
139
140 let types = context
142 .interpreter
143 .bytecode
144 .code_info(idx)
145 .expect("Invalid code section index");
146
147 if context.interpreter.stack.len() + types.max_stack_increase as usize > 1024 {
149 context.interpreter.halt(InstructionResult::StackOverflow);
150 return;
151 }
152 context.interpreter.sub_routine.set_routine_idx(idx);
153 let pc = context
154 .interpreter
155 .bytecode
156 .code_section_pc(idx)
157 .expect("Invalid code section index");
158 context.interpreter.bytecode.absolute_jump(pc);
159}
160
161pub fn pc<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
162 gas!(context.interpreter, gas::BASE);
163 push!(
165 context.interpreter,
166 U256::from(context.interpreter.bytecode.pc() - 1)
167 );
168}
169
170#[inline]
171fn return_inner(
172 interpreter: &mut Interpreter<impl InterpreterTypes>,
173 instruction_result: InstructionResult,
174) {
175 popn!([offset, len], interpreter);
178 let len = as_usize_or_fail!(interpreter, len);
179 let mut output = Bytes::default();
181 if len != 0 {
182 let offset = as_usize_or_fail!(interpreter, offset);
183 resize_memory!(interpreter, offset, len);
184 output = interpreter.memory.slice_len(offset, len).to_vec().into()
185 }
186
187 interpreter
188 .bytecode
189 .set_action(InterpreterAction::new_return(
190 instruction_result,
191 output,
192 interpreter.gas,
193 ));
194}
195
196pub fn ret<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
197 return_inner(context.interpreter, InstructionResult::Return);
198}
199
200pub fn revert<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
202 check!(context.interpreter, BYZANTIUM);
203 return_inner(context.interpreter, InstructionResult::Revert);
204}
205
206pub fn stop<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
208 context.interpreter.halt(InstructionResult::Stop);
209}
210
211pub fn invalid<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
213 context.interpreter.halt(InstructionResult::InvalidFEOpcode);
214}
215
216pub fn unknown<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
218 context.interpreter.halt(InstructionResult::OpcodeNotFound);
219}
220
221#[cfg(test)]
222mod test {
223 use super::*;
224 use crate::interpreter::SubRoutineReturnFrame;
225 use crate::{instruction_table, interpreter::EthInterpreter};
226 use bytecode::opcode::{CALLF, JUMPF, NOP, RETF, RJUMP, RJUMPI, RJUMPV, STOP};
227 use bytecode::{
228 eof::{CodeInfo, Eof},
229 Bytecode,
230 };
231 use primitives::bytes;
232 use std::sync::Arc;
233
234 #[test]
235 fn rjump() {
236 let bytecode = Bytecode::new_raw(Bytes::from(&[RJUMP, 0x00, 0x02, STOP, STOP]));
237 let mut interpreter = Interpreter::<EthInterpreter>::default().with_bytecode(bytecode);
238
239 interpreter.runtime_flag.is_eof = true;
240 let table = instruction_table();
241
242 interpreter.step_dummy(&table);
243 assert_eq!(interpreter.bytecode.pc(), 5)
244 }
245
246 #[test]
247 fn rjumpi() {
248 let bytecode = Bytecode::new_raw(Bytes::from(&[
249 RJUMPI, 0x00, 0x03, RJUMPI, 0x00, 0x01, STOP, STOP,
250 ]));
251 let mut interpreter = Interpreter::default().with_bytecode(bytecode);
252
253 interpreter.runtime_flag.is_eof = true;
254 let table = instruction_table();
255
256 let _ = interpreter.stack.push(U256::from(1));
257 let _ = interpreter.stack.push(U256::from(0));
258
259 interpreter.step_dummy(&table);
261 assert_eq!(interpreter.bytecode.pc(), 3);
262 interpreter.step_dummy(&table);
264 assert_eq!(interpreter.bytecode.pc(), 7);
265 }
266
267 #[test]
268 fn rjumpv() {
269 let bytecode = Bytecode::new_raw(Bytes::from(&[
270 RJUMPV,
271 0x01, 0x00, 0x01,
274 0x00, 0x02,
276 NOP,
277 NOP,
278 NOP,
279 RJUMP,
280 0xFF,
281 (-12i8) as u8,
282 STOP,
283 ]));
284 let mut interpreter = Interpreter::default().with_bytecode(bytecode);
285
286 interpreter.runtime_flag.is_eof = true;
287 let table = instruction_table();
288
289 let _ = interpreter.stack.push(U256::from(10));
291 interpreter.step_dummy(&table);
292 assert_eq!(interpreter.bytecode.pc(), 6);
293
294 interpreter.step_dummy(&table);
296 interpreter.step_dummy(&table);
297 interpreter.step_dummy(&table);
298 interpreter.step_dummy(&table);
299 assert_eq!(interpreter.bytecode.pc(), 0);
300
301 let _ = interpreter.stack.push(U256::from(0));
303 interpreter.step_dummy(&table);
304 assert_eq!(interpreter.bytecode.pc(), 7);
305
306 interpreter.step_dummy(&table);
308 interpreter.step_dummy(&table);
309 interpreter.step_dummy(&table);
310 assert_eq!(interpreter.bytecode.pc(), 0);
311
312 let _ = interpreter.stack.push(U256::from(1));
314 interpreter.step_dummy(&table);
315 assert_eq!(interpreter.bytecode.pc(), 8);
316 }
317
318 fn dummy_eof() -> Eof {
319 let bytes = bytes!("ef00010100040200010001ff00000000800000fe");
320 Eof::decode(bytes).unwrap()
321 }
322
323 fn eof_setup(bytes1: Bytes, bytes2: Bytes) -> Interpreter {
324 eof_setup_with_types(bytes1, bytes2, CodeInfo::default())
325 }
326
327 fn eof_setup_with_types(bytes1: Bytes, bytes2: Bytes, types: CodeInfo) -> Interpreter {
329 let mut eof = dummy_eof();
330
331 eof.body.code_section.clear();
332 eof.body.code_info.clear();
333 eof.header.code_sizes.clear();
334
335 eof.header.code_sizes.push(bytes1.len() as u16);
336 eof.body.code_section.push(bytes1.len());
337 eof.body.code_info.push(CodeInfo::new(0, 0, 11));
338
339 eof.header.code_sizes.push(bytes2.len() as u16);
340 eof.body.code_section.push(bytes2.len() + bytes1.len());
341 eof.body.code_info.push(types);
342
343 eof.header.types_size = 2 * 4;
345
346 eof.body.code = Bytes::from([bytes1, bytes2].concat());
347
348 let encoded = eof.encode_slow();
351
352 let bytecode = Bytecode::Eof(Arc::new(Eof::decode(encoded).unwrap()));
353
354 Interpreter::default().with_bytecode(bytecode)
355 }
356
357 #[test]
358 fn callf_retf_stop() {
359 let table = instruction_table();
360
361 let bytes1 = Bytes::from([CALLF, 0x00, 0x01, STOP]);
362 let bytes2 = Bytes::from([RETF]);
363 let mut interpreter = eof_setup(bytes1, bytes2.clone());
364 interpreter.runtime_flag.is_eof = true;
365 let base_pc = interpreter.bytecode.pc();
366
367 interpreter.step_dummy(&table);
369
370 assert_eq!(interpreter.sub_routine.current_code_idx, 1);
371 assert_eq!(
372 interpreter.sub_routine.return_stack[0],
373 SubRoutineReturnFrame::new(0, 3 + base_pc)
374 );
375 assert_eq!(interpreter.bytecode.pc() - base_pc, 4);
377
378 interpreter.step_dummy(&table);
380
381 assert_eq!(interpreter.sub_routine.current_code_idx, 0);
382 assert_eq!(interpreter.sub_routine.return_stack, Vec::new());
383 assert_eq!(interpreter.bytecode.pc() - base_pc, 3);
385
386 interpreter.step_dummy(&table);
388 assert!(interpreter.bytecode.is_end());
389 }
390
391 #[test]
392 fn callf_stop() {
393 let table = instruction_table();
394
395 let bytes1 = Bytes::from([CALLF, 0x00, 0x01]);
396 let bytes2 = Bytes::from([STOP]);
397 let mut interpreter = eof_setup(bytes1, bytes2.clone());
398 interpreter.runtime_flag.is_eof = true;
399 let base_pc = interpreter.bytecode.pc();
400
401 interpreter.step_dummy(&table);
403
404 assert_eq!(interpreter.sub_routine.current_code_idx, 1);
405 assert_eq!(
406 interpreter.sub_routine.return_stack[0],
407 SubRoutineReturnFrame::new(0, 3 + base_pc)
408 );
409 assert_eq!(interpreter.bytecode.pc(), 3 + base_pc);
411
412 interpreter.step_dummy(&table);
414 assert!(interpreter.bytecode.is_end());
415 }
416
417 #[test]
418 fn callf_stack_overflow() {
419 let table = instruction_table();
420
421 let bytes1 = Bytes::from([CALLF, 0x00, 0x01]);
422 let bytes2 = Bytes::from([STOP]);
423 let mut interpreter =
424 eof_setup_with_types(bytes1, bytes2.clone(), CodeInfo::new(0, 0, 1023));
425 interpreter.runtime_flag.is_eof = true;
426
427 let _ = interpreter.stack.push(U256::from(0));
430 let _ = interpreter.stack.push(U256::from(0));
431
432 interpreter.step_dummy(&table);
434
435 assert_eq!(
437 interpreter.take_next_action(),
438 InterpreterAction::new_halt(InstructionResult::StackOverflow, interpreter.gas)
439 );
440 }
441
442 #[test]
443 fn jumpf_stop() {
444 let table = instruction_table();
445
446 let bytes1 = Bytes::from([JUMPF, 0x00, 0x01]);
447 let bytes2 = Bytes::from([STOP]);
448 let mut interpreter = eof_setup(bytes1, bytes2.clone());
449 interpreter.runtime_flag.is_eof = true;
450 let base_pc = interpreter.bytecode.pc();
451
452 interpreter.step_dummy(&table);
454
455 assert_eq!(interpreter.sub_routine.current_code_idx, 1);
457 assert!(interpreter.sub_routine.return_stack.is_empty());
458 assert_eq!(interpreter.bytecode.pc(), 3 + base_pc);
460
461 interpreter.step_dummy(&table);
463 assert!(interpreter.bytecode.is_end());
464 }
465
466 #[test]
467 fn jumpf_stack_overflow() {
468 let table = instruction_table();
469
470 let bytes1 = Bytes::from([JUMPF, 0x00, 0x01, STOP]);
471 let bytes2 = Bytes::from([STOP]);
472 let mut interpreter =
473 eof_setup_with_types(bytes1, bytes2.clone(), CodeInfo::new(0, 0, 1023));
474 interpreter.runtime_flag.is_eof = true;
475
476 let _ = interpreter.stack.push(U256::from(0));
479 let _ = interpreter.stack.push(U256::from(0));
480
481 interpreter.step_dummy(&table);
483
484 let gas = interpreter.gas;
485 assert_eq!(
487 interpreter.take_next_action(),
488 InterpreterAction::new_halt(InstructionResult::StackOverflow, gas)
489 );
490 }
491}