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!(
21        context.interpreter,
22        context.interpreter.gas_params.keccak256_cost(len)
23    );
24    let hash = if len == 0 {
25        KECCAK_EMPTY
26    } else {
27        let from = as_usize_or_fail!(context.interpreter, offset);
28        resize_memory!(context.interpreter, from, len);
29        primitives::keccak256(context.interpreter.memory.slice_len(from, len).as_ref())
30    };
31    *top = hash.into();
32}
33
34/// Implements the ADDRESS instruction.
35///
36/// Pushes the current contract's address onto the stack.
37pub fn address<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
38    push!(
39        context.interpreter,
40        context
41            .interpreter
42            .input
43            .target_address()
44            .into_word()
45            .into()
46    );
47}
48
49/// Implements the CALLER instruction.
50///
51/// Pushes the caller's address onto the stack.
52pub fn caller<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
53    push!(
54        context.interpreter,
55        context
56            .interpreter
57            .input
58            .caller_address()
59            .into_word()
60            .into()
61    );
62}
63
64/// Implements the CODESIZE instruction.
65///
66/// Pushes the size of running contract's bytecode onto the stack.
67pub fn codesize<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
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) = copy_cost_and_memory_resize(context.interpreter, memory_offset, len)
81    else {
82        return;
83    };
84    let code_offset = as_usize_saturated!(code_offset);
85
86    // Note: This can't panic because we resized memory to fit.
87    context.interpreter.memory.set_data(
88        memory_offset,
89        code_offset,
90        len,
91        context.interpreter.bytecode.bytecode_slice(),
92    );
93}
94
95/// Implements the CALLDATALOAD instruction.
96///
97/// Loads 32 bytes of input data from the specified offset.
98pub fn calldataload<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
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    push!(
137        context.interpreter,
138        U256::from(context.interpreter.input.input().len())
139    );
140}
141
142/// Implements the CALLVALUE instruction.
143///
144/// Pushes the value sent with the current call onto the stack.
145pub fn callvalue<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
146    push!(context.interpreter, context.interpreter.input.call_value());
147}
148
149/// Implements the CALLDATACOPY instruction.
150///
151/// Copies input data to memory.
152pub fn calldatacopy<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
153    popn!([memory_offset, data_offset, len], context.interpreter);
154    let len = as_usize_or_fail!(context.interpreter, len);
155    let Some(memory_offset) = copy_cost_and_memory_resize(context.interpreter, memory_offset, len)
156    else {
157        return;
158    };
159
160    let data_offset = as_usize_saturated!(data_offset);
161    match context.interpreter.input.input() {
162        CallInput::Bytes(bytes) => {
163            context
164                .interpreter
165                .memory
166                .set_data(memory_offset, data_offset, len, bytes.as_ref());
167        }
168        CallInput::SharedBuffer(range) => {
169            context.interpreter.memory.set_data_from_global(
170                memory_offset,
171                data_offset,
172                len,
173                range.clone(),
174            );
175        }
176    }
177}
178
179/// EIP-211: New opcodes: RETURNDATASIZE and RETURNDATACOPY
180pub fn returndatasize<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
181    check!(context.interpreter, BYZANTIUM);
182    push!(
183        context.interpreter,
184        U256::from(context.interpreter.return_data.buffer().len())
185    );
186}
187
188/// EIP-211: New opcodes: RETURNDATASIZE and RETURNDATACOPY
189pub fn returndatacopy<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
190    check!(context.interpreter, BYZANTIUM);
191    popn!([memory_offset, offset, len], context.interpreter);
192
193    let len = as_usize_or_fail!(context.interpreter, len);
194    let data_offset = as_usize_saturated!(offset);
195
196    // Old legacy behavior is to panic if data_end is out of scope of return buffer.
197    let data_end = data_offset.saturating_add(len);
198    if data_end > context.interpreter.return_data.buffer().len() {
199        context.interpreter.halt(InstructionResult::OutOfOffset);
200        return;
201    }
202
203    let Some(memory_offset) = copy_cost_and_memory_resize(context.interpreter, memory_offset, len)
204    else {
205        return;
206    };
207
208    // Note: This can't panic because we resized memory to fit.
209    context.interpreter.memory.set_data(
210        memory_offset,
211        data_offset,
212        len,
213        context.interpreter.return_data.buffer(),
214    );
215}
216
217/// Implements the GAS instruction.
218///
219/// Pushes the amount of remaining gas onto the stack.
220pub fn gas<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
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.
228///
229/// Handles memory expansion and gas calculation for data copy operations.
230pub fn copy_cost_and_memory_resize(
231    interpreter: &mut Interpreter<impl InterpreterTypes>,
232    memory_offset: U256,
233    len: usize,
234) -> Option<usize> {
235    // Safe to cast usize to u64
236    gas!(interpreter, interpreter.gas_params.copy_cost(len), None);
237    if len == 0 {
238        return None;
239    }
240    let memory_offset = as_usize_or_fail_ret!(interpreter, memory_offset, None);
241    resize_memory!(interpreter, memory_offset, len, None);
242
243    Some(memory_offset)
244}