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    CallInput, 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
94        // SAFETY: `count` is bounded by the calldata length.
95        // This is `word[..count].copy_from_slice(input[offset..offset + count])`, written using
96        // raw pointers as apparently the compiler cannot optimize the slice version, and using
97        // `get_unchecked` twice is uglier.
98        match interpreter.input.input() {
99            CallInput::Bytes(bytes) => {
100                unsafe {
101                    ptr::copy_nonoverlapping(bytes.as_ptr().add(offset), word.as_mut_ptr(), count)
102                };
103            }
104            CallInput::SharedBuffer(range) => {
105                let input_slice = interpreter.memory.global_slice(range.clone());
106                unsafe {
107                    ptr::copy_nonoverlapping(
108                        input_slice.as_ptr().add(offset),
109                        word.as_mut_ptr(),
110                        count,
111                    )
112                };
113            }
114        }
115    }
116    *offset_ptr = word.into();
117}
118
119pub fn calldatasize<WIRE: InterpreterTypes, H: Host + ?Sized>(
120    interpreter: &mut Interpreter<WIRE>,
121    _host: &mut H,
122) {
123    gas!(interpreter, gas::BASE);
124    push!(interpreter, U256::from(interpreter.input.input().len()));
125}
126
127pub fn callvalue<WIRE: InterpreterTypes, H: Host + ?Sized>(
128    interpreter: &mut Interpreter<WIRE>,
129    _host: &mut H,
130) {
131    gas!(interpreter, gas::BASE);
132    push!(interpreter, interpreter.input.call_value());
133}
134
135pub fn calldatacopy<WIRE: InterpreterTypes, H: Host + ?Sized>(
136    interpreter: &mut Interpreter<WIRE>,
137    _host: &mut H,
138) {
139    popn!([memory_offset, data_offset, len], interpreter);
140    let len = as_usize_or_fail!(interpreter, len);
141    let Some(memory_offset) = memory_resize(interpreter, memory_offset, len) else {
142        return;
143    };
144
145    let data_offset = as_usize_saturated!(data_offset);
146    match interpreter.input.input() {
147        CallInput::Bytes(bytes) => {
148            interpreter
149                .memory
150                .set_data(memory_offset, data_offset, len, bytes.as_ref());
151        }
152        CallInput::SharedBuffer(range) => {
153            interpreter
154                .memory
155                .set_data_from_global(memory_offset, data_offset, len, range.clone());
156        }
157    }
158}
159
160/// EIP-211: New opcodes: RETURNDATASIZE and RETURNDATACOPY
161pub fn returndatasize<WIRE: InterpreterTypes, H: Host + ?Sized>(
162    interpreter: &mut Interpreter<WIRE>,
163    _host: &mut H,
164) {
165    check!(interpreter, BYZANTIUM);
166    gas!(interpreter, gas::BASE);
167    push!(
168        interpreter,
169        U256::from(interpreter.return_data.buffer().len())
170    );
171}
172
173/// EIP-211: New opcodes: RETURNDATASIZE and RETURNDATACOPY
174pub fn returndatacopy<WIRE: InterpreterTypes, H: Host + ?Sized>(
175    interpreter: &mut Interpreter<WIRE>,
176    _host: &mut H,
177) {
178    check!(interpreter, BYZANTIUM);
179    popn!([memory_offset, offset, len], interpreter);
180
181    let len = as_usize_or_fail!(interpreter, len);
182    let data_offset = as_usize_saturated!(offset);
183
184    // Old legacy behavior is to panic if data_end is out of scope of return buffer.
185    // This behavior is changed in EOF.
186    let data_end = data_offset.saturating_add(len);
187    if data_end > interpreter.return_data.buffer().len() && !interpreter.runtime_flag.is_eof() {
188        interpreter
189            .control
190            .set_instruction_result(InstructionResult::OutOfOffset);
191        return;
192    }
193
194    let Some(memory_offset) = memory_resize(interpreter, memory_offset, len) else {
195        return;
196    };
197
198    // Note: This can't panic because we resized memory to fit.
199    interpreter.memory.set_data(
200        memory_offset,
201        data_offset,
202        len,
203        interpreter.return_data.buffer(),
204    );
205}
206
207/// Part of EOF `<https://eips.ethereum.org/EIPS/eip-7069>`.
208pub fn returndataload<WIRE: InterpreterTypes, H: Host + ?Sized>(
209    interpreter: &mut Interpreter<WIRE>,
210    _host: &mut H,
211) {
212    require_eof!(interpreter);
213    gas!(interpreter, gas::VERYLOW);
214    popn_top!([], offset, interpreter);
215    let offset_usize = as_usize_saturated!(offset);
216
217    let mut output = [0u8; 32];
218    if let Some(available) = interpreter
219        .return_data
220        .buffer()
221        .len()
222        .checked_sub(offset_usize)
223    {
224        let copy_len = available.min(32);
225        output[..copy_len].copy_from_slice(
226            &interpreter.return_data.buffer()[offset_usize..offset_usize + copy_len],
227        );
228    }
229
230    *offset = B256::from(output).into();
231}
232
233pub fn gas<WIRE: InterpreterTypes, H: Host + ?Sized>(
234    interpreter: &mut Interpreter<WIRE>,
235    _host: &mut H,
236) {
237    gas!(interpreter, gas::BASE);
238    push!(
239        interpreter,
240        U256::from(interpreter.control.gas().remaining())
241    );
242}
243
244// common logic for copying data from a source buffer to the EVM's memory
245pub fn memory_resize(
246    interpreter: &mut Interpreter<impl InterpreterTypes>,
247    memory_offset: U256,
248    len: usize,
249) -> Option<usize> {
250    // Safe to cast usize to u64
251    gas_or_fail!(interpreter, gas::copy_cost_verylow(len), None);
252    if len == 0 {
253        return None;
254    }
255    let memory_offset = as_usize_or_fail_ret!(interpreter, memory_offset, None);
256    resize_memory!(interpreter, memory_offset, len, None);
257
258    Some(memory_offset)
259}
260
261#[cfg(test)]
262mod test {
263    use super::*;
264    use crate::{host::DummyHost, instruction_table, InstructionResult};
265    use bytecode::{opcode::RETURNDATACOPY, opcode::RETURNDATALOAD, Bytecode};
266    use primitives::{bytes, Bytes};
267
268    #[test]
269    fn returndataload() {
270        let bytecode = Bytecode::new_raw(Bytes::from(&[
271            RETURNDATALOAD,
272            RETURNDATALOAD,
273            RETURNDATALOAD,
274            RETURNDATALOAD,
275        ]));
276        let mut interpreter = Interpreter::default().with_bytecode(bytecode);
277
278        let table = instruction_table();
279        let mut host = DummyHost;
280        interpreter.runtime_flag.is_eof = true;
281
282        let _ = interpreter.stack.push(U256::from(0));
283        interpreter.return_data.set_buffer(bytes!(
284            "000000000000000400000000000000030000000000000002000000000000000100"
285        ));
286        interpreter.step(&table, &mut host);
287        assert_eq!(
288            interpreter.stack.data(),
289            &vec![U256::from_limbs([0x01, 0x02, 0x03, 0x04])]
290        );
291
292        let _ = interpreter.stack.pop();
293        let _ = interpreter.stack.push(U256::from(1));
294
295        interpreter.step(&table, &mut host);
296        assert_eq!(
297            interpreter.control.instruction_result,
298            InstructionResult::Continue
299        );
300        assert_eq!(
301            interpreter.stack.data(),
302            &vec![U256::from_limbs([0x0100, 0x0200, 0x0300, 0x0400])]
303        );
304
305        let _ = interpreter.stack.pop();
306        let _ = interpreter.stack.push(U256::from(32));
307        interpreter.step(&table, &mut host);
308        assert_eq!(
309            interpreter.control.instruction_result,
310            InstructionResult::Continue
311        );
312        assert_eq!(
313            interpreter.stack.data(),
314            &vec![U256::from_limbs([0x00, 0x00, 0x00, 0x00])]
315        );
316
317        // Offset right at the boundary of the return data buffer size
318        let _ = interpreter.stack.pop();
319        let _ = interpreter
320            .stack
321            .push(U256::from(interpreter.return_data.buffer().len()));
322        interpreter.step(&table, &mut host);
323        assert_eq!(
324            interpreter.control.instruction_result,
325            InstructionResult::Continue
326        );
327        assert_eq!(
328            interpreter.stack.data(),
329            &vec![U256::from_limbs([0x00, 0x00, 0x00, 0x00])]
330        );
331    }
332
333    #[test]
334    fn returndatacopy() {
335        let bytecode = Bytecode::new_raw(Bytes::from(&[
336            RETURNDATACOPY,
337            RETURNDATACOPY,
338            RETURNDATACOPY,
339            RETURNDATACOPY,
340            RETURNDATACOPY,
341            RETURNDATACOPY,
342        ]));
343        let mut interpreter = Interpreter::default().with_bytecode(bytecode);
344
345        let table = instruction_table();
346        let mut host = DummyHost;
347        interpreter.runtime_flag.is_eof = true;
348
349        interpreter.return_data.set_buffer(bytes!(
350            "000000000000000400000000000000030000000000000002000000000000000100"
351        ));
352        interpreter.memory.resize(256);
353
354        // Copying within bounds
355        let _ = interpreter.stack.push(U256::from(32));
356        let _ = interpreter.stack.push(U256::from(0));
357        let _ = interpreter.stack.push(U256::from(0));
358        interpreter.step(&table, &mut host);
359        assert_eq!(
360            interpreter.control.instruction_result,
361            InstructionResult::Continue
362        );
363        assert_eq!(
364            *interpreter.memory.slice(0..32),
365            interpreter.return_data.buffer()[0..32]
366        );
367
368        // Copying with partial out-of-bounds (should zero pad)
369        let _ = interpreter.stack.push(U256::from(64));
370        let _ = interpreter.stack.push(U256::from(16));
371        let _ = interpreter.stack.push(U256::from(64));
372        interpreter.step(&table, &mut host);
373        assert_eq!(
374            interpreter.control.instruction_result,
375            InstructionResult::Continue
376        );
377        assert_eq!(
378            *interpreter.memory.slice(64..80),
379            interpreter.return_data.buffer()[16..32]
380        );
381        assert_eq!(*interpreter.memory.slice(80..128), [0u8; 48]);
382
383        // Completely out-of-bounds (should be all zeros)
384        let _ = interpreter.stack.push(U256::from(32));
385        let _ = interpreter.stack.push(U256::from(96));
386        let _ = interpreter.stack.push(U256::from(128));
387        interpreter.step(&table, &mut host);
388        assert_eq!(
389            interpreter.control.instruction_result,
390            InstructionResult::Continue
391        );
392        assert_eq!(*interpreter.memory.slice(128..160), [0u8; 32]);
393
394        // Large offset
395        let _ = interpreter.stack.push(U256::from(32));
396        let _ = interpreter.stack.push(U256::MAX);
397        let _ = interpreter.stack.push(U256::from(0));
398        interpreter.step(&table, &mut host);
399        assert_eq!(
400            interpreter.control.instruction_result,
401            InstructionResult::Continue
402        );
403        assert_eq!(*interpreter.memory.slice(0..32), [0u8; 32]);
404
405        // Offset just before the boundary of the return data buffer size
406        let _ = interpreter.stack.push(U256::from(32));
407        let _ = interpreter
408            .stack
409            .push(U256::from(interpreter.return_data.buffer().len() - 32));
410        let _ = interpreter.stack.push(U256::from(0));
411        interpreter.step(&table, &mut host);
412        assert_eq!(
413            interpreter.control.instruction_result,
414            InstructionResult::Continue
415        );
416        assert_eq!(
417            *interpreter.memory.slice(0..32),
418            interpreter.return_data.buffer()[interpreter.return_data.buffer().len() - 32..]
419        );
420
421        // Offset right at the boundary of the return data buffer size
422        let _ = interpreter.stack.push(U256::from(32));
423        let _ = interpreter
424            .stack
425            .push(U256::from(interpreter.return_data.buffer().len()));
426        let _ = interpreter.stack.push(U256::from(0));
427        interpreter.step(&table, &mut host);
428        assert_eq!(
429            interpreter.control.instruction_result,
430            InstructionResult::Continue
431        );
432        assert_eq!(*interpreter.memory.slice(0..32), [0u8; 32]);
433    }
434}