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))]
9pub struct Recovered<T> {
10 signer: Address,
12 #[deref]
14 #[as_ref]
15 inner: T,
16}
17
18impl<T> Recovered<T> {
19 pub const fn signer(&self) -> Address {
21 self.signer
22 }
23
24 pub const fn signer_ref(&self) -> &Address {
26 &self.signer
27 }
28
29 pub const fn inner(&self) -> &T {
31 &self.inner
32 }
33
34 pub fn inner_mut(&mut self) -> &mut T {
36 &mut self.inner
37 }
38
39 pub fn into_inner(self) -> T {
41 self.inner
42 }
43
44 pub fn clone_inner(&self) -> T
46 where
47 T: Clone,
48 {
49 self.inner.clone()
50 }
51
52 #[doc(alias = "transaction")]
54 #[deprecated = "Use `inner` instead"]
55 pub const fn tx(&self) -> &T {
56 &self.inner
57 }
58
59 #[doc(alias = "into_transaction")]
61 #[deprecated = "Use `into_inner` instead"]
62 pub fn into_tx(self) -> T {
63 self.inner
64 }
65
66 #[doc(alias = "clone_transaction")]
68 #[deprecated = "Use `clone_inner` instead"]
69 pub fn clone_tx(&self) -> T
70 where
71 T: Clone,
72 {
73 self.inner.clone()
74 }
75
76 #[doc(alias = "split")]
78 pub fn into_parts(self) -> (T, Address) {
79 (self.inner, self.signer)
80 }
81
82 pub const fn as_recovered_ref(&self) -> Recovered<&T> {
84 Recovered { inner: &self.inner, signer: self.signer() }
85 }
86
87 #[inline]
91 pub const fn new_unchecked(inner: T, signer: Address) -> Self {
92 Self { inner, signer }
93 }
94
95 pub fn convert<Tx>(self) -> Recovered<Tx>
97 where
98 Tx: From<T>,
99 {
100 self.map(Tx::from)
101 }
102
103 #[deprecated = "Use `convert_inner` instead"]
105 pub fn convert_transaction<Tx>(self) -> Recovered<Tx>
106 where
107 Tx: From<T>,
108 {
109 self.map(Tx::from)
110 }
111
112 pub fn try_convert<Tx, E>(self) -> Result<Recovered<Tx>, Tx::Error>
114 where
115 Tx: TryFrom<T>,
116 {
117 self.try_map(Tx::try_from)
118 }
119
120 #[deprecated = "Use `try_convert_inner` instead"]
122 pub fn try_convert_transaction<Tx, E>(self) -> Result<Recovered<Tx>, Tx::Error>
123 where
124 Tx: TryFrom<T>,
125 {
126 self.try_map(Tx::try_from)
127 }
128
129 pub fn map<Tx>(self, f: impl FnOnce(T) -> Tx) -> Recovered<Tx> {
131 Recovered::new_unchecked(f(self.inner), self.signer)
132 }
133
134 #[deprecated = "Use `map_inner` instead"]
136 pub fn map_transaction<Tx>(self, f: impl FnOnce(T) -> Tx) -> Recovered<Tx> {
137 Recovered::new_unchecked(f(self.inner), self.signer)
138 }
139
140 pub fn try_map<Tx, E>(self, f: impl FnOnce(T) -> Result<Tx, E>) -> Result<Recovered<Tx>, E> {
142 Ok(Recovered::new_unchecked(f(self.inner)?, self.signer))
143 }
144
145 #[deprecated = "Use `try_map_inner` instead"]
147 pub fn try_map_transaction<Tx, E>(
148 self,
149 f: impl FnOnce(T) -> Result<Tx, E>,
150 ) -> Result<Recovered<Tx>, E> {
151 Ok(Recovered::new_unchecked(f(self.inner)?, self.signer))
152 }
153}
154
155impl<T> Recovered<&T> {
156 pub fn cloned(self) -> Recovered<T>
158 where
159 T: Clone,
160 {
161 let Self { inner, signer } = self;
162 Recovered::new_unchecked(inner.clone(), signer)
163 }
164}
165
166impl<T: Encodable> Encodable for Recovered<T> {
167 fn encode(&self, out: &mut dyn bytes::BufMut) {
169 self.inner.encode(out)
170 }
171
172 fn length(&self) -> usize {
173 self.inner.length()
174 }
175}
176
177impl<T: Decodable + SignerRecoverable> Decodable for Recovered<T> {
178 fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
179 let tx = T::decode(buf)?;
180 let signer = tx.recover_signer().map_err(|_| {
181 alloy_rlp::Error::Custom("Unable to recover decoded transaction signer.")
182 })?;
183 Ok(Self::new_unchecked(tx, signer))
184 }
185}
186
187impl<T: Typed2718> Typed2718 for Recovered<T> {
188 fn ty(&self) -> u8 {
189 self.inner.ty()
190 }
191}
192
193impl<T: Encodable2718> Encodable2718 for Recovered<T> {
194 fn encode_2718_len(&self) -> usize {
195 self.inner.encode_2718_len()
196 }
197
198 fn encode_2718(&self, out: &mut dyn alloy_rlp::BufMut) {
199 self.inner.encode_2718(out)
200 }
201
202 fn trie_hash(&self) -> B256 {
203 self.inner.trie_hash()
204 }
205}
206
207pub trait SignerRecoverable {
212 fn recover_signer(&self) -> Result<Address, alloy_primitives::SignatureError>;
222
223 fn recover_signer_unchecked(&self) -> Result<Address, alloy_primitives::SignatureError>;
228}