1use crate::{block::BlockEnv, cfg::CfgEnv, journal::Journal, tx::TxEnv, LocalContext};
3use context_interface::{
4 cfg::GasParams,
5 context::{ContextError, ContextSetters, SStoreResult, SelfDestructResult, StateLoad},
6 host::LoadError,
7 journaled_state::AccountInfoLoad,
8 Block, Cfg, ContextTr, Host, JournalTr, LocalContextTr, Transaction, TransactionType,
9};
10use database_interface::{Database, DatabaseRef, EmptyDB, WrapDatabaseRef};
11use derive_where::derive_where;
12use primitives::{
13 hardfork::SpecId, hints_util::cold_path, Address, Log, StorageKey, StorageValue, B256, U256,
14};
15
16#[derive_where(Clone, Debug; BLOCK, CFG, CHAIN, TX, DB, JOURNAL, <DB as Database>::Error, LOCAL)]
18pub struct Context<
19 BLOCK = BlockEnv,
20 TX = TxEnv,
21 CFG = CfgEnv,
22 DB: Database = EmptyDB,
23 JOURNAL: JournalTr<Database = DB> = Journal<DB>,
24 CHAIN = (),
25 LOCAL: LocalContextTr = LocalContext,
26> {
27 pub block: BLOCK,
29 pub tx: TX,
31 pub cfg: CFG,
33 pub journaled_state: JOURNAL,
35 pub chain: CHAIN,
37 pub local: LOCAL,
39 pub error: Result<(), ContextError<DB::Error>>,
41}
42
43impl<
44 BLOCK: Block,
45 TX: Transaction,
46 DB: Database,
47 CFG: Cfg,
48 JOURNAL: JournalTr<Database = DB>,
49 CHAIN,
50 LOCAL: LocalContextTr,
51 > ContextTr for Context<BLOCK, TX, CFG, DB, JOURNAL, CHAIN, LOCAL>
52{
53 type Block = BLOCK;
54 type Tx = TX;
55 type Cfg = CFG;
56 type Db = DB;
57 type Journal = JOURNAL;
58 type Chain = CHAIN;
59 type Local = LOCAL;
60
61 #[inline]
62 fn all(
63 &self,
64 ) -> (
65 &Self::Block,
66 &Self::Tx,
67 &Self::Cfg,
68 &Self::Db,
69 &Self::Journal,
70 &Self::Chain,
71 &Self::Local,
72 ) {
73 let block = &self.block;
74 let tx = &self.tx;
75 let cfg = &self.cfg;
76 let db = self.journaled_state.db();
77 let journal = &self.journaled_state;
78 let chain = &self.chain;
79 let local = &self.local;
80
81 (block, tx, cfg, db, journal, chain, local)
82 }
83
84 #[inline]
85 fn all_mut(
86 &mut self,
87 ) -> (
88 &Self::Block,
89 &Self::Tx,
90 &Self::Cfg,
91 &mut Self::Journal,
92 &mut Self::Chain,
93 &mut Self::Local,
94 ) {
95 let block = &self.block;
96 let tx = &self.tx;
97 let cfg = &self.cfg;
98 let journal = &mut self.journaled_state;
99 let chain = &mut self.chain;
100 let local = &mut self.local;
101
102 (block, tx, cfg, journal, chain, local)
103 }
104
105 #[inline]
106 fn error(&mut self) -> &mut Result<(), ContextError<<Self::Db as Database>::Error>> {
107 &mut self.error
108 }
109}
110
111impl<
112 BLOCK: Block,
113 TX: Transaction,
114 DB: Database,
115 CFG: Cfg,
116 JOURNAL: JournalTr<Database = DB>,
117 CHAIN,
118 LOCAL: LocalContextTr,
119 > ContextSetters for Context<BLOCK, TX, CFG, DB, JOURNAL, CHAIN, LOCAL>
120{
121 fn set_tx(&mut self, tx: Self::Tx) {
122 self.tx = tx;
123 }
124
125 fn set_block(&mut self, block: Self::Block) {
126 self.block = block;
127 }
128}
129
130impl<
131 BLOCK: Block + Default,
132 TX: Transaction + Default,
133 DB: Database,
134 JOURNAL: JournalTr<Database = DB>,
135 CHAIN: Default,
136 LOCAL: LocalContextTr + Default,
137 SPEC: Default + Into<SpecId> + Clone,
138 > Context<BLOCK, TX, CfgEnv<SPEC>, DB, JOURNAL, CHAIN, LOCAL>
139{
140 pub fn new(db: DB, spec: SPEC) -> Self {
144 let cfg = CfgEnv::new_with_spec(spec);
145 let mut journaled_state = JOURNAL::new(db);
146 journaled_state.set_spec_id(cfg.spec.clone().into());
147 journaled_state.set_eip7708_config(
148 cfg.amsterdam_eip7708_disabled,
149 cfg.amsterdam_eip7708_delayed_burn_disabled,
150 );
151 Self {
152 tx: TX::default(),
153 block: BLOCK::default(),
154 cfg,
155 local: LOCAL::default(),
156 journaled_state,
157 chain: Default::default(),
158 error: Ok(()),
159 }
160 }
161}
162
163impl<BLOCK, TX, CFG, DB, JOURNAL, CHAIN, LOCAL> Context<BLOCK, TX, CFG, DB, JOURNAL, CHAIN, LOCAL>
164where
165 BLOCK: Block,
166 TX: Transaction,
167 CFG: Cfg,
168 DB: Database,
169 JOURNAL: JournalTr<Database = DB>,
170 LOCAL: LocalContextTr,
171{
172 pub fn with_new_journal<OJOURNAL: JournalTr<Database = DB>>(
174 self,
175 mut journal: OJOURNAL,
176 ) -> Context<BLOCK, TX, CFG, DB, OJOURNAL, CHAIN, LOCAL> {
177 journal.set_spec_id(self.cfg.spec().into());
178 journal.set_eip7708_config(
179 self.cfg.is_eip7708_disabled(),
180 self.cfg.is_eip7708_delayed_burn_disabled(),
181 );
182 Context {
183 tx: self.tx,
184 block: self.block,
185 cfg: self.cfg,
186 journaled_state: journal,
187 local: self.local,
188 chain: self.chain,
189 error: Ok(()),
190 }
191 }
192
193 pub fn with_db<ODB: Database>(
197 self,
198 db: ODB,
199 ) -> Context<BLOCK, TX, CFG, ODB, Journal<ODB>, CHAIN, LOCAL> {
200 let mut journaled_state = Journal::new(db);
201 journaled_state.set_spec_id(self.cfg.spec().into());
202 journaled_state.set_eip7708_config(
203 self.cfg.is_eip7708_disabled(),
204 self.cfg.is_eip7708_delayed_burn_disabled(),
205 );
206 Context {
207 tx: self.tx,
208 block: self.block,
209 cfg: self.cfg,
210 journaled_state,
211 local: self.local,
212 chain: self.chain,
213 error: Ok(()),
214 }
215 }
216
217 pub fn with_ref_db<ODB: DatabaseRef>(
219 self,
220 db: ODB,
221 ) -> Context<BLOCK, TX, CFG, WrapDatabaseRef<ODB>, Journal<WrapDatabaseRef<ODB>>, CHAIN, LOCAL>
222 {
223 let mut journaled_state = Journal::new(WrapDatabaseRef(db));
224 journaled_state.set_spec_id(self.cfg.spec().into());
225 journaled_state.set_eip7708_config(
226 self.cfg.is_eip7708_disabled(),
227 self.cfg.is_eip7708_delayed_burn_disabled(),
228 );
229 Context {
230 tx: self.tx,
231 block: self.block,
232 cfg: self.cfg,
233 journaled_state,
234 local: self.local,
235 chain: self.chain,
236 error: Ok(()),
237 }
238 }
239
240 pub fn with_block<OB: Block>(
242 self,
243 block: OB,
244 ) -> Context<OB, TX, CFG, DB, JOURNAL, CHAIN, LOCAL> {
245 Context {
246 tx: self.tx,
247 block,
248 cfg: self.cfg,
249 journaled_state: self.journaled_state,
250 local: self.local,
251 chain: self.chain,
252 error: Ok(()),
253 }
254 }
255 pub fn with_tx<OTX: Transaction>(
257 self,
258 tx: OTX,
259 ) -> Context<BLOCK, OTX, CFG, DB, JOURNAL, CHAIN, LOCAL> {
260 Context {
261 tx,
262 block: self.block,
263 cfg: self.cfg,
264 journaled_state: self.journaled_state,
265 local: self.local,
266 chain: self.chain,
267 error: Ok(()),
268 }
269 }
270
271 pub fn with_chain<OC>(self, chain: OC) -> Context<BLOCK, TX, CFG, DB, JOURNAL, OC, LOCAL> {
273 Context {
274 tx: self.tx,
275 block: self.block,
276 cfg: self.cfg,
277 journaled_state: self.journaled_state,
278 local: self.local,
279 chain,
280 error: Ok(()),
281 }
282 }
283
284 pub fn with_cfg<OCFG: Cfg>(
286 mut self,
287 cfg: OCFG,
288 ) -> Context<BLOCK, TX, OCFG, DB, JOURNAL, CHAIN, LOCAL> {
289 self.journaled_state.set_spec_id(cfg.spec().into());
290 self.journaled_state.set_eip7708_config(
291 cfg.is_eip7708_disabled(),
292 cfg.is_eip7708_delayed_burn_disabled(),
293 );
294 Context {
295 tx: self.tx,
296 block: self.block,
297 cfg,
298 journaled_state: self.journaled_state,
299 local: self.local,
300 chain: self.chain,
301 error: Ok(()),
302 }
303 }
304
305 pub fn with_local<OL: LocalContextTr>(
307 self,
308 local: OL,
309 ) -> Context<BLOCK, TX, CFG, DB, JOURNAL, CHAIN, OL> {
310 Context {
311 tx: self.tx,
312 block: self.block,
313 cfg: self.cfg,
314 journaled_state: self.journaled_state,
315 local,
316 chain: self.chain,
317 error: Ok(()),
318 }
319 }
320
321 #[must_use]
323 pub fn modify_cfg_chained<F>(mut self, f: F) -> Self
324 where
325 F: FnOnce(&mut CFG),
326 {
327 f(&mut self.cfg);
328 self.journaled_state.set_spec_id(self.cfg.spec().into());
329 self.journaled_state.set_eip7708_config(
330 self.cfg.is_eip7708_disabled(),
331 self.cfg.is_eip7708_delayed_burn_disabled(),
332 );
333 self
334 }
335
336 #[must_use]
338 pub fn modify_block_chained<F>(mut self, f: F) -> Self
339 where
340 F: FnOnce(&mut BLOCK),
341 {
342 self.modify_block(f);
343 self
344 }
345
346 #[must_use]
348 pub fn modify_tx_chained<F>(mut self, f: F) -> Self
349 where
350 F: FnOnce(&mut TX),
351 {
352 self.modify_tx(f);
353 self
354 }
355
356 #[must_use]
358 pub fn modify_chain_chained<F>(mut self, f: F) -> Self
359 where
360 F: FnOnce(&mut CHAIN),
361 {
362 self.modify_chain(f);
363 self
364 }
365
366 #[must_use]
368 pub fn modify_db_chained<F>(mut self, f: F) -> Self
369 where
370 F: FnOnce(&mut DB),
371 {
372 self.modify_db(f);
373 self
374 }
375
376 #[must_use]
378 pub fn modify_journal_chained<F>(mut self, f: F) -> Self
379 where
380 F: FnOnce(&mut JOURNAL),
381 {
382 self.modify_journal(f);
383 self
384 }
385
386 pub fn modify_block<F>(&mut self, f: F)
388 where
389 F: FnOnce(&mut BLOCK),
390 {
391 f(&mut self.block);
392 }
393
394 pub fn modify_tx<F>(&mut self, f: F)
396 where
397 F: FnOnce(&mut TX),
398 {
399 f(&mut self.tx);
400 }
401
402 pub fn modify_cfg<F>(&mut self, f: F)
404 where
405 F: FnOnce(&mut CFG),
406 {
407 f(&mut self.cfg);
408 self.journaled_state.set_spec_id(self.cfg.spec().into());
409 self.journaled_state.set_eip7708_config(
410 self.cfg.is_eip7708_disabled(),
411 self.cfg.is_eip7708_delayed_burn_disabled(),
412 );
413 }
414
415 pub fn modify_chain<F>(&mut self, f: F)
417 where
418 F: FnOnce(&mut CHAIN),
419 {
420 f(&mut self.chain);
421 }
422
423 pub fn modify_db<F>(&mut self, f: F)
425 where
426 F: FnOnce(&mut DB),
427 {
428 f(self.journaled_state.db_mut());
429 }
430
431 pub fn modify_journal<F>(&mut self, f: F)
433 where
434 F: FnOnce(&mut JOURNAL),
435 {
436 f(&mut self.journaled_state);
437 }
438
439 pub fn modify_local<F>(&mut self, f: F)
441 where
442 F: FnOnce(&mut LOCAL),
443 {
444 f(&mut self.local);
445 }
446}
447
448impl<
449 BLOCK: Block,
450 TX: Transaction,
451 CFG: Cfg,
452 DB: Database,
453 JOURNAL: JournalTr<Database = DB>,
454 CHAIN,
455 LOCAL: LocalContextTr,
456 > Host for Context<BLOCK, TX, CFG, DB, JOURNAL, CHAIN, LOCAL>
457{
458 fn basefee(&self) -> U256 {
461 U256::from(self.block().basefee())
462 }
463
464 fn blob_gasprice(&self) -> U256 {
465 U256::from(self.block().blob_gasprice().unwrap_or(0))
466 }
467
468 fn gas_limit(&self) -> U256 {
469 U256::from(self.block().gas_limit())
470 }
471
472 fn difficulty(&self) -> U256 {
473 self.block().difficulty()
474 }
475
476 fn prevrandao(&self) -> Option<U256> {
477 self.block().prevrandao().map(|r| r.into())
478 }
479
480 #[inline]
481 fn gas_params(&self) -> &GasParams {
482 self.cfg().gas_params()
483 }
484
485 fn block_number(&self) -> U256 {
486 self.block().number()
487 }
488
489 fn timestamp(&self) -> U256 {
490 U256::from(self.block().timestamp())
491 }
492
493 fn beneficiary(&self) -> Address {
494 self.block().beneficiary()
495 }
496
497 fn slot_num(&self) -> U256 {
498 U256::from(self.block().slot_num())
499 }
500
501 fn chain_id(&self) -> U256 {
502 U256::from(self.cfg().chain_id())
503 }
504
505 fn effective_gas_price(&self) -> U256 {
508 let basefee = self.block().basefee();
509 U256::from(self.tx().effective_gas_price(basefee as u128))
510 }
511
512 fn caller(&self) -> Address {
513 self.tx().caller()
514 }
515
516 fn blob_hash(&self, number: usize) -> Option<U256> {
517 let tx = &self.tx();
518 if tx.tx_type() != TransactionType::Eip4844 {
519 return None;
520 }
521 tx.blob_versioned_hashes()
522 .get(number)
523 .map(|t| U256::from_be_bytes(t.0))
524 }
525
526 fn max_initcode_size(&self) -> usize {
529 self.cfg().max_initcode_size()
530 }
531
532 fn block_hash(&mut self, requested_number: u64) -> Option<B256> {
535 self.db_mut()
536 .block_hash(requested_number)
537 .map_err(|e| {
538 cold_path();
539 *self.error() = Err(e.into());
540 })
541 .ok()
542 }
543
544 fn tload(&mut self, address: Address, index: StorageKey) -> StorageValue {
548 self.journal_mut().tload(address, index)
549 }
550
551 fn tstore(&mut self, address: Address, index: StorageKey, value: StorageValue) {
553 self.journal_mut().tstore(address, index, value)
554 }
555
556 fn log(&mut self, log: Log) {
558 self.journal_mut().log(log);
559 }
560
561 #[inline]
563 fn selfdestruct(
564 &mut self,
565 address: Address,
566 target: Address,
567 skip_cold_load: bool,
568 ) -> Result<StateLoad<SelfDestructResult>, LoadError> {
569 self.journal_mut()
570 .selfdestruct(address, target, skip_cold_load)
571 .map_err(|e| {
572 cold_path();
573 let (ret, err) = e.into_parts();
574 if let Some(err) = err {
575 *self.error() = Err(err.into());
576 }
577 ret
578 })
579 }
580
581 #[inline]
582 fn sstore_skip_cold_load(
583 &mut self,
584 address: Address,
585 key: StorageKey,
586 value: StorageValue,
587 skip_cold_load: bool,
588 ) -> Result<StateLoad<SStoreResult>, LoadError> {
589 self.journal_mut()
590 .sstore_skip_cold_load(address, key, value, skip_cold_load)
591 .map_err(|e| {
592 cold_path();
593 let (ret, err) = e.into_parts();
594 if let Some(err) = err {
595 *self.error() = Err(err.into());
596 }
597 ret
598 })
599 }
600
601 #[inline]
602 fn sload_skip_cold_load(
603 &mut self,
604 address: Address,
605 key: StorageKey,
606 skip_cold_load: bool,
607 ) -> Result<StateLoad<StorageValue>, LoadError> {
608 self.journal_mut()
609 .sload_skip_cold_load(address, key, skip_cold_load)
610 .map_err(|e| {
611 cold_path();
612 let (ret, err) = e.into_parts();
613 if let Some(err) = err {
614 *self.error() = Err(err.into());
615 }
616 ret
617 })
618 }
619
620 #[inline]
621 fn load_account_info_skip_cold_load(
622 &mut self,
623 address: Address,
624 load_code: bool,
625 skip_cold_load: bool,
626 ) -> Result<AccountInfoLoad<'_>, LoadError> {
627 match self.journaled_state.load_account_info_skip_cold_load(
628 address,
629 load_code,
630 skip_cold_load,
631 ) {
632 Ok(a) => Ok(a),
633 Err(e) => {
634 cold_path();
635 let (ret, err) = e.into_parts();
636 if let Some(err) = err {
637 self.error = Err(err.into());
638 }
639 Err(ret)
640 }
641 }
642 }
643}