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