rtvm_interpreter/instructions/
system.rs1use 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_bytes(),
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 let len = as_usize_or_fail!(interpreter, len);
129 gas_or_fail!(interpreter, gas::verylowcopy_cost(len as u64));
130 let data_offset = as_usize_saturated!(offset);
131 let data_end = data_offset.saturating_add(len);
132 if data_end > interpreter.return_data_buffer.len() {
133 interpreter.instruction_result = InstructionResult::OutOfOffset;
134 return;
135 }
136 if len != 0 {
137 let memory_offset = as_usize_or_fail!(interpreter, memory_offset);
138 resize_memory!(interpreter, memory_offset, len);
139 interpreter.shared_memory.set(
140 memory_offset,
141 &interpreter.return_data_buffer[data_offset..data_end],
142 );
143 }
144}
145
146pub fn returndataload<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
148 require_eof!(interpreter);
149 gas!(interpreter, gas::VERYLOW);
150 pop_top!(interpreter, offset);
151 let offset_usize = as_usize_or_fail!(interpreter, offset);
152 if offset_usize.saturating_add(32) > interpreter.return_data_buffer.len() {
153 interpreter.instruction_result = InstructionResult::OutOfOffset;
155 return;
156 }
157 *offset =
158 B256::from_slice(&interpreter.return_data_buffer[offset_usize..offset_usize + 32]).into();
159}
160
161pub fn gas<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
162 gas!(interpreter, gas::BASE);
163 push!(interpreter, U256::from(interpreter.gas.remaining()));
164}
165
166#[cfg(test)]
167mod test {
168 use super::*;
169 use crate::{
170 opcode::{make_instruction_table, RETURNDATALOAD},
171 primitives::{bytes, Bytecode, PragueSpec},
172 DummyHost, Gas,
173 };
174
175 #[test]
176 fn returndataload() {
177 let table = make_instruction_table::<_, PragueSpec>();
178 let mut host = DummyHost::default();
179
180 let mut interp = Interpreter::new_bytecode(Bytecode::LegacyRaw(
181 [RETURNDATALOAD, RETURNDATALOAD, RETURNDATALOAD].into(),
182 ));
183 interp.is_eof = true;
184 interp.gas = Gas::new(10000);
185
186 interp.stack.push(U256::from(0)).unwrap();
187 interp.return_data_buffer =
188 bytes!("000000000000000400000000000000030000000000000002000000000000000100");
189 interp.step(&table, &mut host);
190 assert_eq!(
191 interp.stack.data(),
192 &vec![U256::from_limbs([0x01, 0x02, 0x03, 0x04])]
193 );
194
195 let _ = interp.stack.pop();
196 let _ = interp.stack.push(U256::from(1));
197
198 interp.step(&table, &mut host);
199 assert_eq!(interp.instruction_result, InstructionResult::Continue);
200 assert_eq!(
201 interp.stack.data(),
202 &vec![U256::from_limbs([0x0100, 0x0200, 0x0300, 0x0400])]
203 );
204
205 let _ = interp.stack.pop();
206 let _ = interp.stack.push(U256::from(2));
207 interp.step(&table, &mut host);
208 assert_eq!(interp.instruction_result, InstructionResult::OutOfOffset);
209 }
210}