avail_rust_core/
decoded_transaction.rs

1use super::transaction::{AlreadyEncoded, EXTRINSIC_FORMAT_VERSION, TransactionSigned};
2use codec::{Compact, Decode, Encode, Error, Input};
3use serde::{Deserialize, Serialize};
4
5#[cfg(not(feature = "generated_metadata"))]
6use crate::avail::{RuntimeCall, RuntimeEvent};
7#[cfg(feature = "generated_metadata")]
8use crate::avail_generated::runtime_types::da_runtime::{RuntimeCall, RuntimeEvent};
9
10#[derive(Clone)]
11pub struct OpaqueTransaction {
12	/// The signature, address, number of extrinsics have come before from
13	/// the same signer and an era describing the longevity of this transaction,
14	/// if this is a signed extrinsic.
15	pub signature: Option<TransactionSigned>,
16	/// The function that should be called.
17	pub call: Vec<u8>,
18}
19
20impl OpaqueTransaction {
21	pub fn pallet_index(&self) -> u8 {
22		self.call[0]
23	}
24
25	pub fn call_index(&self) -> u8 {
26		self.call[1]
27	}
28}
29
30impl TryFrom<Vec<u8>> for OpaqueTransaction {
31	type Error = codec::Error;
32
33	fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
34		Self::try_from(value.as_slice())
35	}
36}
37
38impl TryFrom<&Vec<u8>> for OpaqueTransaction {
39	type Error = codec::Error;
40
41	fn try_from(value: &Vec<u8>) -> Result<Self, Self::Error> {
42		Self::try_from(value.as_slice())
43	}
44}
45
46impl TryFrom<&[u8]> for OpaqueTransaction {
47	type Error = codec::Error;
48
49	fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
50		let mut value = value;
51		Self::decode(&mut value)
52	}
53}
54
55impl Decode for OpaqueTransaction {
56	fn decode<I: Input>(input: &mut I) -> Result<Self, Error> {
57		// This is a little more complicated than usual since the binary format must be compatible
58		// with SCALE's generic `Vec<u8>` type. Basically this just means accepting that there
59		// will be a prefix of vector length.
60		let expected_length: Compact<u32> = Decode::decode(input)?;
61		let before_length = input.remaining_len()?;
62
63		let version = input.read_byte()?;
64
65		let is_signed = version & 0b1000_0000 != 0;
66		let version = version & 0b0111_1111;
67		if version != EXTRINSIC_FORMAT_VERSION {
68			return Err("Invalid transaction version".into());
69		}
70
71		let signature = is_signed.then(|| Decode::decode(input)).transpose()?;
72		let call: AlreadyEncoded = Decode::decode(input)?;
73
74		if let Some((before_length, after_length)) = input.remaining_len()?.and_then(|a| before_length.map(|b| (b, a)))
75		{
76			let length = before_length.saturating_sub(after_length);
77
78			if length != expected_length.0 as usize {
79				return Err("Invalid length prefix".into());
80			}
81		}
82
83		Ok(Self {
84			signature,
85			call: call.0,
86		})
87	}
88}
89
90impl Encode for OpaqueTransaction {
91	fn encode_to<T: codec::Output + ?Sized>(&self, dest: &mut T) {
92		let mut encoded_tx_inner = Vec::new();
93		if let Some(signed) = &self.signature {
94			0x84u8.encode_to(&mut encoded_tx_inner);
95			signed.address.encode_to(&mut encoded_tx_inner);
96			signed.signature.encode_to(&mut encoded_tx_inner);
97			signed.tx_extra.encode_to(&mut encoded_tx_inner);
98		} else {
99			0x4u8.encode_to(&mut encoded_tx_inner);
100		}
101
102		encoded_tx_inner.extend(&self.call);
103		let mut encoded_tx = Compact(encoded_tx_inner.len() as u32).encode();
104		encoded_tx.append(&mut encoded_tx_inner);
105
106		dest.write(&encoded_tx)
107	}
108}
109
110impl Serialize for OpaqueTransaction {
111	fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
112	where
113		S: serde::Serializer,
114	{
115		let bytes = self.encode();
116		impl_serde::serialize::serialize(&bytes, serializer)
117	}
118}
119
120impl<'a> Deserialize<'a> for OpaqueTransaction {
121	fn deserialize<D>(de: D) -> Result<Self, D::Error>
122	where
123		D: serde::Deserializer<'a>,
124	{
125		let r = impl_serde::serialize::deserialize(de)?;
126		Decode::decode(&mut &r[..]).map_err(|e| serde::de::Error::custom(format!("Decode error: {}", e)))
127	}
128}
129
130#[derive(Clone)]
131pub struct DecodedTransaction {
132	/// The signature, address, number of extrinsics have come before from
133	/// the same signer and an era describing the longevity of this transaction,
134	/// if this is a signed extrinsic.
135	pub signature: Option<TransactionSigned>,
136	/// The function that should be called.
137	pub call: RuntimeCall,
138}
139
140impl DecodedTransaction {
141	pub fn app_id(&self) -> Option<u32> {
142		self.signature.as_ref().map(|s| s.tx_extra.app_id)
143	}
144
145	#[cfg(not(feature = "generated_metadata"))]
146	pub fn pallet_index(&self) -> u8 {
147		self.call.pallet_index()
148	}
149
150	#[cfg(not(feature = "generated_metadata"))]
151	pub fn call_index(&self) -> u8 {
152		self.call.call_index()
153	}
154}
155
156impl TryFrom<&Vec<u8>> for DecodedTransaction {
157	type Error = codec::Error;
158
159	fn try_from(value: &Vec<u8>) -> Result<Self, Self::Error> {
160		Self::try_from(value.as_slice())
161	}
162}
163
164impl TryFrom<&[u8]> for DecodedTransaction {
165	type Error = codec::Error;
166
167	fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
168		let mut value = value;
169		Self::decode(&mut value)
170	}
171}
172
173impl Decode for DecodedTransaction {
174	fn decode<I: Input>(input: &mut I) -> Result<Self, Error> {
175		// This is a little more complicated than usual since the binary format must be compatible
176		// with SCALE's generic `Vec<u8>` type. Basically this just means accepting that there
177		// will be a prefix of vector length.
178		let expected_length: Compact<u32> = Decode::decode(input)?;
179		let before_length = input.remaining_len()?;
180
181		let version = input.read_byte()?;
182
183		let is_signed = version & 0b1000_0000 != 0;
184		let version = version & 0b0111_1111;
185		if version != EXTRINSIC_FORMAT_VERSION {
186			return Err("Invalid transaction version".into());
187		}
188
189		let signature = is_signed.then(|| Decode::decode(input)).transpose()?;
190		let call = Decode::decode(input)?;
191
192		if let Some((before_length, after_length)) = input.remaining_len()?.and_then(|a| before_length.map(|b| (b, a)))
193		{
194			let length = before_length.saturating_sub(after_length);
195
196			if length != expected_length.0 as usize {
197				return Err("Invalid length prefix".into());
198			}
199		}
200
201		Ok(Self { signature, call })
202	}
203}
204
205impl Encode for DecodedTransaction {
206	fn encode_to<T: codec::Output + ?Sized>(&self, dest: &mut T) {
207		let mut encoded_tx_inner = Vec::new();
208		if let Some(signed) = &self.signature {
209			0x84u8.encode_to(&mut encoded_tx_inner);
210			signed.address.encode_to(&mut encoded_tx_inner);
211			signed.signature.encode_to(&mut encoded_tx_inner);
212			signed.tx_extra.encode_to(&mut encoded_tx_inner);
213		} else {
214			0x4u8.encode_to(&mut encoded_tx_inner);
215		}
216
217		self.call.encode_to(&mut encoded_tx_inner);
218		let mut encoded_tx = Compact(encoded_tx_inner.len() as u32).encode();
219		encoded_tx.append(&mut encoded_tx_inner);
220
221		dest.write(&encoded_tx)
222	}
223}
224
225impl Serialize for DecodedTransaction {
226	fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
227	where
228		S: serde::Serializer,
229	{
230		let bytes = self.encode();
231		impl_serde::serialize::serialize(&bytes, serializer)
232	}
233}
234
235impl<'a> Deserialize<'a> for DecodedTransaction {
236	fn deserialize<D>(de: D) -> Result<Self, D::Error>
237	where
238		D: serde::Deserializer<'a>,
239	{
240		let r = impl_serde::serialize::deserialize(de)?;
241		Decode::decode(&mut &r[..]).map_err(|e| serde::de::Error::custom(format!("Decode error: {}", e)))
242	}
243}
244
245#[derive(Debug, Clone, Decode)]
246pub struct DecodedEvent {
247	pub phase: RuntimePhase,
248	pub event: RuntimeEvent,
249}
250
251/// A phase of a block's execution.
252#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Encode, Decode)]
253pub enum RuntimePhase {
254	/// Applying an extrinsic.
255	ApplyExtrinsic(u32),
256	/// Finalizing the block.
257	Finalization,
258	/// Initializing the block.
259	Initialization,
260}
261
262#[cfg(test)]
263pub mod test {
264	use std::borrow::Cow;
265
266	use codec::Encode;
267	use subxt_core::utils::{AccountId32, Era};
268
269	use crate::{
270		DecodedTransaction, MultiAddress, MultiSignature, Transaction, TransactionExtra,
271		avail::data_availability::tx::SubmitData, chain_types::TransactionCallLike,
272		decoded_transaction::OpaqueTransaction, transaction::TransactionSigned,
273	};
274
275	#[test]
276	fn test_encoding_decoding() {
277		let call = SubmitData { data: vec![0, 1, 2, 3] }.to_call();
278
279		let account_id = AccountId32([1u8; 32]);
280		let signature = [1u8; 64];
281		let signed = TransactionSigned {
282			address: MultiAddress::Id(account_id),
283			signature: MultiSignature::Sr25519(signature),
284			tx_extra: TransactionExtra {
285				era: Era::Mortal { period: 4, phase: 2 },
286				nonce: 1,
287				tip: 2u128,
288				app_id: 3,
289			},
290		};
291
292		let tx = Transaction {
293			signed: Some(signed.clone()),
294			call: Cow::Owned(call.clone()),
295		};
296
297		let encoded_tx = tx.encode();
298
299		// Opaque Transaction
300		let opaque = OpaqueTransaction::try_from(&encoded_tx).unwrap();
301		let opaque_encoded = opaque.encode();
302
303		assert_eq!(encoded_tx, opaque_encoded);
304
305		// Decoded Transaction
306		let decoded = DecodedTransaction::try_from(&encoded_tx).unwrap();
307		let decoded_encoded = decoded.encode();
308
309		assert_eq!(encoded_tx, decoded_encoded);
310	}
311
312	#[test]
313	fn test_serialize_deserialize() {
314		let call = SubmitData { data: vec![0, 1, 2, 3] }.to_call();
315
316		let account_id = AccountId32([1u8; 32]);
317		let signature = [1u8; 64];
318		let signed = TransactionSigned {
319			address: MultiAddress::Id(account_id),
320			signature: MultiSignature::Sr25519(signature),
321			tx_extra: TransactionExtra {
322				era: Era::Mortal { period: 4, phase: 2 },
323				nonce: 1,
324				tip: 2u128,
325				app_id: 3,
326			},
327		};
328
329		let tx = Transaction {
330			signed: Some(signed.clone()),
331			call: Cow::Owned(call.clone()),
332		};
333
334		let encoded_tx = tx.encode();
335		let expected_serialized = std::format!("0x{}", hex::encode(&encoded_tx));
336
337		// Transaction Serialized
338		let serialized = serde_json::to_string(&tx).unwrap();
339		assert_eq!(serialized.trim_matches('"'), expected_serialized);
340
341		// Transaction Deserialized
342		let tx_deserialized: Transaction = serde_json::from_str(&serialized).unwrap();
343		assert_eq!(encoded_tx, tx_deserialized.encode());
344
345		// Opaque Serialized
346		let opaque = OpaqueTransaction::try_from(&encoded_tx).unwrap();
347		let serialized = serde_json::to_string(&opaque).unwrap();
348		assert_eq!(serialized.trim_matches('"'), expected_serialized);
349
350		// Opaque Deserialized
351		let opaque_deserialized: OpaqueTransaction = serde_json::from_str(&serialized).unwrap();
352		assert_eq!(encoded_tx, opaque_deserialized.encode());
353
354		// Decoded Serialized
355		let decoded = DecodedTransaction::try_from(&encoded_tx).unwrap();
356		let serialized = serde_json::to_string(&decoded).unwrap();
357		assert_eq!(serialized.trim_matches('"'), expected_serialized);
358
359		// Decoded Deserialized
360		let decoded_deserialized: DecodedTransaction = serde_json::from_str(&serialized).unwrap();
361		assert_eq!(encoded_tx, decoded_deserialized.encode());
362	}
363}