1use std::fmt::Debug;
2
3use alloy_consensus::Typed2718;
4pub use alloy_evm::EvmEnv;
5use alloy_evm::FromRecoveredTx;
6use alloy_network::{AnyRpcTransaction, AnyTxEnvelope, TransactionResponse};
7use alloy_primitives::{Address, B256, Bytes, U256};
8#[cfg(feature = "optimism")]
9use op_revm::transaction::deposit::DEPOSIT_TRANSACTION_TYPE;
10use revm::{
11 Context, Database, Journal,
12 context::{Block, BlockEnv, Cfg, CfgEnv, Transaction, TxEnv},
13 context_interface::{
14 ContextTr,
15 either::Either,
16 transaction::{AccessList, RecoveredAuthorization, SignedAuthorization},
17 },
18 inspector::JournalExt,
19 primitives::{TxKind, hardfork::SpecId},
20};
21use tempo_revm::{TempoBlockEnv, TempoTxEnv};
22
23use crate::backend::JournaledState;
24
25pub trait FoundryBlock: Block {
27 fn set_number(&mut self, number: U256);
29
30 fn set_beneficiary(&mut self, beneficiary: Address);
32
33 fn set_timestamp(&mut self, timestamp: U256);
35
36 fn set_gas_limit(&mut self, gas_limit: u64);
38
39 fn set_basefee(&mut self, basefee: u64);
41
42 fn set_difficulty(&mut self, difficulty: U256);
44
45 fn set_prevrandao(&mut self, prevrandao: Option<B256>);
47
48 fn set_blob_excess_gas_and_price(
50 &mut self,
51 _excess_blob_gas: u64,
52 _base_fee_update_fraction: u64,
53 );
54
55 fn timestamp_millis_part(&self) -> u64 {
59 0
60 }
61
62 fn set_timestamp_millis_part(&mut self, _millis: u64) {}
64}
65
66impl FoundryBlock for BlockEnv {
67 fn set_number(&mut self, number: U256) {
68 self.number = number;
69 }
70
71 fn set_beneficiary(&mut self, beneficiary: Address) {
72 self.beneficiary = beneficiary;
73 }
74
75 fn set_timestamp(&mut self, timestamp: U256) {
76 self.timestamp = timestamp;
77 }
78
79 fn set_gas_limit(&mut self, gas_limit: u64) {
80 self.gas_limit = gas_limit;
81 }
82
83 fn set_basefee(&mut self, basefee: u64) {
84 self.basefee = basefee;
85 }
86
87 fn set_difficulty(&mut self, difficulty: U256) {
88 self.difficulty = difficulty;
89 }
90
91 fn set_prevrandao(&mut self, prevrandao: Option<B256>) {
92 self.prevrandao = prevrandao;
93 }
94
95 fn set_blob_excess_gas_and_price(
96 &mut self,
97 excess_blob_gas: u64,
98 base_fee_update_fraction: u64,
99 ) {
100 self.set_blob_excess_gas_and_price(excess_blob_gas, base_fee_update_fraction);
101 }
102}
103
104impl FoundryBlock for TempoBlockEnv {
105 fn set_number(&mut self, number: U256) {
106 self.inner.set_number(number);
107 }
108
109 fn set_beneficiary(&mut self, beneficiary: Address) {
110 self.inner.set_beneficiary(beneficiary);
111 }
112
113 fn set_timestamp(&mut self, timestamp: U256) {
114 self.inner.set_timestamp(timestamp);
115 }
116
117 fn set_gas_limit(&mut self, gas_limit: u64) {
118 self.inner.set_gas_limit(gas_limit);
119 }
120
121 fn set_basefee(&mut self, basefee: u64) {
122 self.inner.set_basefee(basefee);
123 }
124
125 fn set_difficulty(&mut self, difficulty: U256) {
126 self.inner.set_difficulty(difficulty);
127 }
128
129 fn set_prevrandao(&mut self, prevrandao: Option<B256>) {
130 self.inner.set_prevrandao(prevrandao);
131 }
132
133 fn set_blob_excess_gas_and_price(
134 &mut self,
135 _excess_blob_gas: u64,
136 _base_fee_update_fraction: u64,
137 ) {
138 }
139
140 fn timestamp_millis_part(&self) -> u64 {
141 self.timestamp_millis_part
142 }
143
144 fn set_timestamp_millis_part(&mut self, millis: u64) {
145 self.timestamp_millis_part = millis;
146 }
147}
148
149pub trait FoundryTransaction: Transaction {
152 fn set_tx_type(&mut self, tx_type: u8);
154
155 fn set_caller(&mut self, caller: Address);
157
158 fn set_gas_limit(&mut self, gas_limit: u64);
160
161 fn set_gas_price(&mut self, gas_price: u128);
163
164 fn set_kind(&mut self, kind: TxKind);
166
167 fn set_value(&mut self, value: U256);
169
170 fn set_data(&mut self, data: Bytes);
172
173 fn set_nonce(&mut self, nonce: u64);
175
176 fn set_chain_id(&mut self, chain_id: Option<u64>);
178
179 fn set_access_list(&mut self, access_list: AccessList);
181
182 fn authorization_list_mut(
184 &mut self,
185 ) -> &mut Vec<Either<SignedAuthorization, RecoveredAuthorization>>;
186
187 fn set_gas_priority_fee(&mut self, gas_priority_fee: Option<u128>);
189
190 fn set_blob_hashes(&mut self, blob_hashes: Vec<B256>);
192
193 fn set_max_fee_per_blob_gas(&mut self, max_fee_per_blob_gas: u128);
195
196 fn set_signed_authorization(&mut self, auth: Vec<SignedAuthorization>) {
198 *self.authorization_list_mut() = auth.into_iter().map(Either::Left).collect();
199 }
200
201 fn enveloped_tx(&self) -> Option<&Bytes> {
205 None
206 }
207
208 fn set_enveloped_tx(&mut self, _bytes: Bytes) {}
210
211 fn source_hash(&self) -> Option<B256> {
213 None
214 }
215
216 fn set_source_hash(&mut self, _source_hash: B256) {}
218
219 fn mint(&self) -> Option<u128> {
221 None
222 }
223
224 fn set_mint(&mut self, _mint: u128) {}
226
227 fn is_system_transaction(&self) -> bool {
229 false
230 }
231
232 fn set_system_transaction(&mut self, _is_system_transaction: bool) {}
234
235 fn is_deposit(&self) -> bool {
237 #[cfg(feature = "optimism")]
238 {
239 self.tx_type() == DEPOSIT_TRANSACTION_TYPE
240 }
241 #[cfg(not(feature = "optimism"))]
242 {
243 false
244 }
245 }
246
247 fn fee_token(&self) -> Option<Address> {
251 None
252 }
253
254 fn set_fee_token(&mut self, _token: Option<Address>) {}
256
257 fn fee_payer(&self) -> Option<Option<Address>> {
259 None
260 }
261
262 fn set_fee_payer(&mut self, _payer: Option<Option<Address>>) {}
264}
265
266impl FoundryTransaction for TxEnv {
267 fn set_tx_type(&mut self, tx_type: u8) {
268 self.tx_type = tx_type;
269 }
270
271 fn set_caller(&mut self, caller: Address) {
272 self.caller = caller;
273 }
274
275 fn set_gas_limit(&mut self, gas_limit: u64) {
276 self.gas_limit = gas_limit;
277 }
278
279 fn set_gas_price(&mut self, gas_price: u128) {
280 self.gas_price = gas_price;
281 }
282
283 fn set_kind(&mut self, kind: TxKind) {
284 self.kind = kind;
285 }
286
287 fn set_value(&mut self, value: U256) {
288 self.value = value;
289 }
290
291 fn set_data(&mut self, data: Bytes) {
292 self.data = data;
293 }
294
295 fn set_nonce(&mut self, nonce: u64) {
296 self.nonce = nonce;
297 }
298
299 fn set_chain_id(&mut self, chain_id: Option<u64>) {
300 self.chain_id = chain_id;
301 }
302
303 fn set_access_list(&mut self, access_list: AccessList) {
304 self.access_list = access_list;
305 }
306
307 fn authorization_list_mut(
308 &mut self,
309 ) -> &mut Vec<Either<SignedAuthorization, RecoveredAuthorization>> {
310 &mut self.authorization_list
311 }
312
313 fn set_gas_priority_fee(&mut self, gas_priority_fee: Option<u128>) {
314 self.gas_priority_fee = gas_priority_fee;
315 }
316
317 fn set_blob_hashes(&mut self, blob_hashes: Vec<B256>) {
318 self.blob_hashes = blob_hashes;
319 }
320
321 fn set_max_fee_per_blob_gas(&mut self, max_fee_per_blob_gas: u128) {
322 self.max_fee_per_blob_gas = max_fee_per_blob_gas;
323 }
324}
325
326impl FoundryTransaction for TempoTxEnv {
327 fn set_tx_type(&mut self, tx_type: u8) {
328 self.inner.set_tx_type(tx_type);
329 }
330
331 fn set_caller(&mut self, caller: Address) {
332 self.inner.set_caller(caller);
333 }
334
335 fn set_gas_limit(&mut self, gas_limit: u64) {
336 self.inner.set_gas_limit(gas_limit);
337 }
338
339 fn set_gas_price(&mut self, gas_price: u128) {
340 self.inner.set_gas_price(gas_price);
341 }
342
343 fn set_kind(&mut self, kind: TxKind) {
344 self.inner.set_kind(kind);
345 }
346
347 fn set_value(&mut self, value: U256) {
348 self.inner.set_value(value);
349 }
350
351 fn set_data(&mut self, data: Bytes) {
352 self.inner.set_data(data);
353 }
354
355 fn set_nonce(&mut self, nonce: u64) {
356 self.inner.set_nonce(nonce);
357 }
358
359 fn set_chain_id(&mut self, chain_id: Option<u64>) {
360 self.inner.set_chain_id(chain_id);
361 }
362
363 fn set_access_list(&mut self, access_list: AccessList) {
364 self.inner.set_access_list(access_list);
365 }
366
367 fn authorization_list_mut(
368 &mut self,
369 ) -> &mut Vec<Either<SignedAuthorization, RecoveredAuthorization>> {
370 self.inner.authorization_list_mut()
371 }
372
373 fn set_gas_priority_fee(&mut self, gas_priority_fee: Option<u128>) {
374 self.inner.set_gas_priority_fee(gas_priority_fee);
375 }
376
377 fn set_blob_hashes(&mut self, _blob_hashes: Vec<B256>) {}
378
379 fn set_max_fee_per_blob_gas(&mut self, _max_fee_per_blob_gas: u128) {}
380
381 fn fee_token(&self) -> Option<Address> {
382 self.fee_token
383 }
384
385 fn set_fee_token(&mut self, token: Option<Address>) {
386 self.fee_token = token;
387 }
388
389 fn fee_payer(&self) -> Option<Option<Address>> {
390 self.fee_payer
391 }
392
393 fn set_fee_payer(&mut self, payer: Option<Option<Address>>) {
394 self.fee_payer = payer;
395 }
396}
397
398pub trait FoundryContextExt:
403 ContextTr<
404 Block: FoundryBlock + Clone,
405 Tx: FoundryTransaction + Clone,
406 Cfg = CfgEnv<Self::Spec>,
407 Journal: JournalExt,
408 >
409{
410 type Spec: Into<SpecId> + Copy + Debug;
414
415 fn block_mut(&mut self) -> &mut Self::Block;
417
418 fn tx_mut(&mut self) -> &mut Self::Tx;
420
421 fn cfg_mut(&mut self) -> &mut Self::Cfg;
423
424 fn db_journal_inner_mut(&mut self) -> (&mut Self::Db, &mut JournaledState);
426
427 fn set_block(&mut self, block: Self::Block) {
429 *self.block_mut() = block;
430 }
431
432 fn set_tx(&mut self, tx: Self::Tx) {
434 *self.tx_mut() = tx;
435 }
436
437 fn set_cfg(&mut self, cfg: Self::Cfg) {
439 *self.cfg_mut() = cfg;
440 }
441
442 fn set_journal_inner(&mut self, journal_inner: JournaledState) {
444 *self.db_journal_inner_mut().1 = journal_inner;
445 }
446
447 fn set_evm(&mut self, evm_env: EvmEnv<Self::Spec, Self::Block>) {
449 *self.cfg_mut() = evm_env.cfg_env;
450 *self.block_mut() = evm_env.block_env;
451 }
452
453 fn tx_clone(&self) -> Self::Tx {
455 self.tx().clone()
456 }
457
458 fn evm_clone(&self) -> EvmEnv<Self::Spec, Self::Block> {
460 EvmEnv::new(self.cfg().clone(), self.block().clone())
461 }
462}
463
464impl<
465 BLOCK: FoundryBlock + Clone,
466 TX: FoundryTransaction + Clone,
467 SPEC: Into<SpecId> + Copy + Debug,
468 DB: Database,
469 C,
470> FoundryContextExt for Context<BLOCK, TX, CfgEnv<SPEC>, DB, Journal<DB>, C>
471{
472 type Spec = <Self::Cfg as Cfg>::Spec;
473
474 fn block_mut(&mut self) -> &mut Self::Block {
475 &mut self.block
476 }
477
478 fn tx_mut(&mut self) -> &mut Self::Tx {
479 &mut self.tx
480 }
481
482 fn cfg_mut(&mut self) -> &mut Self::Cfg {
483 &mut self.cfg
484 }
485
486 fn db_journal_inner_mut(&mut self) -> (&mut Self::Db, &mut JournaledState) {
487 (&mut self.journaled_state.database, &mut self.journaled_state.inner)
488 }
489}
490
491pub trait FromAnyRpcTransaction: Sized {
497 fn from_any_rpc_transaction(tx: &AnyRpcTransaction) -> eyre::Result<Self>;
499}
500
501impl FromAnyRpcTransaction for TxEnv {
502 fn from_any_rpc_transaction(tx: &AnyRpcTransaction) -> eyre::Result<Self> {
503 if let Some(envelope) = tx.as_envelope() {
504 Ok(Self::from_recovered_tx(envelope, tx.from()))
505 } else {
506 eyre::bail!("cannot convert unknown transaction type to TxEnv")
507 }
508 }
509}
510
511impl FromAnyRpcTransaction for TempoTxEnv {
512 fn from_any_rpc_transaction(tx: &AnyRpcTransaction) -> eyre::Result<Self> {
513 use alloy_consensus::Transaction as _;
514 if let Some(envelope) = tx.as_envelope() {
515 return Ok(TxEnv::from_recovered_tx(envelope, tx.from()).into());
516 }
517
518 if let AnyTxEnvelope::Unknown(unknown) = &*tx.inner.inner
520 && unknown.ty() == tempo_alloy::primitives::TEMPO_TX_TYPE_ID
521 {
522 let base = TxEnv {
523 tx_type: unknown.ty(),
524 caller: tx.from(),
525 gas_limit: unknown.gas_limit(),
526 gas_price: unknown.max_fee_per_gas(),
527 gas_priority_fee: unknown.max_priority_fee_per_gas(),
528 kind: unknown.kind(),
529 value: unknown.value(),
530 data: unknown.input().clone(),
531 nonce: unknown.nonce(),
532 chain_id: unknown.chain_id(),
533 access_list: unknown.access_list().cloned().unwrap_or_default(),
534 ..Default::default()
535 };
536 let fee_token =
537 unknown.inner.fields.get_deserialized::<Address>("feeToken").and_then(Result::ok);
538 return Ok(Self { inner: base, fee_token, ..Default::default() });
539 }
540
541 eyre::bail!("cannot convert unknown transaction type to TempoTxEnv")
542 }
543}
544
545#[cfg(feature = "optimism")]
546mod optimism {
547 use super::*;
548 use alloy_op_evm::OpTx;
549 use op_alloy_consensus::{DEPOSIT_TX_TYPE_ID, TxDeposit};
550 use op_revm::{OpTransaction, transaction::OpTxTr};
551
552 impl<TX: FoundryTransaction> FoundryTransaction for OpTransaction<TX> {
553 fn set_tx_type(&mut self, tx_type: u8) {
554 self.base.set_tx_type(tx_type);
555 }
556
557 fn set_caller(&mut self, caller: Address) {
558 self.base.set_caller(caller);
559 }
560
561 fn set_gas_limit(&mut self, gas_limit: u64) {
562 self.base.set_gas_limit(gas_limit);
563 }
564
565 fn set_gas_price(&mut self, gas_price: u128) {
566 self.base.set_gas_price(gas_price);
567 }
568
569 fn set_kind(&mut self, kind: TxKind) {
570 self.base.set_kind(kind);
571 }
572
573 fn set_value(&mut self, value: U256) {
574 self.base.set_value(value);
575 }
576
577 fn set_data(&mut self, data: Bytes) {
578 self.base.set_data(data);
579 }
580
581 fn set_nonce(&mut self, nonce: u64) {
582 self.base.set_nonce(nonce);
583 }
584
585 fn set_chain_id(&mut self, chain_id: Option<u64>) {
586 self.base.set_chain_id(chain_id);
587 }
588
589 fn set_access_list(&mut self, access_list: AccessList) {
590 self.base.set_access_list(access_list);
591 }
592
593 fn authorization_list_mut(
594 &mut self,
595 ) -> &mut Vec<Either<SignedAuthorization, RecoveredAuthorization>> {
596 self.base.authorization_list_mut()
597 }
598
599 fn set_gas_priority_fee(&mut self, gas_priority_fee: Option<u128>) {
600 self.base.set_gas_priority_fee(gas_priority_fee);
601 }
602
603 fn set_blob_hashes(&mut self, _blob_hashes: Vec<B256>) {}
604
605 fn set_max_fee_per_blob_gas(&mut self, _max_fee_per_blob_gas: u128) {}
606
607 fn enveloped_tx(&self) -> Option<&Bytes> {
608 OpTxTr::enveloped_tx(self)
609 }
610
611 fn set_enveloped_tx(&mut self, bytes: Bytes) {
612 self.enveloped_tx = Some(bytes);
613 }
614
615 fn source_hash(&self) -> Option<B256> {
616 OpTxTr::source_hash(self)
617 }
618
619 fn set_source_hash(&mut self, source_hash: B256) {
620 if self.tx_type() == DEPOSIT_TRANSACTION_TYPE {
621 self.deposit.source_hash = source_hash;
622 }
623 }
624
625 fn mint(&self) -> Option<u128> {
626 OpTxTr::mint(self)
627 }
628
629 fn set_mint(&mut self, mint: u128) {
630 if self.tx_type() == DEPOSIT_TRANSACTION_TYPE {
631 self.deposit.mint = Some(mint);
632 }
633 }
634
635 fn is_system_transaction(&self) -> bool {
636 OpTxTr::is_system_transaction(self)
637 }
638
639 fn set_system_transaction(&mut self, is_system_transaction: bool) {
640 if self.tx_type() == DEPOSIT_TRANSACTION_TYPE {
641 self.deposit.is_system_transaction = is_system_transaction;
642 }
643 }
644 }
645
646 impl FoundryTransaction for OpTx {
647 fn set_tx_type(&mut self, tx_type: u8) {
648 self.0.set_tx_type(tx_type);
649 }
650
651 fn set_caller(&mut self, caller: Address) {
652 self.0.set_caller(caller);
653 }
654
655 fn set_gas_limit(&mut self, gas_limit: u64) {
656 self.0.set_gas_limit(gas_limit);
657 }
658
659 fn set_gas_price(&mut self, gas_price: u128) {
660 self.0.set_gas_price(gas_price);
661 }
662
663 fn set_kind(&mut self, kind: TxKind) {
664 self.0.set_kind(kind);
665 }
666
667 fn set_value(&mut self, value: U256) {
668 self.0.set_value(value);
669 }
670
671 fn set_data(&mut self, data: Bytes) {
672 self.0.set_data(data);
673 }
674
675 fn set_nonce(&mut self, nonce: u64) {
676 self.0.set_nonce(nonce);
677 }
678
679 fn set_chain_id(&mut self, chain_id: Option<u64>) {
680 self.0.set_chain_id(chain_id);
681 }
682
683 fn set_access_list(&mut self, access_list: AccessList) {
684 self.0.set_access_list(access_list);
685 }
686
687 fn authorization_list_mut(
688 &mut self,
689 ) -> &mut Vec<Either<SignedAuthorization, RecoveredAuthorization>> {
690 self.0.authorization_list_mut()
691 }
692
693 fn set_gas_priority_fee(&mut self, gas_priority_fee: Option<u128>) {
694 self.0.set_gas_priority_fee(gas_priority_fee);
695 }
696
697 fn set_blob_hashes(&mut self, _blob_hashes: Vec<B256>) {}
698
699 fn set_max_fee_per_blob_gas(&mut self, _max_fee_per_blob_gas: u128) {}
700
701 fn enveloped_tx(&self) -> Option<&Bytes> {
702 FoundryTransaction::enveloped_tx(&self.0)
703 }
704
705 fn set_enveloped_tx(&mut self, bytes: Bytes) {
706 self.0.set_enveloped_tx(bytes);
707 }
708
709 fn source_hash(&self) -> Option<B256> {
710 FoundryTransaction::source_hash(&self.0)
711 }
712
713 fn set_source_hash(&mut self, source_hash: B256) {
714 self.0.set_source_hash(source_hash);
715 }
716
717 fn mint(&self) -> Option<u128> {
718 FoundryTransaction::mint(&self.0)
719 }
720
721 fn set_mint(&mut self, mint: u128) {
722 self.0.set_mint(mint);
723 }
724
725 fn is_system_transaction(&self) -> bool {
726 FoundryTransaction::is_system_transaction(&self.0)
727 }
728
729 fn set_system_transaction(&mut self, is_system_transaction: bool) {
730 self.0.set_system_transaction(is_system_transaction);
731 }
732 }
733
734 impl FromAnyRpcTransaction for OpTx {
735 fn from_any_rpc_transaction(tx: &AnyRpcTransaction) -> eyre::Result<Self> {
736 if let Some(envelope) = tx.as_envelope() {
737 return Ok(Self(OpTransaction::<TxEnv> {
738 base: TxEnv::from_recovered_tx(envelope, tx.from()),
739 enveloped_tx: None,
740 deposit: Default::default(),
741 }));
742 }
743
744 if let AnyTxEnvelope::Unknown(unknown) = &*tx.inner.inner
746 && unknown.ty() == DEPOSIT_TX_TYPE_ID
747 {
748 let mut fields = unknown.inner.fields.clone();
749 fields.insert("from".to_string(), serde_json::to_value(tx.from())?);
750 let deposit_tx: TxDeposit = fields
751 .deserialize_into()
752 .map_err(|e| eyre::eyre!("failed to deserialize deposit tx: {e}"))?;
753 return Ok(Self::from_recovered_tx(&deposit_tx, deposit_tx.from));
754 }
755
756 eyre::bail!("cannot convert unknown transaction type to OpTransaction")
757 }
758 }
759}
760
761#[cfg(test)]
762mod tests {
763 use std::num::NonZeroU64;
764
765 use super::*;
766 use alloy_consensus::{Signed, TxEip1559, transaction::Recovered};
767 use alloy_evm::{EthEvmFactory, EvmFactory};
768 use alloy_network::{AnyTxType, UnknownTxEnvelope, UnknownTypedTransaction};
769 use alloy_primitives::Signature;
770 use alloy_rpc_types::{Transaction as RpcTransaction, TransactionInfo};
771 use alloy_serde::WithOtherFields;
772 use foundry_evm_hardforks::TempoHardfork;
773 use revm::database::EmptyDB;
774 use tempo_alloy::primitives::{
775 AASigned, TempoSignature, TempoTransaction, TempoTxEnvelope,
776 transaction::PrimitiveSignature,
777 };
778 use tempo_evm::TempoEvmFactory;
779
780 #[test]
781 fn eth_evm_foundry_context_ext_implementation() {
782 let mut evm = EthEvmFactory::default().create_evm(EmptyDB::default(), EvmEnv::default());
783
784 evm.ctx_mut().block_mut().set_number(U256::from(123));
786 assert_eq!(evm.ctx().block().number(), U256::from(123));
787
788 evm.ctx_mut().tx_mut().set_nonce(99);
790 assert_eq!(evm.ctx().tx().nonce(), 99);
791
792 evm.ctx_mut().cfg_mut().spec = SpecId::AMSTERDAM;
794 assert_eq!(evm.ctx().cfg().spec, SpecId::AMSTERDAM);
795
796 let tx_env = evm.ctx().tx_clone();
798 evm.ctx_mut().set_tx(tx_env);
799 let evm_env = evm.ctx().evm_clone();
800 evm.ctx_mut().set_evm(evm_env);
801 }
802
803 #[test]
804 fn tempo_evm_foundry_context_ext_implementation() {
805 let mut evm = TempoEvmFactory::default().create_evm(EmptyDB::default(), EvmEnv::default());
806
807 evm.ctx_mut().block_mut().set_number(U256::from(123));
809 assert_eq!(evm.ctx().block().number(), U256::from(123));
810
811 evm.ctx_mut().tx_mut().set_nonce(99);
813 assert_eq!(evm.ctx().tx().nonce(), 99);
814
815 evm.ctx_mut().cfg_mut().spec = TempoHardfork::Genesis;
817 assert_eq!(evm.ctx().cfg().spec, TempoHardfork::Genesis);
818
819 let tx_env = evm.ctx().tx_clone();
821 evm.ctx_mut().set_tx(tx_env);
822 let evm_env = evm.ctx().evm_clone();
823 evm.ctx_mut().set_evm(evm_env);
824 }
825
826 fn make_signed_eip1559() -> Signed<TxEip1559> {
827 Signed::new_unchecked(
828 TxEip1559 {
829 chain_id: 1,
830 nonce: 42,
831 gas_limit: 21001,
832 to: TxKind::Call(Address::with_last_byte(0xBB)),
833 value: U256::from(101),
834 ..Default::default()
835 },
836 Signature::new(U256::ZERO, U256::ZERO, false),
837 B256::ZERO,
838 )
839 }
840
841 #[test]
842 fn from_any_rpc_transaction_for_eth() {
843 let from = Address::random();
844 let signed_tx = make_signed_eip1559();
845 let rpc_tx = RpcTransaction::from_transaction(
846 Recovered::new_unchecked(signed_tx.into(), from),
847 TransactionInfo::default(),
848 );
849
850 let any_tx = <AnyRpcTransaction as From<RpcTransaction>>::from(rpc_tx);
851 let tx_env = TxEnv::from_any_rpc_transaction(&any_tx).unwrap();
852
853 assert_eq!(tx_env.caller, from);
854 assert_eq!(tx_env.nonce, 42);
855 assert_eq!(tx_env.gas_limit, 21001);
856 assert_eq!(tx_env.value, U256::from(101));
857 assert_eq!(tx_env.kind, TxKind::Call(Address::with_last_byte(0xBB)));
858 }
859
860 #[test]
861 fn from_any_rpc_transaction_unknown_envelope_errors() {
862 let unknown = AnyTxEnvelope::Unknown(UnknownTxEnvelope {
863 hash: B256::ZERO,
864 inner: UnknownTypedTransaction {
865 ty: AnyTxType(0xFF),
866 fields: Default::default(),
867 memo: Default::default(),
868 },
869 });
870 let from = Address::random();
871 let any_tx = AnyRpcTransaction::new(WithOtherFields::new(RpcTransaction {
872 inner: Recovered::new_unchecked(unknown, from),
873 block_hash: None,
874 block_number: None,
875 transaction_index: None,
876 effective_gas_price: None,
877 block_timestamp: None,
878 }));
879
880 let result = TxEnv::from_any_rpc_transaction(&any_tx).unwrap_err();
881 assert!(result.to_string().contains("unknown transaction type"));
882 }
883
884 #[test]
885 fn from_any_rpc_transaction_for_tempo_eth_envelope() {
886 let from = Address::random();
887 let signed_tx = make_signed_eip1559();
888 let rpc_tx = RpcTransaction::from_transaction(
889 Recovered::new_unchecked(signed_tx.into(), from),
890 TransactionInfo::default(),
891 );
892 let any_tx = <AnyRpcTransaction as From<RpcTransaction>>::from(rpc_tx);
893
894 let tx_env = TempoTxEnv::from_any_rpc_transaction(&any_tx).unwrap();
895 assert_eq!(tx_env.inner.caller, from);
896 assert_eq!(tx_env.inner.nonce, 42);
897 assert_eq!(tx_env.inner.gas_limit, 21001);
898 assert_eq!(tx_env.inner.value, U256::from(101));
899 assert_eq!(tx_env.fee_token, None);
900 }
901
902 #[test]
903 fn from_any_rpc_transaction_for_tempo_aa() {
904 let from = Address::random();
905 let fee_token = Some(Address::random());
906 let tempo_tx = TempoTransaction {
907 chain_id: 42431,
908 nonce: 42,
909 gas_limit: 424242,
910 fee_token,
911 nonce_key: U256::from(4242),
912 valid_after: NonZeroU64::new(1800000000),
913 ..Default::default()
914 };
915 let aa_signed = AASigned::new_unhashed(
916 tempo_tx,
917 TempoSignature::Primitive(PrimitiveSignature::Secp256k1(Signature::new(
918 U256::ZERO,
919 U256::ZERO,
920 false,
921 ))),
922 );
923
924 let rpc_tx = RpcTransaction::from_transaction(
927 Recovered::new_unchecked(TempoTxEnvelope::AA(aa_signed), from),
928 TransactionInfo::default(),
929 );
930 let json = serde_json::to_value(&rpc_tx).unwrap();
931 let any_tx: AnyRpcTransaction = serde_json::from_value(json).unwrap();
932
933 let tx_env = TempoTxEnv::from_any_rpc_transaction(&any_tx).unwrap();
934 assert_eq!(tx_env.inner.caller, from);
935 assert_eq!(tx_env.inner.nonce, 42);
936 assert_eq!(tx_env.inner.gas_limit, 424242);
937 assert_eq!(tx_env.inner.chain_id, Some(42431));
938 assert_eq!(tx_env.fee_token, fee_token);
939 }
940
941 #[cfg(feature = "optimism")]
942 mod optimism {
943 use super::*;
944 use alloy_consensus::Sealed;
945 use alloy_op_evm::{OpEvmFactory, OpTx};
946 use op_alloy_consensus::{OpTxEnvelope, TxDeposit, transaction::OpTransactionInfo};
947 use op_alloy_rpc_types::Transaction as OpRpcTransaction;
948 use op_revm::OpSpecId;
949
950 #[test]
951 fn op_evm_foundry_context_ext_implementation() {
952 let mut evm =
953 OpEvmFactory::<OpTx>::default().create_evm(EmptyDB::default(), EvmEnv::default());
954
955 evm.ctx_mut().block_mut().set_number(U256::from(123));
957 assert_eq!(evm.ctx().block().number(), U256::from(123));
958
959 evm.ctx_mut().tx_mut().set_nonce(99);
961 assert_eq!(evm.ctx().tx().nonce(), 99);
962
963 evm.ctx_mut().cfg_mut().spec = OpSpecId::JOVIAN;
965 assert_eq!(evm.ctx().cfg().spec, OpSpecId::JOVIAN);
966
967 let tx_env = evm.ctx().tx_clone();
969 evm.ctx_mut().set_tx(tx_env);
970 let evm_env = evm.ctx().evm_clone();
971 evm.ctx_mut().set_evm(evm_env);
972 }
973
974 #[test]
975 fn from_any_rpc_transaction_for_op() {
976 let from = Address::random();
977 let signed_tx = make_signed_eip1559();
978
979 let rpc_tx = RpcTransaction::from_transaction(
981 Recovered::new_unchecked(signed_tx.into(), from),
982 TransactionInfo::default(),
983 );
984 let any_tx = <AnyRpcTransaction as From<RpcTransaction>>::from(rpc_tx);
985 let expected_base = TxEnv::from_any_rpc_transaction(&any_tx).unwrap();
986
987 let op_tx_env = OpTx::from_any_rpc_transaction(&any_tx).unwrap();
988 assert_eq!(op_tx_env.base, expected_base);
989 }
990
991 #[test]
992 fn from_any_rpc_transaction_for_op_deposit() {
993 let from = Address::random();
994 let source_hash = B256::random();
995 let deposit = TxDeposit {
996 source_hash,
997 from,
998 to: TxKind::Call(Address::with_last_byte(0xCC)),
999 mint: 1111,
1000 value: U256::from(200),
1001 gas_limit: 21000,
1002 is_system_transaction: true,
1003 input: Default::default(),
1004 };
1005
1006 let op_rpc_tx = OpRpcTransaction::from_transaction(
1009 Recovered::new_unchecked(OpTxEnvelope::Deposit(Sealed::new(deposit)), from),
1010 OpTransactionInfo::default(),
1011 );
1012 let json = serde_json::to_value(&op_rpc_tx).unwrap();
1013 let any_tx: AnyRpcTransaction = serde_json::from_value(json).unwrap();
1014
1015 let op_tx_env = OpTx::from_any_rpc_transaction(&any_tx).unwrap();
1016 assert_eq!(op_tx_env.base.caller, from);
1017 assert_eq!(op_tx_env.base.kind, TxKind::Call(Address::with_last_byte(0xCC)));
1018 assert_eq!(op_tx_env.base.value, U256::from(200));
1019 assert_eq!(op_tx_env.base.gas_limit, 21000);
1020 assert_eq!(op_tx_env.deposit.source_hash, source_hash);
1021 assert_eq!(op_tx_env.deposit.mint, Some(1111));
1022 assert!(op_tx_env.deposit.is_system_transaction);
1023 }
1024 }
1025}