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 if let Some(call) =
346 self.tempo_tx_env.as_deref_mut().and_then(|env| env.aa_calls.first_mut())
347 {
348 call.to = kind;
349 }
350 }
351
352 fn set_value(&mut self, value: U256) {
353 self.inner.set_value(value);
354 if let Some(call) =
355 self.tempo_tx_env.as_deref_mut().and_then(|env| env.aa_calls.first_mut())
356 {
357 call.value = value;
358 }
359 }
360
361 fn set_data(&mut self, data: Bytes) {
362 self.inner.set_data(data.clone());
363 if let Some(call) =
364 self.tempo_tx_env.as_deref_mut().and_then(|env| env.aa_calls.first_mut())
365 {
366 call.input = data;
367 }
368 }
369
370 fn set_nonce(&mut self, nonce: u64) {
371 self.inner.set_nonce(nonce);
372 }
373
374 fn set_chain_id(&mut self, chain_id: Option<u64>) {
375 self.inner.set_chain_id(chain_id);
376 }
377
378 fn set_access_list(&mut self, access_list: AccessList) {
379 self.inner.set_access_list(access_list);
380 }
381
382 fn authorization_list_mut(
383 &mut self,
384 ) -> &mut Vec<Either<SignedAuthorization, RecoveredAuthorization>> {
385 self.inner.authorization_list_mut()
386 }
387
388 fn set_gas_priority_fee(&mut self, gas_priority_fee: Option<u128>) {
389 self.inner.set_gas_priority_fee(gas_priority_fee);
390 }
391
392 fn set_blob_hashes(&mut self, _blob_hashes: Vec<B256>) {}
393
394 fn set_max_fee_per_blob_gas(&mut self, _max_fee_per_blob_gas: u128) {}
395
396 fn fee_token(&self) -> Option<Address> {
397 self.fee_token
398 }
399
400 fn set_fee_token(&mut self, token: Option<Address>) {
401 self.fee_token = token;
402 }
403
404 fn fee_payer(&self) -> Option<Option<Address>> {
405 self.fee_payer
406 }
407
408 fn set_fee_payer(&mut self, payer: Option<Option<Address>>) {
409 self.fee_payer = payer;
410 }
411}
412
413pub trait FoundryContextExt:
418 ContextTr<
419 Block: FoundryBlock + Clone,
420 Tx: FoundryTransaction + Clone,
421 Cfg = CfgEnv<Self::Spec>,
422 Journal: JournalExt,
423 >
424{
425 type Spec: Into<SpecId> + Copy + Debug;
429
430 fn block_mut(&mut self) -> &mut Self::Block;
432
433 fn tx_mut(&mut self) -> &mut Self::Tx;
435
436 fn cfg_mut(&mut self) -> &mut Self::Cfg;
438
439 fn db_journal_inner_mut(&mut self) -> (&mut Self::Db, &mut JournaledState);
441
442 fn set_block(&mut self, block: Self::Block) {
444 *self.block_mut() = block;
445 }
446
447 fn set_tx(&mut self, tx: Self::Tx) {
449 *self.tx_mut() = tx;
450 }
451
452 fn set_cfg(&mut self, cfg: Self::Cfg) {
454 *self.cfg_mut() = cfg;
455 }
456
457 fn set_journal_inner(&mut self, journal_inner: JournaledState) {
459 *self.db_journal_inner_mut().1 = journal_inner;
460 }
461
462 fn set_evm(&mut self, evm_env: EvmEnv<Self::Spec, Self::Block>) {
464 *self.cfg_mut() = evm_env.cfg_env;
465 *self.block_mut() = evm_env.block_env;
466 }
467
468 fn tx_clone(&self) -> Self::Tx {
470 self.tx().clone()
471 }
472
473 fn evm_clone(&self) -> EvmEnv<Self::Spec, Self::Block> {
475 EvmEnv::new(self.cfg().clone(), self.block().clone())
476 }
477}
478
479impl<
480 BLOCK: FoundryBlock + Clone,
481 TX: FoundryTransaction + Clone,
482 SPEC: Into<SpecId> + Copy + Debug,
483 DB: Database,
484 C,
485> FoundryContextExt for Context<BLOCK, TX, CfgEnv<SPEC>, DB, Journal<DB>, C>
486{
487 type Spec = <Self::Cfg as Cfg>::Spec;
488
489 fn block_mut(&mut self) -> &mut Self::Block {
490 &mut self.block
491 }
492
493 fn tx_mut(&mut self) -> &mut Self::Tx {
494 &mut self.tx
495 }
496
497 fn cfg_mut(&mut self) -> &mut Self::Cfg {
498 &mut self.cfg
499 }
500
501 fn db_journal_inner_mut(&mut self) -> (&mut Self::Db, &mut JournaledState) {
502 (&mut self.journaled_state.database, &mut self.journaled_state.inner)
503 }
504}
505
506pub trait FromAnyRpcTransaction: Sized {
512 fn from_any_rpc_transaction(tx: &AnyRpcTransaction) -> eyre::Result<Self>;
514}
515
516impl FromAnyRpcTransaction for TxEnv {
517 fn from_any_rpc_transaction(tx: &AnyRpcTransaction) -> eyre::Result<Self> {
518 if let Some(envelope) = tx.as_envelope() {
519 Ok(Self::from_recovered_tx(envelope, tx.from()))
520 } else {
521 eyre::bail!("cannot convert unknown transaction type to TxEnv")
522 }
523 }
524}
525
526impl FromAnyRpcTransaction for TempoTxEnv {
527 fn from_any_rpc_transaction(tx: &AnyRpcTransaction) -> eyre::Result<Self> {
528 use alloy_consensus::Transaction as _;
529 if let Some(envelope) = tx.as_envelope() {
530 return Ok(TxEnv::from_recovered_tx(envelope, tx.from()).into());
531 }
532
533 if let AnyTxEnvelope::Unknown(unknown) = &*tx.inner.inner
535 && unknown.ty() == tempo_alloy::primitives::TEMPO_TX_TYPE_ID
536 {
537 let base = TxEnv {
538 tx_type: unknown.ty(),
539 caller: tx.from(),
540 gas_limit: unknown.gas_limit(),
541 gas_price: unknown.max_fee_per_gas(),
542 gas_priority_fee: unknown.max_priority_fee_per_gas(),
543 kind: unknown.kind(),
544 value: unknown.value(),
545 data: unknown.input().clone(),
546 nonce: unknown.nonce(),
547 chain_id: unknown.chain_id(),
548 access_list: unknown.access_list().cloned().unwrap_or_default(),
549 ..Default::default()
550 };
551 let fee_token =
552 unknown.inner.fields.get_deserialized::<Address>("feeToken").and_then(Result::ok);
553 return Ok(Self { inner: base, fee_token, ..Default::default() });
554 }
555
556 eyre::bail!("cannot convert unknown transaction type to TempoTxEnv")
557 }
558}
559
560#[cfg(feature = "optimism")]
561mod optimism {
562 use super::*;
563 use alloy_op_evm::OpTx;
564 use op_alloy_consensus::{DEPOSIT_TX_TYPE_ID, TxDeposit};
565 use op_revm::{OpTransaction, transaction::OpTxTr};
566
567 impl<TX: FoundryTransaction> FoundryTransaction for OpTransaction<TX> {
568 fn set_tx_type(&mut self, tx_type: u8) {
569 self.base.set_tx_type(tx_type);
570 }
571
572 fn set_caller(&mut self, caller: Address) {
573 self.base.set_caller(caller);
574 }
575
576 fn set_gas_limit(&mut self, gas_limit: u64) {
577 self.base.set_gas_limit(gas_limit);
578 }
579
580 fn set_gas_price(&mut self, gas_price: u128) {
581 self.base.set_gas_price(gas_price);
582 }
583
584 fn set_kind(&mut self, kind: TxKind) {
585 self.base.set_kind(kind);
586 }
587
588 fn set_value(&mut self, value: U256) {
589 self.base.set_value(value);
590 }
591
592 fn set_data(&mut self, data: Bytes) {
593 self.base.set_data(data);
594 }
595
596 fn set_nonce(&mut self, nonce: u64) {
597 self.base.set_nonce(nonce);
598 }
599
600 fn set_chain_id(&mut self, chain_id: Option<u64>) {
601 self.base.set_chain_id(chain_id);
602 }
603
604 fn set_access_list(&mut self, access_list: AccessList) {
605 self.base.set_access_list(access_list);
606 }
607
608 fn authorization_list_mut(
609 &mut self,
610 ) -> &mut Vec<Either<SignedAuthorization, RecoveredAuthorization>> {
611 self.base.authorization_list_mut()
612 }
613
614 fn set_gas_priority_fee(&mut self, gas_priority_fee: Option<u128>) {
615 self.base.set_gas_priority_fee(gas_priority_fee);
616 }
617
618 fn set_blob_hashes(&mut self, _blob_hashes: Vec<B256>) {}
619
620 fn set_max_fee_per_blob_gas(&mut self, _max_fee_per_blob_gas: u128) {}
621
622 fn enveloped_tx(&self) -> Option<&Bytes> {
623 OpTxTr::enveloped_tx(self)
624 }
625
626 fn set_enveloped_tx(&mut self, bytes: Bytes) {
627 self.enveloped_tx = Some(bytes);
628 }
629
630 fn source_hash(&self) -> Option<B256> {
631 OpTxTr::source_hash(self)
632 }
633
634 fn set_source_hash(&mut self, source_hash: B256) {
635 if self.tx_type() == DEPOSIT_TRANSACTION_TYPE {
636 self.deposit.source_hash = source_hash;
637 }
638 }
639
640 fn mint(&self) -> Option<u128> {
641 OpTxTr::mint(self)
642 }
643
644 fn set_mint(&mut self, mint: u128) {
645 if self.tx_type() == DEPOSIT_TRANSACTION_TYPE {
646 self.deposit.mint = Some(mint);
647 }
648 }
649
650 fn is_system_transaction(&self) -> bool {
651 OpTxTr::is_system_transaction(self)
652 }
653
654 fn set_system_transaction(&mut self, is_system_transaction: bool) {
655 if self.tx_type() == DEPOSIT_TRANSACTION_TYPE {
656 self.deposit.is_system_transaction = is_system_transaction;
657 }
658 }
659 }
660
661 impl FoundryTransaction for OpTx {
662 fn set_tx_type(&mut self, tx_type: u8) {
663 self.0.set_tx_type(tx_type);
664 }
665
666 fn set_caller(&mut self, caller: Address) {
667 self.0.set_caller(caller);
668 }
669
670 fn set_gas_limit(&mut self, gas_limit: u64) {
671 self.0.set_gas_limit(gas_limit);
672 }
673
674 fn set_gas_price(&mut self, gas_price: u128) {
675 self.0.set_gas_price(gas_price);
676 }
677
678 fn set_kind(&mut self, kind: TxKind) {
679 self.0.set_kind(kind);
680 }
681
682 fn set_value(&mut self, value: U256) {
683 self.0.set_value(value);
684 }
685
686 fn set_data(&mut self, data: Bytes) {
687 self.0.set_data(data);
688 }
689
690 fn set_nonce(&mut self, nonce: u64) {
691 self.0.set_nonce(nonce);
692 }
693
694 fn set_chain_id(&mut self, chain_id: Option<u64>) {
695 self.0.set_chain_id(chain_id);
696 }
697
698 fn set_access_list(&mut self, access_list: AccessList) {
699 self.0.set_access_list(access_list);
700 }
701
702 fn authorization_list_mut(
703 &mut self,
704 ) -> &mut Vec<Either<SignedAuthorization, RecoveredAuthorization>> {
705 self.0.authorization_list_mut()
706 }
707
708 fn set_gas_priority_fee(&mut self, gas_priority_fee: Option<u128>) {
709 self.0.set_gas_priority_fee(gas_priority_fee);
710 }
711
712 fn set_blob_hashes(&mut self, _blob_hashes: Vec<B256>) {}
713
714 fn set_max_fee_per_blob_gas(&mut self, _max_fee_per_blob_gas: u128) {}
715
716 fn enveloped_tx(&self) -> Option<&Bytes> {
717 FoundryTransaction::enveloped_tx(&self.0)
718 }
719
720 fn set_enveloped_tx(&mut self, bytes: Bytes) {
721 self.0.set_enveloped_tx(bytes);
722 }
723
724 fn source_hash(&self) -> Option<B256> {
725 FoundryTransaction::source_hash(&self.0)
726 }
727
728 fn set_source_hash(&mut self, source_hash: B256) {
729 self.0.set_source_hash(source_hash);
730 }
731
732 fn mint(&self) -> Option<u128> {
733 FoundryTransaction::mint(&self.0)
734 }
735
736 fn set_mint(&mut self, mint: u128) {
737 self.0.set_mint(mint);
738 }
739
740 fn is_system_transaction(&self) -> bool {
741 FoundryTransaction::is_system_transaction(&self.0)
742 }
743
744 fn set_system_transaction(&mut self, is_system_transaction: bool) {
745 self.0.set_system_transaction(is_system_transaction);
746 }
747 }
748
749 impl FromAnyRpcTransaction for OpTx {
750 fn from_any_rpc_transaction(tx: &AnyRpcTransaction) -> eyre::Result<Self> {
751 if let Some(envelope) = tx.as_envelope() {
752 return Ok(Self(OpTransaction::<TxEnv> {
753 base: TxEnv::from_recovered_tx(envelope, tx.from()),
754 enveloped_tx: None,
755 deposit: Default::default(),
756 }));
757 }
758
759 if let AnyTxEnvelope::Unknown(unknown) = &*tx.inner.inner
761 && unknown.ty() == DEPOSIT_TX_TYPE_ID
762 {
763 let mut fields = unknown.inner.fields.clone();
764 fields.insert("from".to_string(), serde_json::to_value(tx.from())?);
765 let deposit_tx: TxDeposit = fields
766 .deserialize_into()
767 .map_err(|e| eyre::eyre!("failed to deserialize deposit tx: {e}"))?;
768 return Ok(Self::from_recovered_tx(&deposit_tx, deposit_tx.from));
769 }
770
771 eyre::bail!("cannot convert unknown transaction type to OpTransaction")
772 }
773 }
774}
775
776#[cfg(test)]
777mod tests {
778 use std::num::NonZeroU64;
779
780 use super::*;
781 use alloy_consensus::{Signed, TxEip1559, transaction::Recovered};
782 use alloy_evm::{EthEvmFactory, EvmFactory};
783 use alloy_network::{AnyTxType, UnknownTxEnvelope, UnknownTypedTransaction};
784 use alloy_primitives::Signature;
785 use alloy_rpc_types::{Transaction as RpcTransaction, TransactionInfo};
786 use alloy_serde::WithOtherFields;
787 use foundry_evm_hardforks::TempoHardfork;
788 use revm::database::EmptyDB;
789 use tempo_alloy::primitives::{
790 AASigned, TempoSignature, TempoTransaction, TempoTxEnvelope,
791 transaction::{Call, PrimitiveSignature},
792 };
793 use tempo_evm::TempoEvmFactory;
794
795 #[test]
796 fn eth_evm_foundry_context_ext_implementation() {
797 let mut evm = EthEvmFactory::default().create_evm(EmptyDB::default(), EvmEnv::default());
798
799 evm.ctx_mut().block_mut().set_number(U256::from(123));
801 assert_eq!(evm.ctx().block().number(), U256::from(123));
802
803 evm.ctx_mut().tx_mut().set_nonce(99);
805 assert_eq!(evm.ctx().tx().nonce(), 99);
806
807 evm.ctx_mut().cfg_mut().spec = SpecId::AMSTERDAM;
809 assert_eq!(evm.ctx().cfg().spec, SpecId::AMSTERDAM);
810
811 let tx_env = evm.ctx().tx_clone();
813 evm.ctx_mut().set_tx(tx_env);
814 let evm_env = evm.ctx().evm_clone();
815 evm.ctx_mut().set_evm(evm_env);
816 }
817
818 #[test]
819 fn tempo_evm_foundry_context_ext_implementation() {
820 let mut evm = TempoEvmFactory::default().create_evm(EmptyDB::default(), EvmEnv::default());
821
822 evm.ctx_mut().block_mut().set_number(U256::from(123));
824 assert_eq!(evm.ctx().block().number(), U256::from(123));
825
826 evm.ctx_mut().tx_mut().set_nonce(99);
828 assert_eq!(evm.ctx().tx().nonce(), 99);
829
830 evm.ctx_mut().cfg_mut().spec = TempoHardfork::Genesis;
832 assert_eq!(evm.ctx().cfg().spec, TempoHardfork::Genesis);
833
834 let tx_env = evm.ctx().tx_clone();
836 evm.ctx_mut().set_tx(tx_env);
837 let evm_env = evm.ctx().evm_clone();
838 evm.ctx_mut().set_evm(evm_env);
839 }
840
841 #[test]
842 fn tempo_tx_env_setters_update_aa_call_payload() {
843 let old_to = TxKind::Call(Address::with_last_byte(0xAA));
844 let new_to = TxKind::Create;
845 let new_value = U256::from(123);
846 let new_input = Bytes::from_static(b"local bytecode");
847
848 let mut tx_env = TempoTxEnv {
849 inner: TxEnv {
850 kind: old_to,
851 value: U256::from(1),
852 data: Bytes::from_static(b"original bytecode"),
853 ..Default::default()
854 },
855 tempo_tx_env: Some(Box::new(tempo_revm::TempoBatchCallEnv {
856 aa_calls: vec![Call {
857 to: old_to,
858 value: U256::from(1),
859 input: Bytes::from_static(b"original bytecode"),
860 }],
861 ..Default::default()
862 })),
863 ..Default::default()
864 };
865
866 tx_env.set_kind(new_to);
867 tx_env.set_value(new_value);
868 tx_env.set_data(new_input.clone());
869
870 assert_eq!(tx_env.inner.kind, new_to);
871 assert_eq!(tx_env.inner.value, new_value);
872 assert_eq!(tx_env.inner.data, new_input);
873
874 let call = &tx_env.tempo_tx_env.as_ref().unwrap().aa_calls[0];
875 assert_eq!(call.to, new_to);
876 assert_eq!(call.value, new_value);
877 assert_eq!(call.input, new_input);
878 }
879
880 fn make_signed_eip1559() -> Signed<TxEip1559> {
881 Signed::new_unchecked(
882 TxEip1559 {
883 chain_id: 1,
884 nonce: 42,
885 gas_limit: 21001,
886 to: TxKind::Call(Address::with_last_byte(0xBB)),
887 value: U256::from(101),
888 ..Default::default()
889 },
890 Signature::new(U256::ZERO, U256::ZERO, false),
891 B256::ZERO,
892 )
893 }
894
895 #[test]
896 fn from_any_rpc_transaction_for_eth() {
897 let from = Address::random();
898 let signed_tx = make_signed_eip1559();
899 let rpc_tx = RpcTransaction::from_transaction(
900 Recovered::new_unchecked(signed_tx.into(), from),
901 TransactionInfo::default(),
902 );
903
904 let any_tx = <AnyRpcTransaction as From<RpcTransaction>>::from(rpc_tx);
905 let tx_env = TxEnv::from_any_rpc_transaction(&any_tx).unwrap();
906
907 assert_eq!(tx_env.caller, from);
908 assert_eq!(tx_env.nonce, 42);
909 assert_eq!(tx_env.gas_limit, 21001);
910 assert_eq!(tx_env.value, U256::from(101));
911 assert_eq!(tx_env.kind, TxKind::Call(Address::with_last_byte(0xBB)));
912 }
913
914 #[test]
915 fn from_any_rpc_transaction_unknown_envelope_errors() {
916 let unknown = AnyTxEnvelope::Unknown(UnknownTxEnvelope {
917 hash: B256::ZERO,
918 inner: UnknownTypedTransaction {
919 ty: AnyTxType(0xFF),
920 fields: Default::default(),
921 memo: Default::default(),
922 },
923 });
924 let from = Address::random();
925 let any_tx = AnyRpcTransaction::new(WithOtherFields::new(RpcTransaction {
926 inner: Recovered::new_unchecked(unknown, from),
927 block_hash: None,
928 block_number: None,
929 transaction_index: None,
930 effective_gas_price: None,
931 block_timestamp: None,
932 }));
933
934 let result = TxEnv::from_any_rpc_transaction(&any_tx).unwrap_err();
935 assert!(result.to_string().contains("unknown transaction type"));
936 }
937
938 #[test]
939 fn from_any_rpc_transaction_for_tempo_eth_envelope() {
940 let from = Address::random();
941 let signed_tx = make_signed_eip1559();
942 let rpc_tx = RpcTransaction::from_transaction(
943 Recovered::new_unchecked(signed_tx.into(), from),
944 TransactionInfo::default(),
945 );
946 let any_tx = <AnyRpcTransaction as From<RpcTransaction>>::from(rpc_tx);
947
948 let tx_env = TempoTxEnv::from_any_rpc_transaction(&any_tx).unwrap();
949 assert_eq!(tx_env.inner.caller, from);
950 assert_eq!(tx_env.inner.nonce, 42);
951 assert_eq!(tx_env.inner.gas_limit, 21001);
952 assert_eq!(tx_env.inner.value, U256::from(101));
953 assert_eq!(tx_env.fee_token, None);
954 }
955
956 #[test]
957 fn from_any_rpc_transaction_for_tempo_aa() {
958 let from = Address::random();
959 let fee_token = Some(Address::random());
960 let tempo_tx = TempoTransaction {
961 chain_id: 42431,
962 nonce: 42,
963 gas_limit: 424242,
964 fee_token,
965 nonce_key: U256::from(4242),
966 valid_after: NonZeroU64::new(1800000000),
967 ..Default::default()
968 };
969 let aa_signed = AASigned::new_unhashed(
970 tempo_tx,
971 TempoSignature::Primitive(PrimitiveSignature::Secp256k1(Signature::new(
972 U256::ZERO,
973 U256::ZERO,
974 false,
975 ))),
976 );
977
978 let rpc_tx = RpcTransaction::from_transaction(
981 Recovered::new_unchecked(TempoTxEnvelope::AA(aa_signed), from),
982 TransactionInfo::default(),
983 );
984 let json = serde_json::to_value(&rpc_tx).unwrap();
985 let any_tx: AnyRpcTransaction = serde_json::from_value(json).unwrap();
986
987 let tx_env = TempoTxEnv::from_any_rpc_transaction(&any_tx).unwrap();
988 assert_eq!(tx_env.inner.caller, from);
989 assert_eq!(tx_env.inner.nonce, 42);
990 assert_eq!(tx_env.inner.gas_limit, 424242);
991 assert_eq!(tx_env.inner.chain_id, Some(42431));
992 assert_eq!(tx_env.fee_token, fee_token);
993 }
994
995 #[cfg(feature = "optimism")]
996 mod optimism {
997 use super::*;
998 use alloy_consensus::Sealed;
999 use alloy_op_evm::{OpEvmFactory, OpTx};
1000 use op_alloy_consensus::{OpTxEnvelope, TxDeposit, transaction::OpTransactionInfo};
1001 use op_alloy_rpc_types::Transaction as OpRpcTransaction;
1002 use op_revm::OpSpecId;
1003
1004 #[test]
1005 fn op_evm_foundry_context_ext_implementation() {
1006 let mut evm =
1007 OpEvmFactory::<OpTx>::default().create_evm(EmptyDB::default(), EvmEnv::default());
1008
1009 evm.ctx_mut().block_mut().set_number(U256::from(123));
1011 assert_eq!(evm.ctx().block().number(), U256::from(123));
1012
1013 evm.ctx_mut().tx_mut().set_nonce(99);
1015 assert_eq!(evm.ctx().tx().nonce(), 99);
1016
1017 evm.ctx_mut().cfg_mut().spec = OpSpecId::JOVIAN;
1019 assert_eq!(evm.ctx().cfg().spec, OpSpecId::JOVIAN);
1020
1021 let tx_env = evm.ctx().tx_clone();
1023 evm.ctx_mut().set_tx(tx_env);
1024 let evm_env = evm.ctx().evm_clone();
1025 evm.ctx_mut().set_evm(evm_env);
1026 }
1027
1028 #[test]
1029 fn from_any_rpc_transaction_for_op() {
1030 let from = Address::random();
1031 let signed_tx = make_signed_eip1559();
1032
1033 let rpc_tx = RpcTransaction::from_transaction(
1035 Recovered::new_unchecked(signed_tx.into(), from),
1036 TransactionInfo::default(),
1037 );
1038 let any_tx = <AnyRpcTransaction as From<RpcTransaction>>::from(rpc_tx);
1039 let expected_base = TxEnv::from_any_rpc_transaction(&any_tx).unwrap();
1040
1041 let op_tx_env = OpTx::from_any_rpc_transaction(&any_tx).unwrap();
1042 assert_eq!(op_tx_env.base, expected_base);
1043 }
1044
1045 #[test]
1046 fn from_any_rpc_transaction_for_op_deposit() {
1047 let from = Address::random();
1048 let source_hash = B256::random();
1049 let deposit = TxDeposit {
1050 source_hash,
1051 from,
1052 to: TxKind::Call(Address::with_last_byte(0xCC)),
1053 mint: 1111,
1054 value: U256::from(200),
1055 gas_limit: 21000,
1056 is_system_transaction: true,
1057 input: Default::default(),
1058 };
1059
1060 let op_rpc_tx = OpRpcTransaction::from_transaction(
1063 Recovered::new_unchecked(OpTxEnvelope::Deposit(Sealed::new(deposit)), from),
1064 OpTransactionInfo::default(),
1065 );
1066 let json = serde_json::to_value(&op_rpc_tx).unwrap();
1067 let any_tx: AnyRpcTransaction = serde_json::from_value(json).unwrap();
1068
1069 let op_tx_env = OpTx::from_any_rpc_transaction(&any_tx).unwrap();
1070 assert_eq!(op_tx_env.base.caller, from);
1071 assert_eq!(op_tx_env.base.kind, TxKind::Call(Address::with_last_byte(0xCC)));
1072 assert_eq!(op_tx_env.base.value, U256::from(200));
1073 assert_eq!(op_tx_env.base.gas_limit, 21000);
1074 assert_eq!(op_tx_env.deposit.source_hash, source_hash);
1075 assert_eq!(op_tx_env.deposit.mint, Some(1111));
1076 assert!(op_tx_env.deposit.is_system_transaction);
1077 }
1078 }
1079}