alloy_consensus/transaction/
recovered.rs1use alloy_eips::{eip2718::Encodable2718, Typed2718};
2use alloy_primitives::{bytes, Address, B256};
3use alloy_rlp::{Decodable, Encodable};
4use derive_more::{AsRef, Deref};
5
6#[derive(Debug, Clone, Copy, PartialEq, Hash, Eq, AsRef, Deref)]
8#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
9#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
10pub struct Recovered<T> {
11 signer: Address,
13 #[deref]
15 #[as_ref]
16 #[cfg_attr(feature = "serde", serde(flatten))]
17 inner: T,
18}
19
20impl<T> Recovered<T> {
21 pub const fn signer(&self) -> Address {
23 self.signer
24 }
25
26 pub const fn signer_ref(&self) -> &Address {
28 &self.signer
29 }
30
31 pub const fn inner(&self) -> &T {
33 &self.inner
34 }
35
36 pub fn inner_mut(&mut self) -> &mut T {
38 &mut self.inner
39 }
40
41 pub fn into_inner(self) -> T {
43 self.inner
44 }
45
46 pub fn clone_inner(&self) -> T
48 where
49 T: Clone,
50 {
51 self.inner.clone()
52 }
53
54 #[doc(alias = "transaction")]
56 #[deprecated = "Use `inner` instead"]
57 pub const fn tx(&self) -> &T {
58 &self.inner
59 }
60
61 #[doc(alias = "into_transaction")]
63 #[deprecated = "Use `into_inner` instead"]
64 pub fn into_tx(self) -> T {
65 self.inner
66 }
67
68 #[doc(alias = "clone_transaction")]
70 #[deprecated = "Use `clone_inner` instead"]
71 pub fn clone_tx(&self) -> T
72 where
73 T: Clone,
74 {
75 self.inner.clone()
76 }
77
78 #[doc(alias = "split")]
80 pub fn into_parts(self) -> (T, Address) {
81 (self.inner, self.signer)
82 }
83
84 pub const fn as_recovered_ref(&self) -> Recovered<&T> {
86 Recovered { inner: &self.inner, signer: self.signer() }
87 }
88
89 #[inline]
93 pub const fn new_unchecked(inner: T, signer: Address) -> Self {
94 Self { inner, signer }
95 }
96
97 pub fn convert<Tx>(self) -> Recovered<Tx>
99 where
100 Tx: From<T>,
101 {
102 self.map(Tx::from)
103 }
104
105 #[deprecated = "Use `convert_inner` instead"]
107 pub fn convert_transaction<Tx>(self) -> Recovered<Tx>
108 where
109 Tx: From<T>,
110 {
111 self.map(Tx::from)
112 }
113
114 pub fn try_convert<Tx, E>(self) -> Result<Recovered<Tx>, Tx::Error>
116 where
117 Tx: TryFrom<T>,
118 {
119 self.try_map(Tx::try_from)
120 }
121
122 #[deprecated = "Use `try_convert_inner` instead"]
124 pub fn try_convert_transaction<Tx, E>(self) -> Result<Recovered<Tx>, Tx::Error>
125 where
126 Tx: TryFrom<T>,
127 {
128 self.try_map(Tx::try_from)
129 }
130
131 pub fn map<Tx>(self, f: impl FnOnce(T) -> Tx) -> Recovered<Tx> {
133 Recovered::new_unchecked(f(self.inner), self.signer)
134 }
135
136 #[deprecated = "Use `map_inner` instead"]
138 pub fn map_transaction<Tx>(self, f: impl FnOnce(T) -> Tx) -> Recovered<Tx> {
139 Recovered::new_unchecked(f(self.inner), self.signer)
140 }
141
142 pub fn try_map<Tx, E>(self, f: impl FnOnce(T) -> Result<Tx, E>) -> Result<Recovered<Tx>, E> {
144 Ok(Recovered::new_unchecked(f(self.inner)?, self.signer))
145 }
146
147 #[deprecated = "Use `try_map_inner` instead"]
149 pub fn try_map_transaction<Tx, E>(
150 self,
151 f: impl FnOnce(T) -> Result<Tx, E>,
152 ) -> Result<Recovered<Tx>, E> {
153 Ok(Recovered::new_unchecked(f(self.inner)?, self.signer))
154 }
155}
156
157impl<T> Recovered<&T> {
158 pub fn cloned(self) -> Recovered<T>
160 where
161 T: Clone,
162 {
163 let Self { inner, signer } = self;
164 Recovered::new_unchecked(inner.clone(), signer)
165 }
166}
167
168impl<T: Encodable> Encodable for Recovered<T> {
169 fn encode(&self, out: &mut dyn bytes::BufMut) {
171 self.inner.encode(out)
172 }
173
174 fn length(&self) -> usize {
175 self.inner.length()
176 }
177}
178
179impl<T: Decodable + SignerRecoverable> Decodable for Recovered<T> {
180 fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
181 let tx = T::decode(buf)?;
182 let signer = tx.recover_signer().map_err(|_| {
183 alloy_rlp::Error::Custom("Unable to recover decoded transaction signer.")
184 })?;
185 Ok(Self::new_unchecked(tx, signer))
186 }
187}
188
189impl<T: Typed2718> Typed2718 for Recovered<T> {
190 fn ty(&self) -> u8 {
191 self.inner.ty()
192 }
193}
194
195impl<T: Encodable2718> Encodable2718 for Recovered<T> {
196 fn encode_2718_len(&self) -> usize {
197 self.inner.encode_2718_len()
198 }
199
200 fn encode_2718(&self, out: &mut dyn alloy_rlp::BufMut) {
201 self.inner.encode_2718(out)
202 }
203
204 fn trie_hash(&self) -> B256 {
205 self.inner.trie_hash()
206 }
207}
208
209pub trait SignerRecoverable {
214 fn recover_signer(&self) -> Result<Address, alloy_primitives::SignatureError>;
224
225 fn recover_signer_unchecked(&self) -> Result<Address, alloy_primitives::SignatureError>;
230}