revm_interpreter/instructions/
system.rs

1use crate::{
2    gas,
3    interpreter::Interpreter,
4    interpreter_types::{
5        InputsTr, InterpreterTypes, LegacyBytecode, LoopControl, MemoryTr, ReturnData, RuntimeFlag,
6        StackTr,
7    },
8    Host, InstructionResult,
9};
10use core::ptr;
11use primitives::{B256, KECCAK_EMPTY, U256};
12
13pub fn keccak256<WIRE: InterpreterTypes, H: Host + ?Sized>(
14    interpreter: &mut Interpreter<WIRE>,
15    _host: &mut H,
16) {
17    popn_top!([offset], top, interpreter);
18    let len = as_usize_or_fail!(interpreter, top);
19    gas_or_fail!(interpreter, gas::keccak256_cost(len));
20    let hash = if len == 0 {
21        KECCAK_EMPTY
22    } else {
23        let from = as_usize_or_fail!(interpreter, offset);
24        resize_memory!(interpreter, from, len);
25        primitives::keccak256(interpreter.memory.slice_len(from, len).as_ref())
26    };
27    *top = hash.into();
28}
29
30pub fn address<WIRE: InterpreterTypes, H: Host + ?Sized>(
31    interpreter: &mut Interpreter<WIRE>,
32    _host: &mut H,
33) {
34    gas!(interpreter, gas::BASE);
35    push!(
36        interpreter,
37        interpreter.input.target_address().into_word().into()
38    );
39}
40
41pub fn caller<WIRE: InterpreterTypes, H: Host + ?Sized>(
42    interpreter: &mut Interpreter<WIRE>,
43    _host: &mut H,
44) {
45    gas!(interpreter, gas::BASE);
46    push!(
47        interpreter,
48        interpreter.input.caller_address().into_word().into()
49    );
50}
51
52pub fn codesize<WIRE: InterpreterTypes, H: Host + ?Sized>(
53    interpreter: &mut Interpreter<WIRE>,
54    _host: &mut H,
55) {
56    gas!(interpreter, gas::BASE);
57    push!(interpreter, U256::from(interpreter.bytecode.bytecode_len()));
58}
59
60pub fn codecopy<WIRE: InterpreterTypes, H: Host + ?Sized>(
61    interpreter: &mut Interpreter<WIRE>,
62    _host: &mut H,
63) {
64    popn!([memory_offset, code_offset, len], interpreter);
65    let len = as_usize_or_fail!(interpreter, len);
66    let Some(memory_offset) = memory_resize(interpreter, memory_offset, len) else {
67        return;
68    };
69    let code_offset = as_usize_saturated!(code_offset);
70
71    // Note: This can't panic because we resized memory to fit.
72    interpreter.memory.set_data(
73        memory_offset,
74        code_offset,
75        len,
76        interpreter.bytecode.bytecode_slice(),
77    );
78}
79
80pub fn calldataload<WIRE: InterpreterTypes, H: Host + ?Sized>(
81    interpreter: &mut Interpreter<WIRE>,
82    _host: &mut H,
83) {
84    gas!(interpreter, gas::VERYLOW);
85    //pop_top!(interpreter, offset_ptr);
86    popn_top!([], offset_ptr, interpreter);
87    let mut word = B256::ZERO;
88    let offset = as_usize_saturated!(offset_ptr);
89    let input = interpreter.input.input();
90    let input_len = input.len();
91    if offset < input_len {
92        let count = 32.min(input_len - offset);
93        // SAFETY: `count` is bounded by the calldata length.
94        // This is `word[..count].copy_from_slice(input[offset..offset + count])`, written using
95        // raw pointers as apparently the compiler cannot optimize the slice version, and using
96        // `get_unchecked` twice is uglier.
97        debug_assert!(count <= 32 && offset + count <= input_len);
98        unsafe { ptr::copy_nonoverlapping(input.as_ptr().add(offset), word.as_mut_ptr(), count) };
99    }
100    *offset_ptr = word.into();
101}
102
103pub fn calldatasize<WIRE: InterpreterTypes, H: Host + ?Sized>(
104    interpreter: &mut Interpreter<WIRE>,
105    _host: &mut H,
106) {
107    gas!(interpreter, gas::BASE);
108    push!(interpreter, U256::from(interpreter.input.input().len()));
109}
110
111pub fn callvalue<WIRE: InterpreterTypes, H: Host + ?Sized>(
112    interpreter: &mut Interpreter<WIRE>,
113    _host: &mut H,
114) {
115    gas!(interpreter, gas::BASE);
116    push!(interpreter, interpreter.input.call_value());
117}
118
119pub fn calldatacopy<WIRE: InterpreterTypes, H: Host + ?Sized>(
120    interpreter: &mut Interpreter<WIRE>,
121    _host: &mut H,
122) {
123    popn!([memory_offset, data_offset, len], interpreter);
124    let len = as_usize_or_fail!(interpreter, len);
125    let Some(memory_offset) = memory_resize(interpreter, memory_offset, len) else {
126        return;
127    };
128
129    let data_offset = as_usize_saturated!(data_offset);
130    // Note: This can't panic because we resized memory to fit.
131    interpreter
132        .memory
133        .set_data(memory_offset, data_offset, len, interpreter.input.input());
134}
135
136/// EIP-211: New opcodes: RETURNDATASIZE and RETURNDATACOPY
137pub fn returndatasize<WIRE: InterpreterTypes, H: Host + ?Sized>(
138    interpreter: &mut Interpreter<WIRE>,
139    _host: &mut H,
140) {
141    check!(interpreter, BYZANTIUM);
142    gas!(interpreter, gas::BASE);
143    push!(
144        interpreter,
145        U256::from(interpreter.return_data.buffer().len())
146    );
147}
148
149/// EIP-211: New opcodes: RETURNDATASIZE and RETURNDATACOPY
150pub fn returndatacopy<WIRE: InterpreterTypes, H: Host + ?Sized>(
151    interpreter: &mut Interpreter<WIRE>,
152    _host: &mut H,
153) {
154    check!(interpreter, BYZANTIUM);
155    popn!([memory_offset, offset, len], interpreter);
156
157    let len = as_usize_or_fail!(interpreter, len);
158    let data_offset = as_usize_saturated!(offset);
159
160    // Old legacy behavior is to panic if data_end is out of scope of return buffer.
161    // This behavior is changed in EOF.
162    let data_end = data_offset.saturating_add(len);
163    if data_end > interpreter.return_data.buffer().len() && !interpreter.runtime_flag.is_eof() {
164        interpreter
165            .control
166            .set_instruction_result(InstructionResult::OutOfOffset);
167        return;
168    }
169
170    let Some(memory_offset) = memory_resize(interpreter, memory_offset, len) else {
171        return;
172    };
173
174    // Note: This can't panic because we resized memory to fit.
175    interpreter.memory.set_data(
176        memory_offset,
177        data_offset,
178        len,
179        interpreter.return_data.buffer(),
180    );
181}
182
183/// Part of EOF `<https://eips.ethereum.org/EIPS/eip-7069>`.
184pub fn returndataload<WIRE: InterpreterTypes, H: Host + ?Sized>(
185    interpreter: &mut Interpreter<WIRE>,
186    _host: &mut H,
187) {
188    require_eof!(interpreter);
189    gas!(interpreter, gas::VERYLOW);
190    popn_top!([], offset, interpreter);
191    let offset_usize = as_usize_saturated!(offset);
192
193    let mut output = [0u8; 32];
194    if let Some(available) = interpreter
195        .return_data
196        .buffer()
197        .len()
198        .checked_sub(offset_usize)
199    {
200        let copy_len = available.min(32);
201        output[..copy_len].copy_from_slice(
202            &interpreter.return_data.buffer()[offset_usize..offset_usize + copy_len],
203        );
204    }
205
206    *offset = B256::from(output).into();
207}
208
209pub fn gas<WIRE: InterpreterTypes, H: Host + ?Sized>(
210    interpreter: &mut Interpreter<WIRE>,
211    _host: &mut H,
212) {
213    gas!(interpreter, gas::BASE);
214    push!(
215        interpreter,
216        U256::from(interpreter.control.gas().remaining())
217    );
218}
219
220// common logic for copying data from a source buffer to the EVM's memory
221pub fn memory_resize(
222    interpreter: &mut Interpreter<impl InterpreterTypes>,
223    memory_offset: U256,
224    len: usize,
225) -> Option<usize> {
226    // Safe to cast usize to u64
227    gas_or_fail!(interpreter, gas::copy_cost_verylow(len), None);
228    if len == 0 {
229        return None;
230    }
231    let memory_offset = as_usize_or_fail_ret!(interpreter, memory_offset, None);
232    resize_memory!(interpreter, memory_offset, len, None);
233
234    Some(memory_offset)
235}
236
237#[cfg(test)]
238mod test {
239    use super::*;
240    use crate::{host::DummyHost, instruction_table, InstructionResult};
241    use bytecode::{opcode::RETURNDATACOPY, opcode::RETURNDATALOAD, Bytecode};
242    use primitives::{bytes, Bytes};
243
244    #[test]
245    fn returndataload() {
246        let bytecode = Bytecode::new_raw(Bytes::from(&[
247            RETURNDATALOAD,
248            RETURNDATALOAD,
249            RETURNDATALOAD,
250            RETURNDATALOAD,
251        ]));
252        let mut interpreter = Interpreter::default().with_bytecode(bytecode);
253
254        let table = instruction_table();
255        let mut host = DummyHost;
256        interpreter.runtime_flag.is_eof = true;
257
258        let _ = interpreter.stack.push(U256::from(0));
259        interpreter.return_data.set_buffer(bytes!(
260            "000000000000000400000000000000030000000000000002000000000000000100"
261        ));
262        interpreter.step(&table, &mut host);
263        assert_eq!(
264            interpreter.stack.data(),
265            &vec![U256::from_limbs([0x01, 0x02, 0x03, 0x04])]
266        );
267
268        let _ = interpreter.stack.pop();
269        let _ = interpreter.stack.push(U256::from(1));
270
271        interpreter.step(&table, &mut host);
272        assert_eq!(
273            interpreter.control.instruction_result,
274            InstructionResult::Continue
275        );
276        assert_eq!(
277            interpreter.stack.data(),
278            &vec![U256::from_limbs([0x0100, 0x0200, 0x0300, 0x0400])]
279        );
280
281        let _ = interpreter.stack.pop();
282        let _ = interpreter.stack.push(U256::from(32));
283        interpreter.step(&table, &mut host);
284        assert_eq!(
285            interpreter.control.instruction_result,
286            InstructionResult::Continue
287        );
288        assert_eq!(
289            interpreter.stack.data(),
290            &vec![U256::from_limbs([0x00, 0x00, 0x00, 0x00])]
291        );
292
293        // Offset right at the boundary of the return data buffer size
294        let _ = interpreter.stack.pop();
295        let _ = interpreter
296            .stack
297            .push(U256::from(interpreter.return_data.buffer().len()));
298        interpreter.step(&table, &mut host);
299        assert_eq!(
300            interpreter.control.instruction_result,
301            InstructionResult::Continue
302        );
303        assert_eq!(
304            interpreter.stack.data(),
305            &vec![U256::from_limbs([0x00, 0x00, 0x00, 0x00])]
306        );
307    }
308
309    #[test]
310    fn returndatacopy() {
311        let bytecode = Bytecode::new_raw(Bytes::from(&[
312            RETURNDATACOPY,
313            RETURNDATACOPY,
314            RETURNDATACOPY,
315            RETURNDATACOPY,
316            RETURNDATACOPY,
317            RETURNDATACOPY,
318        ]));
319        let mut interpreter = Interpreter::default().with_bytecode(bytecode);
320
321        let table = instruction_table();
322        let mut host = DummyHost;
323        interpreter.runtime_flag.is_eof = true;
324
325        interpreter.return_data.set_buffer(bytes!(
326            "000000000000000400000000000000030000000000000002000000000000000100"
327        ));
328        interpreter.memory.resize(256);
329
330        // Copying within bounds
331        let _ = interpreter.stack.push(U256::from(32));
332        let _ = interpreter.stack.push(U256::from(0));
333        let _ = interpreter.stack.push(U256::from(0));
334        interpreter.step(&table, &mut host);
335        assert_eq!(
336            interpreter.control.instruction_result,
337            InstructionResult::Continue
338        );
339        assert_eq!(
340            *interpreter.memory.slice(0..32),
341            interpreter.return_data.buffer()[0..32]
342        );
343
344        // Copying with partial out-of-bounds (should zero pad)
345        let _ = interpreter.stack.push(U256::from(64));
346        let _ = interpreter.stack.push(U256::from(16));
347        let _ = interpreter.stack.push(U256::from(64));
348        interpreter.step(&table, &mut host);
349        assert_eq!(
350            interpreter.control.instruction_result,
351            InstructionResult::Continue
352        );
353        assert_eq!(
354            *interpreter.memory.slice(64..80),
355            interpreter.return_data.buffer()[16..32]
356        );
357        assert_eq!(*interpreter.memory.slice(80..128), [0u8; 48]);
358
359        // Completely out-of-bounds (should be all zeros)
360        let _ = interpreter.stack.push(U256::from(32));
361        let _ = interpreter.stack.push(U256::from(96));
362        let _ = interpreter.stack.push(U256::from(128));
363        interpreter.step(&table, &mut host);
364        assert_eq!(
365            interpreter.control.instruction_result,
366            InstructionResult::Continue
367        );
368        assert_eq!(*interpreter.memory.slice(128..160), [0u8; 32]);
369
370        // Large offset
371        let _ = interpreter.stack.push(U256::from(32));
372        let _ = interpreter.stack.push(U256::MAX);
373        let _ = interpreter.stack.push(U256::from(0));
374        interpreter.step(&table, &mut host);
375        assert_eq!(
376            interpreter.control.instruction_result,
377            InstructionResult::Continue
378        );
379        assert_eq!(*interpreter.memory.slice(0..32), [0u8; 32]);
380
381        // Offset just before the boundary of the return data buffer size
382        let _ = interpreter.stack.push(U256::from(32));
383        let _ = interpreter
384            .stack
385            .push(U256::from(interpreter.return_data.buffer().len() - 32));
386        let _ = interpreter.stack.push(U256::from(0));
387        interpreter.step(&table, &mut host);
388        assert_eq!(
389            interpreter.control.instruction_result,
390            InstructionResult::Continue
391        );
392        assert_eq!(
393            *interpreter.memory.slice(0..32),
394            interpreter.return_data.buffer()[interpreter.return_data.buffer().len() - 32..]
395        );
396
397        // Offset right at the boundary of the return data buffer size
398        let _ = interpreter.stack.push(U256::from(32));
399        let _ = interpreter
400            .stack
401            .push(U256::from(interpreter.return_data.buffer().len()));
402        let _ = interpreter.stack.push(U256::from(0));
403        interpreter.step(&table, &mut host);
404        assert_eq!(
405            interpreter.control.instruction_result,
406            InstructionResult::Continue
407        );
408        assert_eq!(*interpreter.memory.slice(0..32), [0u8; 32]);
409    }
410}