1use crate::{block::BlockEnv, cfg::CfgEnv, journal::Journal, tx::TxEnv, LocalContext};
3use context_interface::{
4 context::{ContextError, ContextSetters, SStoreResult, SelfDestructResult, StateLoad},
5 journaled_state::AccountLoad,
6 Block, Cfg, ContextTr, Host, JournalTr, LocalContextTr, Transaction, TransactionType,
7};
8use database_interface::{Database, DatabaseRef, EmptyDB, WrapDatabaseRef};
9use derive_where::derive_where;
10use primitives::{hardfork::SpecId, Address, Bytes, Log, StorageKey, StorageValue, B256, U256};
11
12#[derive_where(Clone, Debug; BLOCK, CFG, CHAIN, TX, DB, JOURNAL, <DB as Database>::Error, LOCAL)]
14pub struct Context<
15 BLOCK = BlockEnv,
16 TX = TxEnv,
17 CFG = CfgEnv,
18 DB: Database = EmptyDB,
19 JOURNAL: JournalTr<Database = DB> = Journal<DB>,
20 CHAIN = (),
21 LOCAL: LocalContextTr = LocalContext,
22> {
23 pub block: BLOCK,
25 pub tx: TX,
27 pub cfg: CFG,
29 pub journaled_state: JOURNAL,
31 pub chain: CHAIN,
33 pub local: LOCAL,
35 pub error: Result<(), ContextError<DB::Error>>,
37}
38
39impl<
40 BLOCK: Block,
41 TX: Transaction,
42 DB: Database,
43 CFG: Cfg,
44 JOURNAL: JournalTr<Database = DB>,
45 CHAIN,
46 LOCAL: LocalContextTr,
47 > ContextTr for Context<BLOCK, TX, CFG, DB, JOURNAL, CHAIN, LOCAL>
48{
49 type Block = BLOCK;
50 type Tx = TX;
51 type Cfg = CFG;
52 type Db = DB;
53 type Journal = JOURNAL;
54 type Chain = CHAIN;
55 type Local = LOCAL;
56
57 #[inline]
58 fn tx(&self) -> &Self::Tx {
59 &self.tx
60 }
61
62 #[inline]
63 fn block(&self) -> &Self::Block {
64 &self.block
65 }
66
67 #[inline]
68 fn cfg(&self) -> &Self::Cfg {
69 &self.cfg
70 }
71
72 #[inline]
73 fn journal(&self) -> &Self::Journal {
74 &self.journaled_state
75 }
76
77 #[inline]
78 fn journal_mut(&mut self) -> &mut Self::Journal {
79 &mut self.journaled_state
80 }
81
82 #[inline]
83 fn journal_ref(&self) -> &Self::Journal {
84 &self.journaled_state
85 }
86
87 #[inline]
88 fn db(&self) -> &Self::Db {
89 self.journaled_state.db()
90 }
91
92 #[inline]
93 fn db_mut(&mut self) -> &mut Self::Db {
94 self.journaled_state.db_mut()
95 }
96
97 #[inline]
98 fn chain(&self) -> &Self::Chain {
99 &self.chain
100 }
101
102 #[inline]
103 fn chain_mut(&mut self) -> &mut Self::Chain {
104 &mut self.chain
105 }
106
107 #[inline]
108 fn local(&self) -> &Self::Local {
109 &self.local
110 }
111
112 #[inline]
113 fn local_mut(&mut self) -> &mut Self::Local {
114 &mut self.local
115 }
116
117 #[inline]
118 fn error(&mut self) -> &mut Result<(), ContextError<<Self::Db as Database>::Error>> {
119 &mut self.error
120 }
121
122 #[inline]
123 fn tx_journal_mut(&mut self) -> (&Self::Tx, &mut Self::Journal) {
124 (&self.tx, &mut self.journaled_state)
125 }
126
127 #[inline]
128 fn tx_local_mut(&mut self) -> (&Self::Tx, &mut Self::Local) {
129 (&self.tx, &mut self.local)
130 }
131}
132
133impl<
134 BLOCK: Block,
135 TX: Transaction,
136 DB: Database,
137 CFG: Cfg,
138 JOURNAL: JournalTr<Database = DB>,
139 CHAIN,
140 LOCAL: LocalContextTr,
141 > ContextSetters for Context<BLOCK, TX, CFG, DB, JOURNAL, CHAIN, LOCAL>
142{
143 fn set_tx(&mut self, tx: Self::Tx) {
144 self.tx = tx;
145 }
146
147 fn set_block(&mut self, block: Self::Block) {
148 self.block = block;
149 }
150}
151
152impl<
153 BLOCK: Block + Default,
154 TX: Transaction + Default,
155 DB: Database,
156 JOURNAL: JournalTr<Database = DB>,
157 CHAIN: Default,
158 LOCAL: LocalContextTr + Default,
159 > Context<BLOCK, TX, CfgEnv, DB, JOURNAL, CHAIN, LOCAL>
160{
161 pub fn new(db: DB, spec: SpecId) -> Self {
165 let mut journaled_state = JOURNAL::new(db);
166 journaled_state.set_spec_id(spec);
167 Self {
168 tx: TX::default(),
169 block: BLOCK::default(),
170 cfg: CfgEnv {
171 spec,
172 ..Default::default()
173 },
174 local: LOCAL::default(),
175 journaled_state,
176 chain: Default::default(),
177 error: Ok(()),
178 }
179 }
180}
181
182impl<BLOCK, TX, CFG, DB, JOURNAL, CHAIN, LOCAL> Context<BLOCK, TX, CFG, DB, JOURNAL, CHAIN, LOCAL>
183where
184 BLOCK: Block,
185 TX: Transaction,
186 CFG: Cfg,
187 DB: Database,
188 JOURNAL: JournalTr<Database = DB>,
189 LOCAL: LocalContextTr,
190{
191 pub fn with_new_journal<OJOURNAL: JournalTr<Database = DB>>(
193 self,
194 mut journal: OJOURNAL,
195 ) -> Context<BLOCK, TX, CFG, DB, OJOURNAL, CHAIN, LOCAL> {
196 journal.set_spec_id(self.cfg.spec().into());
197 Context {
198 tx: self.tx,
199 block: self.block,
200 cfg: self.cfg,
201 journaled_state: journal,
202 local: self.local,
203 chain: self.chain,
204 error: Ok(()),
205 }
206 }
207
208 pub fn with_db<ODB: Database>(
212 self,
213 db: ODB,
214 ) -> Context<BLOCK, TX, CFG, ODB, Journal<ODB>, CHAIN, LOCAL> {
215 let spec = self.cfg.spec().into();
216 let mut journaled_state = Journal::new(db);
217 journaled_state.set_spec_id(spec);
218 Context {
219 tx: self.tx,
220 block: self.block,
221 cfg: self.cfg,
222 journaled_state,
223 local: self.local,
224 chain: self.chain,
225 error: Ok(()),
226 }
227 }
228
229 pub fn with_ref_db<ODB: DatabaseRef>(
231 self,
232 db: ODB,
233 ) -> Context<BLOCK, TX, CFG, WrapDatabaseRef<ODB>, Journal<WrapDatabaseRef<ODB>>, CHAIN, LOCAL>
234 {
235 let spec = self.cfg.spec().into();
236 let mut journaled_state = Journal::new(WrapDatabaseRef(db));
237 journaled_state.set_spec_id(spec);
238 Context {
239 tx: self.tx,
240 block: self.block,
241 cfg: self.cfg,
242 journaled_state,
243 local: self.local,
244 chain: self.chain,
245 error: Ok(()),
246 }
247 }
248
249 pub fn with_block<OB: Block>(
251 self,
252 block: OB,
253 ) -> Context<OB, TX, CFG, DB, JOURNAL, CHAIN, LOCAL> {
254 Context {
255 tx: self.tx,
256 block,
257 cfg: self.cfg,
258 journaled_state: self.journaled_state,
259 local: self.local,
260 chain: self.chain,
261 error: Ok(()),
262 }
263 }
264 pub fn with_tx<OTX: Transaction>(
266 self,
267 tx: OTX,
268 ) -> Context<BLOCK, OTX, CFG, DB, JOURNAL, CHAIN, LOCAL> {
269 Context {
270 tx,
271 block: self.block,
272 cfg: self.cfg,
273 journaled_state: self.journaled_state,
274 local: self.local,
275 chain: self.chain,
276 error: Ok(()),
277 }
278 }
279
280 pub fn with_chain<OC>(self, chain: OC) -> Context<BLOCK, TX, CFG, DB, JOURNAL, OC, LOCAL> {
282 Context {
283 tx: self.tx,
284 block: self.block,
285 cfg: self.cfg,
286 journaled_state: self.journaled_state,
287 local: self.local,
288 chain,
289 error: Ok(()),
290 }
291 }
292
293 pub fn with_cfg<OCFG: Cfg>(
295 mut self,
296 cfg: OCFG,
297 ) -> Context<BLOCK, TX, OCFG, DB, JOURNAL, CHAIN, LOCAL> {
298 self.journaled_state.set_spec_id(cfg.spec().into());
299 Context {
300 tx: self.tx,
301 block: self.block,
302 cfg,
303 journaled_state: self.journaled_state,
304 local: self.local,
305 chain: self.chain,
306 error: Ok(()),
307 }
308 }
309
310 pub fn with_local<OL: LocalContextTr>(
312 self,
313 local: OL,
314 ) -> Context<BLOCK, TX, CFG, DB, JOURNAL, CHAIN, OL> {
315 Context {
316 tx: self.tx,
317 block: self.block,
318 cfg: self.cfg,
319 journaled_state: self.journaled_state,
320 local,
321 chain: self.chain,
322 error: Ok(()),
323 }
324 }
325
326 #[must_use]
328 pub fn modify_cfg_chained<F>(mut self, f: F) -> Self
329 where
330 F: FnOnce(&mut CFG),
331 {
332 f(&mut self.cfg);
333 self.journaled_state.set_spec_id(self.cfg.spec().into());
334 self
335 }
336
337 #[must_use]
339 pub fn modify_block_chained<F>(mut self, f: F) -> Self
340 where
341 F: FnOnce(&mut BLOCK),
342 {
343 self.modify_block(f);
344 self
345 }
346
347 #[must_use]
349 pub fn modify_tx_chained<F>(mut self, f: F) -> Self
350 where
351 F: FnOnce(&mut TX),
352 {
353 self.modify_tx(f);
354 self
355 }
356
357 #[must_use]
359 pub fn modify_chain_chained<F>(mut self, f: F) -> Self
360 where
361 F: FnOnce(&mut CHAIN),
362 {
363 self.modify_chain(f);
364 self
365 }
366
367 #[must_use]
369 pub fn modify_db_chained<F>(mut self, f: F) -> Self
370 where
371 F: FnOnce(&mut DB),
372 {
373 self.modify_db(f);
374 self
375 }
376
377 #[must_use]
379 pub fn modify_journal_chained<F>(mut self, f: F) -> Self
380 where
381 F: FnOnce(&mut JOURNAL),
382 {
383 self.modify_journal(f);
384 self
385 }
386
387 pub fn modify_block<F>(&mut self, f: F)
389 where
390 F: FnOnce(&mut BLOCK),
391 {
392 f(&mut self.block);
393 }
394
395 pub fn modify_tx<F>(&mut self, f: F)
397 where
398 F: FnOnce(&mut TX),
399 {
400 f(&mut self.tx);
401 }
402
403 pub fn modify_cfg<F>(&mut self, f: F)
405 where
406 F: FnOnce(&mut CFG),
407 {
408 f(&mut self.cfg);
409 self.journaled_state.set_spec_id(self.cfg.spec().into());
410 }
411
412 pub fn modify_chain<F>(&mut self, f: F)
414 where
415 F: FnOnce(&mut CHAIN),
416 {
417 f(&mut self.chain);
418 }
419
420 pub fn modify_db<F>(&mut self, f: F)
422 where
423 F: FnOnce(&mut DB),
424 {
425 f(self.journaled_state.db_mut());
426 }
427
428 pub fn modify_journal<F>(&mut self, f: F)
430 where
431 F: FnOnce(&mut JOURNAL),
432 {
433 f(&mut self.journaled_state);
434 }
435
436 pub fn modify_local<F>(&mut self, f: F)
438 where
439 F: FnOnce(&mut LOCAL),
440 {
441 f(&mut self.local);
442 }
443}
444
445impl<
446 BLOCK: Block,
447 TX: Transaction,
448 CFG: Cfg,
449 DB: Database,
450 JOURNAL: JournalTr<Database = DB>,
451 CHAIN,
452 LOCAL: LocalContextTr,
453 > Host for Context<BLOCK, TX, CFG, DB, JOURNAL, CHAIN, LOCAL>
454{
455 fn basefee(&self) -> U256 {
458 U256::from(self.block().basefee())
459 }
460
461 fn blob_gasprice(&self) -> U256 {
462 U256::from(self.block().blob_gasprice().unwrap_or(0))
463 }
464
465 fn gas_limit(&self) -> U256 {
466 U256::from(self.block().gas_limit())
467 }
468
469 fn difficulty(&self) -> U256 {
470 self.block().difficulty()
471 }
472
473 fn prevrandao(&self) -> Option<U256> {
474 self.block().prevrandao().map(|r| r.into())
475 }
476
477 fn block_number(&self) -> U256 {
478 self.block().number()
479 }
480
481 fn timestamp(&self) -> U256 {
482 U256::from(self.block().timestamp())
483 }
484
485 fn beneficiary(&self) -> Address {
486 self.block().beneficiary()
487 }
488
489 fn chain_id(&self) -> U256 {
490 U256::from(self.cfg().chain_id())
491 }
492
493 fn effective_gas_price(&self) -> U256 {
496 let basefee = self.block().basefee();
497 U256::from(self.tx().effective_gas_price(basefee as u128))
498 }
499
500 fn caller(&self) -> Address {
501 self.tx().caller()
502 }
503
504 fn blob_hash(&self, number: usize) -> Option<U256> {
505 let tx = &self.tx();
506 if tx.tx_type() != TransactionType::Eip4844 {
507 return None;
508 }
509 tx.blob_versioned_hashes()
510 .get(number)
511 .map(|t| U256::from_be_bytes(t.0))
512 }
513
514 fn max_initcode_size(&self) -> usize {
517 self.cfg().max_initcode_size()
518 }
519
520 fn block_hash(&mut self, requested_number: u64) -> Option<B256> {
523 self.db_mut()
524 .block_hash(requested_number)
525 .map_err(|e| {
526 *self.error() = Err(e.into());
527 })
528 .ok()
529 }
530
531 fn load_account_delegated(&mut self, address: Address) -> Option<StateLoad<AccountLoad>> {
534 self.journal_mut()
535 .load_account_delegated(address)
536 .map_err(|e| {
537 *self.error() = Err(e.into());
538 })
539 .ok()
540 }
541
542 fn balance(&mut self, address: Address) -> Option<StateLoad<U256>> {
544 self.journal_mut()
545 .load_account(address)
546 .map(|acc| acc.map(|a| a.info.balance))
547 .map_err(|e| {
548 *self.error() = Err(e.into());
549 })
550 .ok()
551 }
552
553 fn load_account_code(&mut self, address: Address) -> Option<StateLoad<Bytes>> {
555 self.journal_mut()
556 .code(address)
557 .map_err(|e| {
558 *self.error() = Err(e.into());
559 })
560 .ok()
561 }
562
563 fn load_account_code_hash(&mut self, address: Address) -> Option<StateLoad<B256>> {
565 self.journal_mut()
566 .code_hash(address)
567 .map_err(|e| {
568 *self.error() = Err(e.into());
569 })
570 .ok()
571 }
572
573 fn sload(&mut self, address: Address, index: StorageKey) -> Option<StateLoad<StorageValue>> {
575 self.journal_mut()
576 .sload(address, index)
577 .map_err(|e| {
578 *self.error() = Err(e.into());
579 })
580 .ok()
581 }
582
583 fn sstore(
587 &mut self,
588 address: Address,
589 index: StorageKey,
590 value: StorageValue,
591 ) -> Option<StateLoad<SStoreResult>> {
592 self.journal_mut()
593 .sstore(address, index, value)
594 .map_err(|e| {
595 *self.error() = Err(e.into());
596 })
597 .ok()
598 }
599
600 fn tload(&mut self, address: Address, index: StorageKey) -> StorageValue {
602 self.journal_mut().tload(address, index)
603 }
604
605 fn tstore(&mut self, address: Address, index: StorageKey, value: StorageValue) {
607 self.journal_mut().tstore(address, index, value)
608 }
609
610 fn log(&mut self, log: Log) {
612 self.journal_mut().log(log);
613 }
614
615 fn selfdestruct(
617 &mut self,
618 address: Address,
619 target: Address,
620 ) -> Option<StateLoad<SelfDestructResult>> {
621 self.journal_mut()
622 .selfdestruct(address, target)
623 .map_err(|e| {
624 *self.error() = Err(e.into());
625 })
626 .ok()
627 }
628}