revm_interpreter/instructions/system.rs
1use crate::{
2 gas,
3 interpreter::Interpreter,
4 interpreter_types::{
5 InputsTr, InterpreterTypes, LegacyBytecode, LoopControl, MemoryTr, ReturnData, RuntimeFlag,
6 StackTr,
7 },
8 Host, InstructionResult,
9};
10use core::ptr;
11use primitives::{B256, KECCAK_EMPTY, U256};
12
13pub fn keccak256<WIRE: InterpreterTypes, H: Host + ?Sized>(
14 interpreter: &mut Interpreter<WIRE>,
15 _host: &mut H,
16) {
17 popn_top!([offset], top, interpreter);
18 let len = as_usize_or_fail!(interpreter, top);
19 gas_or_fail!(interpreter, gas::keccak256_cost(len));
20 let hash = if len == 0 {
21 KECCAK_EMPTY
22 } else {
23 let from = as_usize_or_fail!(interpreter, offset);
24 resize_memory!(interpreter, from, len);
25 primitives::keccak256(interpreter.memory.slice_len(from, len).as_ref())
26 };
27 *top = hash.into();
28}
29
30pub fn address<WIRE: InterpreterTypes, H: Host + ?Sized>(
31 interpreter: &mut Interpreter<WIRE>,
32 _host: &mut H,
33) {
34 gas!(interpreter, gas::BASE);
35 push!(
36 interpreter,
37 interpreter.input.target_address().into_word().into()
38 );
39}
40
41pub fn caller<WIRE: InterpreterTypes, H: Host + ?Sized>(
42 interpreter: &mut Interpreter<WIRE>,
43 _host: &mut H,
44) {
45 gas!(interpreter, gas::BASE);
46 push!(
47 interpreter,
48 interpreter.input.caller_address().into_word().into()
49 );
50}
51
52pub fn codesize<WIRE: InterpreterTypes, H: Host + ?Sized>(
53 interpreter: &mut Interpreter<WIRE>,
54 _host: &mut H,
55) {
56 gas!(interpreter, gas::BASE);
57 push!(interpreter, U256::from(interpreter.bytecode.bytecode_len()));
58}
59
60pub fn codecopy<WIRE: InterpreterTypes, H: Host + ?Sized>(
61 interpreter: &mut Interpreter<WIRE>,
62 _host: &mut H,
63) {
64 popn!([memory_offset, code_offset, len], interpreter);
65 let len = as_usize_or_fail!(interpreter, len);
66 let Some(memory_offset) = memory_resize(interpreter, memory_offset, len) else {
67 return;
68 };
69 let code_offset = as_usize_saturated!(code_offset);
70
71 // Note: This can't panic because we resized memory to fit.
72 interpreter.memory.set_data(
73 memory_offset,
74 code_offset,
75 len,
76 interpreter.bytecode.bytecode_slice(),
77 );
78}
79
80pub fn calldataload<WIRE: InterpreterTypes, H: Host + ?Sized>(
81 interpreter: &mut Interpreter<WIRE>,
82 _host: &mut H,
83) {
84 gas!(interpreter, gas::VERYLOW);
85 //pop_top!(interpreter, offset_ptr);
86 popn_top!([], offset_ptr, interpreter);
87 let mut word = B256::ZERO;
88 let offset = as_usize_saturated!(offset_ptr);
89 let input = interpreter.input.input();
90 let input_len = input.len();
91 if offset < input_len {
92 let count = 32.min(input_len - offset);
93 // SAFETY: `count` is bounded by the calldata length.
94 // This is `word[..count].copy_from_slice(input[offset..offset + count])`, written using
95 // raw pointers as apparently the compiler cannot optimize the slice version, and using
96 // `get_unchecked` twice is uglier.
97 debug_assert!(count <= 32 && offset + count <= input_len);
98 unsafe { ptr::copy_nonoverlapping(input.as_ptr().add(offset), word.as_mut_ptr(), count) };
99 }
100 *offset_ptr = word.into();
101}
102
103pub fn calldatasize<WIRE: InterpreterTypes, H: Host + ?Sized>(
104 interpreter: &mut Interpreter<WIRE>,
105 _host: &mut H,
106) {
107 gas!(interpreter, gas::BASE);
108 push!(interpreter, U256::from(interpreter.input.input().len()));
109}
110
111pub fn callvalue<WIRE: InterpreterTypes, H: Host + ?Sized>(
112 interpreter: &mut Interpreter<WIRE>,
113 _host: &mut H,
114) {
115 gas!(interpreter, gas::BASE);
116 push!(interpreter, interpreter.input.call_value());
117}
118
119pub fn calldatacopy<WIRE: InterpreterTypes, H: Host + ?Sized>(
120 interpreter: &mut Interpreter<WIRE>,
121 _host: &mut H,
122) {
123 popn!([memory_offset, data_offset, len], interpreter);
124 let len = as_usize_or_fail!(interpreter, len);
125 let Some(memory_offset) = memory_resize(interpreter, memory_offset, len) else {
126 return;
127 };
128
129 let data_offset = as_usize_saturated!(data_offset);
130 // Note: This can't panic because we resized memory to fit.
131 interpreter
132 .memory
133 .set_data(memory_offset, data_offset, len, interpreter.input.input());
134}
135
136/// EIP-211: New opcodes: RETURNDATASIZE and RETURNDATACOPY
137pub fn returndatasize<WIRE: InterpreterTypes, H: Host + ?Sized>(
138 interpreter: &mut Interpreter<WIRE>,
139 _host: &mut H,
140) {
141 check!(interpreter, BYZANTIUM);
142 gas!(interpreter, gas::BASE);
143 push!(
144 interpreter,
145 U256::from(interpreter.return_data.buffer().len())
146 );
147}
148
149/// EIP-211: New opcodes: RETURNDATASIZE and RETURNDATACOPY
150pub fn returndatacopy<WIRE: InterpreterTypes, H: Host + ?Sized>(
151 interpreter: &mut Interpreter<WIRE>,
152 _host: &mut H,
153) {
154 check!(interpreter, BYZANTIUM);
155 popn!([memory_offset, offset, len], interpreter);
156
157 let len = as_usize_or_fail!(interpreter, len);
158 let data_offset = as_usize_saturated!(offset);
159
160 // Old legacy behavior is to panic if data_end is out of scope of return buffer.
161 // This behavior is changed in EOF.
162 let data_end = data_offset.saturating_add(len);
163 if data_end > interpreter.return_data.buffer().len() && !interpreter.runtime_flag.is_eof() {
164 interpreter
165 .control
166 .set_instruction_result(InstructionResult::OutOfOffset);
167 return;
168 }
169
170 let Some(memory_offset) = memory_resize(interpreter, memory_offset, len) else {
171 return;
172 };
173
174 // Note: This can't panic because we resized memory to fit.
175 interpreter.memory.set_data(
176 memory_offset,
177 data_offset,
178 len,
179 interpreter.return_data.buffer(),
180 );
181}
182
183/// Part of EOF `<https://eips.ethereum.org/EIPS/eip-7069>`.
184pub fn returndataload<WIRE: InterpreterTypes, H: Host + ?Sized>(
185 interpreter: &mut Interpreter<WIRE>,
186 _host: &mut H,
187) {
188 require_eof!(interpreter);
189 gas!(interpreter, gas::VERYLOW);
190 popn_top!([], offset, interpreter);
191 let offset_usize = as_usize_saturated!(offset);
192
193 let mut output = [0u8; 32];
194 if let Some(available) = interpreter
195 .return_data
196 .buffer()
197 .len()
198 .checked_sub(offset_usize)
199 {
200 let copy_len = available.min(32);
201 output[..copy_len].copy_from_slice(
202 &interpreter.return_data.buffer()[offset_usize..offset_usize + copy_len],
203 );
204 }
205
206 *offset = B256::from(output).into();
207}
208
209pub fn gas<WIRE: InterpreterTypes, H: Host + ?Sized>(
210 interpreter: &mut Interpreter<WIRE>,
211 _host: &mut H,
212) {
213 gas!(interpreter, gas::BASE);
214 push!(
215 interpreter,
216 U256::from(interpreter.control.gas().remaining())
217 );
218}
219
220// common logic for copying data from a source buffer to the EVM's memory
221pub fn memory_resize(
222 interpreter: &mut Interpreter<impl InterpreterTypes>,
223 memory_offset: U256,
224 len: usize,
225) -> Option<usize> {
226 // Safe to cast usize to u64
227 gas_or_fail!(interpreter, gas::copy_cost_verylow(len), None);
228 if len == 0 {
229 return None;
230 }
231 let memory_offset = as_usize_or_fail_ret!(interpreter, memory_offset, None);
232 resize_memory!(interpreter, memory_offset, len, None);
233
234 Some(memory_offset)
235}
236
237// TODO : Tests
238/*
239#[cfg(test)]
240mod test {
241 use super::*;
242 use crate::{table::make_instruction_table, DummyHost, Gas, InstructionResult};
243 use bytecode::opcode::{RETURNDATACOPY, RETURNDATALOAD};
244 use bytecode::Bytecode;
245 use primitives::bytes;
246 use specification::hardfork::{PragueSpec, SpecId};
247 use context_interface::DefaultEthereumWiring;
248
249 #[test]
250 fn returndataload() {
251 let table = make_instruction_table::<Interpreter, DummyHost<DefaultEthereumWiring>>();
252 let mut host = DummyHost::default();
253
254 let mut interp = Interpreter::new_bytecode(Bytecode::LegacyRaw(
255 [
256 RETURNDATALOAD,
257 RETURNDATALOAD,
258 RETURNDATALOAD,
259 RETURNDATALOAD,
260 ]
261 .into(),
262 ));
263 interp.is_eof = true;
264 interp.spec_id = SpecId::PRAGUE;
265 interp.gas = Gas::new(10000);
266
267 interp.stack.push(U256::from(0)).unwrap();
268 interp.return_data_buffer =
269 bytes!("000000000000000400000000000000030000000000000002000000000000000100");
270 interp.step(&table, &mut host);
271 assert_eq!(
272 interp.stack.data(),
273 &vec![U256::from_limbs([0x01, 0x02, 0x03, 0x04])]
274 );
275
276 let _ = interp.stack.pop();
277 let _ = interp.stack.push(U256::from(1));
278
279 interp.step(&table, &mut host);
280 assert_eq!(interp.instruction_result, InstructionResult::Continue);
281 assert_eq!(
282 interp.stack.data(),
283 &vec![U256::from_limbs([0x0100, 0x0200, 0x0300, 0x0400])]
284 );
285
286 let _ = interp.stack.pop();
287 let _ = interp.stack.push(U256::from(32));
288 interp.step(&table, &mut host);
289 assert_eq!(interp.instruction_result, InstructionResult::Continue);
290 assert_eq!(
291 interp.stack.data(),
292 &vec![U256::from_limbs([0x00, 0x00, 0x00, 0x00])]
293 );
294
295 // Offset right at the boundary of the return data buffer size
296 let _ = interp.stack.pop();
297 let _ = interp
298 .stack
299 .push(U256::from(interp.return_data_buffer.len()));
300 interp.step(&table, &mut host);
301 assert_eq!(interp.instruction_result, InstructionResult::Continue);
302 assert_eq!(
303 interp.stack.data(),
304 &vec![U256::from_limbs([0x00, 0x00, 0x00, 0x00])]
305 );
306 }
307
308 #[test]
309 fn returndatacopy() {
310 let table = make_instruction_table::<Interpreter, _>();
311 let mut host = DummyHost::<DefaultEthereumWiring>::default();
312
313 let mut interp = Interpreter::new_bytecode(Bytecode::LegacyRaw(
314 [
315 RETURNDATACOPY,
316 RETURNDATACOPY,
317 RETURNDATACOPY,
318 RETURNDATACOPY,
319 RETURNDATACOPY,
320 RETURNDATACOPY,
321 ]
322 .into(),
323 ));
324 interp.is_eof = true;
325 interp.spec_id = SpecId::PRAGUE;
326 interp.gas = Gas::new(10000);
327
328 interp.return_data_buffer =
329 bytes!("000000000000000400000000000000030000000000000002000000000000000100");
330 interp.shared_memory.resize(256);
331
332 // Copying within bounds
333 interp.stack.push(U256::from(32)).unwrap();
334 interp.stack.push(U256::from(0)).unwrap();
335 interp.stack.push(U256::from(0)).unwrap();
336 interp.step(&table, &mut host);
337 assert_eq!(interp.instruction_result, InstructionResult::Continue);
338 assert_eq!(
339 interp.shared_memory.slice(0, 32),
340 &interp.return_data_buffer[0..32]
341 );
342
343 // Copying with partial out-of-bounds (should zero pad)
344 interp.stack.push(U256::from(64)).unwrap();
345 interp.stack.push(U256::from(16)).unwrap();
346 interp.stack.push(U256::from(64)).unwrap();
347 interp.step(&table, &mut host);
348 assert_eq!(interp.instruction_result, InstructionResult::Continue);
349 assert_eq!(
350 interp.shared_memory.slice(64, 16),
351 &interp.return_data_buffer[16..32]
352 );
353 assert_eq!(&interp.shared_memory.slice(80, 48), &[0u8; 48]);
354
355 // Completely out-of-bounds (should be all zeros)
356 interp.stack.push(U256::from(32)).unwrap();
357 interp.stack.push(U256::from(96)).unwrap();
358 interp.stack.push(U256::from(128)).unwrap();
359 interp.step(&table, &mut host);
360 assert_eq!(interp.instruction_result, InstructionResult::Continue);
361 assert_eq!(&interp.shared_memory.slice(128, 32), &[0u8; 32]);
362
363 // Large offset
364 interp.stack.push(U256::from(32)).unwrap();
365 interp.stack.push(U256::MAX).unwrap();
366 interp.stack.push(U256::from(0)).unwrap();
367 interp.step(&table, &mut host);
368 assert_eq!(interp.instruction_result, InstructionResult::Continue);
369 assert_eq!(&interp.shared_memory.slice(0, 32), &[0u8; 32]);
370
371 // Offset just before the boundary of the return data buffer size
372 interp.stack.push(U256::from(32)).unwrap();
373 interp
374 .stack
375 .push(U256::from(interp.return_data_buffer.len() - 32))
376 .unwrap();
377 interp.stack.push(U256::from(0)).unwrap();
378 interp.step(&table, &mut host);
379 assert_eq!(interp.instruction_result, InstructionResult::Continue);
380 assert_eq!(
381 interp.shared_memory.slice(0, 32),
382 &interp.return_data_buffer[interp.return_data_buffer.len() - 32..]
383 );
384
385 // Offset right at the boundary of the return data buffer size
386 interp.stack.push(U256::from(32)).unwrap();
387 interp
388 .stack
389 .push(U256::from(interp.return_data_buffer.len()))
390 .unwrap();
391 interp.stack.push(U256::from(0)).unwrap();
392 interp.step(&table, &mut host);
393 assert_eq!(interp.instruction_result, InstructionResult::Continue);
394 assert_eq!(&interp.shared_memory.slice(0, 32), &[0u8; 32]);
395 }
396}
397
398*/