1use super::{AccountId, MultiAddress, MultiSignature};
2use codec::{Compact, Decode, Encode};
3use primitive_types::H256;
4use serde::{Deserialize, Serialize};
5use std::borrow::Cow;
6use subxt_core::config::{Hasher, substrate::BlakeTwo256};
7use subxt_signer::sr25519::Keypair;
8
9pub use subxt_core::utils::Era;
10
11pub const EXTRINSIC_FORMAT_VERSION: u8 = 4;
17
18#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)]
19pub struct TransactionExtra {
20 pub era: Era,
21 #[codec(compact)]
22 pub nonce: u32,
23 #[codec(compact)]
24 pub tip: u128,
25 #[codec(compact)]
26 pub app_id: u32,
27}
28
29#[derive(Debug, Clone)]
30pub struct TransactionAdditional {
31 pub spec_version: u32,
32 pub tx_version: u32,
33 pub genesis_hash: H256,
34 pub fork_hash: H256,
35}
36impl Encode for TransactionAdditional {
37 fn encode_to<T: codec::Output + ?Sized>(&self, dest: &mut T) {
38 self.spec_version.encode_to(dest);
39 self.tx_version.encode_to(dest);
40 self.genesis_hash.encode_to(dest);
41 self.fork_hash.encode_to(dest);
42 }
43}
44impl Decode for TransactionAdditional {
45 fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
46 let spec_version = Decode::decode(input)?;
47 let tx_version = Decode::decode(input)?;
48 let genesis_hash = Decode::decode(input)?;
49 let fork_hash = Decode::decode(input)?;
50 Ok(Self { spec_version, tx_version, genesis_hash, fork_hash })
51 }
52}
53
54#[derive(Debug, Clone)]
55pub struct AlreadyEncoded(pub Vec<u8>);
56impl Encode for AlreadyEncoded {
57 fn size_hint(&self) -> usize {
58 self.0.len()
59 }
60
61 fn encode_to<T: codec::Output + ?Sized>(&self, dest: &mut T) {
62 dest.write(&self.0);
63 }
64}
65impl Decode for AlreadyEncoded {
66 fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
67 let length = input.remaining_len()?;
68 let Some(length) = length else {
69 return Err("Failed to decode transaction".into());
70 };
71 if length == 0 {
72 return Ok(Self(Vec::new()));
73 }
74 let mut value = vec![0u8; length];
75 input.read(&mut value)?;
76 Ok(Self(value))
77 }
78}
79
80impl From<Vec<u8>> for AlreadyEncoded {
81 fn from(value: Vec<u8>) -> Self {
82 AlreadyEncoded(value)
83 }
84}
85
86#[derive(Debug, Clone)]
87pub struct TransactionCall {
88 pub pallet_id: u8,
89 pub call_id: u8,
90 pub data: AlreadyEncoded,
91}
92impl TransactionCall {
93 pub fn new(pallet_id: u8, call_id: u8, data: Vec<u8>) -> Self {
94 Self { pallet_id, call_id, data: AlreadyEncoded::from(data) }
95 }
96}
97impl Encode for TransactionCall {
98 fn encode_to<T: codec::Output + ?Sized>(&self, dest: &mut T) {
99 self.pallet_id.encode_to(dest);
100 self.call_id.encode_to(dest);
101 self.data.encode_to(dest);
102 }
103}
104impl Decode for TransactionCall {
105 fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
106 let pallet_id = Decode::decode(input)?;
107 let call_id = Decode::decode(input)?;
108 let data = Decode::decode(input)?;
109 Ok(Self { pallet_id, call_id, data })
110 }
111}
112
113#[derive(Debug, Clone)]
114pub struct TransactionCallDecoded<T> {
115 pub pallet_id: u8,
116 pub call_id: u8,
117 pub data: T,
118}
119
120#[derive(Debug, Clone)]
122pub struct TransactionPayload<'a> {
123 pub call: Cow<'a, TransactionCall>,
124 pub extra: TransactionExtra,
125 pub additional: TransactionAdditional,
126}
127
128impl<'a> TransactionPayload<'a> {
129 pub fn new(call: TransactionCall, extra: TransactionExtra, additional: TransactionAdditional) -> Self {
130 Self { call: Cow::Owned(call), extra, additional }
131 }
132
133 pub fn new_borrowed(call: &'a TransactionCall, extra: TransactionExtra, additional: TransactionAdditional) -> Self {
134 Self { call: Cow::Borrowed(call), extra, additional }
135 }
136
137 pub fn sign(&self, signer: &Keypair) -> [u8; 64] {
138 let call = self.call.as_ref();
139 let size_hint = call.size_hint() + self.extra.size_hint() + self.additional.size_hint();
140
141 let mut data: Vec<u8> = Vec::with_capacity(size_hint);
142 self.call.encode_to(&mut data);
143 self.extra.encode_to(&mut data);
144 self.additional.encode_to(&mut data);
145
146 if data.len() > 256 {
147 let hash = BlakeTwo256::hash(&data);
148 signer.sign(hash.as_ref()).0
149 } else {
150 signer.sign(&data).0
151 }
152 }
153}
154
155#[derive(Debug, Clone)]
156pub struct TransactionSigned {
157 pub address: MultiAddress,
158 pub signature: MultiSignature,
159 pub tx_extra: TransactionExtra,
160}
161impl Encode for TransactionSigned {
162 fn encode_to<T: codec::Output + ?Sized>(&self, dest: &mut T) {
163 self.address.encode_to(dest);
164 self.signature.encode_to(dest);
165 self.tx_extra.encode_to(dest);
166 }
167}
168impl Decode for TransactionSigned {
169 fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
170 let address = Decode::decode(input)?;
171 let signature = Decode::decode(input)?;
172 let tx_extra = Decode::decode(input)?;
173 Ok(Self { address, signature, tx_extra })
174 }
175}
176
177#[derive(Debug, Clone)]
178pub struct Transaction<'a> {
179 pub signed: Option<TransactionSigned>,
180 pub call: Cow<'a, TransactionCall>,
181}
182
183impl<'a> Transaction<'a> {
184 pub fn new(account_id: AccountId, signature: [u8; 64], payload: TransactionPayload<'a>) -> Self {
185 let address = MultiAddress::Id(account_id);
186 let signature = MultiSignature::Sr25519(signature);
187
188 let signed = Some(TransactionSigned { address, signature, tx_extra: payload.extra.clone() });
189
190 Self { signed, call: payload.call }
191 }
192
193 pub fn encode(&self) -> Vec<u8> {
194 let mut encoded_tx_inner = Vec::new();
195 if let Some(signed) = &self.signed {
196 0x84u8.encode_to(&mut encoded_tx_inner);
197 signed.address.encode_to(&mut encoded_tx_inner);
198 signed.signature.encode_to(&mut encoded_tx_inner);
199 signed.tx_extra.encode_to(&mut encoded_tx_inner);
200 } else {
201 0x4u8.encode_to(&mut encoded_tx_inner);
202 }
203
204 let call = self.call.as_ref();
205 call.encode_to(&mut encoded_tx_inner);
206 let mut encoded_tx = Compact(encoded_tx_inner.len() as u32).encode();
207 encoded_tx.append(&mut encoded_tx_inner);
208
209 encoded_tx
210 }
211
212 pub fn hash(&self) -> H256 {
213 let encoded = self.encode();
214 BlakeTwo256::hash(&encoded)
215 }
216}
217
218impl TryFrom<&Vec<u8>> for Transaction<'_> {
219 type Error = codec::Error;
220
221 fn try_from(value: &Vec<u8>) -> Result<Self, Self::Error> {
222 Self::try_from(value.as_slice())
223 }
224}
225
226impl TryFrom<&[u8]> for Transaction<'_> {
227 type Error = codec::Error;
228
229 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
230 let mut value = value;
231 Self::decode(&mut value)
232 }
233}
234
235impl Decode for Transaction<'_> {
236 fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
237 let expected_length = Compact::<u32>::decode(input)?;
241 let before_length = input.remaining_len()?;
242
243 let version = input.read_byte()?;
244
245 let is_signed = version & 0b1000_0000 != 0;
246 let version = version & 0b0111_1111;
247 if version != EXTRINSIC_FORMAT_VERSION {
248 return Err("Invalid transaction version".into());
249 }
250
251 let signed = is_signed.then(|| TransactionSigned::decode(input)).transpose()?;
252 let call = TransactionCall::decode(input)?;
253
254 if let Some((before_length, after_length)) = input.remaining_len()?.and_then(|a| before_length.map(|b| (b, a)))
255 {
256 let length = before_length.saturating_sub(after_length);
257
258 if length != expected_length.0 as usize {
259 return Err("Invalid length prefix".into());
260 }
261 }
262
263 Ok(Self { signed, call: Cow::Owned(call) })
264 }
265}
266
267impl Serialize for Transaction<'_> {
268 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
269 where
270 S: serde::Serializer,
271 {
272 let bytes = self.encode();
273 impl_serde::serialize::serialize(&bytes, serializer)
274 }
275}
276
277impl<'a> Deserialize<'a> for Transaction<'_> {
278 fn deserialize<D>(de: D) -> Result<Self, D::Error>
279 where
280 D: serde::Deserializer<'a>,
281 {
282 let r = impl_serde::serialize::deserialize(de)?;
283 Decode::decode(&mut &r[..]).map_err(|e| serde::de::Error::custom(format!("Decode error: {}", e)))
284 }
285}