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 spec: SpecId,
214}
215
216impl DummyHost {
217 pub fn new(spec: SpecId) -> Self {
219 Self {
220 gas_params: GasParams::new_spec(spec),
221 spec,
222 }
223 }
224}
225
226impl Host for DummyHost {
227 fn basefee(&self) -> U256 {
228 U256::ZERO
229 }
230
231 fn blob_gasprice(&self) -> U256 {
232 U256::ZERO
233 }
234
235 fn gas_limit(&self) -> U256 {
236 U256::ZERO
237 }
238
239 fn gas_params(&self) -> &GasParams {
240 &self.gas_params
241 }
242
243 fn is_amsterdam_eip8037_enabled(&self) -> bool {
244 self.spec.is_enabled_in(SpecId::AMSTERDAM)
245 }
246
247 fn difficulty(&self) -> U256 {
248 U256::ZERO
249 }
250
251 fn prevrandao(&self) -> Option<U256> {
252 None
253 }
254
255 fn block_number(&self) -> U256 {
256 U256::ZERO
257 }
258
259 fn timestamp(&self) -> U256 {
260 U256::ZERO
261 }
262
263 fn beneficiary(&self) -> Address {
264 Address::ZERO
265 }
266
267 fn slot_num(&self) -> U256 {
268 U256::ZERO
269 }
270
271 fn chain_id(&self) -> U256 {
272 U256::ZERO
273 }
274
275 fn effective_gas_price(&self) -> U256 {
276 U256::ZERO
277 }
278
279 fn caller(&self) -> Address {
280 Address::ZERO
281 }
282
283 fn blob_hash(&self, _number: usize) -> Option<U256> {
284 None
285 }
286
287 fn max_initcode_size(&self) -> usize {
288 0
289 }
290
291 fn block_hash(&mut self, _number: u64) -> Option<B256> {
292 None
293 }
294
295 fn selfdestruct(
296 &mut self,
297 _address: Address,
298 _target: Address,
299 _skip_cold_load: bool,
300 ) -> Result<StateLoad<SelfDestructResult>, LoadError> {
301 Ok(Default::default())
302 }
303
304 fn log(&mut self, _log: Log) {}
305
306 fn tstore(&mut self, _address: Address, _key: StorageKey, _value: StorageValue) {}
307
308 fn tload(&mut self, _address: Address, _key: StorageKey) -> StorageValue {
309 StorageValue::ZERO
310 }
311
312 fn load_account_info_skip_cold_load(
313 &mut self,
314 _address: Address,
315 _load_code: bool,
316 _skip_cold_load: bool,
317 ) -> Result<AccountInfoLoad<'_>, LoadError> {
318 Ok(Default::default())
319 }
320
321 fn sstore_skip_cold_load(
322 &mut self,
323 _address: Address,
324 _key: StorageKey,
325 _value: StorageValue,
326 _skip_cold_load: bool,
327 ) -> Result<StateLoad<SStoreResult>, LoadError> {
328 Ok(Default::default())
329 }
330
331 fn sload_skip_cold_load(
332 &mut self,
333 _address: Address,
334 _key: StorageKey,
335 _skip_cold_load: bool,
336 ) -> Result<StateLoad<StorageValue>, LoadError> {
337 Ok(Default::default())
338 }
339}
340
341#[cfg(test)]
342mod tests {
343 use super::*;
344 use primitives::{hardfork::SpecId, Address, U256};
345 use state::{AccountInfo, Bytecode};
346 use std::borrow::Cow;
347
348 struct Eip7702Host {
352 dummy: DummyHost,
353 delegated: Address,
354 delegate: Address,
355 delegated_info: AccountInfo,
356 }
357
358 impl Eip7702Host {
359 fn new() -> Self {
360 let delegated = Address::repeat_byte(0x11);
361 let delegate = Address::repeat_byte(0x22);
362 let delegated_info = AccountInfo::new(
363 U256::from(1),
364 1,
365 B256::ZERO,
366 Bytecode::new_eip7702(delegate),
367 );
368 Self {
369 dummy: DummyHost::new(SpecId::PRAGUE),
370 delegated,
371 delegate,
372 delegated_info,
373 }
374 }
375 }
376
377 impl Host for Eip7702Host {
378 fn basefee(&self) -> U256 {
379 self.dummy.basefee()
380 }
381 fn blob_gasprice(&self) -> U256 {
382 self.dummy.blob_gasprice()
383 }
384 fn gas_limit(&self) -> U256 {
385 self.dummy.gas_limit()
386 }
387 fn gas_params(&self) -> &GasParams {
388 self.dummy.gas_params()
389 }
390 fn is_amsterdam_eip8037_enabled(&self) -> bool {
391 self.dummy.is_amsterdam_eip8037_enabled()
392 }
393 fn difficulty(&self) -> U256 {
394 self.dummy.difficulty()
395 }
396 fn prevrandao(&self) -> Option<U256> {
397 self.dummy.prevrandao()
398 }
399 fn block_number(&self) -> U256 {
400 self.dummy.block_number()
401 }
402 fn timestamp(&self) -> U256 {
403 self.dummy.timestamp()
404 }
405 fn beneficiary(&self) -> Address {
406 self.dummy.beneficiary()
407 }
408 fn slot_num(&self) -> U256 {
409 self.dummy.slot_num()
410 }
411 fn chain_id(&self) -> U256 {
412 self.dummy.chain_id()
413 }
414 fn effective_gas_price(&self) -> U256 {
415 self.dummy.effective_gas_price()
416 }
417 fn caller(&self) -> Address {
418 self.dummy.caller()
419 }
420 fn blob_hash(&self, number: usize) -> Option<U256> {
421 self.dummy.blob_hash(number)
422 }
423 fn max_initcode_size(&self) -> usize {
424 self.dummy.max_initcode_size()
425 }
426 fn block_hash(&mut self, number: u64) -> Option<B256> {
427 self.dummy.block_hash(number)
428 }
429 fn selfdestruct(
430 &mut self,
431 address: Address,
432 target: Address,
433 skip_cold_load: bool,
434 ) -> Result<StateLoad<SelfDestructResult>, LoadError> {
435 self.dummy.selfdestruct(address, target, skip_cold_load)
436 }
437 fn log(&mut self, log: Log) {
438 self.dummy.log(log)
439 }
440 fn tstore(&mut self, address: Address, key: StorageKey, value: StorageValue) {
441 self.dummy.tstore(address, key, value)
442 }
443 fn tload(&mut self, address: Address, key: StorageKey) -> StorageValue {
444 self.dummy.tload(address, key)
445 }
446 fn sstore_skip_cold_load(
447 &mut self,
448 address: Address,
449 key: StorageKey,
450 value: StorageValue,
451 skip_cold_load: bool,
452 ) -> Result<StateLoad<SStoreResult>, LoadError> {
453 self.dummy
454 .sstore_skip_cold_load(address, key, value, skip_cold_load)
455 }
456 fn sload_skip_cold_load(
457 &mut self,
458 address: Address,
459 key: StorageKey,
460 skip_cold_load: bool,
461 ) -> Result<StateLoad<StorageValue>, LoadError> {
462 self.dummy
463 .sload_skip_cold_load(address, key, skip_cold_load)
464 }
465
466 fn load_account_info_skip_cold_load(
467 &mut self,
468 address: Address,
469 _load_code: bool,
470 _skip_cold_load: bool,
471 ) -> Result<AccountInfoLoad<'_>, LoadError> {
472 if address == self.delegated {
473 Ok(AccountInfoLoad {
474 account: Cow::Owned(self.delegated_info.clone()),
475 is_cold: false,
476 is_empty: false,
477 })
478 } else if address == self.delegate {
479 Ok(AccountInfoLoad {
481 account: Cow::Owned(AccountInfo::default()),
482 is_cold: true,
483 is_empty: true,
484 })
485 } else {
486 Ok(Default::default())
487 }
488 }
489 }
490
491 #[test]
492 fn load_account_delegated_keeps_caller_is_empty_not_delegate() {
493 let mut host = Eip7702Host::new();
497 let load = host
498 .load_account_delegated(host.delegated)
499 .expect("delegated account loads");
500
501 assert!(
502 load.data.is_delegate_account_cold.is_some(),
503 "delegate account must be loaded"
504 );
505 assert!(
506 !load.data.is_empty,
507 "is_empty must stay false for the non-empty EIP-7702 account"
508 );
509 }
510}