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