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 all(
60 &self,
61 ) -> (
62 &Self::Block,
63 &Self::Tx,
64 &Self::Cfg,
65 &Self::Db,
66 &Self::Journal,
67 &Self::Chain,
68 &Self::Local,
69 ) {
70 let block = &self.block;
71 let tx = &self.tx;
72 let cfg = &self.cfg;
73 let db = self.journaled_state.db();
74 let journal = &self.journaled_state;
75 let chain = &self.chain;
76 let local = &self.local;
77
78 (block, tx, cfg, db, journal, chain, local)
79 }
80
81 #[inline]
82 fn all_mut(
83 &mut self,
84 ) -> (
85 &Self::Block,
86 &Self::Tx,
87 &Self::Cfg,
88 &mut Self::Journal,
89 &mut Self::Chain,
90 &mut Self::Local,
91 ) {
92 let block = &self.block;
93 let tx = &self.tx;
94 let cfg = &self.cfg;
95 let journal = &mut self.journaled_state;
96 let chain = &mut self.chain;
97 let local = &mut self.local;
98
99 (block, tx, cfg, journal, chain, local)
100 }
101
102 #[inline]
103 fn error(&mut self) -> &mut Result<(), ContextError<<Self::Db as Database>::Error>> {
104 &mut self.error
105 }
106}
107
108impl<
109 BLOCK: Block,
110 TX: Transaction,
111 DB: Database,
112 CFG: Cfg,
113 JOURNAL: JournalTr<Database = DB>,
114 CHAIN,
115 LOCAL: LocalContextTr,
116 > ContextSetters for Context<BLOCK, TX, CFG, DB, JOURNAL, CHAIN, LOCAL>
117{
118 fn set_tx(&mut self, tx: Self::Tx) {
119 self.tx = tx;
120 }
121
122 fn set_block(&mut self, block: Self::Block) {
123 self.block = block;
124 }
125}
126
127impl<
128 BLOCK: Block + Default,
129 TX: Transaction + Default,
130 DB: Database,
131 JOURNAL: JournalTr<Database = DB>,
132 CHAIN: Default,
133 LOCAL: LocalContextTr + Default,
134 SPEC: Default + Copy + Into<SpecId>,
135 > Context<BLOCK, TX, CfgEnv<SPEC>, DB, JOURNAL, CHAIN, LOCAL>
136{
137 pub fn new(db: DB, spec: SPEC) -> Self {
141 let mut journaled_state = JOURNAL::new(db);
142 journaled_state.set_spec_id(spec.into());
143 Self {
144 tx: TX::default(),
145 block: BLOCK::default(),
146 cfg: CfgEnv {
147 spec,
148 ..Default::default()
149 },
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 fn block_number(&self) -> U256 {
454 self.block().number()
455 }
456
457 fn timestamp(&self) -> U256 {
458 U256::from(self.block().timestamp())
459 }
460
461 fn beneficiary(&self) -> Address {
462 self.block().beneficiary()
463 }
464
465 fn chain_id(&self) -> U256 {
466 U256::from(self.cfg().chain_id())
467 }
468
469 fn effective_gas_price(&self) -> U256 {
472 let basefee = self.block().basefee();
473 U256::from(self.tx().effective_gas_price(basefee as u128))
474 }
475
476 fn caller(&self) -> Address {
477 self.tx().caller()
478 }
479
480 fn blob_hash(&self, number: usize) -> Option<U256> {
481 let tx = &self.tx();
482 if tx.tx_type() != TransactionType::Eip4844 {
483 return None;
484 }
485 tx.blob_versioned_hashes()
486 .get(number)
487 .map(|t| U256::from_be_bytes(t.0))
488 }
489
490 fn max_initcode_size(&self) -> usize {
493 self.cfg().max_initcode_size()
494 }
495
496 fn block_hash(&mut self, requested_number: u64) -> Option<B256> {
499 self.db_mut()
500 .block_hash(requested_number)
501 .map_err(|e| {
502 *self.error() = Err(e.into());
503 })
504 .ok()
505 }
506
507 fn tload(&mut self, address: Address, index: StorageKey) -> StorageValue {
511 self.journal_mut().tload(address, index)
512 }
513
514 fn tstore(&mut self, address: Address, index: StorageKey, value: StorageValue) {
516 self.journal_mut().tstore(address, index, value)
517 }
518
519 fn log(&mut self, log: Log) {
521 self.journal_mut().log(log);
522 }
523
524 #[inline]
526 fn selfdestruct(
527 &mut self,
528 address: Address,
529 target: Address,
530 skip_cold_load: bool,
531 ) -> Result<StateLoad<SelfDestructResult>, LoadError> {
532 self.journal_mut()
533 .selfdestruct(address, target, skip_cold_load)
534 .map_err(|e| {
535 let (ret, err) = e.into_parts();
536 if let Some(err) = err {
537 *self.error() = Err(err.into());
538 }
539 ret
540 })
541 }
542
543 #[inline]
544 fn sstore_skip_cold_load(
545 &mut self,
546 address: Address,
547 key: StorageKey,
548 value: StorageValue,
549 skip_cold_load: bool,
550 ) -> Result<StateLoad<SStoreResult>, LoadError> {
551 self.journal_mut()
552 .sstore_skip_cold_load(address, key, value, skip_cold_load)
553 .map_err(|e| {
554 let (ret, err) = e.into_parts();
555 if let Some(err) = err {
556 *self.error() = Err(err.into());
557 }
558 ret
559 })
560 }
561
562 #[inline]
563 fn sload_skip_cold_load(
564 &mut self,
565 address: Address,
566 key: StorageKey,
567 skip_cold_load: bool,
568 ) -> Result<StateLoad<StorageValue>, LoadError> {
569 self.journal_mut()
570 .sload_skip_cold_load(address, key, skip_cold_load)
571 .map_err(|e| {
572 let (ret, err) = e.into_parts();
573 if let Some(err) = err {
574 *self.error() = Err(err.into());
575 }
576 ret
577 })
578 }
579
580 #[inline]
581 fn load_account_info_skip_cold_load(
582 &mut self,
583 address: Address,
584 load_code: bool,
585 skip_cold_load: bool,
586 ) -> Result<AccountInfoLoad<'_>, LoadError> {
587 let error = &mut self.error;
588 let journal = &mut self.journaled_state;
589 match journal.load_account_info_skip_cold_load(address, load_code, skip_cold_load) {
590 Ok(a) => Ok(a),
591 Err(e) => {
592 let (ret, err) = e.into_parts();
593 if let Some(err) = err {
594 *error = Err(err.into());
595 }
596 Err(ret)
597 }
598 }
599 }
600}