Skip to main content

alloy_consensus/transaction/
recovered.rs

1use crate::crypto::RecoveryError;
2use alloc::{borrow::Cow, vec::Vec};
3use alloy_eips::{
4    eip2718::{Encodable2718, WithEncoded},
5    Typed2718,
6};
7use alloy_primitives::{bytes, Address, Bytes, Sealed, B256};
8use alloy_rlp::{Decodable, Encodable};
9use derive_more::{AsRef, Deref};
10
11/// Signed object with recovered signer.
12#[derive(Debug, Clone, Copy, PartialEq, Hash, Eq, AsRef, Deref)]
13#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
14#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
15pub struct Recovered<T> {
16    /// Signer of the type
17    signer: Address,
18    /// Signed object
19    #[deref]
20    #[as_ref]
21    #[cfg_attr(feature = "serde", serde(flatten))]
22    inner: T,
23}
24
25impl<T> Recovered<T> {
26    /// Signer of the object recovered from signature
27    pub const fn signer(&self) -> Address {
28        self.signer
29    }
30
31    /// Reference to the signer of the object recovered from signature
32    pub const fn signer_ref(&self) -> &Address {
33        &self.signer
34    }
35
36    /// Reference to the inner recovered object.
37    pub const fn inner(&self) -> &T {
38        &self.inner
39    }
40
41    /// Reference to the inner recovered object.
42    pub const fn inner_mut(&mut self) -> &mut T {
43        &mut self.inner
44    }
45
46    /// Reference to the inner signed object.
47    pub fn into_inner(self) -> T {
48        self.inner
49    }
50
51    /// Clone the inner signed object.
52    pub fn clone_inner(&self) -> T
53    where
54        T: Clone,
55    {
56        self.inner.clone()
57    }
58
59    /// Dissolve Self to its component
60    #[doc(alias = "split")]
61    pub fn into_parts(self) -> (T, Address) {
62        (self.inner, self.signer)
63    }
64
65    /// Converts from `&Recovered<T>` to `Recovered<&T>`.
66    pub const fn as_recovered_ref(&self) -> Recovered<&T> {
67        Recovered { inner: &self.inner, signer: self.signer() }
68    }
69
70    /// Create [`Recovered`] from the given transaction and [`Address`] of the signer.
71    ///
72    /// Note: This does not check if the signer is the actual signer of the transaction.
73    #[inline]
74    pub const fn new_unchecked(inner: T, signer: Address) -> Self {
75        Self { inner, signer }
76    }
77
78    /// Converts the inner signed object to the given alternative that is `From<T>`
79    pub fn convert<Tx>(self) -> Recovered<Tx>
80    where
81        Tx: From<T>,
82    {
83        self.map(Tx::from)
84    }
85
86    /// Converts the inner signed object to the given alternative that is `TryFrom<T>`
87    pub fn try_convert<Tx>(self) -> Result<Recovered<Tx>, Tx::Error>
88    where
89        Tx: TryFrom<T>,
90    {
91        self.try_map(Tx::try_from)
92    }
93
94    /// Applies the given closure to the inner signed object.
95    pub fn map<Tx>(self, f: impl FnOnce(T) -> Tx) -> Recovered<Tx> {
96        Recovered::new_unchecked(f(self.inner), self.signer)
97    }
98
99    /// Applies the given fallible closure to the inner signed object.
100    pub fn try_map<Tx, E>(self, f: impl FnOnce(T) -> Result<Tx, E>) -> Result<Recovered<Tx>, E> {
101        Ok(Recovered::new_unchecked(f(self.inner)?, self.signer))
102    }
103
104    /// Returns the [`WithEncoded`] representation of [`Recovered`] with the given encoding.
105    pub fn into_encoded_with(self, encoding: impl Into<Bytes>) -> WithEncoded<Self> {
106        WithEncoded::new(encoding.into(), self)
107    }
108
109    /// Encodes the inner type and returns the [`WithEncoded`] representation of [`Recovered`].
110    pub fn into_encoded(self) -> WithEncoded<Self>
111    where
112        T: Encodable2718,
113    {
114        let mut out = alloc::vec![];
115        self.inner.encode_2718(&mut out);
116
117        self.into_encoded_with(out)
118    }
119}
120
121impl<T> Recovered<&T> {
122    /// Maps a `Recovered<&T>` to a `Recovered<T>` by cloning the transaction.
123    pub fn cloned(self) -> Recovered<T>
124    where
125        T: Clone,
126    {
127        let Self { inner, signer } = self;
128        Recovered::new_unchecked(inner.clone(), signer)
129    }
130
131    /// Helper function to explicitly create a new copy of `Recovered<&T>`
132    pub const fn copied(&self) -> Self {
133        *self
134    }
135}
136
137impl<T: Clone> Recovered<Cow<'_, T>> {
138    /// Converts `Recovered<Cow<'_, T>>` into `Recovered<T>` by cloning the borrowed data if
139    /// necessary.
140    pub fn into_owned(self) -> Recovered<T> {
141        let Self { inner, signer } = self;
142        Recovered::new_unchecked(inner.into_owned(), signer)
143    }
144}
145
146impl<T: Encodable> Encodable for Recovered<T> {
147    /// This encodes the transaction _with_ the signature, and an rlp header.
148    fn encode(&self, out: &mut dyn bytes::BufMut) {
149        self.inner.encode(out)
150    }
151
152    fn length(&self) -> usize {
153        self.inner.length()
154    }
155}
156
157impl<T: Decodable + SignerRecoverable> Decodable for Recovered<T> {
158    fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
159        let tx = T::decode(buf)?;
160        let signer = tx.recover_signer().map_err(|_| {
161            alloy_rlp::Error::Custom("Unable to recover decoded transaction signer.")
162        })?;
163        Ok(Self::new_unchecked(tx, signer))
164    }
165}
166
167impl<T: Typed2718> Typed2718 for Recovered<T> {
168    fn ty(&self) -> u8 {
169        self.inner.ty()
170    }
171}
172
173impl<T: Encodable2718> Encodable2718 for Recovered<T> {
174    fn encode_2718_len(&self) -> usize {
175        self.inner.encode_2718_len()
176    }
177
178    fn encode_2718(&self, out: &mut dyn alloy_rlp::BufMut) {
179        self.inner.encode_2718(out)
180    }
181
182    fn trie_hash(&self) -> B256 {
183        self.inner.trie_hash()
184    }
185}
186
187impl<T> AsRef<Self> for Recovered<T> {
188    fn as_ref(&self) -> &Self {
189        self
190    }
191}
192
193/// A type that can recover the signer of a transaction.
194///
195/// This is a helper trait that only provides the ability to recover the signer (address) of a
196/// transaction.
197pub trait SignerRecoverable {
198    /// Recover signer from signature and hash.
199    ///
200    /// Returns an error if the transaction's signature is invalid following [EIP-2](https://eips.ethereum.org/EIPS/eip-2).
201    ///
202    /// Note:
203    ///
204    /// This can fail for some early ethereum mainnet transactions pre EIP-2, use
205    /// [`Self::recover_signer_unchecked`] if you want to recover the signer without ensuring that
206    /// the signature has a low `s` value.
207    fn recover_signer(&self) -> Result<Address, RecoveryError>;
208
209    /// Recover signer from signature and hash _without ensuring that the signature has a low `s`
210    /// value_.
211    ///
212    /// Returns an error if the transaction's signature is invalid.
213    fn recover_signer_unchecked(&self) -> Result<Address, RecoveryError>;
214
215    /// Same as [`SignerRecoverable::recover_signer`] but receives a buffer to operate on
216    /// for encoding. This is useful during batch recovery of transactions to avoid allocating a new
217    /// buffer for each transaction.
218    ///
219    /// Caution: it is expected that implementations always clear this buffer before using it.
220    fn recover_with_buf(&self, buf: &mut alloc::vec::Vec<u8>) -> Result<Address, RecoveryError> {
221        let _ = buf;
222        self.recover_signer()
223    }
224
225    /// Same as [`SignerRecoverable::recover_signer_unchecked`] but receives a buffer to operate on
226    /// for encoding. This is useful during batch recovery of historical transactions to avoid
227    /// allocating a new buffer for each transaction.
228    ///
229    /// Caution: it is expected that implementations always clear this buffer before using it.
230    fn recover_unchecked_with_buf(
231        &self,
232        buf: &mut alloc::vec::Vec<u8>,
233    ) -> Result<Address, RecoveryError> {
234        let _ = buf;
235        self.recover_signer()
236    }
237
238    /// Recover the signer via [`SignerRecoverable::recover_signer`] and returns a
239    /// `Recovered<Self>`
240    fn try_into_recovered(self) -> Result<Recovered<Self>, RecoveryError>
241    where
242        Self: Sized,
243    {
244        let signer = self.recover_signer()?;
245        Ok(Recovered::new_unchecked(self, signer))
246    }
247
248    /// Recover the signer via [`SignerRecoverable::recover_signer_unchecked`] and returns a
249    /// `Recovered<&Self>`
250    fn try_into_recovered_unchecked(self) -> Result<Recovered<Self>, RecoveryError>
251    where
252        Self: Sized,
253    {
254        let signer = self.recover_signer_unchecked()?;
255        Ok(Recovered::new_unchecked(self, signer))
256    }
257
258    /// Same as [`SignerRecoverable::try_into_recovered`] but receives a buffer to operate on
259    /// for encoding. This is useful during batch recovery of transactions to avoid
260    /// allocating a new buffer for each transaction.
261    ///
262    /// Caution: it is expected that implementations always clear this buffer before using it.
263    fn try_into_recovered_with_buf(
264        self,
265        buf: &mut alloc::vec::Vec<u8>,
266    ) -> Result<Recovered<Self>, RecoveryError>
267    where
268        Self: Sized,
269    {
270        let signer = self.recover_with_buf(buf)?;
271        Ok(Recovered::new_unchecked(self, signer))
272    }
273    /// Same as [`SignerRecoverable::try_into_recovered_unchecked`] but receives a buffer to operate
274    /// on for encoding. This is useful during batch recovery of historical transactions to
275    /// avoid allocating a new buffer for each transaction.
276    ///
277    /// Caution: it is expected that implementations always clear this buffer before using it.
278    fn try_into_recovered_unchecked_with_buf(
279        self,
280        buf: &mut alloc::vec::Vec<u8>,
281    ) -> Result<Recovered<Self>, RecoveryError>
282    where
283        Self: Sized,
284    {
285        let signer = self.recover_unchecked_with_buf(buf)?;
286        Ok(Recovered::new_unchecked(self, signer))
287    }
288
289    /// Recover the signer via [`SignerRecoverable::recover_signer`] and returns a
290    /// `Recovered<&Self>`
291    fn try_to_recovered_ref(&self) -> Result<Recovered<&Self>, RecoveryError> {
292        let signer = self.recover_signer()?;
293        Ok(Recovered::new_unchecked(self, signer))
294    }
295
296    /// Same as [`SignerRecoverable::try_to_recovered_ref`] but receives a buffer to operate on
297    /// for encoding. This is useful during batch recovery of transactions to avoid
298    /// allocating a new buffer for each transaction.
299    ///
300    /// Caution: it is expected that implementations always clear this buffer before using it.
301    fn try_to_recovered_ref_with_buf(
302        &self,
303        buf: &mut alloc::vec::Vec<u8>,
304    ) -> Result<Recovered<&Self>, RecoveryError> {
305        let signer = self.recover_with_buf(buf)?;
306        Ok(Recovered::new_unchecked(self, signer))
307    }
308
309    /// Recover the signer via [`SignerRecoverable::recover_signer_unchecked`] and returns a
310    /// `Recovered<&Self>`
311    fn try_to_recovered_ref_unchecked(&self) -> Result<Recovered<&Self>, RecoveryError> {
312        let signer = self.recover_signer_unchecked()?;
313        Ok(Recovered::new_unchecked(self, signer))
314    }
315
316    /// Same as [`SignerRecoverable::try_to_recovered_ref_unchecked`] but receives a buffer to
317    /// operate on for encoding. This is useful during batch recovery of historical transactions
318    /// to avoid allocating a new buffer for each transaction.
319    ///
320    /// Caution: it is expected that implementations always clear this buffer before using it.
321    fn try_to_recovered_ref_unchecked_with_buf(
322        &self,
323        buf: &mut alloc::vec::Vec<u8>,
324    ) -> Result<Recovered<&Self>, RecoveryError> {
325        let signer = self.recover_unchecked_with_buf(buf)?;
326        Ok(Recovered::new_unchecked(self, signer))
327    }
328}
329
330impl<T> SignerRecoverable for WithEncoded<T>
331where
332    T: SignerRecoverable,
333{
334    fn recover_signer(&self) -> Result<Address, RecoveryError> {
335        self.1.recover_signer()
336    }
337
338    fn recover_signer_unchecked(&self) -> Result<Address, RecoveryError> {
339        self.1.recover_signer_unchecked()
340    }
341
342    fn recover_with_buf(&self, buf: &mut Vec<u8>) -> Result<Address, RecoveryError> {
343        self.1.recover_with_buf(buf)
344    }
345
346    fn recover_unchecked_with_buf(
347        &self,
348        buf: &mut alloc::vec::Vec<u8>,
349    ) -> Result<Address, RecoveryError> {
350        self.1.recover_unchecked_with_buf(buf)
351    }
352}
353
354impl<T> SignerRecoverable for Sealed<T>
355where
356    T: SignerRecoverable,
357{
358    fn recover_signer(&self) -> Result<Address, RecoveryError> {
359        self.inner().recover_signer()
360    }
361
362    fn recover_signer_unchecked(&self) -> Result<Address, RecoveryError> {
363        self.inner().recover_signer_unchecked()
364    }
365
366    fn recover_with_buf(&self, buf: &mut alloc::vec::Vec<u8>) -> Result<Address, RecoveryError> {
367        self.inner().recover_with_buf(buf)
368    }
369
370    fn recover_unchecked_with_buf(
371        &self,
372        buf: &mut alloc::vec::Vec<u8>,
373    ) -> Result<Address, RecoveryError> {
374        self.inner().recover_unchecked_with_buf(buf)
375    }
376}