1use crate::{
2 gas,
3 primitives::{Spec, B256, KECCAK_EMPTY, U256},
4 Host, InstructionResult, Interpreter,
5};
6use core::ptr;
7
8pub fn keccak256<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
9 pop_top!(interpreter, offset, len_ptr);
10 let len = as_usize_or_fail!(interpreter, len_ptr);
11 gas_or_fail!(interpreter, gas::keccak256_cost(len as u64));
12 let hash = if len == 0 {
13 KECCAK_EMPTY
14 } else {
15 let from = as_usize_or_fail!(interpreter, offset);
16 resize_memory!(interpreter, from, len);
17 crate::primitives::keccak256(interpreter.shared_memory.slice(from, len))
18 };
19 *len_ptr = hash.into();
20}
21
22pub fn address<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
23 gas!(interpreter, gas::BASE);
24 push_b256!(interpreter, interpreter.contract.target_address.into_word());
25}
26
27pub fn caller<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
28 gas!(interpreter, gas::BASE);
29 push_b256!(interpreter, interpreter.contract.caller.into_word());
30}
31
32pub fn codesize<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
33 gas!(interpreter, gas::BASE);
34 assume!(!interpreter.contract.bytecode.is_eof());
36 push!(interpreter, U256::from(interpreter.contract.bytecode.len()));
37}
38
39pub fn codecopy<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
40 pop!(interpreter, memory_offset, code_offset, len);
41 let len = as_usize_or_fail!(interpreter, len);
42 gas_or_fail!(interpreter, gas::verylowcopy_cost(len as u64));
43 if len == 0 {
44 return;
45 }
46 let memory_offset = as_usize_or_fail!(interpreter, memory_offset);
47 let code_offset = as_usize_saturated!(code_offset);
48 resize_memory!(interpreter, memory_offset, len);
49
50 assume!(!interpreter.contract.bytecode.is_eof());
52 interpreter.shared_memory.set_data(
54 memory_offset,
55 code_offset,
56 len,
57 interpreter.contract.bytecode.original_byte_slice(),
58 );
59}
60
61pub fn calldataload<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
62 gas!(interpreter, gas::VERYLOW);
63 pop_top!(interpreter, offset_ptr);
64 let mut word = B256::ZERO;
65 let offset = as_usize_saturated!(offset_ptr);
66 if offset < interpreter.contract.input.len() {
67 let count = 32.min(interpreter.contract.input.len() - offset);
68 debug_assert!(count <= 32 && offset + count <= interpreter.contract.input.len());
73 unsafe {
74 ptr::copy_nonoverlapping(
75 interpreter.contract.input.as_ptr().add(offset),
76 word.as_mut_ptr(),
77 count,
78 )
79 };
80 }
81 *offset_ptr = word.into();
82}
83
84pub fn calldatasize<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
85 gas!(interpreter, gas::BASE);
86 push!(interpreter, U256::from(interpreter.contract.input.len()));
87}
88
89pub fn callvalue<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
90 gas!(interpreter, gas::BASE);
91 push!(interpreter, interpreter.contract.call_value);
92}
93
94pub fn calldatacopy<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
95 pop!(interpreter, memory_offset, data_offset, len);
96 let len = as_usize_or_fail!(interpreter, len);
97 gas_or_fail!(interpreter, gas::verylowcopy_cost(len as u64));
98 if len == 0 {
99 return;
100 }
101 let memory_offset = as_usize_or_fail!(interpreter, memory_offset);
102 let data_offset = as_usize_saturated!(data_offset);
103 resize_memory!(interpreter, memory_offset, len);
104
105 interpreter.shared_memory.set_data(
107 memory_offset,
108 data_offset,
109 len,
110 &interpreter.contract.input,
111 );
112}
113
114pub fn returndatasize<H: Host + ?Sized, SPEC: Spec>(interpreter: &mut Interpreter, _host: &mut H) {
116 check!(interpreter, BYZANTIUM);
117 gas!(interpreter, gas::BASE);
118 push!(
119 interpreter,
120 U256::from(interpreter.return_data_buffer.len())
121 );
122}
123
124pub fn returndatacopy<H: Host + ?Sized, SPEC: Spec>(interpreter: &mut Interpreter, _host: &mut H) {
126 check!(interpreter, BYZANTIUM);
127 pop!(interpreter, memory_offset, offset, len);
128
129 let len = as_usize_or_fail!(interpreter, len);
130 gas_or_fail!(interpreter, gas::verylowcopy_cost(len as u64));
131
132 let data_offset = as_usize_saturated!(offset);
133 let data_end = data_offset.saturating_add(len);
134
135 if data_end > interpreter.return_data_buffer.len() && !interpreter.is_eof {
138 interpreter.instruction_result = InstructionResult::OutOfOffset;
139 return;
140 }
141
142 if len == 0 {
144 return;
145 }
146
147 let memory_offset = as_usize_or_fail!(interpreter, memory_offset);
149 resize_memory!(interpreter, memory_offset, len);
150
151 interpreter.shared_memory.set_data(
153 memory_offset,
154 data_offset,
155 len,
156 &interpreter.return_data_buffer,
157 );
158}
159
160pub fn returndataload<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
162 require_eof!(interpreter);
163 gas!(interpreter, gas::VERYLOW);
164 pop_top!(interpreter, offset);
165 let offset_usize = as_usize_saturated!(offset);
166
167 let mut output = [0u8; 32];
168 if let Some(available) = interpreter
169 .return_data_buffer
170 .len()
171 .checked_sub(offset_usize)
172 {
173 let copy_len = available.min(32);
174 output[..copy_len].copy_from_slice(
175 &interpreter.return_data_buffer[offset_usize..offset_usize + copy_len],
176 );
177 }
178
179 *offset = B256::from(output).into();
180}
181
182pub fn gas<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
183 gas!(interpreter, gas::BASE);
184 push!(interpreter, U256::from(interpreter.gas.remaining()));
185}
186
187#[cfg(test)]
188mod test {
189 use super::*;
190 use crate::{
191 opcode::{make_instruction_table, RETURNDATACOPY, RETURNDATALOAD},
192 primitives::{bytes, Bytecode, PragueSpec},
193 DummyHost, Gas, InstructionResult,
194 };
195
196 #[test]
197 fn returndataload() {
198 let table = make_instruction_table::<_, PragueSpec>();
199 let mut host = DummyHost::default();
200
201 let mut interp = Interpreter::new_bytecode(Bytecode::LegacyRaw(
202 [
203 RETURNDATALOAD,
204 RETURNDATALOAD,
205 RETURNDATALOAD,
206 RETURNDATALOAD,
207 ]
208 .into(),
209 ));
210 interp.is_eof = true;
211 interp.gas = Gas::new(10000);
212
213 interp.stack.push(U256::from(0)).unwrap();
214 interp.return_data_buffer =
215 bytes!("000000000000000400000000000000030000000000000002000000000000000100");
216 interp.step(&table, &mut host);
217 assert_eq!(
218 interp.stack.data(),
219 &vec![U256::from_limbs([0x01, 0x02, 0x03, 0x04])]
220 );
221
222 let _ = interp.stack.pop();
223 let _ = interp.stack.push(U256::from(1));
224
225 interp.step(&table, &mut host);
226 assert_eq!(interp.instruction_result, InstructionResult::Continue);
227 assert_eq!(
228 interp.stack.data(),
229 &vec![U256::from_limbs([0x0100, 0x0200, 0x0300, 0x0400])]
230 );
231
232 let _ = interp.stack.pop();
233 let _ = interp.stack.push(U256::from(32));
234 interp.step(&table, &mut host);
235 assert_eq!(interp.instruction_result, InstructionResult::Continue);
236 assert_eq!(
237 interp.stack.data(),
238 &vec![U256::from_limbs([0x00, 0x00, 0x00, 0x00])]
239 );
240
241 let _ = interp.stack.pop();
243 let _ = interp
244 .stack
245 .push(U256::from(interp.return_data_buffer.len()));
246 interp.step(&table, &mut host);
247 assert_eq!(interp.instruction_result, InstructionResult::Continue);
248 assert_eq!(
249 interp.stack.data(),
250 &vec![U256::from_limbs([0x00, 0x00, 0x00, 0x00])]
251 );
252 }
253
254 #[test]
255 fn returndatacopy() {
256 let table = make_instruction_table::<_, PragueSpec>();
257 let mut host = DummyHost::default();
258
259 let mut interp = Interpreter::new_bytecode(Bytecode::LegacyRaw(
260 [
261 RETURNDATACOPY,
262 RETURNDATACOPY,
263 RETURNDATACOPY,
264 RETURNDATACOPY,
265 RETURNDATACOPY,
266 RETURNDATACOPY,
267 ]
268 .into(),
269 ));
270 interp.is_eof = true;
271 interp.gas = Gas::new(10000);
272
273 interp.return_data_buffer =
274 bytes!("000000000000000400000000000000030000000000000002000000000000000100");
275 interp.shared_memory.resize(256);
276
277 interp.stack.push(U256::from(32)).unwrap();
279 interp.stack.push(U256::from(0)).unwrap();
280 interp.stack.push(U256::from(0)).unwrap();
281 interp.step(&table, &mut host);
282 assert_eq!(interp.instruction_result, InstructionResult::Continue);
283 assert_eq!(
284 interp.shared_memory.slice(0, 32),
285 &interp.return_data_buffer[0..32]
286 );
287
288 interp.stack.push(U256::from(64)).unwrap();
290 interp.stack.push(U256::from(16)).unwrap();
291 interp.stack.push(U256::from(64)).unwrap();
292 interp.step(&table, &mut host);
293 assert_eq!(interp.instruction_result, InstructionResult::Continue);
294 assert_eq!(
295 interp.shared_memory.slice(64, 16),
296 &interp.return_data_buffer[16..32]
297 );
298 assert_eq!(&interp.shared_memory.slice(80, 48), &[0u8; 48]);
299
300 interp.stack.push(U256::from(32)).unwrap();
302 interp.stack.push(U256::from(96)).unwrap();
303 interp.stack.push(U256::from(128)).unwrap();
304 interp.step(&table, &mut host);
305 assert_eq!(interp.instruction_result, InstructionResult::Continue);
306 assert_eq!(&interp.shared_memory.slice(128, 32), &[0u8; 32]);
307
308 interp.stack.push(U256::from(32)).unwrap();
310 interp.stack.push(U256::MAX).unwrap();
311 interp.stack.push(U256::from(0)).unwrap();
312 interp.step(&table, &mut host);
313 assert_eq!(interp.instruction_result, InstructionResult::Continue);
314 assert_eq!(&interp.shared_memory.slice(0, 32), &[0u8; 32]);
315
316 interp.stack.push(U256::from(32)).unwrap();
318 interp
319 .stack
320 .push(U256::from(interp.return_data_buffer.len() - 32))
321 .unwrap();
322 interp.stack.push(U256::from(0)).unwrap();
323 interp.step(&table, &mut host);
324 assert_eq!(interp.instruction_result, InstructionResult::Continue);
325 assert_eq!(
326 interp.shared_memory.slice(0, 32),
327 &interp.return_data_buffer[interp.return_data_buffer.len() - 32..]
328 );
329
330 interp.stack.push(U256::from(32)).unwrap();
332 interp
333 .stack
334 .push(U256::from(interp.return_data_buffer.len()))
335 .unwrap();
336 interp.stack.push(U256::from(0)).unwrap();
337 interp.step(&table, &mut host);
338 assert_eq!(interp.instruction_result, InstructionResult::Continue);
339 assert_eq!(&interp.shared_memory.slice(0, 32), &[0u8; 32]);
340 }
341}