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