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_eip8246_delayed_clear_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 fn is_amsterdam_eip8024_enabled(&self) -> bool {
471 self.cfg().is_amsterdam_eip8024_enabled()
472 }
473
474 fn block_number(&self) -> U256 {
475 self.block().number()
476 }
477
478 fn timestamp(&self) -> U256 {
479 U256::from(self.block().timestamp())
480 }
481
482 fn beneficiary(&self) -> Address {
483 self.block().beneficiary()
484 }
485
486 fn slot_num(&self) -> U256 {
487 U256::from(self.block().slot_num())
488 }
489
490 fn chain_id(&self) -> U256 {
491 U256::from(self.cfg().chain_id())
492 }
493
494 fn effective_gas_price(&self) -> U256 {
497 let basefee = self.block().basefee();
498 U256::from(self.tx().effective_gas_price(basefee as u128))
499 }
500
501 fn caller(&self) -> Address {
502 self.tx().caller()
503 }
504
505 fn blob_hash(&self, number: usize) -> Option<U256> {
506 let tx = &self.tx();
507 if tx.tx_type() != TransactionType::Eip4844 {
508 return None;
509 }
510 tx.blob_versioned_hashes()
511 .get(number)
512 .map(|t| U256::from_be_bytes(t.0))
513 }
514
515 fn max_initcode_size(&self) -> usize {
518 self.cfg().max_initcode_size()
519 }
520
521 fn block_hash(&mut self, requested_number: u64) -> Option<B256> {
524 self.db_mut()
525 .block_hash(requested_number)
526 .map_err(|e| {
527 cold_path();
528 *self.error() = Err(e.into());
529 })
530 .ok()
531 }
532
533 fn tload(&mut self, address: Address, index: StorageKey) -> StorageValue {
537 self.journal_mut().tload(address, index)
538 }
539
540 fn tstore(&mut self, address: Address, index: StorageKey, value: StorageValue) {
542 self.journal_mut().tstore(address, index, value)
543 }
544
545 fn log(&mut self, log: Log) {
547 self.journal_mut().log(log);
548 }
549
550 #[inline]
552 fn selfdestruct(
553 &mut self,
554 address: Address,
555 target: Address,
556 skip_cold_load: bool,
557 ) -> Result<StateLoad<SelfDestructResult>, LoadError> {
558 self.journal_mut()
559 .selfdestruct(address, target, skip_cold_load)
560 .map_err(|e| {
561 cold_path();
562 let (ret, err) = e.into_parts();
563 if let Some(err) = err {
564 *self.error() = Err(err.into());
565 }
566 ret
567 })
568 }
569
570 #[inline]
571 fn sstore_skip_cold_load(
572 &mut self,
573 address: Address,
574 key: StorageKey,
575 value: StorageValue,
576 skip_cold_load: bool,
577 ) -> Result<StateLoad<SStoreResult>, LoadError> {
578 self.journal_mut()
579 .sstore_skip_cold_load(address, key, value, skip_cold_load)
580 .map_err(|e| {
581 cold_path();
582 let (ret, err) = e.into_parts();
583 if let Some(err) = err {
584 *self.error() = Err(err.into());
585 }
586 ret
587 })
588 }
589
590 #[inline]
591 fn sload_skip_cold_load(
592 &mut self,
593 address: Address,
594 key: StorageKey,
595 skip_cold_load: bool,
596 ) -> Result<StateLoad<StorageValue>, LoadError> {
597 self.journal_mut()
598 .sload_skip_cold_load(address, key, skip_cold_load)
599 .map_err(|e| {
600 cold_path();
601 let (ret, err) = e.into_parts();
602 if let Some(err) = err {
603 *self.error() = Err(err.into());
604 }
605 ret
606 })
607 }
608
609 #[inline]
610 fn load_account_info_skip_cold_load(
611 &mut self,
612 address: Address,
613 load_code: bool,
614 skip_cold_load: bool,
615 ) -> Result<AccountInfoLoad<'_>, LoadError> {
616 match self.journaled_state.load_account_info_skip_cold_load(
617 address,
618 load_code,
619 skip_cold_load,
620 ) {
621 Ok(a) => Ok(a),
622 Err(e) => {
623 cold_path();
624 let (ret, err) = e.into_parts();
625 if let Some(err) = err {
626 self.error = Err(err.into());
627 }
628 Err(ret)
629 }
630 }
631 }
632}