revm_interpreter/instructions/
host.rs
1use crate::{
2 gas::{self, warm_cold_cost, warm_cold_cost_with_delegation},
3 interpreter::Interpreter,
4 primitives::{Bytes, Log, LogData, Spec, SpecId::*, B256, U256},
5 Host, InstructionResult,
6};
7use core::cmp::min;
8use std::vec::Vec;
9
10pub fn balance<H: Host + ?Sized, SPEC: Spec>(interpreter: &mut Interpreter, host: &mut H) {
11 pop_address!(interpreter, address);
12 let Some(balance) = host.balance(address) else {
13 interpreter.instruction_result = InstructionResult::FatalExternalError;
14 return;
15 };
16 gas!(
17 interpreter,
18 if SPEC::enabled(BERLIN) {
19 warm_cold_cost(balance.is_cold)
20 } else if SPEC::enabled(ISTANBUL) {
21 700
23 } else if SPEC::enabled(TANGERINE) {
24 400
25 } else {
26 20
27 }
28 );
29 push!(interpreter, balance.data);
30}
31
32pub fn selfbalance<H: Host + ?Sized, SPEC: Spec>(interpreter: &mut Interpreter, host: &mut H) {
34 check!(interpreter, ISTANBUL);
35 gas!(interpreter, gas::LOW);
36 let Some(balance) = host.balance(interpreter.contract.target_address) else {
37 interpreter.instruction_result = InstructionResult::FatalExternalError;
38 return;
39 };
40 push!(interpreter, balance.data);
41}
42
43pub fn extcodesize<H: Host + ?Sized, SPEC: Spec>(interpreter: &mut Interpreter, host: &mut H) {
44 pop_address!(interpreter, address);
45 let Some(code) = host.code(address) else {
46 interpreter.instruction_result = InstructionResult::FatalExternalError;
47 return;
48 };
49 let (code, load) = code.into_components();
50 if SPEC::enabled(BERLIN) {
51 gas!(interpreter, warm_cold_cost_with_delegation(load));
52 } else if SPEC::enabled(TANGERINE) {
53 gas!(interpreter, 700);
54 } else {
55 gas!(interpreter, 20);
56 }
57
58 push!(interpreter, U256::from(code.len()));
59}
60
61pub fn extcodehash<H: Host + ?Sized, SPEC: Spec>(interpreter: &mut Interpreter, host: &mut H) {
63 check!(interpreter, CONSTANTINOPLE);
64 pop_address!(interpreter, address);
65 let Some(code_hash) = host.code_hash(address) else {
66 interpreter.instruction_result = InstructionResult::FatalExternalError;
67 return;
68 };
69 let (code_hash, load) = code_hash.into_components();
70 if SPEC::enabled(BERLIN) {
71 gas!(interpreter, warm_cold_cost_with_delegation(load))
72 } else if SPEC::enabled(ISTANBUL) {
73 gas!(interpreter, 700);
74 } else {
75 gas!(interpreter, 400);
76 }
77 push_b256!(interpreter, code_hash);
78}
79
80pub fn extcodecopy<H: Host + ?Sized, SPEC: Spec>(interpreter: &mut Interpreter, host: &mut H) {
81 pop_address!(interpreter, address);
82 pop!(interpreter, memory_offset, code_offset, len_u256);
83
84 let Some(code) = host.code(address) else {
85 interpreter.instruction_result = InstructionResult::FatalExternalError;
86 return;
87 };
88
89 let len = as_usize_or_fail!(interpreter, len_u256);
90 let (code, load) = code.into_components();
91 gas_or_fail!(
92 interpreter,
93 gas::extcodecopy_cost(SPEC::SPEC_ID, len as u64, load)
94 );
95 if len == 0 {
96 return;
97 }
98 let memory_offset = as_usize_or_fail!(interpreter, memory_offset);
99 let code_offset = min(as_usize_saturated!(code_offset), code.len());
100 resize_memory!(interpreter, memory_offset, len);
101
102 interpreter
104 .shared_memory
105 .set_data(memory_offset, code_offset, len, &code);
106}
107
108pub fn blockhash<H: Host + ?Sized, SPEC: Spec>(interpreter: &mut Interpreter, host: &mut H) {
109 gas!(interpreter, gas::BLOCKHASH);
110 pop_top!(interpreter, number);
111
112 let number_u64 = as_u64_saturated!(number);
113 let Some(hash) = host.block_hash(number_u64) else {
114 interpreter.instruction_result = InstructionResult::FatalExternalError;
115 return;
116 };
117 *number = U256::from_be_bytes(hash.0);
118}
119
120pub fn sload<H: Host + ?Sized, SPEC: Spec>(interpreter: &mut Interpreter, host: &mut H) {
121 pop_top!(interpreter, index);
122 let Some(value) = host.sload(interpreter.contract.target_address, *index) else {
123 interpreter.instruction_result = InstructionResult::FatalExternalError;
124 return;
125 };
126 gas!(interpreter, gas::sload_cost(SPEC::SPEC_ID, value.is_cold));
127 *index = value.data;
128}
129
130pub fn sstore<H: Host + ?Sized, SPEC: Spec>(interpreter: &mut Interpreter, host: &mut H) {
131 require_non_staticcall!(interpreter);
132
133 pop!(interpreter, index, value);
134 let Some(state_load) = host.sstore(interpreter.contract.target_address, index, value) else {
135 interpreter.instruction_result = InstructionResult::FatalExternalError;
136 return;
137 };
138 gas_or_fail!(interpreter, {
139 let remaining_gas = interpreter.gas.remaining();
140 gas::sstore_cost(
141 SPEC::SPEC_ID,
142 &state_load.data,
143 remaining_gas,
144 state_load.is_cold,
145 )
146 });
147 refund!(
148 interpreter,
149 gas::sstore_refund(SPEC::SPEC_ID, &state_load.data)
150 );
151}
152
153pub fn tstore<H: Host + ?Sized, SPEC: Spec>(interpreter: &mut Interpreter, host: &mut H) {
156 check!(interpreter, CANCUN);
157 require_non_staticcall!(interpreter);
158 gas!(interpreter, gas::WARM_STORAGE_READ_COST);
159
160 pop!(interpreter, index, value);
161
162 host.tstore(interpreter.contract.target_address, index, value);
163}
164
165pub fn tload<H: Host + ?Sized, SPEC: Spec>(interpreter: &mut Interpreter, host: &mut H) {
168 check!(interpreter, CANCUN);
169 gas!(interpreter, gas::WARM_STORAGE_READ_COST);
170
171 pop_top!(interpreter, index);
172
173 *index = host.tload(interpreter.contract.target_address, *index);
174}
175
176pub fn log<const N: usize, H: Host + ?Sized>(interpreter: &mut Interpreter, host: &mut H) {
177 require_non_staticcall!(interpreter);
178
179 pop!(interpreter, offset, len);
180 let len = as_usize_or_fail!(interpreter, len);
181 gas_or_fail!(interpreter, gas::log_cost(N as u8, len as u64));
182 let data = if len == 0 {
183 Bytes::new()
184 } else {
185 let offset = as_usize_or_fail!(interpreter, offset);
186 resize_memory!(interpreter, offset, len);
187 Bytes::copy_from_slice(interpreter.shared_memory.slice(offset, len))
188 };
189
190 if interpreter.stack.len() < N {
191 interpreter.instruction_result = InstructionResult::StackUnderflow;
192 return;
193 }
194
195 let mut topics = Vec::with_capacity(N);
196 for _ in 0..N {
197 topics.push(B256::from(unsafe { interpreter.stack.pop_unsafe() }));
199 }
200
201 let log = Log {
202 address: interpreter.contract.target_address,
203 data: LogData::new(topics, data).expect("LogData should have <=4 topics"),
204 };
205
206 host.log(log);
207}
208
209pub fn selfdestruct<H: Host + ?Sized, SPEC: Spec>(interpreter: &mut Interpreter, host: &mut H) {
210 require_non_staticcall!(interpreter);
211 pop_address!(interpreter, target);
212
213 let Some(res) = host.selfdestruct(interpreter.contract.target_address, target) else {
214 interpreter.instruction_result = InstructionResult::FatalExternalError;
215 return;
216 };
217
218 if !SPEC::enabled(LONDON) && !res.previously_destroyed {
220 refund!(interpreter, gas::SELFDESTRUCT)
221 }
222 gas!(interpreter, gas::selfdestruct_cost(SPEC::SPEC_ID, res));
223
224 interpreter.instruction_result = InstructionResult::SelfDestruct;
225}