pallet_revive/vm/evm/instructions/
host.rs1use super::Context;
19
20use crate::{
21 storage::WriteOutcome,
22 vec::Vec,
23 vm::{evm::U256Converter, Ext},
24 DispatchError, Key, RuntimeCosts,
25};
26use revm::{
27 interpreter::{interpreter_types::StackTr, InstructionResult},
28 primitives::{Bytes, U256},
29};
30
31pub fn balance<'ext, E: Ext>(context: Context<'_, 'ext, E>) {
35 gas!(context.interpreter, RuntimeCosts::BalanceOf);
36 popn_top!([], top, context.interpreter);
37 let h160 = sp_core::H160::from_slice(&top.to_be_bytes::<32>()[12..]);
38 *top = context.interpreter.extend.balance_of(&h160).into_revm_u256();
39}
40
41pub fn selfbalance<'ext, E: Ext>(context: Context<'_, 'ext, E>) {
43 gas!(context.interpreter, RuntimeCosts::Balance);
44 let balance = context.interpreter.extend.balance();
45 push!(context.interpreter, balance.into_revm_u256());
46}
47
48pub fn extcodesize<'ext, E: Ext>(context: Context<'_, 'ext, E>) {
52 popn_top!([], top, context.interpreter);
53 gas!(context.interpreter, RuntimeCosts::CodeSize);
54 let h160 = sp_core::H160::from_slice(&top.to_be_bytes::<32>()[12..]);
55 let code_size = context.interpreter.extend.code_size(&h160);
56 *top = U256::from(code_size);
57}
58
59pub fn extcodehash<'ext, E: Ext>(context: Context<'_, 'ext, E>) {
61 popn_top!([], top, context.interpreter);
62 gas!(context.interpreter, RuntimeCosts::CodeHash);
63 let h160 = sp_core::H160::from_slice(&top.to_be_bytes::<32>()[12..]);
64 let code_hash = context.interpreter.extend.code_hash(&h160);
65 *top = U256::from_be_bytes(code_hash.0);
66}
67
68pub fn extcodecopy<'ext, E: Ext>(context: Context<'_, 'ext, E>) {
72 popn!([address, memory_offset, code_offset, len_u256], context.interpreter);
73 let len = as_usize_or_fail!(context.interpreter, len_u256);
74
75 gas!(context.interpreter, RuntimeCosts::ExtCodeCopy(len as u32));
76 let address = sp_core::H160::from_slice(&address.to_be_bytes::<32>()[12..]);
77
78 if len == 0 {
79 return;
80 }
81 let memory_offset = as_usize_or_fail!(context.interpreter, memory_offset);
82 let code_offset = as_usize_saturated!(code_offset);
83
84 resize_memory!(context.interpreter, memory_offset, len);
85
86 let mut buf = context.interpreter.memory.slice_mut(memory_offset, len);
87 context.interpreter.extend.copy_code_slice(&mut buf, &address, code_offset);
89}
90
91pub fn blockhash<'ext, E: Ext>(context: Context<'_, 'ext, E>) {
95 gas!(context.interpreter, RuntimeCosts::BlockHash);
96 popn_top!([], number, context.interpreter);
97 let requested_number = <sp_core::U256 as U256Converter>::from_revm_u256(&number);
98
99 if let Some(hash) = context.interpreter.extend.block_hash(requested_number) {
101 *number = U256::from_be_bytes(hash.0)
102 } else {
103 *number = U256::ZERO
104 };
105}
106
107pub fn sload<'ext, E: Ext>(context: Context<'_, 'ext, E>) {
111 popn_top!([], index, context.interpreter);
112 gas!(context.interpreter, RuntimeCosts::GetStorage(32));
114 let key = Key::Fix(index.to_be_bytes());
115 let value = context.interpreter.extend.get_storage(&key);
116
117 *index = if let Some(storage_value) = value {
118 let Ok::<[u8; 32], _>(bytes) = storage_value.try_into() else {
120 context.interpreter.halt(InstructionResult::FatalExternalError);
121 return
122 };
123 U256::from_be_bytes(bytes)
124 } else {
125 U256::ZERO
127 };
128}
129
130fn store_helper<'ext, E: Ext>(
131 context: Context<'_, 'ext, E>,
132 cost_before: RuntimeCosts,
133 set_function: fn(&mut E, &Key, Option<Vec<u8>>, bool) -> Result<WriteOutcome, DispatchError>,
134 adjust_cost: fn(new_bytes: u32, old_bytes: u32) -> RuntimeCosts,
135) {
136 if context.interpreter.extend.is_read_only() {
137 context.interpreter.halt(InstructionResult::Revert);
138 return;
139 }
140
141 popn!([index, value], context.interpreter);
142
143 let Ok(charged_amount) = context.interpreter.extend.gas_meter_mut().charge(cost_before) else {
145 context.interpreter.halt(InstructionResult::OutOfGas);
146 return;
147 };
148
149 let key = Key::Fix(index.to_be_bytes());
150 let take_old = false;
151 let Ok(write_outcome) = set_function(
152 context.interpreter.extend,
153 &key,
154 Some(value.to_be_bytes::<32>().to_vec()),
155 take_old,
156 ) else {
157 context.interpreter.halt(InstructionResult::FatalExternalError);
158 return;
159 };
160
161 context
162 .interpreter
163 .extend
164 .gas_meter_mut()
165 .adjust_gas(charged_amount, adjust_cost(32, write_outcome.old_len()));
166}
167
168pub fn sstore<'ext, E: Ext>(context: Context<'_, 'ext, E>) {
172 store_helper(
173 context,
174 RuntimeCosts::SetStorage { new_bytes: 32, old_bytes: 0 },
175 |ext, key, value, take_old| ext.set_storage(key, value, take_old),
176 |new_bytes, old_bytes| RuntimeCosts::SetStorage { new_bytes, old_bytes },
177 );
178}
179
180pub fn tstore<'ext, E: Ext>(context: Context<'_, 'ext, E>) {
183 store_helper(
184 context,
185 RuntimeCosts::SetTransientStorage { new_bytes: 32, old_bytes: 0 },
186 |ext, key, value, take_old| ext.set_transient_storage(key, value, take_old),
187 |new_bytes, old_bytes| RuntimeCosts::SetTransientStorage { new_bytes, old_bytes },
188 );
189}
190
191pub fn tload<'ext, E: Ext>(context: Context<'_, 'ext, E>) {
194 popn_top!([], index, context.interpreter);
195 gas!(context.interpreter, RuntimeCosts::GetTransientStorage(32));
196
197 let key = Key::Fix(index.to_be_bytes());
198 let bytes = context.interpreter.extend.get_transient_storage(&key);
199 *index = if let Some(storage_value) = bytes {
200 if storage_value.len() != 32 {
201 context.interpreter.halt(InstructionResult::FatalExternalError);
203 return;
204 }
205 let mut bytes = [0u8; 32];
206 bytes.copy_from_slice(&storage_value);
207 U256::from_be_bytes(bytes)
208 } else {
209 U256::ZERO
211 };
212}
213
214pub fn log<'ext, const N: usize, E: Ext>(context: Context<'_, 'ext, E>) {
218 if context.interpreter.extend.is_read_only() {
219 context.interpreter.halt(InstructionResult::Revert);
220 return;
221 }
222
223 popn!([offset, len], context.interpreter);
224 let len = as_usize_or_fail!(context.interpreter, len);
225 if len as u32 > context.interpreter.extend.max_value_size() {
226 context
227 .interpreter
228 .halt(revm::interpreter::InstructionResult::InvalidOperandOOG);
229 return;
230 }
231
232 gas!(context.interpreter, RuntimeCosts::DepositEvent { num_topic: N as u32, len: len as u32 });
233 let data = if len == 0 {
234 Bytes::new()
235 } else {
236 let offset = as_usize_or_fail!(context.interpreter, offset);
237 resize_memory!(context.interpreter, offset, len);
238 Bytes::copy_from_slice(context.interpreter.memory.slice_len(offset, len).as_ref())
239 };
240 if context.interpreter.stack.len() < N {
241 context.interpreter.halt(InstructionResult::StackUnderflow);
242 return;
243 }
244 let Some(topics) = <_ as StackTr>::popn::<N>(&mut context.interpreter.stack) else {
245 context.interpreter.halt(InstructionResult::StackUnderflow);
246 return;
247 };
248
249 let topics = topics.into_iter().map(|v| sp_core::H256::from(v.to_be_bytes())).collect();
250
251 context.interpreter.extend.deposit_event(topics, data.to_vec());
252}
253
254pub fn selfdestruct<'ext, E: Ext>(context: Context<'_, 'ext, E>) {
258 context.interpreter.halt(InstructionResult::NotActivated);
260}