alloy_consensus/transaction/
recovered.rs1use crate::crypto::RecoveryError;
2use alloy_eips::{
3 eip2718::{Encodable2718, WithEncoded},
4 Typed2718,
5};
6use alloy_primitives::{bytes, Address, Bytes, Sealed, B256};
7use alloy_rlp::{Decodable, Encodable};
8use derive_more::{AsRef, Deref};
9
10#[derive(Debug, Clone, Copy, PartialEq, Hash, Eq, AsRef, Deref)]
12#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
13#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
14pub struct Recovered<T> {
15 signer: Address,
17 #[deref]
19 #[as_ref]
20 #[cfg_attr(feature = "serde", serde(flatten))]
21 inner: T,
22}
23
24impl<T> Recovered<T> {
25 pub const fn signer(&self) -> Address {
27 self.signer
28 }
29
30 pub const fn signer_ref(&self) -> &Address {
32 &self.signer
33 }
34
35 pub const fn inner(&self) -> &T {
37 &self.inner
38 }
39
40 pub const fn inner_mut(&mut self) -> &mut T {
42 &mut self.inner
43 }
44
45 pub fn into_inner(self) -> T {
47 self.inner
48 }
49
50 pub fn clone_inner(&self) -> T
52 where
53 T: Clone,
54 {
55 self.inner.clone()
56 }
57
58 #[doc(alias = "transaction")]
60 #[deprecated = "Use `inner` instead"]
61 pub const fn tx(&self) -> &T {
62 &self.inner
63 }
64
65 #[doc(alias = "into_transaction")]
67 #[deprecated = "Use `into_inner` instead"]
68 pub fn into_tx(self) -> T {
69 self.inner
70 }
71
72 #[doc(alias = "clone_transaction")]
74 #[deprecated = "Use `clone_inner` instead"]
75 pub fn clone_tx(&self) -> T
76 where
77 T: Clone,
78 {
79 self.inner.clone()
80 }
81
82 #[doc(alias = "split")]
84 pub fn into_parts(self) -> (T, Address) {
85 (self.inner, self.signer)
86 }
87
88 pub const fn as_recovered_ref(&self) -> Recovered<&T> {
90 Recovered { inner: &self.inner, signer: self.signer() }
91 }
92
93 #[inline]
97 pub const fn new_unchecked(inner: T, signer: Address) -> Self {
98 Self { inner, signer }
99 }
100
101 pub fn convert<Tx>(self) -> Recovered<Tx>
103 where
104 Tx: From<T>,
105 {
106 self.map(Tx::from)
107 }
108
109 #[deprecated = "Use `convert_inner` instead"]
111 pub fn convert_transaction<Tx>(self) -> Recovered<Tx>
112 where
113 Tx: From<T>,
114 {
115 self.map(Tx::from)
116 }
117
118 pub fn try_convert<Tx, E>(self) -> Result<Recovered<Tx>, Tx::Error>
120 where
121 Tx: TryFrom<T>,
122 {
123 self.try_map(Tx::try_from)
124 }
125
126 #[deprecated = "Use `try_convert_inner` instead"]
128 pub fn try_convert_transaction<Tx, E>(self) -> Result<Recovered<Tx>, Tx::Error>
129 where
130 Tx: TryFrom<T>,
131 {
132 self.try_map(Tx::try_from)
133 }
134
135 pub fn map<Tx>(self, f: impl FnOnce(T) -> Tx) -> Recovered<Tx> {
137 Recovered::new_unchecked(f(self.inner), self.signer)
138 }
139
140 #[deprecated = "Use `map_inner` instead"]
142 pub fn map_transaction<Tx>(self, f: impl FnOnce(T) -> Tx) -> Recovered<Tx> {
143 Recovered::new_unchecked(f(self.inner), self.signer)
144 }
145
146 pub fn try_map<Tx, E>(self, f: impl FnOnce(T) -> Result<Tx, E>) -> Result<Recovered<Tx>, E> {
148 Ok(Recovered::new_unchecked(f(self.inner)?, self.signer))
149 }
150
151 #[deprecated = "Use `try_map_inner` instead"]
153 pub fn try_map_transaction<Tx, E>(
154 self,
155 f: impl FnOnce(T) -> Result<Tx, E>,
156 ) -> Result<Recovered<Tx>, E> {
157 Ok(Recovered::new_unchecked(f(self.inner)?, self.signer))
158 }
159
160 pub fn into_encoded_with(self, encoding: impl Into<Bytes>) -> WithEncoded<Self> {
162 WithEncoded::new(encoding.into(), self)
163 }
164
165 pub fn into_encoded(self) -> WithEncoded<Self>
167 where
168 T: Encodable2718,
169 {
170 let mut out = alloc::vec![];
171 self.inner.encode_2718(&mut out);
172
173 self.into_encoded_with(out)
174 }
175}
176
177impl<T> Recovered<&T> {
178 pub fn cloned(self) -> Recovered<T>
180 where
181 T: Clone,
182 {
183 let Self { inner, signer } = self;
184 Recovered::new_unchecked(inner.clone(), signer)
185 }
186
187 pub const fn copied(&self) -> Self {
189 *self
190 }
191}
192
193impl<T: Encodable> Encodable for Recovered<T> {
194 fn encode(&self, out: &mut dyn bytes::BufMut) {
196 self.inner.encode(out)
197 }
198
199 fn length(&self) -> usize {
200 self.inner.length()
201 }
202}
203
204impl<T: Decodable + SignerRecoverable> Decodable for Recovered<T> {
205 fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
206 let tx = T::decode(buf)?;
207 let signer = tx.recover_signer().map_err(|_| {
208 alloy_rlp::Error::Custom("Unable to recover decoded transaction signer.")
209 })?;
210 Ok(Self::new_unchecked(tx, signer))
211 }
212}
213
214impl<T: Typed2718> Typed2718 for Recovered<T> {
215 fn ty(&self) -> u8 {
216 self.inner.ty()
217 }
218}
219
220impl<T: Encodable2718> Encodable2718 for Recovered<T> {
221 fn encode_2718_len(&self) -> usize {
222 self.inner.encode_2718_len()
223 }
224
225 fn encode_2718(&self, out: &mut dyn alloy_rlp::BufMut) {
226 self.inner.encode_2718(out)
227 }
228
229 fn trie_hash(&self) -> B256 {
230 self.inner.trie_hash()
231 }
232}
233
234pub trait SignerRecoverable {
239 fn recover_signer(&self) -> Result<Address, RecoveryError>;
249
250 fn recover_signer_unchecked(&self) -> Result<Address, RecoveryError>;
255
256 fn recover_unchecked_with_buf(
262 &self,
263 buf: &mut alloc::vec::Vec<u8>,
264 ) -> Result<Address, RecoveryError> {
265 let _ = buf;
266 self.recover_signer()
267 }
268
269 fn try_into_recovered(self) -> Result<Recovered<Self>, RecoveryError>
272 where
273 Self: Sized,
274 {
275 let signer = self.recover_signer()?;
276 Ok(Recovered::new_unchecked(self, signer))
277 }
278
279 fn try_into_recovered_unchecked(self) -> Result<Recovered<Self>, RecoveryError>
282 where
283 Self: Sized,
284 {
285 let signer = self.recover_signer_unchecked()?;
286 Ok(Recovered::new_unchecked(self, signer))
287 }
288
289 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 fn try_to_recovered_ref_unchecked(&self) -> Result<Recovered<&Self>, RecoveryError> {
299 let signer = self.recover_signer_unchecked()?;
300 Ok(Recovered::new_unchecked(self, signer))
301 }
302}
303
304impl<T> SignerRecoverable for WithEncoded<T>
305where
306 T: SignerRecoverable,
307{
308 fn recover_signer(&self) -> Result<Address, RecoveryError> {
309 self.1.recover_signer()
310 }
311
312 fn recover_signer_unchecked(&self) -> Result<Address, RecoveryError> {
313 self.1.recover_signer_unchecked()
314 }
315
316 fn recover_unchecked_with_buf(
317 &self,
318 buf: &mut alloc::vec::Vec<u8>,
319 ) -> Result<Address, RecoveryError> {
320 self.1.recover_unchecked_with_buf(buf)
321 }
322}
323
324impl<T> SignerRecoverable for Sealed<T>
325where
326 T: SignerRecoverable,
327{
328 fn recover_signer(&self) -> Result<Address, RecoveryError> {
329 self.inner().recover_signer()
330 }
331
332 fn recover_signer_unchecked(&self) -> Result<Address, RecoveryError> {
333 self.inner().recover_signer_unchecked()
334 }
335
336 fn recover_unchecked_with_buf(
337 &self,
338 buf: &mut alloc::vec::Vec<u8>,
339 ) -> Result<Address, RecoveryError> {
340 self.inner().recover_unchecked_with_buf(buf)
341 }
342}