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