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    //pop_top!(interpreter, offset_ptr);
100    popn_top!([], offset_ptr, context.interpreter);
101    let mut word = B256::ZERO;
102    let offset = as_usize_saturated!(offset_ptr);
103    let input = context.interpreter.input.input();
104    let input_len = input.len();
105    if offset < input_len {
106        let count = 32.min(input_len - offset);
107
108        // SAFETY: `count` is bounded by the calldata length.
109        // This is `word[..count].copy_from_slice(input[offset..offset + count])`, written using
110        // raw pointers as apparently the compiler cannot optimize the slice version, and using
111        // `get_unchecked` twice is uglier.
112        match context.interpreter.input.input() {
113            CallInput::Bytes(bytes) => {
114                unsafe {
115                    ptr::copy_nonoverlapping(bytes.as_ptr().add(offset), word.as_mut_ptr(), count)
116                };
117            }
118            CallInput::SharedBuffer(range) => {
119                let input_slice = context.interpreter.memory.global_slice(range.clone());
120                unsafe {
121                    ptr::copy_nonoverlapping(
122                        input_slice.as_ptr().add(offset),
123                        word.as_mut_ptr(),
124                        count,
125                    )
126                };
127            }
128        }
129    }
130    *offset_ptr = word.into();
131}
132
133/// Implements the CALLDATASIZE instruction.
134///
135/// Pushes the size of input data onto the stack.
136pub fn calldatasize<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
137    gas!(context.interpreter, gas::BASE);
138    push!(
139        context.interpreter,
140        U256::from(context.interpreter.input.input().len())
141    );
142}
143
144/// Implements the CALLVALUE instruction.
145///
146/// Pushes the value sent with the current call onto the stack.
147pub fn callvalue<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
148    gas!(context.interpreter, gas::BASE);
149    push!(context.interpreter, context.interpreter.input.call_value());
150}
151
152/// Implements the CALLDATACOPY instruction.
153///
154/// Copies input data to memory.
155pub fn calldatacopy<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
156    popn!([memory_offset, data_offset, len], context.interpreter);
157    let len = as_usize_or_fail!(context.interpreter, len);
158    let Some(memory_offset) = memory_resize(context.interpreter, memory_offset, len) else {
159        return;
160    };
161
162    let data_offset = as_usize_saturated!(data_offset);
163    match context.interpreter.input.input() {
164        CallInput::Bytes(bytes) => {
165            context
166                .interpreter
167                .memory
168                .set_data(memory_offset, data_offset, len, bytes.as_ref());
169        }
170        CallInput::SharedBuffer(range) => {
171            context.interpreter.memory.set_data_from_global(
172                memory_offset,
173                data_offset,
174                len,
175                range.clone(),
176            );
177        }
178    }
179}
180
181/// EIP-211: New opcodes: RETURNDATASIZE and RETURNDATACOPY
182pub fn returndatasize<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
183    check!(context.interpreter, BYZANTIUM);
184    gas!(context.interpreter, gas::BASE);
185    push!(
186        context.interpreter,
187        U256::from(context.interpreter.return_data.buffer().len())
188    );
189}
190
191/// EIP-211: New opcodes: RETURNDATASIZE and RETURNDATACOPY
192pub fn returndatacopy<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
193    check!(context.interpreter, BYZANTIUM);
194    popn!([memory_offset, offset, len], context.interpreter);
195
196    let len = as_usize_or_fail!(context.interpreter, len);
197    let data_offset = as_usize_saturated!(offset);
198
199    // Old legacy behavior is to panic if data_end is out of scope of return buffer.
200    let data_end = data_offset.saturating_add(len);
201    if data_end > context.interpreter.return_data.buffer().len() {
202        context.interpreter.halt(InstructionResult::OutOfOffset);
203        return;
204    }
205
206    let Some(memory_offset) = memory_resize(context.interpreter, memory_offset, len) else {
207        return;
208    };
209
210    // Note: This can't panic because we resized memory to fit.
211    context.interpreter.memory.set_data(
212        memory_offset,
213        data_offset,
214        len,
215        context.interpreter.return_data.buffer(),
216    );
217}
218
219/// Implements the GAS instruction.
220///
221/// Pushes the amount of remaining gas onto the stack.
222pub fn gas<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
223    gas!(context.interpreter, gas::BASE);
224    push!(
225        context.interpreter,
226        U256::from(context.interpreter.gas.remaining())
227    );
228}
229
230/// Common logic for copying data from a source buffer to the EVM's memory.
231///
232/// Handles memory expansion and gas calculation for data copy operations.
233pub fn memory_resize(
234    interpreter: &mut Interpreter<impl InterpreterTypes>,
235    memory_offset: U256,
236    len: usize,
237) -> Option<usize> {
238    // Safe to cast usize to u64
239    gas_or_fail!(interpreter, gas::copy_cost_verylow(len), None);
240    if len == 0 {
241        return None;
242    }
243    let memory_offset = as_usize_or_fail_ret!(interpreter, memory_offset, None);
244    resize_memory!(interpreter, memory_offset, len, None);
245
246    Some(memory_offset)
247}