avail_rust_core/
decoded_extrinsics.rs

1use super::substrate::extrinsic::EXTRINSIC_FORMAT_VERSION;
2use crate::{
3	decoded_events::check_header,
4	types::{ExtrinsicSignature, metadata::StringOrBytes},
5	utils::decode_already_decoded,
6};
7use codec::{Compact, Decode, Encode, Error, Input};
8use serde::{Deserialize, Serialize};
9
10pub trait HasHeader {
11	// Pallet ID, Variant ID
12	const HEADER_INDEX: (u8, u8);
13}
14
15pub trait TransactionEncodable {
16	/// SCALE encodes the event
17	///
18	/// If you need to Hex and SCALE encode then call `encode_as_hex_event`
19	fn to_call(&self) -> Vec<u8>;
20}
21
22pub trait ExtrinsicDecodable: Sized {
23	fn from_call<'a>(call: impl Into<StringOrBytes<'a>>) -> Result<Self, String>;
24	fn from_ext<'a>(call: impl Into<StringOrBytes<'a>>) -> Result<Self, String>;
25}
26
27impl<T: HasHeader + Encode> TransactionEncodable for T {
28	fn to_call(&self) -> Vec<u8> {
29		let pallet_id = Self::HEADER_INDEX.0;
30		let variant_id = Self::HEADER_INDEX.1;
31		let mut encoded_event: Vec<u8> = vec![pallet_id, variant_id];
32		Self::encode_to(self, &mut encoded_event);
33
34		encoded_event
35	}
36}
37
38impl<T: HasHeader + Decode> ExtrinsicDecodable for T {
39	fn from_call<'a>(call: impl Into<StringOrBytes<'a>>) -> Result<T, String> {
40		fn inner<T: HasHeader + Decode>(call: StringOrBytes) -> Result<T, String> {
41			let call: &[u8] = match &call {
42				StringOrBytes::StringRef(s) => {
43					&const_hex::decode(s.trim_start_matches("0x")).map_err(|x| x.to_string())?
44				},
45				StringOrBytes::BoxedString(s) => {
46					&const_hex::decode(s.trim_start_matches("0x")).map_err(|x| x.to_string())?
47				},
48				StringOrBytes::Bytes(b) => b,
49				StringOrBytes::BoxedBytes(b) => b,
50			};
51
52			check_header(call, T::HEADER_INDEX)?;
53
54			let mut data = if call.len() <= 2 { &[] } else { &call[2..] };
55			Ok(T::decode(&mut data).map_err(|x| x.to_string())?)
56		}
57
58		inner(call.into())
59	}
60
61	fn from_ext<'a>(ext: impl Into<StringOrBytes<'a>>) -> Result<T, String> {
62		fn inner<T: HasHeader + Decode>(ext: StringOrBytes) -> Result<T, String> {
63			let ext: &[u8] = match &ext {
64				StringOrBytes::StringRef(s) => &const_hex::decode(s.trim_start_matches("0x"))
65					.map_err(|x: const_hex::FromHexError| x.to_string())?,
66				StringOrBytes::BoxedString(s) => {
67					&const_hex::decode(s.trim_start_matches("0x")).map_err(|x| x.to_string())?
68				},
69				StringOrBytes::Bytes(b) => b,
70				StringOrBytes::BoxedBytes(b) => b,
71			};
72
73			let ext = Extrinsic::<T>::try_from(ext)?;
74			Ok(ext.call)
75		}
76
77		inner(ext.into())
78	}
79}
80
81#[derive(Clone)]
82pub struct EncodedExtrinsic {
83	/// The signature, address, number of extrinsics have come before from
84	/// the same signer and an era describing the longevity of this transaction,
85	/// if this is a signed extrinsic.
86	pub signature: Option<ExtrinsicSignature>,
87	/// The function that should be called.
88	pub call: Vec<u8>,
89}
90
91impl<'a> TryFrom<StringOrBytes<'a>> for EncodedExtrinsic {
92	type Error = String;
93
94	fn try_from(value: StringOrBytes<'a>) -> Result<Self, Self::Error> {
95		match value {
96			StringOrBytes::StringRef(s) => Self::try_from(s),
97			StringOrBytes::BoxedString(s) => Self::try_from(&*s),
98			StringOrBytes::Bytes(b) => Self::try_from(b),
99			StringOrBytes::BoxedBytes(b) => Self::try_from(&*b),
100		}
101	}
102}
103
104impl TryFrom<Vec<u8>> for EncodedExtrinsic {
105	type Error = String;
106
107	fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
108		Self::try_from(value.as_slice())
109	}
110}
111
112impl TryFrom<&Vec<u8>> for EncodedExtrinsic {
113	type Error = String;
114
115	fn try_from(value: &Vec<u8>) -> Result<Self, Self::Error> {
116		Self::try_from(value.as_slice())
117	}
118}
119
120impl TryFrom<&[u8]> for EncodedExtrinsic {
121	type Error = String;
122
123	fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
124		let mut value = value;
125		Self::decode(&mut value).map_err(|x| x.to_string())
126	}
127}
128
129impl TryFrom<String> for EncodedExtrinsic {
130	type Error = String;
131
132	fn try_from(value: String) -> Result<Self, Self::Error> {
133		Self::try_from(value.as_str())
134	}
135}
136
137impl TryFrom<&String> for EncodedExtrinsic {
138	type Error = String;
139
140	fn try_from(value: &String) -> Result<Self, Self::Error> {
141		Self::try_from(value.as_str())
142	}
143}
144
145impl TryFrom<&str> for EncodedExtrinsic {
146	type Error = String;
147
148	fn try_from(value: &str) -> Result<Self, Self::Error> {
149		let Ok(hex_decoded) = const_hex::decode(value.trim_start_matches("0x")) else {
150			return Err("Failed to hex decode transaction".into());
151		};
152
153		Self::try_from(hex_decoded.as_slice())
154	}
155}
156
157impl Decode for EncodedExtrinsic {
158	fn decode<I: Input>(input: &mut I) -> Result<Self, Error> {
159		// This is a little more complicated than usual since the binary format must be compatible
160		// with SCALE's generic `Vec<u8>` type. Basically this just means accepting that there
161		// will be a prefix of vector length.
162		let expected_length: Compact<u32> = Decode::decode(input)?;
163		let before_length = input.remaining_len()?;
164
165		let version = input.read_byte()?;
166
167		let is_signed = version & 0b1000_0000 != 0;
168		let version = version & 0b0111_1111;
169		if version != EXTRINSIC_FORMAT_VERSION {
170			return Err("Invalid transaction version".into());
171		}
172
173		let signature = is_signed.then(|| Decode::decode(input)).transpose()?;
174		let call = decode_already_decoded(input)?;
175
176		if let Some((before_length, after_length)) = input.remaining_len()?.and_then(|a| before_length.map(|b| (b, a)))
177		{
178			let length = before_length.saturating_sub(after_length);
179
180			if length != expected_length.0 as usize {
181				return Err("Invalid length prefix".into());
182			}
183		}
184
185		Ok(Self { signature, call })
186	}
187}
188
189impl Encode for EncodedExtrinsic {
190	fn encode_to<T: codec::Output + ?Sized>(&self, dest: &mut T) {
191		let mut encoded_tx_inner = Vec::new();
192		if let Some(signed) = &self.signature {
193			0x84u8.encode_to(&mut encoded_tx_inner);
194			signed.address.encode_to(&mut encoded_tx_inner);
195			signed.signature.encode_to(&mut encoded_tx_inner);
196			signed.extra.encode_to(&mut encoded_tx_inner);
197		} else {
198			0x4u8.encode_to(&mut encoded_tx_inner);
199		}
200
201		encoded_tx_inner.extend(&self.call);
202		let mut encoded_tx = Compact(encoded_tx_inner.len() as u32).encode();
203		encoded_tx.append(&mut encoded_tx_inner);
204
205		dest.write(&encoded_tx)
206	}
207}
208
209impl Serialize for EncodedExtrinsic {
210	fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
211	where
212		S: serde::Serializer,
213	{
214		let bytes = self.encode();
215		impl_serde::serialize::serialize(&bytes, serializer)
216	}
217}
218
219impl<'a> Deserialize<'a> for EncodedExtrinsic {
220	fn deserialize<D>(de: D) -> Result<Self, D::Error>
221	where
222		D: serde::Deserializer<'a>,
223	{
224		let r = impl_serde::serialize::deserialize(de)?;
225		Decode::decode(&mut &r[..]).map_err(|e| serde::de::Error::custom(format!("Decode error: {}", e)))
226	}
227}
228
229#[derive(Debug, Clone)]
230pub struct SignedExtrinsic<T: HasHeader + Decode + Sized> {
231	pub signature: ExtrinsicSignature,
232	pub call: T,
233}
234
235impl<'a, T: HasHeader + Decode> TryFrom<StringOrBytes<'a>> for SignedExtrinsic<T> {
236	type Error = String;
237
238	fn try_from(value: StringOrBytes<'a>) -> Result<Self, Self::Error> {
239		match value {
240			StringOrBytes::StringRef(s) => Self::try_from(s),
241			StringOrBytes::BoxedString(s) => Self::try_from(&*s),
242			StringOrBytes::Bytes(b) => Self::try_from(b),
243			StringOrBytes::BoxedBytes(b) => Self::try_from(&*b),
244		}
245	}
246}
247
248impl<T: HasHeader + Decode> TryFrom<Vec<u8>> for SignedExtrinsic<T> {
249	type Error = String;
250
251	fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
252		Self::try_from(value.as_slice())
253	}
254}
255
256impl<T: HasHeader + Decode> TryFrom<&Vec<u8>> for SignedExtrinsic<T> {
257	type Error = String;
258
259	fn try_from(value: &Vec<u8>) -> Result<Self, Self::Error> {
260		Self::try_from(value.as_slice())
261	}
262}
263
264impl<T: HasHeader + Decode> TryFrom<&[u8]> for SignedExtrinsic<T> {
265	type Error = String;
266
267	fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
268		let ext = EncodedExtrinsic::try_from(value)?;
269		Self::try_from(ext)
270	}
271}
272
273impl<T: HasHeader + Decode> TryFrom<String> for SignedExtrinsic<T> {
274	type Error = String;
275
276	fn try_from(value: String) -> Result<Self, Self::Error> {
277		Self::try_from(value.as_str())
278	}
279}
280
281impl<T: HasHeader + Decode> TryFrom<&String> for SignedExtrinsic<T> {
282	type Error = String;
283
284	fn try_from(value: &String) -> Result<Self, Self::Error> {
285		Self::try_from(value.as_str())
286	}
287}
288
289impl<T: HasHeader + Decode> TryFrom<&str> for SignedExtrinsic<T> {
290	type Error = String;
291
292	fn try_from(value: &str) -> Result<Self, Self::Error> {
293		let ext = EncodedExtrinsic::try_from(value)?;
294		Self::try_from(ext)
295	}
296}
297
298impl<T: HasHeader + Decode> TryFrom<EncodedExtrinsic> for SignedExtrinsic<T> {
299	type Error = String;
300
301	fn try_from(value: EncodedExtrinsic) -> Result<Self, Self::Error> {
302		let signature = value.signature.ok_or("Extrinsic has no signature")?;
303		let call = T::from_call(&value.call)?;
304		Ok(Self { signature, call })
305	}
306}
307
308impl<T: HasHeader + Decode> TryFrom<&EncodedExtrinsic> for SignedExtrinsic<T> {
309	type Error = String;
310
311	fn try_from(value: &EncodedExtrinsic) -> Result<Self, Self::Error> {
312		let signature = value.signature.as_ref().ok_or("Extrinsic has no signature")?.clone();
313		let call = T::from_call(&value.call)?;
314		Ok(Self { signature, call })
315	}
316}
317
318#[derive(Debug, Clone)]
319pub struct Extrinsic<T: HasHeader + Decode + Sized> {
320	pub signature: Option<ExtrinsicSignature>,
321	pub call: T,
322}
323
324impl<'a, T: HasHeader + Decode> TryFrom<StringOrBytes<'a>> for Extrinsic<T> {
325	type Error = String;
326
327	fn try_from(value: StringOrBytes<'a>) -> Result<Self, Self::Error> {
328		match value {
329			StringOrBytes::StringRef(s) => Self::try_from(s),
330			StringOrBytes::BoxedString(s) => Self::try_from(&*s),
331			StringOrBytes::Bytes(b) => Self::try_from(b),
332			StringOrBytes::BoxedBytes(b) => Self::try_from(&*b),
333		}
334	}
335}
336
337impl<T: HasHeader + Decode> TryFrom<Vec<u8>> for Extrinsic<T> {
338	type Error = String;
339
340	fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
341		Self::try_from(value.as_slice())
342	}
343}
344
345impl<T: HasHeader + Decode> TryFrom<&Vec<u8>> for Extrinsic<T> {
346	type Error = String;
347
348	fn try_from(value: &Vec<u8>) -> Result<Self, Self::Error> {
349		Self::try_from(value.as_slice())
350	}
351}
352
353impl<T: HasHeader + Decode> TryFrom<&[u8]> for Extrinsic<T> {
354	type Error = String;
355
356	fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
357		let ext = EncodedExtrinsic::try_from(value)?;
358		Self::try_from(ext)
359	}
360}
361
362impl<T: HasHeader + Decode> TryFrom<String> for Extrinsic<T> {
363	type Error = String;
364
365	fn try_from(value: String) -> Result<Self, Self::Error> {
366		Self::try_from(value.as_str())
367	}
368}
369
370impl<T: HasHeader + Decode> TryFrom<&String> for Extrinsic<T> {
371	type Error = String;
372
373	fn try_from(value: &String) -> Result<Self, Self::Error> {
374		Self::try_from(value.as_str())
375	}
376}
377
378impl<T: HasHeader + Decode> TryFrom<&str> for Extrinsic<T> {
379	type Error = String;
380
381	fn try_from(value: &str) -> Result<Self, Self::Error> {
382		let ext = EncodedExtrinsic::try_from(value)?;
383		Self::try_from(ext)
384	}
385}
386
387impl<T: HasHeader + Decode> TryFrom<EncodedExtrinsic> for Extrinsic<T> {
388	type Error = String;
389
390	fn try_from(value: EncodedExtrinsic) -> Result<Self, Self::Error> {
391		Self::try_from(&value)
392	}
393}
394
395impl<T: HasHeader + Decode> TryFrom<&EncodedExtrinsic> for Extrinsic<T> {
396	type Error = String;
397
398	fn try_from(value: &EncodedExtrinsic) -> Result<Self, Self::Error> {
399		let call = T::from_call(&value.call)?;
400		Ok(Self { signature: value.signature.clone(), call })
401	}
402}
403
404#[cfg(test)]
405pub mod test {
406	/* 	#[test]
407	fn test_encoding_decoding() {
408		let call = SubmitData { data: vec![0, 1, 2, 3] }.to_call();
409
410		let account_id = AccountId32([1u8; 32]);
411		let signature = [1u8; 64];
412		let signed = SignedExtra {
413			address: MultiAddress::Id(account_id),
414			signature: MultiSignature::Sr25519(signature),
415			tx_extra: ExtrinsicExtra {
416				era: Era::Mortal { period: 4, phase: 2 },
417				nonce: 1,
418				tip: 2u128,
419				app_id: 3,
420			},
421		};
422
423		let tx = Extrinsic {
424			signature: Some(signed.clone()),
425			call: Cow::Owned(call.clone()),
426		};
427
428		let encoded_tx = tx.encode();
429
430		// Opaque Transaction
431		let opaque = EncodedExtrinsic::try_from(&encoded_tx).unwrap();
432		let opaque_encoded = opaque.encode();
433
434		assert_eq!(encoded_tx, opaque_encoded);
435	}
436
437	#[test]
438	fn test_serialize_deserialize() {
439		let call = SubmitData { data: vec![0, 1, 2, 3] }.to_call();
440
441		let account_id = AccountId32([1u8; 32]);
442		let signature = [1u8; 64];
443		let signed = SignedExtra {
444			address: MultiAddress::Id(account_id),
445			signature: MultiSignature::Sr25519(signature),
446			tx_extra: ExtrinsicExtra {
447				era: Era::Mortal { period: 4, phase: 2 },
448				nonce: 1,
449				tip: 2u128,
450				app_id: 3,
451			},
452		};
453
454		let tx = Extrinsic {
455			signature: Some(signed.clone()),
456			call: Cow::Owned(call.clone()),
457		};
458
459		let encoded_tx = tx.encode();
460		let expected_serialized = std::format!("0x{}", const_hex::encode(&encoded_tx));
461
462		// Transaction Serialized
463		let serialized = serde_json::to_string(&tx).unwrap();
464		assert_eq!(serialized.trim_matches('"'), expected_serialized);
465
466		// Transaction Deserialized
467		let tx_deserialized: Extrinsic = serde_json::from_str(&serialized).unwrap();
468		assert_eq!(encoded_tx, tx_deserialized.encode());
469
470		// Opaque Serialized
471		let opaque = EncodedExtrinsic::try_from(&encoded_tx).unwrap();
472		let serialized = serde_json::to_string(&opaque).unwrap();
473		assert_eq!(serialized.trim_matches('"'), expected_serialized);
474
475		// Opaque Deserialized
476		let opaque_deserialized: EncodedExtrinsic = serde_json::from_str(&serialized).unwrap();
477		assert_eq!(encoded_tx, opaque_deserialized.encode());
478	} */
479}