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