avail_rust_core/
transaction.rs

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
11/// Current version of the [`UncheckedExtrinsic`] encoded format.
12///
13/// This version needs to be bumped if the encoded representation changes.
14/// It ensures that if the representation is changed and the format is not known,
15/// the decoding fails.
16pub 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// There is no need for Encode and Decode
121#[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		// This is a little more complicated than usual since the binary format must be compatible
238		// with SCALE's generic `Vec<u8>` type. Basically this just means accepting that there
239		// will be a prefix of vector length.
240		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}