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