reth_primitives_traits/transaction/
signed.rs
1use crate::{
4 crypto::secp256k1::{recover_signer, recover_signer_unchecked},
5 InMemorySize, MaybeCompact, MaybeSerde, MaybeSerdeBincodeCompat,
6};
7use alloc::{fmt, vec::Vec};
8use alloy_consensus::{
9 transaction::{Recovered, RlpEcdsaEncodableTx},
10 EthereumTxEnvelope, SignableTransaction,
11};
12use alloy_eips::eip2718::{Decodable2718, Encodable2718};
13use alloy_primitives::{keccak256, Address, Signature, TxHash, B256};
14use alloy_rlp::{Decodable, Encodable};
15use core::hash::Hash;
16
17pub trait FullSignedTx: SignedTransaction + MaybeCompact + MaybeSerdeBincodeCompat {}
19impl<T> FullSignedTx for T where T: SignedTransaction + MaybeCompact + MaybeSerdeBincodeCompat {}
20
21#[auto_impl::auto_impl(&, Arc)]
23pub trait SignedTransaction:
24 Send
25 + Sync
26 + Unpin
27 + Clone
28 + fmt::Debug
29 + PartialEq
30 + Eq
31 + Hash
32 + Encodable
33 + Decodable
34 + Encodable2718
35 + Decodable2718
36 + alloy_consensus::Transaction
37 + MaybeSerde
38 + InMemorySize
39{
40 fn tx_hash(&self) -> &TxHash;
42
43 fn is_broadcastable_in_full(&self) -> bool {
49 !self.is_eip4844()
51 }
52
53 fn recover_signer(&self) -> Result<Address, RecoveryError>;
63
64 fn try_recover(&self) -> Result<Address, RecoveryError> {
68 self.recover_signer()
69 }
70
71 fn recover_signer_unchecked(&self) -> Result<Address, RecoveryError> {
77 self.recover_signer_unchecked_with_buf(&mut Vec::new())
78 }
79
80 fn try_recover_unchecked(&self) -> Result<Address, RecoveryError> {
85 self.recover_signer_unchecked()
86 }
87
88 fn recover_signer_unchecked_with_buf(
91 &self,
92 buf: &mut Vec<u8>,
93 ) -> Result<Address, RecoveryError>;
94
95 fn recalculate_hash(&self) -> B256 {
98 keccak256(self.encoded_2718())
99 }
100
101 #[auto_impl(keep_default_for(&, Arc))]
103 fn try_clone_into_recovered(&self) -> Result<Recovered<Self>, RecoveryError> {
104 self.recover_signer().map(|signer| Recovered::new_unchecked(self.clone(), signer))
105 }
106
107 #[auto_impl(keep_default_for(&, Arc))]
112 fn try_into_recovered(self) -> Result<Recovered<Self>, Self> {
113 match self.recover_signer() {
114 Ok(signer) => Ok(Recovered::new_unchecked(self, signer)),
115 Err(_) => Err(self),
116 }
117 }
118
119 #[auto_impl(keep_default_for(&, Arc))]
124 fn into_recovered_unchecked(self) -> Result<Recovered<Self>, RecoveryError> {
125 self.recover_signer_unchecked().map(|signer| Recovered::new_unchecked(self, signer))
126 }
127
128 #[auto_impl(keep_default_for(&, Arc))]
132 fn with_signer(self, signer: Address) -> Recovered<Self> {
133 Recovered::new_unchecked(self, signer)
134 }
135}
136
137impl<T> SignedTransaction for EthereumTxEnvelope<T>
138where
139 T: RlpEcdsaEncodableTx + SignableTransaction<Signature> + Unpin,
140 Self: Clone + PartialEq + Eq + Decodable + Decodable2718 + MaybeSerde + InMemorySize,
141{
142 fn tx_hash(&self) -> &TxHash {
143 match self {
144 Self::Legacy(tx) => tx.hash(),
145 Self::Eip2930(tx) => tx.hash(),
146 Self::Eip1559(tx) => tx.hash(),
147 Self::Eip7702(tx) => tx.hash(),
148 Self::Eip4844(tx) => tx.hash(),
149 }
150 }
151
152 fn recover_signer(&self) -> Result<Address, RecoveryError> {
153 let signature_hash = self.signature_hash();
154 recover_signer(self.signature(), signature_hash)
155 }
156
157 fn recover_signer_unchecked_with_buf(
158 &self,
159 buf: &mut Vec<u8>,
160 ) -> Result<Address, RecoveryError> {
161 match self {
162 Self::Legacy(tx) => tx.tx().encode_for_signing(buf),
163 Self::Eip2930(tx) => tx.tx().encode_for_signing(buf),
164 Self::Eip1559(tx) => tx.tx().encode_for_signing(buf),
165 Self::Eip7702(tx) => tx.tx().encode_for_signing(buf),
166 Self::Eip4844(tx) => tx.tx().encode_for_signing(buf),
167 }
168 let signature_hash = keccak256(buf);
169 recover_signer_unchecked(self.signature(), signature_hash)
170 }
171}
172
173#[cfg(feature = "op")]
174mod op {
175 use super::*;
176 use op_alloy_consensus::{OpPooledTransaction, OpTxEnvelope};
177
178 impl SignedTransaction for OpPooledTransaction {
179 fn tx_hash(&self) -> &TxHash {
180 match self {
181 Self::Legacy(tx) => tx.hash(),
182 Self::Eip2930(tx) => tx.hash(),
183 Self::Eip1559(tx) => tx.hash(),
184 Self::Eip7702(tx) => tx.hash(),
185 }
186 }
187
188 fn recover_signer(&self) -> Result<Address, RecoveryError> {
189 recover_signer(self.signature(), self.signature_hash())
190 }
191
192 fn recover_signer_unchecked_with_buf(
193 &self,
194 buf: &mut Vec<u8>,
195 ) -> Result<Address, RecoveryError> {
196 match self {
197 Self::Legacy(tx) => tx.tx().encode_for_signing(buf),
198 Self::Eip2930(tx) => tx.tx().encode_for_signing(buf),
199 Self::Eip1559(tx) => tx.tx().encode_for_signing(buf),
200 Self::Eip7702(tx) => tx.tx().encode_for_signing(buf),
201 }
202 let signature_hash = keccak256(buf);
203 recover_signer_unchecked(self.signature(), signature_hash)
204 }
205 }
206
207 impl SignedTransaction for OpTxEnvelope {
208 fn tx_hash(&self) -> &TxHash {
209 match self {
210 Self::Legacy(tx) => tx.hash(),
211 Self::Eip2930(tx) => tx.hash(),
212 Self::Eip1559(tx) => tx.hash(),
213 Self::Eip7702(tx) => tx.hash(),
214 Self::Deposit(tx) => tx.hash_ref(),
215 }
216 }
217
218 fn recover_signer(&self) -> Result<Address, RecoveryError> {
219 let signature_hash = match self {
220 Self::Legacy(tx) => tx.signature_hash(),
221 Self::Eip2930(tx) => tx.signature_hash(),
222 Self::Eip1559(tx) => tx.signature_hash(),
223 Self::Eip7702(tx) => tx.signature_hash(),
224 Self::Deposit(tx) => return Ok(tx.from),
227 };
228 let signature = match self {
229 Self::Legacy(tx) => tx.signature(),
230 Self::Eip2930(tx) => tx.signature(),
231 Self::Eip1559(tx) => tx.signature(),
232 Self::Eip7702(tx) => tx.signature(),
233 Self::Deposit(_) => unreachable!("Deposit transactions should not be handled here"),
234 };
235 recover_signer(signature, signature_hash)
236 }
237
238 fn recover_signer_unchecked(&self) -> Result<Address, RecoveryError> {
239 let signature_hash = match self {
240 Self::Legacy(tx) => tx.signature_hash(),
241 Self::Eip2930(tx) => tx.signature_hash(),
242 Self::Eip1559(tx) => tx.signature_hash(),
243 Self::Eip7702(tx) => tx.signature_hash(),
244 Self::Deposit(tx) => return Ok(tx.from),
247 };
248 let signature = match self {
249 Self::Legacy(tx) => tx.signature(),
250 Self::Eip2930(tx) => tx.signature(),
251 Self::Eip1559(tx) => tx.signature(),
252 Self::Eip7702(tx) => tx.signature(),
253 Self::Deposit(_) => unreachable!("Deposit transactions should not be handled here"),
254 };
255 recover_signer_unchecked(signature, signature_hash)
256 }
257
258 fn recover_signer_unchecked_with_buf(
259 &self,
260 buf: &mut Vec<u8>,
261 ) -> Result<Address, RecoveryError> {
262 match self {
263 Self::Deposit(tx) => return Ok(tx.from),
264 Self::Legacy(tx) => tx.tx().encode_for_signing(buf),
265 Self::Eip2930(tx) => tx.tx().encode_for_signing(buf),
266 Self::Eip1559(tx) => tx.tx().encode_for_signing(buf),
267 Self::Eip7702(tx) => tx.tx().encode_for_signing(buf),
268 }
269 let signature_hash = keccak256(buf);
270 let signature = match self {
271 Self::Legacy(tx) => tx.signature(),
272 Self::Eip2930(tx) => tx.signature(),
273 Self::Eip1559(tx) => tx.signature(),
274 Self::Eip7702(tx) => tx.signature(),
275 Self::Deposit(_) => unreachable!("Deposit transactions should not be handled here"),
276 };
277 recover_signer_unchecked(signature, signature_hash)
278 }
279 }
280}
281#[derive(Debug, Default, thiserror::Error)]
283#[error("Failed to recover the signer")]
284pub struct RecoveryError;