reth_primitives_traits/transaction/
signed.rs1use crate::{InMemorySize, MaybeCompact, MaybeSerde, MaybeSerdeBincodeCompat};
4use alloc::fmt;
5use alloy_consensus::{
6 transaction::{Recovered, RlpEcdsaEncodableTx, SignerRecoverable},
7 EthereumTxEnvelope, SignableTransaction,
8};
9use alloy_eips::eip2718::{Decodable2718, Encodable2718};
10use alloy_primitives::{keccak256, Address, Signature, TxHash, B256};
11use alloy_rlp::{Decodable, Encodable};
12use core::hash::Hash;
13
14pub use alloy_consensus::crypto::RecoveryError;
15
16pub trait FullSignedTx: SignedTransaction + MaybeCompact + MaybeSerdeBincodeCompat {}
18impl<T> FullSignedTx for T where T: SignedTransaction + MaybeCompact + MaybeSerdeBincodeCompat {}
19
20#[auto_impl::auto_impl(&, Arc)]
31pub trait SignedTransaction:
32 Send
33 + Sync
34 + Unpin
35 + Clone
36 + fmt::Debug
37 + PartialEq
38 + Eq
39 + Hash
40 + Encodable
41 + Decodable
42 + Encodable2718
43 + Decodable2718
44 + alloy_consensus::Transaction
45 + MaybeSerde
46 + InMemorySize
47 + SignerRecoverable
48{
49 fn tx_hash(&self) -> &TxHash;
51
52 fn is_broadcastable_in_full(&self) -> bool {
58 !self.is_eip4844()
60 }
61
62 fn try_recover(&self) -> Result<Address, RecoveryError> {
66 self.recover_signer()
67 }
68
69 fn try_recover_unchecked(&self) -> Result<Address, RecoveryError> {
74 self.recover_signer_unchecked()
75 }
76
77 fn recalculate_hash(&self) -> B256 {
80 keccak256(self.encoded_2718())
81 }
82
83 #[auto_impl(keep_default_for(&, Arc))]
85 fn try_clone_into_recovered(&self) -> Result<Recovered<Self>, RecoveryError> {
86 self.recover_signer().map(|signer| Recovered::new_unchecked(self.clone(), signer))
87 }
88
89 #[auto_impl(keep_default_for(&, Arc))]
91 fn try_clone_into_recovered_unchecked(&self) -> Result<Recovered<Self>, RecoveryError> {
92 self.recover_signer_unchecked().map(|signer| Recovered::new_unchecked(self.clone(), signer))
93 }
94
95 #[auto_impl(keep_default_for(&, Arc))]
100 fn try_into_recovered(self) -> Result<Recovered<Self>, Self> {
101 match self.recover_signer() {
102 Ok(signer) => Ok(Recovered::new_unchecked(self, signer)),
103 Err(_) => Err(self),
104 }
105 }
106
107 #[deprecated(note = "Use try_into_recovered_unchecked instead")]
112 #[auto_impl(keep_default_for(&, Arc))]
113 fn into_recovered_unchecked(self) -> Result<Recovered<Self>, RecoveryError> {
114 self.recover_signer_unchecked().map(|signer| Recovered::new_unchecked(self, signer))
115 }
116
117 #[auto_impl(keep_default_for(&, Arc))]
121 fn with_signer(self, signer: Address) -> Recovered<Self> {
122 Recovered::new_unchecked(self, signer)
123 }
124
125 #[auto_impl(keep_default_for(&, Arc))]
129 fn with_signer_ref(&self, signer: Address) -> Recovered<&Self> {
130 Recovered::new_unchecked(self, signer)
131 }
132}
133
134impl<T> SignedTransaction for EthereumTxEnvelope<T>
135where
136 T: RlpEcdsaEncodableTx + SignableTransaction<Signature> + Unpin,
137 Self: Clone + PartialEq + Eq + Decodable + Decodable2718 + MaybeSerde + InMemorySize,
138{
139 fn tx_hash(&self) -> &TxHash {
140 match self {
141 Self::Legacy(tx) => tx.hash(),
142 Self::Eip2930(tx) => tx.hash(),
143 Self::Eip1559(tx) => tx.hash(),
144 Self::Eip7702(tx) => tx.hash(),
145 Self::Eip4844(tx) => tx.hash(),
146 }
147 }
148}
149
150#[cfg(feature = "op")]
151mod op {
152 use super::*;
153 use op_alloy_consensus::{OpPooledTransaction, OpTxEnvelope};
154
155 impl SignedTransaction for OpPooledTransaction {
156 fn tx_hash(&self) -> &TxHash {
157 match self {
158 Self::Legacy(tx) => tx.hash(),
159 Self::Eip2930(tx) => tx.hash(),
160 Self::Eip1559(tx) => tx.hash(),
161 Self::Eip7702(tx) => tx.hash(),
162 }
163 }
164 }
165
166 impl SignedTransaction for OpTxEnvelope {
167 fn tx_hash(&self) -> &TxHash {
168 match self {
169 Self::Legacy(tx) => tx.hash(),
170 Self::Eip2930(tx) => tx.hash(),
171 Self::Eip1559(tx) => tx.hash(),
172 Self::Eip7702(tx) => tx.hash(),
173 Self::Deposit(tx) => tx.hash_ref(),
174 }
175 }
176 }
177}