revm_interpreter/instructions/
system.rs

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