1use crate::{block::BlockEnv, cfg::CfgEnv, journal::Journal, tx::TxEnv, LocalContext};
3use context_interface::{
4 context::{ContextError, ContextSetters, SStoreResult, SelfDestructResult, StateLoad},
5 host::LoadError,
6 journaled_state::AccountInfoLoad,
7 Block, Cfg, ContextTr, Host, JournalTr, LocalContextTr, Transaction, TransactionType,
8};
9use database_interface::{Database, DatabaseRef, EmptyDB, WrapDatabaseRef};
10use derive_where::derive_where;
11use primitives::{hardfork::SpecId, Address, Log, StorageKey, StorageValue, B256, U256};
12
13#[derive_where(Clone, Debug; BLOCK, CFG, CHAIN, TX, DB, JOURNAL, <DB as Database>::Error, LOCAL)]
15pub struct Context<
16 BLOCK = BlockEnv,
17 TX = TxEnv,
18 CFG = CfgEnv,
19 DB: Database = EmptyDB,
20 JOURNAL: JournalTr<Database = DB> = Journal<DB>,
21 CHAIN = (),
22 LOCAL: LocalContextTr = LocalContext,
23> {
24 pub block: BLOCK,
26 pub tx: TX,
28 pub cfg: CFG,
30 pub journaled_state: JOURNAL,
32 pub chain: CHAIN,
34 pub local: LOCAL,
36 pub error: Result<(), ContextError<DB::Error>>,
38}
39
40impl<
41 BLOCK: Block,
42 TX: Transaction,
43 DB: Database,
44 CFG: Cfg,
45 JOURNAL: JournalTr<Database = DB>,
46 CHAIN,
47 LOCAL: LocalContextTr,
48 > ContextTr for Context<BLOCK, TX, CFG, DB, JOURNAL, CHAIN, LOCAL>
49{
50 type Block = BLOCK;
51 type Tx = TX;
52 type Cfg = CFG;
53 type Db = DB;
54 type Journal = JOURNAL;
55 type Chain = CHAIN;
56 type Local = LOCAL;
57
58 #[inline]
59 fn tx(&self) -> &Self::Tx {
60 &self.tx
61 }
62
63 #[inline]
64 fn block(&self) -> &Self::Block {
65 &self.block
66 }
67
68 #[inline]
69 fn cfg(&self) -> &Self::Cfg {
70 &self.cfg
71 }
72
73 #[inline]
74 fn journal(&self) -> &Self::Journal {
75 &self.journaled_state
76 }
77
78 #[inline]
79 fn journal_mut(&mut self) -> &mut Self::Journal {
80 &mut self.journaled_state
81 }
82
83 #[inline]
84 fn journal_ref(&self) -> &Self::Journal {
85 &self.journaled_state
86 }
87
88 #[inline]
89 fn db(&self) -> &Self::Db {
90 self.journaled_state.db()
91 }
92
93 #[inline]
94 fn db_mut(&mut self) -> &mut Self::Db {
95 self.journaled_state.db_mut()
96 }
97
98 #[inline]
99 fn chain(&self) -> &Self::Chain {
100 &self.chain
101 }
102
103 #[inline]
104 fn chain_mut(&mut self) -> &mut Self::Chain {
105 &mut self.chain
106 }
107
108 #[inline]
109 fn local(&self) -> &Self::Local {
110 &self.local
111 }
112
113 #[inline]
114 fn local_mut(&mut self) -> &mut Self::Local {
115 &mut self.local
116 }
117
118 #[inline]
119 fn error(&mut self) -> &mut Result<(), ContextError<<Self::Db as Database>::Error>> {
120 &mut self.error
121 }
122
123 #[inline]
124 fn tx_journal_mut(&mut self) -> (&Self::Tx, &mut Self::Journal) {
125 (&self.tx, &mut self.journaled_state)
126 }
127
128 #[inline]
129 fn tx_local_mut(&mut self) -> (&Self::Tx, &mut Self::Local) {
130 (&self.tx, &mut self.local)
131 }
132}
133
134impl<
135 BLOCK: Block,
136 TX: Transaction,
137 DB: Database,
138 CFG: Cfg,
139 JOURNAL: JournalTr<Database = DB>,
140 CHAIN,
141 LOCAL: LocalContextTr,
142 > ContextSetters for Context<BLOCK, TX, CFG, DB, JOURNAL, CHAIN, LOCAL>
143{
144 fn set_tx(&mut self, tx: Self::Tx) {
145 self.tx = tx;
146 }
147
148 fn set_block(&mut self, block: Self::Block) {
149 self.block = block;
150 }
151}
152
153impl<
154 BLOCK: Block + Default,
155 TX: Transaction + Default,
156 DB: Database,
157 JOURNAL: JournalTr<Database = DB>,
158 CHAIN: Default,
159 LOCAL: LocalContextTr + Default,
160 > Context<BLOCK, TX, CfgEnv, DB, JOURNAL, CHAIN, LOCAL>
161{
162 pub fn new(db: DB, spec: SpecId) -> Self {
166 let mut journaled_state = JOURNAL::new(db);
167 journaled_state.set_spec_id(spec);
168 Self {
169 tx: TX::default(),
170 block: BLOCK::default(),
171 cfg: CfgEnv {
172 spec,
173 ..Default::default()
174 },
175 local: LOCAL::default(),
176 journaled_state,
177 chain: Default::default(),
178 error: Ok(()),
179 }
180 }
181}
182
183impl<BLOCK, TX, CFG, DB, JOURNAL, CHAIN, LOCAL> Context<BLOCK, TX, CFG, DB, JOURNAL, CHAIN, LOCAL>
184where
185 BLOCK: Block,
186 TX: Transaction,
187 CFG: Cfg,
188 DB: Database,
189 JOURNAL: JournalTr<Database = DB>,
190 LOCAL: LocalContextTr,
191{
192 pub fn with_new_journal<OJOURNAL: JournalTr<Database = DB>>(
194 self,
195 mut journal: OJOURNAL,
196 ) -> Context<BLOCK, TX, CFG, DB, OJOURNAL, CHAIN, LOCAL> {
197 journal.set_spec_id(self.cfg.spec().into());
198 Context {
199 tx: self.tx,
200 block: self.block,
201 cfg: self.cfg,
202 journaled_state: journal,
203 local: self.local,
204 chain: self.chain,
205 error: Ok(()),
206 }
207 }
208
209 pub fn with_db<ODB: Database>(
213 self,
214 db: ODB,
215 ) -> Context<BLOCK, TX, CFG, ODB, Journal<ODB>, CHAIN, LOCAL> {
216 let spec = self.cfg.spec().into();
217 let mut journaled_state = Journal::new(db);
218 journaled_state.set_spec_id(spec);
219 Context {
220 tx: self.tx,
221 block: self.block,
222 cfg: self.cfg,
223 journaled_state,
224 local: self.local,
225 chain: self.chain,
226 error: Ok(()),
227 }
228 }
229
230 pub fn with_ref_db<ODB: DatabaseRef>(
232 self,
233 db: ODB,
234 ) -> Context<BLOCK, TX, CFG, WrapDatabaseRef<ODB>, Journal<WrapDatabaseRef<ODB>>, CHAIN, LOCAL>
235 {
236 let spec = self.cfg.spec().into();
237 let mut journaled_state = Journal::new(WrapDatabaseRef(db));
238 journaled_state.set_spec_id(spec);
239 Context {
240 tx: self.tx,
241 block: self.block,
242 cfg: self.cfg,
243 journaled_state,
244 local: self.local,
245 chain: self.chain,
246 error: Ok(()),
247 }
248 }
249
250 pub fn with_block<OB: Block>(
252 self,
253 block: OB,
254 ) -> Context<OB, TX, CFG, DB, JOURNAL, CHAIN, LOCAL> {
255 Context {
256 tx: self.tx,
257 block,
258 cfg: self.cfg,
259 journaled_state: self.journaled_state,
260 local: self.local,
261 chain: self.chain,
262 error: Ok(()),
263 }
264 }
265 pub fn with_tx<OTX: Transaction>(
267 self,
268 tx: OTX,
269 ) -> Context<BLOCK, OTX, CFG, DB, JOURNAL, CHAIN, LOCAL> {
270 Context {
271 tx,
272 block: self.block,
273 cfg: self.cfg,
274 journaled_state: self.journaled_state,
275 local: self.local,
276 chain: self.chain,
277 error: Ok(()),
278 }
279 }
280
281 pub fn with_chain<OC>(self, chain: OC) -> Context<BLOCK, TX, CFG, DB, JOURNAL, OC, LOCAL> {
283 Context {
284 tx: self.tx,
285 block: self.block,
286 cfg: self.cfg,
287 journaled_state: self.journaled_state,
288 local: self.local,
289 chain,
290 error: Ok(()),
291 }
292 }
293
294 pub fn with_cfg<OCFG: Cfg>(
296 mut self,
297 cfg: OCFG,
298 ) -> Context<BLOCK, TX, OCFG, DB, JOURNAL, CHAIN, LOCAL> {
299 self.journaled_state.set_spec_id(cfg.spec().into());
300 Context {
301 tx: self.tx,
302 block: self.block,
303 cfg,
304 journaled_state: self.journaled_state,
305 local: self.local,
306 chain: self.chain,
307 error: Ok(()),
308 }
309 }
310
311 pub fn with_local<OL: LocalContextTr>(
313 self,
314 local: OL,
315 ) -> Context<BLOCK, TX, CFG, DB, JOURNAL, CHAIN, OL> {
316 Context {
317 tx: self.tx,
318 block: self.block,
319 cfg: self.cfg,
320 journaled_state: self.journaled_state,
321 local,
322 chain: self.chain,
323 error: Ok(()),
324 }
325 }
326
327 #[must_use]
329 pub fn modify_cfg_chained<F>(mut self, f: F) -> Self
330 where
331 F: FnOnce(&mut CFG),
332 {
333 f(&mut self.cfg);
334 self.journaled_state.set_spec_id(self.cfg.spec().into());
335 self
336 }
337
338 #[must_use]
340 pub fn modify_block_chained<F>(mut self, f: F) -> Self
341 where
342 F: FnOnce(&mut BLOCK),
343 {
344 self.modify_block(f);
345 self
346 }
347
348 #[must_use]
350 pub fn modify_tx_chained<F>(mut self, f: F) -> Self
351 where
352 F: FnOnce(&mut TX),
353 {
354 self.modify_tx(f);
355 self
356 }
357
358 #[must_use]
360 pub fn modify_chain_chained<F>(mut self, f: F) -> Self
361 where
362 F: FnOnce(&mut CHAIN),
363 {
364 self.modify_chain(f);
365 self
366 }
367
368 #[must_use]
370 pub fn modify_db_chained<F>(mut self, f: F) -> Self
371 where
372 F: FnOnce(&mut DB),
373 {
374 self.modify_db(f);
375 self
376 }
377
378 #[must_use]
380 pub fn modify_journal_chained<F>(mut self, f: F) -> Self
381 where
382 F: FnOnce(&mut JOURNAL),
383 {
384 self.modify_journal(f);
385 self
386 }
387
388 pub fn modify_block<F>(&mut self, f: F)
390 where
391 F: FnOnce(&mut BLOCK),
392 {
393 f(&mut self.block);
394 }
395
396 pub fn modify_tx<F>(&mut self, f: F)
398 where
399 F: FnOnce(&mut TX),
400 {
401 f(&mut self.tx);
402 }
403
404 pub fn modify_cfg<F>(&mut self, f: F)
406 where
407 F: FnOnce(&mut CFG),
408 {
409 f(&mut self.cfg);
410 self.journaled_state.set_spec_id(self.cfg.spec().into());
411 }
412
413 pub fn modify_chain<F>(&mut self, f: F)
415 where
416 F: FnOnce(&mut CHAIN),
417 {
418 f(&mut self.chain);
419 }
420
421 pub fn modify_db<F>(&mut self, f: F)
423 where
424 F: FnOnce(&mut DB),
425 {
426 f(self.journaled_state.db_mut());
427 }
428
429 pub fn modify_journal<F>(&mut self, f: F)
431 where
432 F: FnOnce(&mut JOURNAL),
433 {
434 f(&mut self.journaled_state);
435 }
436
437 pub fn modify_local<F>(&mut self, f: F)
439 where
440 F: FnOnce(&mut LOCAL),
441 {
442 f(&mut self.local);
443 }
444}
445
446impl<
447 BLOCK: Block,
448 TX: Transaction,
449 CFG: Cfg,
450 DB: Database,
451 JOURNAL: JournalTr<Database = DB>,
452 CHAIN,
453 LOCAL: LocalContextTr,
454 > Host for Context<BLOCK, TX, CFG, DB, JOURNAL, CHAIN, LOCAL>
455{
456 fn basefee(&self) -> U256 {
459 U256::from(self.block().basefee())
460 }
461
462 fn blob_gasprice(&self) -> U256 {
463 U256::from(self.block().blob_gasprice().unwrap_or(0))
464 }
465
466 fn gas_limit(&self) -> U256 {
467 U256::from(self.block().gas_limit())
468 }
469
470 fn difficulty(&self) -> U256 {
471 self.block().difficulty()
472 }
473
474 fn prevrandao(&self) -> Option<U256> {
475 self.block().prevrandao().map(|r| r.into())
476 }
477
478 fn block_number(&self) -> U256 {
479 self.block().number()
480 }
481
482 fn timestamp(&self) -> U256 {
483 U256::from(self.block().timestamp())
484 }
485
486 fn beneficiary(&self) -> Address {
487 self.block().beneficiary()
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 *self.error() = Err(e.into());
528 })
529 .ok()
530 }
531
532 fn tload(&mut self, address: Address, index: StorageKey) -> StorageValue {
536 self.journal_mut().tload(address, index)
537 }
538
539 fn tstore(&mut self, address: Address, index: StorageKey, value: StorageValue) {
541 self.journal_mut().tstore(address, index, value)
542 }
543
544 fn log(&mut self, log: Log) {
546 self.journal_mut().log(log);
547 }
548
549 fn selfdestruct(
551 &mut self,
552 address: Address,
553 target: Address,
554 ) -> Option<StateLoad<SelfDestructResult>> {
555 self.journal_mut()
556 .selfdestruct(address, target)
557 .map_err(|e| {
558 *self.error() = Err(e.into());
559 })
560 .ok()
561 }
562
563 fn sstore_skip_cold_load(
564 &mut self,
565 address: Address,
566 key: StorageKey,
567 value: StorageValue,
568 skip_cold_load: bool,
569 ) -> Result<StateLoad<SStoreResult>, LoadError> {
570 self.journal_mut()
571 .sstore_skip_cold_load(address, key, value, skip_cold_load)
572 .map_err(|e| {
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 fn sload_skip_cold_load(
582 &mut self,
583 address: Address,
584 key: StorageKey,
585 skip_cold_load: bool,
586 ) -> Result<StateLoad<StorageValue>, LoadError> {
587 self.journal_mut()
588 .sload_skip_cold_load(address, key, skip_cold_load)
589 .map_err(|e| {
590 let (ret, err) = e.into_parts();
591 if let Some(err) = err {
592 *self.error() = Err(err.into());
593 }
594 ret
595 })
596 }
597
598 fn load_account_info_skip_cold_load(
599 &mut self,
600 address: Address,
601 load_code: bool,
602 skip_cold_load: bool,
603 ) -> Result<AccountInfoLoad<'_>, LoadError> {
604 let error = &mut self.error;
605 let journal = &mut self.journaled_state;
606 match journal.load_account_info_skip_cold_load(address, load_code, skip_cold_load) {
607 Ok(a) => Ok(a),
608 Err(e) => {
609 let (ret, err) = e.into_parts();
610 if let Some(err) = err {
611 *error = Err(err.into());
612 }
613 Err(ret)
614 }
615 }
616 }
617}