revm_interpreter/instructions/
host.rs1use crate::{
2 gas::{self, warm_cold_cost, CALL_STIPEND},
3 instructions::utility::{IntoAddress, IntoU256},
4 interpreter::Interpreter,
5 interpreter_types::{InputsTr, InterpreterTypes, LoopControl, MemoryTr, RuntimeFlag, StackTr},
6 Host, InstructionResult,
7};
8use core::cmp::min;
9use primitives::{hardfork::SpecId::*, Bytes, Log, LogData, B256, BLOCK_HASH_HISTORY, U256};
10
11pub fn balance<WIRE: InterpreterTypes, H: Host + ?Sized>(
12 interpreter: &mut Interpreter<WIRE>,
13 host: &mut H,
14) {
15 popn_top!([], top, interpreter);
16 let address = top.into_address();
17 let Some(balance) = host.balance(address) else {
18 interpreter
19 .control
20 .set_instruction_result(InstructionResult::FatalExternalError);
21 return;
22 };
23 let spec_id = interpreter.runtime_flag.spec_id();
24 gas!(
25 interpreter,
26 if spec_id.is_enabled_in(BERLIN) {
27 warm_cold_cost(balance.is_cold)
28 } else if spec_id.is_enabled_in(ISTANBUL) {
29 700
31 } else if spec_id.is_enabled_in(TANGERINE) {
32 400
33 } else {
34 20
35 }
36 );
37 *top = balance.data;
38}
39
40pub fn selfbalance<WIRE: InterpreterTypes, H: Host + ?Sized>(
42 interpreter: &mut Interpreter<WIRE>,
43 host: &mut H,
44) {
45 check!(interpreter, ISTANBUL);
46 gas!(interpreter, gas::LOW);
47
48 let Some(balance) = host.balance(interpreter.input.target_address()) else {
49 interpreter
50 .control
51 .set_instruction_result(InstructionResult::FatalExternalError);
52 return;
53 };
54 push!(interpreter, balance.data);
55}
56
57pub fn extcodesize<WIRE: InterpreterTypes, H: Host + ?Sized>(
58 interpreter: &mut Interpreter<WIRE>,
59 host: &mut H,
60) {
61 popn_top!([], top, interpreter);
62 let address = top.into_address();
63 let Some(code) = host.load_account_code(address) else {
64 interpreter
65 .control
66 .set_instruction_result(InstructionResult::FatalExternalError);
67 return;
68 };
69 let spec_id = interpreter.runtime_flag.spec_id();
70 if spec_id.is_enabled_in(BERLIN) {
71 gas!(interpreter, warm_cold_cost(code.is_cold));
72 } else if spec_id.is_enabled_in(TANGERINE) {
73 gas!(interpreter, 700);
74 } else {
75 gas!(interpreter, 20);
76 }
77
78 *top = U256::from(code.len());
79}
80
81pub fn extcodehash<WIRE: InterpreterTypes, H: Host + ?Sized>(
83 interpreter: &mut Interpreter<WIRE>,
84 host: &mut H,
85) {
86 check!(interpreter, CONSTANTINOPLE);
87 popn_top!([], top, interpreter);
88 let address = top.into_address();
89 let Some(code_hash) = host.load_account_code_hash(address) else {
90 interpreter
91 .control
92 .set_instruction_result(InstructionResult::FatalExternalError);
93 return;
94 };
95 let spec_id = interpreter.runtime_flag.spec_id();
96 if spec_id.is_enabled_in(BERLIN) {
97 gas!(interpreter, warm_cold_cost(code_hash.is_cold));
98 } else if spec_id.is_enabled_in(ISTANBUL) {
99 gas!(interpreter, 700);
100 } else {
101 gas!(interpreter, 400);
102 }
103 *top = code_hash.into_u256();
104}
105
106pub fn extcodecopy<WIRE: InterpreterTypes, H: Host + ?Sized>(
107 interpreter: &mut Interpreter<WIRE>,
108 host: &mut H,
109) {
110 popn!([address, memory_offset, code_offset, len_u256], interpreter);
111 let address = address.into_address();
112 let Some(code) = host.load_account_code(address) else {
113 interpreter
114 .control
115 .set_instruction_result(InstructionResult::FatalExternalError);
116 return;
117 };
118
119 let len = as_usize_or_fail!(interpreter, len_u256);
120 gas_or_fail!(
121 interpreter,
122 gas::extcodecopy_cost(interpreter.runtime_flag.spec_id(), len, code.is_cold)
123 );
124 if len == 0 {
125 return;
126 }
127 let memory_offset = as_usize_or_fail!(interpreter, memory_offset);
128 let code_offset = min(as_usize_saturated!(code_offset), code.len());
129 resize_memory!(interpreter, memory_offset, len);
130
131 interpreter
133 .memory
134 .set_data(memory_offset, code_offset, len, &code);
135}
136
137pub fn blockhash<WIRE: InterpreterTypes, H: Host + ?Sized>(
138 interpreter: &mut Interpreter<WIRE>,
139 host: &mut H,
140) {
141 gas!(interpreter, gas::BLOCKHASH);
142 popn_top!([], number, interpreter);
143
144 let requested_number = as_u64_saturated!(number);
145
146 let block_number = host.block_number();
147
148 let Some(diff) = block_number.checked_sub(requested_number) else {
149 *number = U256::ZERO;
150 return;
151 };
152
153 if diff == 0 {
155 *number = U256::ZERO;
156 return;
157 }
158
159 *number = if diff <= BLOCK_HASH_HISTORY {
160 let Some(hash) = host.block_hash(requested_number) else {
161 interpreter
162 .control
163 .set_instruction_result(InstructionResult::FatalExternalError);
164 return;
165 };
166 U256::from_be_bytes(hash.0)
167 } else {
168 U256::ZERO
169 }
170}
171
172pub fn sload<WIRE: InterpreterTypes, H: Host + ?Sized>(
173 interpreter: &mut Interpreter<WIRE>,
174 host: &mut H,
175) {
176 popn_top!([], index, interpreter);
177
178 let Some(value) = host.sload(interpreter.input.target_address(), *index) else {
179 interpreter
180 .control
181 .set_instruction_result(InstructionResult::FatalExternalError);
182 return;
183 };
184
185 gas!(
186 interpreter,
187 gas::sload_cost(interpreter.runtime_flag.spec_id(), value.is_cold)
188 );
189 *index = value.data;
190}
191
192pub fn sstore<WIRE: InterpreterTypes, H: Host + ?Sized>(
193 interpreter: &mut Interpreter<WIRE>,
194 host: &mut H,
195) {
196 require_non_staticcall!(interpreter);
197
198 popn!([index, value], interpreter);
199
200 let Some(state_load) = host.sstore(interpreter.input.target_address(), index, value) else {
201 interpreter
202 .control
203 .set_instruction_result(InstructionResult::FatalExternalError);
204 return;
205 };
206
207 if interpreter.runtime_flag.spec_id().is_enabled_in(ISTANBUL)
209 && interpreter.control.gas().remaining() <= CALL_STIPEND
210 {
211 interpreter
212 .control
213 .set_instruction_result(InstructionResult::ReentrancySentryOOG);
214 return;
215 }
216 gas!(
217 interpreter,
218 gas::sstore_cost(
219 interpreter.runtime_flag.spec_id(),
220 &state_load.data,
221 state_load.is_cold
222 )
223 );
224
225 interpreter
226 .control
227 .gas_mut()
228 .record_refund(gas::sstore_refund(
229 interpreter.runtime_flag.spec_id(),
230 &state_load.data,
231 ));
232}
233
234pub fn tstore<WIRE: InterpreterTypes, H: Host + ?Sized>(
237 interpreter: &mut Interpreter<WIRE>,
238 host: &mut H,
239) {
240 check!(interpreter, CANCUN);
241 require_non_staticcall!(interpreter);
242 gas!(interpreter, gas::WARM_STORAGE_READ_COST);
243
244 popn!([index, value], interpreter);
245
246 host.tstore(interpreter.input.target_address(), index, value);
247}
248
249pub fn tload<WIRE: InterpreterTypes, H: Host + ?Sized>(
252 interpreter: &mut Interpreter<WIRE>,
253 host: &mut H,
254) {
255 check!(interpreter, CANCUN);
256 gas!(interpreter, gas::WARM_STORAGE_READ_COST);
257
258 popn_top!([], index, interpreter);
259
260 *index = host.tload(interpreter.input.target_address(), *index);
261}
262
263pub fn log<const N: usize, H: Host + ?Sized>(
264 interpreter: &mut Interpreter<impl InterpreterTypes>,
265 host: &mut H,
266) {
267 require_non_staticcall!(interpreter);
268
269 popn!([offset, len], interpreter);
270 let len = as_usize_or_fail!(interpreter, len);
271 gas_or_fail!(interpreter, gas::log_cost(N as u8, len as u64));
272 let data = if len == 0 {
273 Bytes::new()
274 } else {
275 let offset = as_usize_or_fail!(interpreter, offset);
276 resize_memory!(interpreter, offset, len);
277 Bytes::copy_from_slice(interpreter.memory.slice_len(offset, len).as_ref())
278 };
279 if interpreter.stack.len() < N {
280 interpreter
281 .control
282 .set_instruction_result(InstructionResult::StackUnderflow);
283 return;
284 }
285 let Some(topics) = interpreter.stack.popn::<N>() else {
286 interpreter
287 .control
288 .set_instruction_result(InstructionResult::StackUnderflow);
289 return;
290 };
291
292 let log = Log {
293 address: interpreter.input.target_address(),
294 data: LogData::new(topics.into_iter().map(B256::from).collect(), data)
295 .expect("LogData should have <=4 topics"),
296 };
297
298 host.log(log);
299}
300
301pub fn selfdestruct<WIRE: InterpreterTypes, H: Host + ?Sized>(
302 interpreter: &mut Interpreter<WIRE>,
303 host: &mut H,
304) {
305 require_non_staticcall!(interpreter);
306 popn!([target], interpreter);
307 let target = target.into_address();
308
309 let Some(res) = host.selfdestruct(interpreter.input.target_address(), target) else {
310 interpreter
311 .control
312 .set_instruction_result(InstructionResult::FatalExternalError);
313 return;
314 };
315
316 if !interpreter.runtime_flag.spec_id().is_enabled_in(LONDON) && !res.previously_destroyed {
318 interpreter
319 .control
320 .gas_mut()
321 .record_refund(gas::SELFDESTRUCT)
322 }
323
324 gas!(
325 interpreter,
326 gas::selfdestruct_cost(interpreter.runtime_flag.spec_id(), res)
327 );
328
329 interpreter
330 .control
331 .set_instruction_result(InstructionResult::SelfDestruct);
332}