revm_interpreter/instructions/
system.rs1use crate::{
2 interpreter::Interpreter,
3 interpreter_types::{
4 InputsTr, InterpreterTypes, LegacyBytecode, MemoryTr, ReturnData, RuntimeFlag, StackTr,
5 },
6 CallInput, InstructionResult,
7};
8use context_interface::{cfg::GasParams, Host};
9use core::ptr;
10use primitives::{B256, KECCAK_EMPTY, U256};
11
12use crate::InstructionContext;
13
14pub fn keccak256<WIRE: InterpreterTypes, H: Host + ?Sized>(
18 context: InstructionContext<'_, H, WIRE>,
19) {
20 popn_top!([offset], top, context.interpreter);
21 let len = as_usize_or_fail!(context.interpreter, top);
22 gas!(
23 context.interpreter,
24 context.host.gas_params().keccak256_cost(len)
25 );
26 let hash = if len == 0 {
27 KECCAK_EMPTY
28 } else {
29 let from = as_usize_or_fail!(context.interpreter, offset);
30 resize_memory!(context.interpreter, context.host.gas_params(), from, len);
31 primitives::keccak256(context.interpreter.memory.slice_len(from, len).as_ref())
32 };
33 *top = hash.into();
34}
35
36pub fn address<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
40 push!(
41 context.interpreter,
42 context
43 .interpreter
44 .input
45 .target_address()
46 .into_word()
47 .into()
48 );
49}
50
51pub fn caller<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
55 push!(
56 context.interpreter,
57 context
58 .interpreter
59 .input
60 .caller_address()
61 .into_word()
62 .into()
63 );
64}
65
66pub fn codesize<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
70 push!(
71 context.interpreter,
72 U256::from(context.interpreter.bytecode.bytecode_len())
73 );
74}
75
76pub fn codecopy<WIRE: InterpreterTypes, H: Host + ?Sized>(
80 context: InstructionContext<'_, H, WIRE>,
81) {
82 popn!([memory_offset, code_offset, len], context.interpreter);
83 let len = as_usize_or_fail!(context.interpreter, len);
84 let Some(memory_offset) = copy_cost_and_memory_resize(
85 context.interpreter,
86 context.host.gas_params(),
87 memory_offset,
88 len,
89 ) else {
90 return;
91 };
92 let code_offset = as_usize_saturated!(code_offset);
93
94 context.interpreter.memory.set_data(
96 memory_offset,
97 code_offset,
98 len,
99 context.interpreter.bytecode.bytecode_slice(),
100 );
101}
102
103pub fn calldataload<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
107 popn_top!([], offset_ptr, context.interpreter);
108 let mut word = B256::ZERO;
109 let offset = as_usize_saturated!(*offset_ptr);
110 let input = context.interpreter.input.input();
111 let input_len = input.len();
112 if offset < input_len {
113 let count = 32.min(input_len - offset);
114 let input = &*input.as_bytes_memory(&context.interpreter.memory);
115 unsafe { ptr::copy_nonoverlapping(input.as_ptr().add(offset), word.as_mut_ptr(), count) };
120 }
121 *offset_ptr = word.into();
122}
123
124pub fn calldatasize<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
128 push!(
129 context.interpreter,
130 U256::from(context.interpreter.input.input().len())
131 );
132}
133
134pub fn callvalue<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
138 push!(context.interpreter, context.interpreter.input.call_value());
139}
140
141pub fn calldatacopy<WIRE: InterpreterTypes, H: Host + ?Sized>(
145 context: InstructionContext<'_, H, WIRE>,
146) {
147 popn!([memory_offset, data_offset, len], context.interpreter);
148 let len = as_usize_or_fail!(context.interpreter, len);
149 let Some(memory_offset) = copy_cost_and_memory_resize(
150 context.interpreter,
151 context.host.gas_params(),
152 memory_offset,
153 len,
154 ) else {
155 return;
156 };
157
158 let data_offset = as_usize_saturated!(data_offset);
159 match context.interpreter.input.input() {
160 CallInput::Bytes(bytes) => {
161 context
162 .interpreter
163 .memory
164 .set_data(memory_offset, data_offset, len, bytes.as_ref());
165 }
166 CallInput::SharedBuffer(range) => {
167 context.interpreter.memory.set_data_from_global(
168 memory_offset,
169 data_offset,
170 len,
171 range.clone(),
172 );
173 }
174 }
175}
176
177pub fn returndatasize<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
179 check!(context.interpreter, BYZANTIUM);
180 push!(
181 context.interpreter,
182 U256::from(context.interpreter.return_data.buffer().len())
183 );
184}
185
186pub fn returndatacopy<WIRE: InterpreterTypes, H: Host + ?Sized>(
188 context: InstructionContext<'_, H, WIRE>,
189) {
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 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(
204 context.interpreter,
205 context.host.gas_params(),
206 memory_offset,
207 len,
208 ) else {
209 return;
210 };
211
212 context.interpreter.memory.set_data(
214 memory_offset,
215 data_offset,
216 len,
217 context.interpreter.return_data.buffer(),
218 );
219}
220
221pub fn gas<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
225 push!(
226 context.interpreter,
227 U256::from(context.interpreter.gas.remaining())
228 );
229}
230
231pub fn copy_cost_and_memory_resize(
235 interpreter: &mut Interpreter<impl InterpreterTypes>,
236 gas_params: &GasParams,
237 memory_offset: U256,
238 len: usize,
239) -> Option<usize> {
240 gas!(interpreter, gas_params.copy_cost(len), None);
242 if len == 0 {
243 return None;
244 }
245 let memory_offset = as_usize_or_fail_ret!(interpreter, memory_offset, None);
246 resize_memory!(interpreter, gas_params, memory_offset, len, None);
247
248 Some(memory_offset)
249}