revm_interpreter/instructions/
system.rs1use crate::{
2 interpreter::{resize_memory, Interpreter},
3 interpreter_types::{
4 InputsTr, InterpreterTypes as ITy, LegacyBytecode, MemoryTr, ReturnData, RuntimeFlag,
5 StackTr,
6 },
7 CallInput, InstructionExecResult as Result, InstructionResult,
8};
9use context_interface::{cfg::GasParams, Host};
10use core::ptr;
11use primitives::{B256, KECCAK_EMPTY, U256};
12
13use crate::InstructionContext as Ictx;
14
15pub fn keccak256<IT: ITy, H: Host + ?Sized>(context: Ictx<'_, H, IT>) -> Result {
19 popn_top!([offset], top, context.interpreter);
20 let len = as_usize_or_fail!(context.interpreter, top);
21 gas!(
22 context.interpreter,
23 context.host.gas_params().keccak256_cost(len)
24 );
25 let hash = if len == 0 {
26 KECCAK_EMPTY
27 } else {
28 let from = as_usize_or_fail!(context.interpreter, offset);
29 resize_memory(
30 &mut context.interpreter.gas,
31 &mut context.interpreter.memory,
32 context.host.gas_params(),
33 from,
34 len,
35 )?;
36 primitives::keccak256(context.interpreter.memory.slice_len(from, len).as_ref())
37 };
38 *top = hash.into();
39 Ok(())
40}
41
42pub fn address<IT: ITy, H: ?Sized>(context: Ictx<'_, H, IT>) -> Result {
46 push!(
47 context.interpreter,
48 context
49 .interpreter
50 .input
51 .target_address()
52 .into_word()
53 .into()
54 );
55 Ok(())
56}
57
58pub fn caller<IT: ITy, H: ?Sized>(context: Ictx<'_, H, IT>) -> Result {
62 push!(
63 context.interpreter,
64 context
65 .interpreter
66 .input
67 .caller_address()
68 .into_word()
69 .into()
70 );
71 Ok(())
72}
73
74pub fn codesize<IT: ITy, H: ?Sized>(context: Ictx<'_, H, IT>) -> Result {
78 push!(
79 context.interpreter,
80 U256::from(context.interpreter.bytecode.bytecode_len())
81 );
82 Ok(())
83}
84
85pub fn codecopy<IT: ITy, H: Host + ?Sized>(context: Ictx<'_, H, IT>) -> Result {
89 popn!([memory_offset, code_offset, len], context.interpreter);
90 let len = as_usize_or_fail!(context.interpreter, len);
91 let Some(memory_offset) = copy_cost_and_memory_resize(
92 context.interpreter,
93 context.host.gas_params(),
94 memory_offset,
95 len,
96 )?
97 else {
98 return Ok(());
99 };
100 let code_offset = as_usize_saturated!(code_offset);
101
102 context.interpreter.memory.set_data(
104 memory_offset,
105 code_offset,
106 len,
107 context.interpreter.bytecode.bytecode_slice(),
108 );
109 Ok(())
110}
111
112pub fn calldataload<IT: ITy, H: ?Sized>(context: Ictx<'_, H, IT>) -> Result {
116 popn_top!([], offset_ptr, context.interpreter);
117 let mut word = B256::ZERO;
118 let offset = as_usize_saturated!(*offset_ptr);
119 let input = context.interpreter.input.input();
120 let input_len = input.len();
121 if offset < input_len {
122 let count = 32.min(input_len - offset);
123 let input = &*input.as_bytes_memory(&context.interpreter.memory);
124 unsafe { ptr::copy_nonoverlapping(input.as_ptr().add(offset), word.as_mut_ptr(), count) };
129 }
130 *offset_ptr = word.into();
131 Ok(())
132}
133
134pub fn calldatasize<IT: ITy, H: ?Sized>(context: Ictx<'_, H, IT>) -> Result {
138 push!(
139 context.interpreter,
140 U256::from(context.interpreter.input.input().len())
141 );
142 Ok(())
143}
144
145pub fn callvalue<IT: ITy, H: ?Sized>(context: Ictx<'_, H, IT>) -> Result {
149 push!(context.interpreter, context.interpreter.input.call_value());
150 Ok(())
151}
152
153pub fn calldatacopy<IT: ITy, H: Host + ?Sized>(context: Ictx<'_, H, IT>) -> Result {
157 popn!([memory_offset, data_offset, len], context.interpreter);
158 let len = as_usize_or_fail!(context.interpreter, len);
159 let Some(memory_offset) = copy_cost_and_memory_resize(
160 context.interpreter,
161 context.host.gas_params(),
162 memory_offset,
163 len,
164 )?
165 else {
166 return Ok(());
167 };
168
169 let data_offset = as_usize_saturated!(data_offset);
170 match context.interpreter.input.input() {
171 CallInput::Bytes(bytes) => {
172 context
173 .interpreter
174 .memory
175 .set_data(memory_offset, data_offset, len, bytes.as_ref());
176 }
177 CallInput::SharedBuffer(range) => {
178 context.interpreter.memory.set_data_from_global(
179 memory_offset,
180 data_offset,
181 len,
182 range.clone(),
183 );
184 }
185 }
186 Ok(())
187}
188
189pub fn returndatasize<IT: ITy, H: ?Sized>(context: Ictx<'_, H, IT>) -> Result {
191 check!(context.interpreter, BYZANTIUM);
192 push!(
193 context.interpreter,
194 U256::from(context.interpreter.return_data.buffer().len())
195 );
196 Ok(())
197}
198
199pub fn returndatacopy<IT: ITy, H: Host + ?Sized>(context: Ictx<'_, H, IT>) -> Result {
201 check!(context.interpreter, BYZANTIUM);
202 popn!([memory_offset, offset, len], context.interpreter);
203
204 let len = as_usize_or_fail!(context.interpreter, len);
205 let data_offset = as_usize_saturated!(offset);
206
207 let data_end = data_offset.saturating_add(len);
209 if data_end > context.interpreter.return_data.buffer().len() {
210 return Err(InstructionResult::OutOfOffset);
211 }
212
213 let Some(memory_offset) = copy_cost_and_memory_resize(
214 context.interpreter,
215 context.host.gas_params(),
216 memory_offset,
217 len,
218 )?
219 else {
220 return Ok(());
221 };
222
223 context.interpreter.memory.set_data(
225 memory_offset,
226 data_offset,
227 len,
228 context.interpreter.return_data.buffer(),
229 );
230 Ok(())
231}
232
233pub fn gas<IT: ITy, H: ?Sized>(context: Ictx<'_, H, IT>) -> Result {
239 let gas = &context.interpreter.gas;
240 push!(context.interpreter, U256::from(gas.remaining()));
241 Ok(())
242}
243
244pub fn copy_cost_and_memory_resize(
248 interpreter: &mut Interpreter<impl ITy>,
249 gas_params: &GasParams,
250 memory_offset: U256,
251 len: usize,
252) -> Result<Option<usize>, InstructionResult> {
253 gas!(interpreter, gas_params.copy_cost(len));
255 if len == 0 {
256 return Ok(None);
257 }
258 let memory_offset = as_usize_or_fail!(interpreter, memory_offset);
259 interpreter.resize_memory(gas_params, memory_offset, len)?;
260
261 Ok(Some(memory_offset))
262}