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
14/// Implements the KECCAK256 instruction.
15///
16/// Computes Keccak-256 hash of memory data.
17pub fn keccak256<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
18    popn_top!([offset], top, context.interpreter);
19    let len = as_usize_or_fail!(context.interpreter, top);
20    gas_or_fail!(context.interpreter, gas::keccak256_cost(len));
21    let hash = if len == 0 {
22        KECCAK_EMPTY
23    } else {
24        let from = as_usize_or_fail!(context.interpreter, offset);
25        resize_memory!(context.interpreter, from, len);
26        primitives::keccak256(context.interpreter.memory.slice_len(from, len).as_ref())
27    };
28    *top = hash.into();
29}
30
31/// Implements the ADDRESS instruction.
32///
33/// Pushes the current contract's address onto the stack.
34pub fn address<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
35    //gas!(context.interpreter, gas::BASE);
36    push!(
37        context.interpreter,
38        context
39            .interpreter
40            .input
41            .target_address()
42            .into_word()
43            .into()
44    );
45}
46
47/// Implements the CALLER instruction.
48///
49/// Pushes the caller's address onto the stack.
50pub fn caller<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
51    //gas!(context.interpreter, gas::BASE);
52    push!(
53        context.interpreter,
54        context
55            .interpreter
56            .input
57            .caller_address()
58            .into_word()
59            .into()
60    );
61}
62
63/// Implements the CODESIZE instruction.
64///
65/// Pushes the size of running contract's bytecode onto the stack.
66pub fn codesize<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
67    //gas!(context.interpreter, gas::BASE);
68    push!(
69        context.interpreter,
70        U256::from(context.interpreter.bytecode.bytecode_len())
71    );
72}
73
74/// Implements the CODECOPY instruction.
75///
76/// Copies running contract's bytecode to memory.
77pub fn codecopy<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
78    popn!([memory_offset, code_offset, len], context.interpreter);
79    let len = as_usize_or_fail!(context.interpreter, len);
80    let Some(memory_offset) = memory_resize(context.interpreter, memory_offset, len) else {
81        return;
82    };
83    let code_offset = as_usize_saturated!(code_offset);
84
85    // Note: This can't panic because we resized memory to fit.
86    context.interpreter.memory.set_data(
87        memory_offset,
88        code_offset,
89        len,
90        context.interpreter.bytecode.bytecode_slice(),
91    );
92}
93
94/// Implements the CALLDATALOAD instruction.
95///
96/// Loads 32 bytes of input data from the specified offset.
97pub fn calldataload<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
98    //gas!(context.interpreter, gas::VERYLOW);
99    popn_top!([], offset_ptr, context.interpreter);
100    let mut word = B256::ZERO;
101    let offset = as_usize_saturated!(offset_ptr);
102    let input = context.interpreter.input.input();
103    let input_len = input.len();
104    if offset < input_len {
105        let count = 32.min(input_len - offset);
106
107        // SAFETY: `count` is bounded by the calldata length.
108        // This is `word[..count].copy_from_slice(input[offset..offset + count])`, written using
109        // raw pointers as apparently the compiler cannot optimize the slice version, and using
110        // `get_unchecked` twice is uglier.
111        match context.interpreter.input.input() {
112            CallInput::Bytes(bytes) => {
113                unsafe {
114                    ptr::copy_nonoverlapping(bytes.as_ptr().add(offset), word.as_mut_ptr(), count)
115                };
116            }
117            CallInput::SharedBuffer(range) => {
118                let input_slice = context.interpreter.memory.global_slice(range.clone());
119                unsafe {
120                    ptr::copy_nonoverlapping(
121                        input_slice.as_ptr().add(offset),
122                        word.as_mut_ptr(),
123                        count,
124                    )
125                };
126            }
127        }
128    }
129    *offset_ptr = word.into();
130}
131
132/// Implements the CALLDATASIZE instruction.
133///
134/// Pushes the size of input data onto the stack.
135pub fn calldatasize<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
136    //gas!(context.interpreter, gas::BASE);
137    push!(
138        context.interpreter,
139        U256::from(context.interpreter.input.input().len())
140    );
141}
142
143/// Implements the CALLVALUE instruction.
144///
145/// Pushes the value sent with the current call onto the stack.
146pub fn callvalue<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
147    //gas!(context.interpreter, gas::BASE);
148    push!(context.interpreter, context.interpreter.input.call_value());
149}
150
151/// Implements the CALLDATACOPY instruction.
152///
153/// Copies input data to memory.
154pub fn calldatacopy<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
155    popn!([memory_offset, data_offset, len], context.interpreter);
156    let len = as_usize_or_fail!(context.interpreter, len);
157    let Some(memory_offset) = memory_resize(context.interpreter, memory_offset, len) else {
158        return;
159    };
160
161    let data_offset = as_usize_saturated!(data_offset);
162    match context.interpreter.input.input() {
163        CallInput::Bytes(bytes) => {
164            context
165                .interpreter
166                .memory
167                .set_data(memory_offset, data_offset, len, bytes.as_ref());
168        }
169        CallInput::SharedBuffer(range) => {
170            context.interpreter.memory.set_data_from_global(
171                memory_offset,
172                data_offset,
173                len,
174                range.clone(),
175            );
176        }
177    }
178}
179
180/// EIP-211: New opcodes: RETURNDATASIZE and RETURNDATACOPY
181pub fn returndatasize<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
182    check!(context.interpreter, BYZANTIUM);
183    //gas!(context.interpreter, gas::BASE);
184    push!(
185        context.interpreter,
186        U256::from(context.interpreter.return_data.buffer().len())
187    );
188}
189
190/// EIP-211: New opcodes: RETURNDATASIZE and RETURNDATACOPY
191pub fn returndatacopy<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
192    check!(context.interpreter, BYZANTIUM);
193    popn!([memory_offset, offset, len], context.interpreter);
194
195    let len = as_usize_or_fail!(context.interpreter, len);
196    let data_offset = as_usize_saturated!(offset);
197
198    // Old legacy behavior is to panic if data_end is out of scope of return buffer.
199    let data_end = data_offset.saturating_add(len);
200    if data_end > context.interpreter.return_data.buffer().len() {
201        context.interpreter.halt(InstructionResult::OutOfOffset);
202        return;
203    }
204
205    let Some(memory_offset) = memory_resize(context.interpreter, memory_offset, len) else {
206        return;
207    };
208
209    // Note: This can't panic because we resized memory to fit.
210    context.interpreter.memory.set_data(
211        memory_offset,
212        data_offset,
213        len,
214        context.interpreter.return_data.buffer(),
215    );
216}
217
218/// Implements the GAS instruction.
219///
220/// Pushes the amount of remaining gas onto the stack.
221pub fn gas<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
222    //gas!(context.interpreter, gas::BASE);
223    push!(
224        context.interpreter,
225        U256::from(context.interpreter.gas.remaining())
226    );
227}
228
229/// Common logic for copying data from a source buffer to the EVM's memory.
230///
231/// Handles memory expansion and gas calculation for data copy operations.
232pub fn memory_resize(
233    interpreter: &mut Interpreter<impl InterpreterTypes>,
234    memory_offset: U256,
235    len: usize,
236) -> Option<usize> {
237    // Safe to cast usize to u64
238    gas_or_fail!(interpreter, gas::copy_cost_verylow(len), None);
239    if len == 0 {
240        return None;
241    }
242    let memory_offset = as_usize_or_fail_ret!(interpreter, memory_offset, None);
243    resize_memory!(interpreter, memory_offset, len, None);
244
245    Some(memory_offset)
246}