1use crate::{
4 cfg::GasParams,
5 context::{SStoreResult, SelfDestructResult, StateLoad},
6 journaled_state::{AccountInfoLoad, AccountLoad},
7};
8use auto_impl::auto_impl;
9use primitives::{hardfork::SpecId, Address, Bytes, Log, StorageKey, StorageValue, B256, U256};
10use state::Bytecode;
11
12#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
14#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
15pub enum LoadError {
16 ColdLoadSkipped,
18 DBError,
20}
21
22#[auto_impl(&mut, Box)]
28pub trait Host {
29 fn basefee(&self) -> U256;
33 fn blob_gasprice(&self) -> U256;
35 fn gas_limit(&self) -> U256;
37 fn difficulty(&self) -> U256;
39 fn prevrandao(&self) -> Option<U256>;
41 fn block_number(&self) -> U256;
43 fn timestamp(&self) -> U256;
45 fn beneficiary(&self) -> Address;
47 fn slot_num(&self) -> U256;
49 fn chain_id(&self) -> U256;
51
52 fn effective_gas_price(&self) -> U256;
56 fn caller(&self) -> Address;
58 fn blob_hash(&self, number: usize) -> Option<U256>;
60
61 fn max_initcode_size(&self) -> usize;
65
66 fn gas_params(&self) -> &GasParams;
68
69 fn is_amsterdam_eip8037_enabled(&self) -> bool;
71
72 fn block_hash(&mut self, number: u64) -> Option<B256>;
76
77 fn selfdestruct(
81 &mut self,
82 address: Address,
83 target: Address,
84 skip_cold_load: bool,
85 ) -> Result<StateLoad<SelfDestructResult>, LoadError>;
86
87 fn log(&mut self, log: Log);
89
90 fn sstore_skip_cold_load(
92 &mut self,
93 address: Address,
94 key: StorageKey,
95 value: StorageValue,
96 skip_cold_load: bool,
97 ) -> Result<StateLoad<SStoreResult>, LoadError>;
98
99 fn sstore(
101 &mut self,
102 address: Address,
103 key: StorageKey,
104 value: StorageValue,
105 ) -> Option<StateLoad<SStoreResult>> {
106 self.sstore_skip_cold_load(address, key, value, false).ok()
107 }
108
109 fn sload_skip_cold_load(
111 &mut self,
112 address: Address,
113 key: StorageKey,
114 skip_cold_load: bool,
115 ) -> Result<StateLoad<StorageValue>, LoadError>;
116
117 fn sload(&mut self, address: Address, key: StorageKey) -> Option<StateLoad<StorageValue>> {
119 self.sload_skip_cold_load(address, key, false).ok()
120 }
121
122 fn tstore(&mut self, address: Address, key: StorageKey, value: StorageValue);
124
125 fn tload(&mut self, address: Address, key: StorageKey) -> StorageValue;
127
128 fn load_account_info_skip_cold_load(
137 &mut self,
138 address: Address,
139 load_code: bool,
140 skip_cold_load: bool,
141 ) -> Result<AccountInfoLoad<'_>, LoadError>;
142
143 #[inline]
145 fn balance(&mut self, address: Address) -> Option<StateLoad<U256>> {
146 self.load_account_info_skip_cold_load(address, false, false)
147 .ok()
148 .map(|load| load.into_state_load(|i| i.balance))
149 }
150
151 #[inline]
153 fn load_account_delegated(&mut self, address: Address) -> Option<StateLoad<AccountLoad>> {
154 let account = self
155 .load_account_info_skip_cold_load(address, true, false)
156 .ok()?;
157
158 let mut account_load = StateLoad::new(
159 AccountLoad {
160 is_delegate_account_cold: None,
161 is_empty: account.is_empty,
162 },
163 account.is_cold,
164 );
165
166 if let Some(address) = account.code.as_ref().and_then(Bytecode::eip7702_address) {
168 let delegate_account = self
169 .load_account_info_skip_cold_load(address, true, false)
170 .ok()?;
171 account_load.data.is_delegate_account_cold = Some(delegate_account.is_cold);
172 }
173
174 Some(account_load)
175 }
176
177 #[inline]
179 fn load_account_code(&mut self, address: Address) -> Option<StateLoad<Bytes>> {
180 self.load_account_info_skip_cold_load(address, true, false)
181 .ok()
182 .map(|load| {
183 load.into_state_load(|i| {
184 i.code
185 .as_ref()
186 .map(|b| b.original_bytes())
187 .unwrap_or_default()
188 })
189 })
190 }
191
192 #[inline]
194 fn load_account_code_hash(&mut self, address: Address) -> Option<StateLoad<B256>> {
195 self.load_account_info_skip_cold_load(address, false, false)
196 .ok()
197 .map(|load| {
198 load.into_state_load(|i| {
199 if i.is_empty() {
200 B256::ZERO
201 } else {
202 i.code_hash
203 }
204 })
205 })
206 }
207}
208
209#[derive(Default, Debug)]
211pub struct DummyHost {
212 gas_params: GasParams,
213}
214
215impl DummyHost {
216 pub fn new(spec: SpecId) -> Self {
218 Self {
219 gas_params: GasParams::new_spec(spec),
220 }
221 }
222}
223
224impl Host for DummyHost {
225 fn basefee(&self) -> U256 {
226 U256::ZERO
227 }
228
229 fn blob_gasprice(&self) -> U256 {
230 U256::ZERO
231 }
232
233 fn gas_limit(&self) -> U256 {
234 U256::ZERO
235 }
236
237 fn gas_params(&self) -> &GasParams {
238 &self.gas_params
239 }
240
241 fn is_amsterdam_eip8037_enabled(&self) -> bool {
242 false
243 }
244
245 fn difficulty(&self) -> U256 {
246 U256::ZERO
247 }
248
249 fn prevrandao(&self) -> Option<U256> {
250 None
251 }
252
253 fn block_number(&self) -> U256 {
254 U256::ZERO
255 }
256
257 fn timestamp(&self) -> U256 {
258 U256::ZERO
259 }
260
261 fn beneficiary(&self) -> Address {
262 Address::ZERO
263 }
264
265 fn slot_num(&self) -> U256 {
266 U256::ZERO
267 }
268
269 fn chain_id(&self) -> U256 {
270 U256::ZERO
271 }
272
273 fn effective_gas_price(&self) -> U256 {
274 U256::ZERO
275 }
276
277 fn caller(&self) -> Address {
278 Address::ZERO
279 }
280
281 fn blob_hash(&self, _number: usize) -> Option<U256> {
282 None
283 }
284
285 fn max_initcode_size(&self) -> usize {
286 0
287 }
288
289 fn block_hash(&mut self, _number: u64) -> Option<B256> {
290 None
291 }
292
293 fn selfdestruct(
294 &mut self,
295 _address: Address,
296 _target: Address,
297 _skip_cold_load: bool,
298 ) -> Result<StateLoad<SelfDestructResult>, LoadError> {
299 Ok(Default::default())
300 }
301
302 fn log(&mut self, _log: Log) {}
303
304 fn tstore(&mut self, _address: Address, _key: StorageKey, _value: StorageValue) {}
305
306 fn tload(&mut self, _address: Address, _key: StorageKey) -> StorageValue {
307 StorageValue::ZERO
308 }
309
310 fn load_account_info_skip_cold_load(
311 &mut self,
312 _address: Address,
313 _load_code: bool,
314 _skip_cold_load: bool,
315 ) -> Result<AccountInfoLoad<'_>, LoadError> {
316 Ok(Default::default())
317 }
318
319 fn sstore_skip_cold_load(
320 &mut self,
321 _address: Address,
322 _key: StorageKey,
323 _value: StorageValue,
324 _skip_cold_load: bool,
325 ) -> Result<StateLoad<SStoreResult>, LoadError> {
326 Ok(Default::default())
327 }
328
329 fn sload_skip_cold_load(
330 &mut self,
331 _address: Address,
332 _key: StorageKey,
333 _skip_cold_load: bool,
334 ) -> Result<StateLoad<StorageValue>, LoadError> {
335 Ok(Default::default())
336 }
337}
338
339#[cfg(test)]
340mod tests {
341 use super::*;
342 use primitives::{hardfork::SpecId, Address, U256};
343 use state::{AccountInfo, Bytecode};
344 use std::borrow::Cow;
345
346 struct Eip7702Host {
350 dummy: DummyHost,
351 delegated: Address,
352 delegate: Address,
353 delegated_info: AccountInfo,
354 }
355
356 impl Eip7702Host {
357 fn new() -> Self {
358 let delegated = Address::repeat_byte(0x11);
359 let delegate = Address::repeat_byte(0x22);
360 let delegated_info = AccountInfo::new(
361 U256::from(1),
362 1,
363 B256::ZERO,
364 Bytecode::new_eip7702(delegate),
365 );
366 Self {
367 dummy: DummyHost::new(SpecId::PRAGUE),
368 delegated,
369 delegate,
370 delegated_info,
371 }
372 }
373 }
374
375 impl Host for Eip7702Host {
376 fn basefee(&self) -> U256 {
377 self.dummy.basefee()
378 }
379 fn blob_gasprice(&self) -> U256 {
380 self.dummy.blob_gasprice()
381 }
382 fn gas_limit(&self) -> U256 {
383 self.dummy.gas_limit()
384 }
385 fn gas_params(&self) -> &GasParams {
386 self.dummy.gas_params()
387 }
388 fn is_amsterdam_eip8037_enabled(&self) -> bool {
389 self.dummy.is_amsterdam_eip8037_enabled()
390 }
391 fn difficulty(&self) -> U256 {
392 self.dummy.difficulty()
393 }
394 fn prevrandao(&self) -> Option<U256> {
395 self.dummy.prevrandao()
396 }
397 fn block_number(&self) -> U256 {
398 self.dummy.block_number()
399 }
400 fn timestamp(&self) -> U256 {
401 self.dummy.timestamp()
402 }
403 fn beneficiary(&self) -> Address {
404 self.dummy.beneficiary()
405 }
406 fn slot_num(&self) -> U256 {
407 self.dummy.slot_num()
408 }
409 fn chain_id(&self) -> U256 {
410 self.dummy.chain_id()
411 }
412 fn effective_gas_price(&self) -> U256 {
413 self.dummy.effective_gas_price()
414 }
415 fn caller(&self) -> Address {
416 self.dummy.caller()
417 }
418 fn blob_hash(&self, number: usize) -> Option<U256> {
419 self.dummy.blob_hash(number)
420 }
421 fn max_initcode_size(&self) -> usize {
422 self.dummy.max_initcode_size()
423 }
424 fn block_hash(&mut self, number: u64) -> Option<B256> {
425 self.dummy.block_hash(number)
426 }
427 fn selfdestruct(
428 &mut self,
429 address: Address,
430 target: Address,
431 skip_cold_load: bool,
432 ) -> Result<StateLoad<SelfDestructResult>, LoadError> {
433 self.dummy.selfdestruct(address, target, skip_cold_load)
434 }
435 fn log(&mut self, log: Log) {
436 self.dummy.log(log)
437 }
438 fn tstore(&mut self, address: Address, key: StorageKey, value: StorageValue) {
439 self.dummy.tstore(address, key, value)
440 }
441 fn tload(&mut self, address: Address, key: StorageKey) -> StorageValue {
442 self.dummy.tload(address, key)
443 }
444 fn sstore_skip_cold_load(
445 &mut self,
446 address: Address,
447 key: StorageKey,
448 value: StorageValue,
449 skip_cold_load: bool,
450 ) -> Result<StateLoad<SStoreResult>, LoadError> {
451 self.dummy
452 .sstore_skip_cold_load(address, key, value, skip_cold_load)
453 }
454 fn sload_skip_cold_load(
455 &mut self,
456 address: Address,
457 key: StorageKey,
458 skip_cold_load: bool,
459 ) -> Result<StateLoad<StorageValue>, LoadError> {
460 self.dummy
461 .sload_skip_cold_load(address, key, skip_cold_load)
462 }
463
464 fn load_account_info_skip_cold_load(
465 &mut self,
466 address: Address,
467 _load_code: bool,
468 _skip_cold_load: bool,
469 ) -> Result<AccountInfoLoad<'_>, LoadError> {
470 if address == self.delegated {
471 Ok(AccountInfoLoad {
472 account: Cow::Owned(self.delegated_info.clone()),
473 is_cold: false,
474 is_empty: false,
475 })
476 } else if address == self.delegate {
477 Ok(AccountInfoLoad {
479 account: Cow::Owned(AccountInfo::default()),
480 is_cold: true,
481 is_empty: true,
482 })
483 } else {
484 Ok(Default::default())
485 }
486 }
487 }
488
489 #[test]
490 fn load_account_delegated_keeps_caller_is_empty_not_delegate() {
491 let mut host = Eip7702Host::new();
495 let load = host
496 .load_account_delegated(host.delegated)
497 .expect("delegated account loads");
498
499 assert!(
500 load.data.is_delegate_account_cold.is_some(),
501 "delegate account must be loaded"
502 );
503 assert!(
504 !load.data.is_empty,
505 "is_empty must stay false for the non-empty EIP-7702 account"
506 );
507 }
508}