revm_interpreter/instructions/
system.rs1use 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
14pub 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
34pub 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
49pub 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
64pub 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
74pub 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 context.interpreter.memory.set_data(
88 memory_offset,
89 code_offset,
90 len,
91 context.interpreter.bytecode.bytecode_slice(),
92 );
93}
94
95pub 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 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
132pub 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
142pub fn callvalue<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
146 push!(context.interpreter, context.interpreter.input.call_value());
147}
148
149pub 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
179pub 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
188pub 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 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 context.interpreter.memory.set_data(
210 memory_offset,
211 data_offset,
212 len,
213 context.interpreter.return_data.buffer(),
214 );
215}
216
217pub 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
227pub fn copy_cost_and_memory_resize(
231 interpreter: &mut Interpreter<impl InterpreterTypes>,
232 memory_offset: U256,
233 len: usize,
234) -> Option<usize> {
235 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}