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` 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` 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` 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` 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
234impl<T> AsRef<Self> for Recovered<T> {
235 fn as_ref(&self) -> &Self {
236 self
237 }
238}
239
240pub trait SignerRecoverable {
245 fn recover_signer(&self) -> Result<Address, RecoveryError>;
255
256 fn recover_signer_unchecked(&self) -> Result<Address, RecoveryError>;
261
262 fn recover_unchecked_with_buf(
268 &self,
269 buf: &mut alloc::vec::Vec<u8>,
270 ) -> Result<Address, RecoveryError> {
271 let _ = buf;
272 self.recover_signer()
273 }
274
275 fn try_into_recovered(self) -> Result<Recovered<Self>, RecoveryError>
278 where
279 Self: Sized,
280 {
281 let signer = self.recover_signer()?;
282 Ok(Recovered::new_unchecked(self, signer))
283 }
284
285 fn try_into_recovered_unchecked(self) -> Result<Recovered<Self>, RecoveryError>
288 where
289 Self: Sized,
290 {
291 let signer = self.recover_signer_unchecked()?;
292 Ok(Recovered::new_unchecked(self, signer))
293 }
294
295 fn try_to_recovered_ref(&self) -> Result<Recovered<&Self>, RecoveryError> {
298 let signer = self.recover_signer()?;
299 Ok(Recovered::new_unchecked(self, signer))
300 }
301
302 fn try_to_recovered_ref_unchecked(&self) -> Result<Recovered<&Self>, RecoveryError> {
305 let signer = self.recover_signer_unchecked()?;
306 Ok(Recovered::new_unchecked(self, signer))
307 }
308}
309
310impl<T> SignerRecoverable for WithEncoded<T>
311where
312 T: SignerRecoverable,
313{
314 fn recover_signer(&self) -> Result<Address, RecoveryError> {
315 self.1.recover_signer()
316 }
317
318 fn recover_signer_unchecked(&self) -> Result<Address, RecoveryError> {
319 self.1.recover_signer_unchecked()
320 }
321
322 fn recover_unchecked_with_buf(
323 &self,
324 buf: &mut alloc::vec::Vec<u8>,
325 ) -> Result<Address, RecoveryError> {
326 self.1.recover_unchecked_with_buf(buf)
327 }
328}
329
330impl<T> SignerRecoverable for Sealed<T>
331where
332 T: SignerRecoverable,
333{
334 fn recover_signer(&self) -> Result<Address, RecoveryError> {
335 self.inner().recover_signer()
336 }
337
338 fn recover_signer_unchecked(&self) -> Result<Address, RecoveryError> {
339 self.inner().recover_signer_unchecked()
340 }
341
342 fn recover_unchecked_with_buf(
343 &self,
344 buf: &mut alloc::vec::Vec<u8>,
345 ) -> Result<Address, RecoveryError> {
346 self.inner().recover_unchecked_with_buf(buf)
347 }
348}