revm_interpreter/instructions/control.rs
1use crate::{
2 gas,
3 interpreter::Interpreter,
4 interpreter_types::{
5 EofCodeInfo, Immediates, InterpreterTypes, Jumps, LoopControl, MemoryTr, RuntimeFlag,
6 StackTr, SubRoutineStack,
7 },
8 Host, InstructionResult, InterpreterAction, InterpreterResult,
9};
10use primitives::{Bytes, U256};
11
12pub fn rjump<WIRE: InterpreterTypes, H: ?Sized>(
13 interpreter: &mut Interpreter<WIRE>,
14 _host: &mut H,
15) {
16 require_eof!(interpreter);
17 gas!(interpreter, gas::BASE);
18 let offset = interpreter.bytecode.read_i16() as isize;
19 // In spec it is +3 but pointer is already incremented in
20 // `Interpreter::step` so for revm is +2.
21 interpreter.bytecode.relative_jump(offset + 2);
22}
23
24pub fn rjumpi<WIRE: InterpreterTypes, H: Host + ?Sized>(
25 interpreter: &mut Interpreter<WIRE>,
26 _host: &mut H,
27) {
28 require_eof!(interpreter);
29 gas!(interpreter, gas::CONDITION_JUMP_GAS);
30 popn!([condition], interpreter);
31 // In spec it is +3 but pointer is already incremented in
32 // `Interpreter::step` so for revm is +2.
33 let mut offset = 2;
34 if !condition.is_zero() {
35 offset += interpreter.bytecode.read_i16() as isize;
36 }
37
38 interpreter.bytecode.relative_jump(offset);
39}
40
41pub fn rjumpv<WIRE: InterpreterTypes, H: Host + ?Sized>(
42 interpreter: &mut Interpreter<WIRE>,
43 _host: &mut H,
44) {
45 require_eof!(interpreter);
46 gas!(interpreter, gas::CONDITION_JUMP_GAS);
47 popn!([case], interpreter);
48 let case = as_isize_saturated!(case);
49
50 let max_index = interpreter.bytecode.read_u8() as isize;
51 // For number of items we are adding 1 to max_index, multiply by 2 as each offset is 2 bytes
52 // and add 1 for max_index itself. Note that revm already incremented the instruction pointer
53 let mut offset = (max_index + 1) * 2 + 1;
54
55 if case <= max_index {
56 offset += interpreter.bytecode.read_offset_i16(1 + case * 2) as isize;
57 }
58 interpreter.bytecode.relative_jump(offset);
59}
60
61pub fn jump<WIRE: InterpreterTypes, H: Host + ?Sized>(
62 interpreter: &mut Interpreter<WIRE>,
63 _host: &mut H,
64) {
65 gas!(interpreter, gas::MID);
66 popn!([target], interpreter);
67 jump_inner(interpreter, target);
68}
69
70pub fn jumpi<WIRE: InterpreterTypes, H: Host + ?Sized>(
71 interpreter: &mut Interpreter<WIRE>,
72 _host: &mut H,
73) {
74 gas!(interpreter, gas::HIGH);
75 popn!([target, cond], interpreter);
76
77 if !cond.is_zero() {
78 jump_inner(interpreter, target);
79 }
80}
81
82#[inline]
83fn jump_inner<WIRE: InterpreterTypes>(interpreter: &mut Interpreter<WIRE>, target: U256) {
84 let target = as_usize_or_fail!(interpreter, target, InstructionResult::InvalidJump);
85 if !interpreter.bytecode.is_valid_legacy_jump(target) {
86 interpreter
87 .control
88 .set_instruction_result(InstructionResult::InvalidJump);
89 return;
90 }
91 // SAFETY: `is_valid_jump` ensures that `dest` is in bounds.
92 interpreter.bytecode.absolute_jump(target);
93}
94
95pub fn jumpdest_or_nop<WIRE: InterpreterTypes, H: Host + ?Sized>(
96 interpreter: &mut Interpreter<WIRE>,
97 _host: &mut H,
98) {
99 gas!(interpreter, gas::JUMPDEST);
100}
101
102pub fn callf<WIRE: InterpreterTypes, H: Host + ?Sized>(
103 interpreter: &mut Interpreter<WIRE>,
104 _host: &mut H,
105) {
106 require_eof!(interpreter);
107 gas!(interpreter, gas::LOW);
108
109 let idx = interpreter.bytecode.read_u16() as usize;
110
111 // Get target types
112 let Some(types) = interpreter.bytecode.code_section_info(idx) else {
113 panic!("Invalid EOF in execution, expecting correct intermediate in callf")
114 };
115
116 // Check max stack height for target code section.
117 // Safe to subtract as max_stack_height is always more than inputs.
118 if interpreter.stack.len() + (types.max_stack_size - types.inputs as u16) as usize > 1024 {
119 interpreter
120 .control
121 .set_instruction_result(InstructionResult::StackOverflow);
122 return;
123 }
124
125 // Push current idx and PC to the callf stack.
126 // PC is incremented by 2 to point to the next instruction after callf.
127 if !(interpreter
128 .sub_routine
129 .push(interpreter.bytecode.pc() + 2, idx))
130 {
131 interpreter
132 .control
133 .set_instruction_result(InstructionResult::SubRoutineStackOverflow);
134 return;
135 };
136 let pc = interpreter
137 .bytecode
138 .code_section_pc(idx)
139 .expect("Invalid code section index");
140 interpreter.bytecode.absolute_jump(pc);
141}
142
143pub fn retf<WIRE: InterpreterTypes, H: Host + ?Sized>(
144 interpreter: &mut Interpreter<WIRE>,
145 _host: &mut H,
146) {
147 require_eof!(interpreter);
148 gas!(interpreter, gas::RETF_GAS);
149
150 let Some(jump) = interpreter.sub_routine.pop() else {
151 panic!("Expected function frame")
152 };
153
154 interpreter.bytecode.absolute_jump(jump);
155}
156
157pub fn jumpf<WIRE: InterpreterTypes, H: Host + ?Sized>(
158 interpreter: &mut Interpreter<WIRE>,
159 _host: &mut H,
160) {
161 require_eof!(interpreter);
162 gas!(interpreter, gas::LOW);
163
164 let idx = interpreter.bytecode.read_u16() as usize;
165
166 // Get target types
167 let types = interpreter
168 .bytecode
169 .code_section_info(idx)
170 .expect("Invalid code section index");
171
172 // Check max stack height for target code section.
173 // Safe to subtract as max_stack_height is always more than inputs.
174 if interpreter.stack.len() + (types.max_stack_size - types.inputs as u16) as usize > 1024 {
175 interpreter
176 .control
177 .set_instruction_result(InstructionResult::StackOverflow);
178 return;
179 }
180 interpreter.sub_routine.set_routine_idx(idx);
181 let pc = interpreter
182 .bytecode
183 .code_section_pc(idx)
184 .expect("Invalid code section index");
185 interpreter.bytecode.absolute_jump(pc);
186}
187
188pub fn pc<WIRE: InterpreterTypes, H: Host + ?Sized>(
189 interpreter: &mut Interpreter<WIRE>,
190 _host: &mut H,
191) {
192 gas!(interpreter, gas::BASE);
193 // - 1 because we have already advanced the instruction pointer in `Interpreter::step`
194 push!(interpreter, U256::from(interpreter.bytecode.pc() - 1));
195}
196
197#[inline]
198fn return_inner(
199 interpreter: &mut Interpreter<impl InterpreterTypes>,
200 instruction_result: InstructionResult,
201) {
202 // Zero gas cost
203 // gas!(interpreter, gas::ZERO)
204 popn!([offset, len], interpreter);
205 let len = as_usize_or_fail!(interpreter, len);
206 // Important: Offset must be ignored if len is zeros
207 let mut output = Bytes::default();
208 if len != 0 {
209 let offset = as_usize_or_fail!(interpreter, offset);
210 resize_memory!(interpreter, offset, len);
211 output = interpreter.memory.slice_len(offset, len).to_vec().into()
212 }
213
214 let gas = *interpreter.control.gas();
215 interpreter.control.set_next_action(
216 InterpreterAction::Return {
217 result: InterpreterResult {
218 output,
219 gas,
220 result: instruction_result,
221 },
222 },
223 instruction_result,
224 );
225}
226
227pub fn ret<WIRE: InterpreterTypes, H: Host + ?Sized>(
228 interpreter: &mut Interpreter<WIRE>,
229 _host: &mut H,
230) {
231 return_inner(interpreter, InstructionResult::Return);
232}
233
234/// EIP-140: REVERT instruction
235pub fn revert<WIRE: InterpreterTypes, H: Host + ?Sized>(
236 interpreter: &mut Interpreter<WIRE>,
237 _host: &mut H,
238) {
239 check!(interpreter, BYZANTIUM);
240 return_inner(interpreter, InstructionResult::Revert);
241}
242
243/// Stop opcode. This opcode halts the execution.
244pub fn stop<WIRE: InterpreterTypes, H: Host + ?Sized>(
245 interpreter: &mut Interpreter<WIRE>,
246 _host: &mut H,
247) {
248 interpreter
249 .control
250 .set_instruction_result(InstructionResult::Stop);
251}
252
253/// Invalid opcode. This opcode halts the execution.
254pub fn invalid<WIRE: InterpreterTypes, H: Host + ?Sized>(
255 interpreter: &mut Interpreter<WIRE>,
256 _host: &mut H,
257) {
258 interpreter
259 .control
260 .set_instruction_result(InstructionResult::InvalidFEOpcode);
261}
262
263/// Unknown opcode. This opcode halts the execution.
264pub fn unknown<WIRE: InterpreterTypes, H: Host + ?Sized>(
265 interpreter: &mut Interpreter<WIRE>,
266 _host: &mut H,
267) {
268 interpreter
269 .control
270 .set_instruction_result(InstructionResult::OpcodeNotFound);
271}
272
273// TODO : Test
274/*
275#[cfg(test)]
276mod test {
277 use super::*;
278 use crate::{table::make_instruction_table, DummyHost, Gas};
279 use bytecode::opcode::{CALLF, JUMPF, NOP, RETF, RJUMP, RJUMPI, RJUMPV, STOP};
280 use bytecode::{
281 eof::{Eof, TypesSection},
282 Bytecode,
283 };
284 use primitives::bytes;
285 use specification::hardfork::SpecId;
286 use std::sync::Arc;
287 use context_interface::DefaultEthereumWiring;
288
289 #[test]
290 fn rjump() {
291 let table = make_instruction_table::<Interpreter, DummyHost<DefaultEthereumWiring>>();
292 let mut host = DummyHost::default();
293 let mut interp =
294 Interpreter::new_bytecode(Bytecode::LegacyRaw([RJUMP, 0x00, 0x02, STOP, STOP].into()));
295 interp.is_eof = true;
296 interp.gas = Gas::new(10000);
297 interp.spec_id = SpecId::PRAGUE;
298
299 interp.step(&table, &mut host);
300 assert_eq!(interp.program_counter(), 5);
301 }
302
303 #[test]
304 fn rjumpi() {
305 let table = make_instruction_table::<Interpreter, DummyHost<DefaultEthereumWiring>>();
306 let mut host = DummyHost::default();
307 let mut interp = Interpreter::new_bytecode(Bytecode::LegacyRaw(
308 [RJUMPI, 0x00, 0x03, RJUMPI, 0x00, 0x01, STOP, STOP].into(),
309 ));
310 interp.is_eof = true;
311 interp.stack.push(U256::from(1)).unwrap();
312 interp.stack.push(U256::from(0)).unwrap();
313 interp.gas = Gas::new(10000);
314 interp.spec_id = SpecId::PRAGUE;
315
316 // Dont jump
317 interp.step(&table, &mut host);
318 assert_eq!(interp.program_counter(), 3);
319 // Jumps to last opcode
320 interp.step(&table, &mut host);
321 assert_eq!(interp.program_counter(), 7);
322 }
323
324 #[test]
325 fn rjumpv() {
326 let table = make_instruction_table::<Interpreter, DummyHost<DefaultEthereumWiring>>();
327 let mut host = DummyHost::default();
328 let mut interp = Interpreter::new_bytecode(Bytecode::LegacyRaw(
329 [
330 RJUMPV,
331 0x01, // max index, 0 and 1
332 0x00, // first x0001
333 0x01,
334 0x00, // second 0x002
335 0x02,
336 NOP,
337 NOP,
338 NOP,
339 RJUMP,
340 0xFF,
341 (-12i8) as u8,
342 STOP,
343 ]
344 .into(),
345 ));
346 interp.is_eof = true;
347 interp.gas = Gas::new(1000);
348 interp.spec_id = SpecId::PRAGUE;
349
350 // More then max_index
351 interp.stack.push(U256::from(10)).unwrap();
352 interp.step(&table, &mut host);
353 assert_eq!(interp.program_counter(), 6);
354
355 // Cleanup
356 interp.step(&table, &mut host);
357 interp.step(&table, &mut host);
358 interp.step(&table, &mut host);
359 interp.step(&table, &mut host);
360 assert_eq!(interp.program_counter(), 0);
361
362 // Jump to first index of vtable
363 interp.stack.push(U256::from(0)).unwrap();
364 interp.step(&table, &mut host);
365 assert_eq!(interp.program_counter(), 7);
366
367 // Cleanup
368 interp.step(&table, &mut host);
369 interp.step(&table, &mut host);
370 interp.step(&table, &mut host);
371 assert_eq!(interp.program_counter(), 0);
372
373 // Jump to second index of vtable
374 interp.stack.push(U256::from(1)).unwrap();
375 interp.step(&table, &mut host);
376 assert_eq!(interp.program_counter(), 8);
377 }
378
379 fn dummy_eof() -> Eof {
380 let bytes = bytes!("ef000101000402000100010400000000800000fe");
381 Eof::decode(bytes).unwrap()
382 }
383
384 fn eof_setup(bytes1: Bytes, bytes2: Bytes) -> Interpreter {
385 eof_setup_with_types(bytes1, bytes2, TypesSection::default())
386 }
387
388 /// Two code section and types section is for last code.
389 fn eof_setup_with_types(bytes1: Bytes, bytes2: Bytes, types: TypesSection) -> Interpreter {
390 let mut eof = dummy_eof();
391
392 eof.body.code_section.clear();
393 eof.body.types_section.clear();
394 eof.header.code_sizes.clear();
395
396 eof.header.code_sizes.push(bytes1.len() as u16);
397 eof.body.code_section.push(bytes1.len());
398 eof.body.types_section.push(TypesSection::new(0, 0, 11));
399
400 eof.header.code_sizes.push(bytes2.len() as u16);
401 eof.body.code_section.push(bytes2.len() + bytes1.len());
402 eof.body.types_section.push(types);
403
404 eof.body.code = Bytes::from([bytes1, bytes2].concat());
405
406 let mut interp = Interpreter::new_bytecode(Bytecode::Eof(Arc::new(eof)));
407 interp.gas = Gas::new(10000);
408 interp.spec_id = SpecId::PRAGUE;
409 interp
410 }
411
412 #[test]
413 fn callf_retf_stop() {
414 let table = make_instruction_table::<Interpreter, _>();
415 let mut host = DummyHost::<DefaultEthereumWiring>::default();
416
417 let bytes1 = Bytes::from([CALLF, 0x00, 0x01, STOP]);
418 let bytes2 = Bytes::from([RETF]);
419 let mut interp = eof_setup(bytes1, bytes2.clone());
420
421 // CALLF
422 interp.step(&table, &mut host);
423
424 assert_eq!(interp.function_stack.current_code_idx, 1);
425 assert_eq!(
426 interp.function_stack.return_stack[0],
427 SubRoutineReturnFrame::new(0, 3)
428 );
429 assert_eq!(interp.instruction_pointer, bytes2.as_ptr());
430
431 // RETF
432 interp.step(&table, &mut host);
433
434 assert_eq!(interp.function_stack.current_code_idx, 0);
435 assert_eq!(interp.function_stack.return_stack, Vec::new());
436 assert_eq!(interp.program_counter(), 3);
437
438 // STOP
439 interp.step(&table, &mut host);
440 assert_eq!(interp.instruction_result, InstructionResult::Stop);
441 }
442
443 #[test]
444 fn callf_stop() {
445 let table = make_instruction_table::<Interpreter, _>();
446 let mut host = DummyHost::<DefaultEthereumWiring>::default();
447
448 let bytes1 = Bytes::from([CALLF, 0x00, 0x01]);
449 let bytes2 = Bytes::from([STOP]);
450 let mut interp = eof_setup(bytes1, bytes2.clone());
451
452 // CALLF
453 interp.step(&table, &mut host);
454
455 assert_eq!(interp.function_stack.current_code_idx, 1);
456 assert_eq!(
457 interp.function_stack.return_stack[0],
458 SubRoutineReturnFrame::new(0, 3)
459 );
460 assert_eq!(interp.instruction_pointer, bytes2.as_ptr());
461
462 // STOP
463 interp.step(&table, &mut host);
464 assert_eq!(interp.instruction_result, InstructionResult::Stop);
465 }
466
467 #[test]
468 fn callf_stack_overflow() {
469 let table = make_instruction_table::<Interpreter, _>();
470 let mut host = DummyHost::<DefaultEthereumWiring>::default();
471
472 let bytes1 = Bytes::from([CALLF, 0x00, 0x01]);
473 let bytes2 = Bytes::from([STOP]);
474 let mut interp =
475 eof_setup_with_types(bytes1, bytes2.clone(), TypesSection::new(0, 0, 1025));
476
477 // CALLF
478 interp.step(&table, &mut host);
479
480 // Stack overflow
481 assert_eq!(interp.instruction_result, InstructionResult::StackOverflow);
482 }
483
484 #[test]
485 fn jumpf_stop() {
486 let table = make_instruction_table::<Interpreter, _>();
487 let mut host = DummyHost::<DefaultEthereumWiring>::default();
488
489 let bytes1 = Bytes::from([JUMPF, 0x00, 0x01]);
490 let bytes2 = Bytes::from([STOP]);
491 let mut interp = eof_setup(bytes1, bytes2.clone());
492
493 // JUMPF
494 interp.step(&table, &mut host);
495
496 assert_eq!(interp.function_stack.current_code_idx, 1);
497 assert!(interp.function_stack.return_stack.is_empty());
498 assert_eq!(interp.instruction_pointer, bytes2.as_ptr());
499
500 // STOP
501 interp.step(&table, &mut host);
502 assert_eq!(interp.instruction_result, InstructionResult::Stop);
503 }
504
505 #[test]
506 fn jumpf_stack_overflow() {
507 let table = make_instruction_table::<Interpreter, _>();
508 let mut host = DummyHost::<DefaultEthereumWiring>::default();
509
510 let bytes1 = Bytes::from([JUMPF, 0x00, 0x01]);
511 let bytes2 = Bytes::from([STOP]);
512 let mut interp =
513 eof_setup_with_types(bytes1, bytes2.clone(), TypesSection::new(0, 0, 1025));
514
515 // JUMPF
516 interp.step(&table, &mut host);
517
518 // Stack overflow
519 assert_eq!(interp.instruction_result, InstructionResult::StackOverflow);
520 }
521}
522*/