alloy_consensus/transaction/
recovered.rs1use alloy_eips::{
2 eip2718::{Encodable2718, WithEncoded},
3 Typed2718,
4};
5use alloy_primitives::{bytes, Address, Bytes, B256};
6use alloy_rlp::{Decodable, Encodable};
7use derive_more::{AsRef, Deref};
8
9#[derive(Debug, Clone, Copy, PartialEq, Hash, Eq, AsRef, Deref)]
11#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
12#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
13pub struct Recovered<T> {
14 signer: Address,
16 #[deref]
18 #[as_ref]
19 #[cfg_attr(feature = "serde", serde(flatten))]
20 inner: T,
21}
22
23impl<T> Recovered<T> {
24 pub const fn signer(&self) -> Address {
26 self.signer
27 }
28
29 pub const fn signer_ref(&self) -> &Address {
31 &self.signer
32 }
33
34 pub const fn inner(&self) -> &T {
36 &self.inner
37 }
38
39 pub fn inner_mut(&mut self) -> &mut T {
41 &mut self.inner
42 }
43
44 pub fn into_inner(self) -> T {
46 self.inner
47 }
48
49 pub fn clone_inner(&self) -> T
51 where
52 T: Clone,
53 {
54 self.inner.clone()
55 }
56
57 #[doc(alias = "transaction")]
59 #[deprecated = "Use `inner` instead"]
60 pub const fn tx(&self) -> &T {
61 &self.inner
62 }
63
64 #[doc(alias = "into_transaction")]
66 #[deprecated = "Use `into_inner` instead"]
67 pub fn into_tx(self) -> T {
68 self.inner
69 }
70
71 #[doc(alias = "clone_transaction")]
73 #[deprecated = "Use `clone_inner` instead"]
74 pub fn clone_tx(&self) -> T
75 where
76 T: Clone,
77 {
78 self.inner.clone()
79 }
80
81 #[doc(alias = "split")]
83 pub fn into_parts(self) -> (T, Address) {
84 (self.inner, self.signer)
85 }
86
87 pub const fn as_recovered_ref(&self) -> Recovered<&T> {
89 Recovered { inner: &self.inner, signer: self.signer() }
90 }
91
92 #[inline]
96 pub const fn new_unchecked(inner: T, signer: Address) -> Self {
97 Self { inner, signer }
98 }
99
100 pub fn convert<Tx>(self) -> Recovered<Tx>
102 where
103 Tx: From<T>,
104 {
105 self.map(Tx::from)
106 }
107
108 #[deprecated = "Use `convert_inner` instead"]
110 pub fn convert_transaction<Tx>(self) -> Recovered<Tx>
111 where
112 Tx: From<T>,
113 {
114 self.map(Tx::from)
115 }
116
117 pub fn try_convert<Tx, E>(self) -> Result<Recovered<Tx>, Tx::Error>
119 where
120 Tx: TryFrom<T>,
121 {
122 self.try_map(Tx::try_from)
123 }
124
125 #[deprecated = "Use `try_convert_inner` instead"]
127 pub fn try_convert_transaction<Tx, E>(self) -> Result<Recovered<Tx>, Tx::Error>
128 where
129 Tx: TryFrom<T>,
130 {
131 self.try_map(Tx::try_from)
132 }
133
134 pub fn map<Tx>(self, f: impl FnOnce(T) -> Tx) -> Recovered<Tx> {
136 Recovered::new_unchecked(f(self.inner), self.signer)
137 }
138
139 #[deprecated = "Use `map_inner` instead"]
141 pub fn map_transaction<Tx>(self, f: impl FnOnce(T) -> Tx) -> Recovered<Tx> {
142 Recovered::new_unchecked(f(self.inner), self.signer)
143 }
144
145 pub fn try_map<Tx, E>(self, f: impl FnOnce(T) -> Result<Tx, E>) -> Result<Recovered<Tx>, E> {
147 Ok(Recovered::new_unchecked(f(self.inner)?, self.signer))
148 }
149
150 #[deprecated = "Use `try_map_inner` instead"]
152 pub fn try_map_transaction<Tx, E>(
153 self,
154 f: impl FnOnce(T) -> Result<Tx, E>,
155 ) -> Result<Recovered<Tx>, E> {
156 Ok(Recovered::new_unchecked(f(self.inner)?, self.signer))
157 }
158
159 pub fn into_encoded_with(self, encoding: impl Into<Bytes>) -> WithEncoded<Self> {
161 WithEncoded::new(encoding.into(), self)
162 }
163
164 pub fn into_encoded(self) -> WithEncoded<Self>
166 where
167 T: Encodable2718,
168 {
169 let mut out = alloc::vec![];
170 self.inner.encode_2718(&mut out);
171
172 self.into_encoded_with(out)
173 }
174}
175
176impl<T> Recovered<&T> {
177 pub fn cloned(self) -> Recovered<T>
179 where
180 T: Clone,
181 {
182 let Self { inner, signer } = self;
183 Recovered::new_unchecked(inner.clone(), signer)
184 }
185}
186
187impl<T: Encodable> Encodable for Recovered<T> {
188 fn encode(&self, out: &mut dyn bytes::BufMut) {
190 self.inner.encode(out)
191 }
192
193 fn length(&self) -> usize {
194 self.inner.length()
195 }
196}
197
198impl<T: Decodable + SignerRecoverable> Decodable for Recovered<T> {
199 fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
200 let tx = T::decode(buf)?;
201 let signer = tx.recover_signer().map_err(|_| {
202 alloy_rlp::Error::Custom("Unable to recover decoded transaction signer.")
203 })?;
204 Ok(Self::new_unchecked(tx, signer))
205 }
206}
207
208impl<T: Typed2718> Typed2718 for Recovered<T> {
209 fn ty(&self) -> u8 {
210 self.inner.ty()
211 }
212}
213
214impl<T: Encodable2718> Encodable2718 for Recovered<T> {
215 fn encode_2718_len(&self) -> usize {
216 self.inner.encode_2718_len()
217 }
218
219 fn encode_2718(&self, out: &mut dyn alloy_rlp::BufMut) {
220 self.inner.encode_2718(out)
221 }
222
223 fn trie_hash(&self) -> B256 {
224 self.inner.trie_hash()
225 }
226}
227
228pub trait SignerRecoverable {
233 fn recover_signer(&self) -> Result<Address, alloy_primitives::SignatureError>;
243
244 fn recover_signer_unchecked(&self) -> Result<Address, alloy_primitives::SignatureError>;
249}