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 mut journaled_state = JOURNAL::new(db);
145 journaled_state.set_spec_id(spec.clone().into());
146 Self {
147 tx: TX::default(),
148 block: BLOCK::default(),
149 cfg: CfgEnv::new_with_spec(spec),
150 local: LOCAL::default(),
151 journaled_state,
152 chain: Default::default(),
153 error: Ok(()),
154 }
155 }
156}
157
158impl<BLOCK, TX, CFG, DB, JOURNAL, CHAIN, LOCAL> Context<BLOCK, TX, CFG, DB, JOURNAL, CHAIN, LOCAL>
159where
160 BLOCK: Block,
161 TX: Transaction,
162 CFG: Cfg,
163 DB: Database,
164 JOURNAL: JournalTr<Database = DB>,
165 LOCAL: LocalContextTr,
166{
167 pub fn with_new_journal<OJOURNAL: JournalTr<Database = DB>>(
169 self,
170 mut journal: OJOURNAL,
171 ) -> Context<BLOCK, TX, CFG, DB, OJOURNAL, CHAIN, LOCAL> {
172 journal.set_spec_id(self.cfg.spec().into());
173 Context {
174 tx: self.tx,
175 block: self.block,
176 cfg: self.cfg,
177 journaled_state: journal,
178 local: self.local,
179 chain: self.chain,
180 error: Ok(()),
181 }
182 }
183
184 pub fn with_db<ODB: Database>(
188 self,
189 db: ODB,
190 ) -> Context<BLOCK, TX, CFG, ODB, Journal<ODB>, CHAIN, LOCAL> {
191 let spec = self.cfg.spec().into();
192 let mut journaled_state = Journal::new(db);
193 journaled_state.set_spec_id(spec);
194 Context {
195 tx: self.tx,
196 block: self.block,
197 cfg: self.cfg,
198 journaled_state,
199 local: self.local,
200 chain: self.chain,
201 error: Ok(()),
202 }
203 }
204
205 pub fn with_ref_db<ODB: DatabaseRef>(
207 self,
208 db: ODB,
209 ) -> Context<BLOCK, TX, CFG, WrapDatabaseRef<ODB>, Journal<WrapDatabaseRef<ODB>>, CHAIN, LOCAL>
210 {
211 let spec = self.cfg.spec().into();
212 let mut journaled_state = Journal::new(WrapDatabaseRef(db));
213 journaled_state.set_spec_id(spec);
214 Context {
215 tx: self.tx,
216 block: self.block,
217 cfg: self.cfg,
218 journaled_state,
219 local: self.local,
220 chain: self.chain,
221 error: Ok(()),
222 }
223 }
224
225 pub fn with_block<OB: Block>(
227 self,
228 block: OB,
229 ) -> Context<OB, TX, CFG, DB, JOURNAL, CHAIN, LOCAL> {
230 Context {
231 tx: self.tx,
232 block,
233 cfg: self.cfg,
234 journaled_state: self.journaled_state,
235 local: self.local,
236 chain: self.chain,
237 error: Ok(()),
238 }
239 }
240 pub fn with_tx<OTX: Transaction>(
242 self,
243 tx: OTX,
244 ) -> Context<BLOCK, OTX, CFG, DB, JOURNAL, CHAIN, LOCAL> {
245 Context {
246 tx,
247 block: self.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
256 pub fn with_chain<OC>(self, chain: OC) -> Context<BLOCK, TX, CFG, DB, JOURNAL, OC, LOCAL> {
258 Context {
259 tx: self.tx,
260 block: self.block,
261 cfg: self.cfg,
262 journaled_state: self.journaled_state,
263 local: self.local,
264 chain,
265 error: Ok(()),
266 }
267 }
268
269 pub fn with_cfg<OCFG: Cfg>(
271 mut self,
272 cfg: OCFG,
273 ) -> Context<BLOCK, TX, OCFG, DB, JOURNAL, CHAIN, LOCAL> {
274 self.journaled_state.set_spec_id(cfg.spec().into());
275 Context {
276 tx: self.tx,
277 block: self.block,
278 cfg,
279 journaled_state: self.journaled_state,
280 local: self.local,
281 chain: self.chain,
282 error: Ok(()),
283 }
284 }
285
286 pub fn with_local<OL: LocalContextTr>(
288 self,
289 local: OL,
290 ) -> Context<BLOCK, TX, CFG, DB, JOURNAL, CHAIN, OL> {
291 Context {
292 tx: self.tx,
293 block: self.block,
294 cfg: self.cfg,
295 journaled_state: self.journaled_state,
296 local,
297 chain: self.chain,
298 error: Ok(()),
299 }
300 }
301
302 #[must_use]
304 pub fn modify_cfg_chained<F>(mut self, f: F) -> Self
305 where
306 F: FnOnce(&mut CFG),
307 {
308 f(&mut self.cfg);
309 self.journaled_state.set_spec_id(self.cfg.spec().into());
310 self
311 }
312
313 #[must_use]
315 pub fn modify_block_chained<F>(mut self, f: F) -> Self
316 where
317 F: FnOnce(&mut BLOCK),
318 {
319 self.modify_block(f);
320 self
321 }
322
323 #[must_use]
325 pub fn modify_tx_chained<F>(mut self, f: F) -> Self
326 where
327 F: FnOnce(&mut TX),
328 {
329 self.modify_tx(f);
330 self
331 }
332
333 #[must_use]
335 pub fn modify_chain_chained<F>(mut self, f: F) -> Self
336 where
337 F: FnOnce(&mut CHAIN),
338 {
339 self.modify_chain(f);
340 self
341 }
342
343 #[must_use]
345 pub fn modify_db_chained<F>(mut self, f: F) -> Self
346 where
347 F: FnOnce(&mut DB),
348 {
349 self.modify_db(f);
350 self
351 }
352
353 #[must_use]
355 pub fn modify_journal_chained<F>(mut self, f: F) -> Self
356 where
357 F: FnOnce(&mut JOURNAL),
358 {
359 self.modify_journal(f);
360 self
361 }
362
363 pub fn modify_block<F>(&mut self, f: F)
365 where
366 F: FnOnce(&mut BLOCK),
367 {
368 f(&mut self.block);
369 }
370
371 pub fn modify_tx<F>(&mut self, f: F)
373 where
374 F: FnOnce(&mut TX),
375 {
376 f(&mut self.tx);
377 }
378
379 pub fn modify_cfg<F>(&mut self, f: F)
381 where
382 F: FnOnce(&mut CFG),
383 {
384 f(&mut self.cfg);
385 self.journaled_state.set_spec_id(self.cfg.spec().into());
386 }
387
388 pub fn modify_chain<F>(&mut self, f: F)
390 where
391 F: FnOnce(&mut CHAIN),
392 {
393 f(&mut self.chain);
394 }
395
396 pub fn modify_db<F>(&mut self, f: F)
398 where
399 F: FnOnce(&mut DB),
400 {
401 f(self.journaled_state.db_mut());
402 }
403
404 pub fn modify_journal<F>(&mut self, f: F)
406 where
407 F: FnOnce(&mut JOURNAL),
408 {
409 f(&mut self.journaled_state);
410 }
411
412 pub fn modify_local<F>(&mut self, f: F)
414 where
415 F: FnOnce(&mut LOCAL),
416 {
417 f(&mut self.local);
418 }
419}
420
421impl<
422 BLOCK: Block,
423 TX: Transaction,
424 CFG: Cfg,
425 DB: Database,
426 JOURNAL: JournalTr<Database = DB>,
427 CHAIN,
428 LOCAL: LocalContextTr,
429 > Host for Context<BLOCK, TX, CFG, DB, JOURNAL, CHAIN, LOCAL>
430{
431 fn basefee(&self) -> U256 {
434 U256::from(self.block().basefee())
435 }
436
437 fn blob_gasprice(&self) -> U256 {
438 U256::from(self.block().blob_gasprice().unwrap_or(0))
439 }
440
441 fn gas_limit(&self) -> U256 {
442 U256::from(self.block().gas_limit())
443 }
444
445 fn difficulty(&self) -> U256 {
446 self.block().difficulty()
447 }
448
449 fn prevrandao(&self) -> Option<U256> {
450 self.block().prevrandao().map(|r| r.into())
451 }
452
453 #[inline]
454 fn gas_params(&self) -> &GasParams {
455 self.cfg().gas_params()
456 }
457
458 fn block_number(&self) -> U256 {
459 self.block().number()
460 }
461
462 fn timestamp(&self) -> U256 {
463 U256::from(self.block().timestamp())
464 }
465
466 fn beneficiary(&self) -> Address {
467 self.block().beneficiary()
468 }
469
470 fn chain_id(&self) -> U256 {
471 U256::from(self.cfg().chain_id())
472 }
473
474 fn effective_gas_price(&self) -> U256 {
477 let basefee = self.block().basefee();
478 U256::from(self.tx().effective_gas_price(basefee as u128))
479 }
480
481 fn caller(&self) -> Address {
482 self.tx().caller()
483 }
484
485 fn blob_hash(&self, number: usize) -> Option<U256> {
486 let tx = &self.tx();
487 if tx.tx_type() != TransactionType::Eip4844 {
488 return None;
489 }
490 tx.blob_versioned_hashes()
491 .get(number)
492 .map(|t| U256::from_be_bytes(t.0))
493 }
494
495 fn max_initcode_size(&self) -> usize {
498 self.cfg().max_initcode_size()
499 }
500
501 fn block_hash(&mut self, requested_number: u64) -> Option<B256> {
504 self.db_mut()
505 .block_hash(requested_number)
506 .map_err(|e| {
507 cold_path();
508 *self.error() = Err(e.into());
509 })
510 .ok()
511 }
512
513 fn tload(&mut self, address: Address, index: StorageKey) -> StorageValue {
517 self.journal_mut().tload(address, index)
518 }
519
520 fn tstore(&mut self, address: Address, index: StorageKey, value: StorageValue) {
522 self.journal_mut().tstore(address, index, value)
523 }
524
525 fn log(&mut self, log: Log) {
527 self.journal_mut().log(log);
528 }
529
530 #[inline]
532 fn selfdestruct(
533 &mut self,
534 address: Address,
535 target: Address,
536 skip_cold_load: bool,
537 ) -> Result<StateLoad<SelfDestructResult>, LoadError> {
538 self.journal_mut()
539 .selfdestruct(address, target, skip_cold_load)
540 .map_err(|e| {
541 cold_path();
542 let (ret, err) = e.into_parts();
543 if let Some(err) = err {
544 *self.error() = Err(err.into());
545 }
546 ret
547 })
548 }
549
550 #[inline]
551 fn sstore_skip_cold_load(
552 &mut self,
553 address: Address,
554 key: StorageKey,
555 value: StorageValue,
556 skip_cold_load: bool,
557 ) -> Result<StateLoad<SStoreResult>, LoadError> {
558 self.journal_mut()
559 .sstore_skip_cold_load(address, key, value, 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 sload_skip_cold_load(
572 &mut self,
573 address: Address,
574 key: StorageKey,
575 skip_cold_load: bool,
576 ) -> Result<StateLoad<StorageValue>, LoadError> {
577 self.journal_mut()
578 .sload_skip_cold_load(address, key, skip_cold_load)
579 .map_err(|e| {
580 cold_path();
581 let (ret, err) = e.into_parts();
582 if let Some(err) = err {
583 *self.error() = Err(err.into());
584 }
585 ret
586 })
587 }
588
589 #[inline]
590 fn load_account_info_skip_cold_load(
591 &mut self,
592 address: Address,
593 load_code: bool,
594 skip_cold_load: bool,
595 ) -> Result<AccountInfoLoad<'_>, LoadError> {
596 match self.journaled_state.load_account_info_skip_cold_load(
597 address,
598 load_code,
599 skip_cold_load,
600 ) {
601 Ok(a) => Ok(a),
602 Err(e) => {
603 cold_path();
604 let (ret, err) = e.into_parts();
605 if let Some(err) = err {
606 self.error = Err(err.into());
607 }
608 Err(ret)
609 }
610 }
611 }
612}