1use crate::methods::extrinsic_type_info::ExtrinsicInfoError;
17use crate::methods::extrinsic_type_info::ExtrinsicTypeInfo;
18use crate::utils::{DecodeErrorTrace, decode_with_error_tracing};
19use alloc::borrow::Cow;
20use alloc::string::{String, ToString};
21use alloc::vec;
22use alloc::vec::Vec;
23use core::ops::Range;
24use parity_scale_codec::{Compact, Decode};
25use scale_type_resolver::TypeResolver;
26
27#[non_exhaustive]
29#[allow(missing_docs)]
30#[derive(Debug, Clone, thiserror::Error)]
31pub enum ExtrinsicDecodeError {
32 #[error("Cannot decode the compact-encoded extrinsic length.")]
33 CannotDecodeLength,
34 #[error(
35 "The actual number of bytes does not match the compact-encoded extrinsic length; expected {expected_len} bytes but got {actual_len} bytes."
36 )]
37 WrongLength {
38 expected_len: usize,
39 actual_len: usize,
40 },
41 #[error("Not enough bytes to decode a valid extrinsic.")]
42 NotEnoughBytes,
43 #[error("This extrinsic version ({0}) is not supported.")]
44 VersionNotSupported(u8),
45 #[error(
46 "The extrinsic type 0b{extrinsic_type:02b} is not supported (given extrinsic version {version})."
47 )]
48 ExtrinsicTypeNotSupported { version: u8, extrinsic_type: u8 },
49 #[error("Cannot get extrinsic info:\n\n{0}")]
50 CannotGetInfo(ExtrinsicInfoError<'static>),
51 #[error("Cannot decode signature:\n\n{0}")]
52 CannotDecodeSignature(DecodeErrorTrace),
53 #[error("Cannot decode pallet index byte:\n\n{0}")]
54 CannotDecodePalletIndex(parity_scale_codec::Error),
55 #[error("Cannot decode call index byte:\n\n{0}")]
56 CannotDecodeCallIndex(parity_scale_codec::Error),
57 #[error("Cannot decode transaction extensions version byte:\n\n{0}")]
58 CannotDecodeExtensionsVersion(parity_scale_codec::Error),
59 #[error(
60 "Cannot decode call data for argument {argument_name} in {pallet_name}.{call_name}:\n\n{reason}"
61 )]
62 CannotDecodeCallData {
63 pallet_name: String,
64 call_name: String,
65 argument_name: String,
66 reason: DecodeErrorTrace,
67 },
68}
69
70pub type ExtrinsicOwned<TypeId> = Extrinsic<'static, TypeId>;
74
75#[derive(Clone, Debug)]
77pub struct Extrinsic<'info, TypeId> {
78 compact_prefix_len: u8,
79 version: u8,
80 version_ty: ExtrinsicType,
81 byte_len: u32,
82 signature: Option<ExtrinsicSignature<TypeId>>,
83 extensions: Option<ExtrinsicExtensions<'info, TypeId>>,
84 pallet_name: Cow<'info, str>,
85 pallet_index: u8,
86 pallet_index_idx: u32,
87 call_name: Cow<'info, str>,
88 call_index: u8,
89 call_data: Vec<NamedArg<'info, TypeId>>,
90}
91
92impl<'info, TypeId> Extrinsic<'info, TypeId> {
93 pub fn into_owned(self) -> ExtrinsicOwned<TypeId> {
96 Extrinsic {
97 compact_prefix_len: self.compact_prefix_len,
98 version: self.version,
99 version_ty: self.version_ty,
100 byte_len: self.byte_len,
101 signature: self.signature,
102 extensions: self.extensions.map(|e| e.into_owned()),
103 pallet_name: Cow::Owned(self.pallet_name.into_owned()),
104 pallet_index: self.pallet_index,
105 pallet_index_idx: self.pallet_index_idx,
106 call_name: Cow::Owned(self.call_name.into_owned()),
107 call_index: self.call_index,
108 call_data: self.call_data.into_iter().map(|e| e.into_owned()).collect(),
109 }
110 }
111
112 pub fn version(&self) -> u8 {
114 self.version
115 }
116
117 pub fn ty(&self) -> ExtrinsicType {
119 self.version_ty
120 }
121
122 #[allow(clippy::len_without_is_empty)]
124 pub fn len(&self) -> usize {
125 self.byte_len as usize
126 }
127
128 pub fn pallet_name(&self) -> &str {
130 &self.pallet_name
131 }
132
133 pub fn pallet_index(&self) -> u8 {
135 self.pallet_index
136 }
137
138 pub fn call_name(&self) -> &str {
140 &self.call_name
141 }
142
143 pub fn call_index(&self) -> u8 {
145 self.call_index
146 }
147
148 pub fn is_signed(&self) -> bool {
150 self.signature.is_some()
151 }
152
153 pub fn signature_payload(&self) -> Option<&ExtrinsicSignature<TypeId>> {
156 self.signature.as_ref()
157 }
158
159 pub fn transaction_extension_payload(&self) -> Option<&ExtrinsicExtensions<'info, TypeId>> {
162 self.extensions.as_ref()
163 }
164
165 pub fn call_data(&self) -> impl ExactSizeIterator<Item = &NamedArg<'info, TypeId>> {
167 self.call_data.iter()
168 }
169
170 pub fn call_data_range(&self) -> Range<usize> {
173 let start = self.pallet_index_idx as usize;
174 let end = self
175 .call_data()
176 .map(|a| a.range.end as usize)
177 .max()
178 .unwrap_or(start);
179
180 Range { start, end }
181 }
182
183 pub fn call_data_args_range(&self) -> Range<usize> {
186 let start = (self.pallet_index_idx + 2) as usize;
187 let end = self
188 .call_data()
189 .map(|a| a.range.end as usize)
190 .max()
191 .unwrap_or(start);
192
193 Range { start, end }
194 }
195
196 pub fn map_type_id<NewTypeId, F>(self, mut f: F) -> Extrinsic<'info, NewTypeId>
198 where
199 F: FnMut(TypeId) -> NewTypeId,
200 {
201 Extrinsic {
202 compact_prefix_len: self.compact_prefix_len,
203 version: self.version,
204 version_ty: self.version_ty,
205 byte_len: self.byte_len,
206 signature: self.signature.map(|s| s.map_type_id(&mut f)),
207 extensions: self.extensions.map(|e| e.map_type_id(&mut f)),
208 pallet_name: self.pallet_name,
209 pallet_index: self.pallet_index,
210 pallet_index_idx: self.pallet_index_idx,
211 call_name: self.call_name,
212 call_index: self.call_index,
213 call_data: self
214 .call_data
215 .into_iter()
216 .map(|s| s.map_type_id(&mut f))
217 .collect(),
218 }
219 }
220}
221
222#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
224pub enum ExtrinsicType {
225 Bare,
227 General,
229 Signed,
231}
232
233#[derive(Clone, Debug)]
235pub struct ExtrinsicSignature<TypeId> {
236 address_start_idx: u32,
239 address_end_idx: u32,
240 signature_end_idx: u32,
241 address_ty: TypeId,
247 signature_ty: TypeId,
248}
249
250impl<TypeId> ExtrinsicSignature<TypeId> {
251 pub fn address_range(&self) -> Range<usize> {
253 Range {
254 start: self.address_start_idx as usize,
255 end: self.address_end_idx as usize,
256 }
257 }
258
259 pub fn address_type(&self) -> &TypeId {
261 &self.address_ty
262 }
263
264 pub fn signature_range(&self) -> Range<usize> {
266 Range {
267 start: self.address_end_idx as usize,
268 end: self.signature_end_idx as usize,
269 }
270 }
271
272 pub fn signature_type(&self) -> &TypeId {
274 &self.signature_ty
275 }
276
277 pub fn map_type_id<NewTypeId, F>(self, mut f: F) -> ExtrinsicSignature<NewTypeId>
279 where
280 F: FnMut(TypeId) -> NewTypeId,
281 {
282 ExtrinsicSignature {
283 address_start_idx: self.address_start_idx,
284 address_end_idx: self.address_end_idx,
285 signature_end_idx: self.signature_end_idx,
286 address_ty: f(self.address_ty),
287 signature_ty: f(self.signature_ty),
288 }
289 }
290}
291
292#[derive(Clone, Debug)]
294pub struct ExtrinsicExtensions<'info, TypeId> {
295 transaction_extensions_version: u8,
296 transaction_extensions: Vec<NamedArg<'info, TypeId>>,
297}
298
299impl<'info, TypeId> ExtrinsicExtensions<'info, TypeId> {
300 pub fn into_owned(self) -> ExtrinsicExtensions<'static, TypeId> {
302 ExtrinsicExtensions {
303 transaction_extensions_version: self.transaction_extensions_version,
304 transaction_extensions: self
305 .transaction_extensions
306 .into_iter()
307 .map(|e| e.into_owned())
308 .collect(),
309 }
310 }
311
312 pub fn version(&self) -> u8 {
314 self.transaction_extensions_version
315 }
316
317 pub fn iter(&self) -> impl ExactSizeIterator<Item = &NamedArg<'info, TypeId>> {
319 self.transaction_extensions.iter()
320 }
321
322 pub fn range(&self) -> Range<usize> {
325 let start = self
326 .iter()
327 .map(|a| a.range.start as usize)
328 .min()
329 .unwrap_or(0);
330 let end = self
331 .iter()
332 .map(|a| a.range.end as usize)
333 .max()
334 .unwrap_or(start);
335
336 Range { start, end }
337 }
338
339 pub fn map_type_id<NewTypeId, F>(self, mut f: F) -> ExtrinsicExtensions<'info, NewTypeId>
341 where
342 F: FnMut(TypeId) -> NewTypeId,
343 {
344 ExtrinsicExtensions {
345 transaction_extensions_version: self.transaction_extensions_version,
346 transaction_extensions: self
347 .transaction_extensions
348 .into_iter()
349 .map(|s| s.map_type_id(&mut f))
350 .collect(),
351 }
352 }
353}
354
355#[derive(Clone, Debug)]
357pub struct NamedArg<'info, TypeId> {
358 name: Cow<'info, str>,
359 range: Range<u32>,
360 ty: TypeId,
361}
362
363impl<'info, TypeId> NamedArg<'info, TypeId> {
364 pub fn map_type_id<NewTypeId, F>(self, mut f: F) -> NamedArg<'info, NewTypeId>
366 where
367 F: FnMut(TypeId) -> NewTypeId,
368 {
369 NamedArg {
370 name: self.name,
371 range: self.range,
372 ty: f(self.ty),
373 }
374 }
375}
376
377impl<TypeId> NamedArg<'_, TypeId> {
378 pub fn into_owned(self) -> NamedArg<'static, TypeId> {
380 NamedArg {
381 name: Cow::Owned(self.name.into_owned()),
382 range: self.range,
383 ty: self.ty,
384 }
385 }
386
387 pub fn name(&self) -> &str {
389 &self.name
390 }
391
392 pub fn range(&self) -> Range<usize> {
394 Range {
395 start: self.range.start as usize,
396 end: self.range.end as usize,
397 }
398 }
399
400 pub fn ty(&self) -> &TypeId {
402 &self.ty
403 }
404}
405
406pub fn decode_extrinsic<'info, Info, Resolver>(
481 cursor: &mut &[u8],
482 info: &'info Info,
483 type_resolver: &Resolver,
484) -> Result<Extrinsic<'info, Info::TypeId>, ExtrinsicDecodeError>
485where
486 Info: ExtrinsicTypeInfo,
487 Info::TypeId: core::fmt::Debug + Clone,
488 Resolver: TypeResolver<TypeId = Info::TypeId>,
489{
490 let bytes = *cursor;
491 let ext_len = Compact::<u64>::decode(cursor)
492 .map_err(|_| ExtrinsicDecodeError::CannotDecodeLength)?
493 .0 as usize;
494
495 let compact_prefix_len = (bytes.len() - cursor.len()) as u8;
496
497 if cursor.len() != ext_len {
498 return Err(ExtrinsicDecodeError::WrongLength {
499 expected_len: ext_len,
500 actual_len: cursor.len(),
501 });
502 }
503
504 if cursor.is_empty() {
505 return Err(ExtrinsicDecodeError::NotEnoughBytes);
506 }
507
508 let version = cursor[0] & 0b0011_1111;
512 let version_type = cursor[0] >> 6;
513 *cursor = &cursor[1..];
514
515 if version != 4 && version != 5 {
517 return Err(ExtrinsicDecodeError::VersionNotSupported(version));
518 }
519
520 let version_ty = match version_type {
525 0b00 => ExtrinsicType::Bare,
526 0b10 if version == 4 => ExtrinsicType::Signed,
527 0b01 if version == 5 => ExtrinsicType::General,
528 _ => {
529 return Err(ExtrinsicDecodeError::ExtrinsicTypeNotSupported {
530 version,
531 extrinsic_type: version_type,
532 });
533 }
534 };
535
536 let curr_idx = |cursor: &mut &[u8]| (bytes.len() - cursor.len()) as u32;
537
538 let signature = (version_ty == ExtrinsicType::Signed)
540 .then(|| {
541 let signature_info = info
542 .extrinsic_signature_info()
543 .map_err(|e| ExtrinsicDecodeError::CannotGetInfo(e.into_owned()))?;
544
545 let address_start_idx = curr_idx(cursor);
546 decode_with_error_tracing(
547 cursor,
548 signature_info.address_id.clone(),
549 type_resolver,
550 scale_decode::visitor::IgnoreVisitor::new(),
551 )
552 .map_err(ExtrinsicDecodeError::CannotDecodeSignature)?;
553 let address_end_idx = curr_idx(cursor);
554
555 decode_with_error_tracing(
556 cursor,
557 signature_info.signature_id.clone(),
558 type_resolver,
559 scale_decode::visitor::IgnoreVisitor::new(),
560 )
561 .map_err(ExtrinsicDecodeError::CannotDecodeSignature)?;
562 let signature_end_idx = curr_idx(cursor);
563
564 Ok(ExtrinsicSignature {
565 address_start_idx,
566 address_end_idx,
567 signature_end_idx,
568 address_ty: signature_info.address_id,
569 signature_ty: signature_info.signature_id,
570 })
571 })
572 .transpose()?;
573
574 let extension_version = (version_ty == ExtrinsicType::General)
576 .then(|| u8::decode(cursor).map_err(ExtrinsicDecodeError::CannotDecodeExtensionsVersion))
577 .transpose()?;
578
579 let extensions = (version_ty == ExtrinsicType::General || version_ty == ExtrinsicType::Signed)
581 .then(|| {
582 let extension_info = info
583 .extrinsic_extension_info(extension_version)
584 .map_err(|e| ExtrinsicDecodeError::CannotGetInfo(e.into_owned()))?;
585
586 let mut transaction_extensions = vec![];
587 for ext in extension_info.extension_ids {
588 let start_idx = curr_idx(cursor);
589 decode_with_error_tracing(
590 cursor,
591 ext.id.clone(),
592 type_resolver,
593 scale_decode::visitor::IgnoreVisitor::new(),
594 )
595 .map_err(ExtrinsicDecodeError::CannotDecodeSignature)?;
596 let end_idx = curr_idx(cursor);
597
598 transaction_extensions.push(NamedArg {
599 name: ext.name,
600 range: Range {
601 start: start_idx,
602 end: end_idx,
603 },
604 ty: ext.id,
605 });
606 }
607
608 Ok::<_, ExtrinsicDecodeError>(ExtrinsicExtensions {
609 transaction_extensions_version: extension_version.unwrap_or(0),
610 transaction_extensions,
611 })
612 })
613 .transpose()?;
614
615 let pallet_index_idx = curr_idx(cursor);
617 let pallet_index: u8 =
618 Decode::decode(cursor).map_err(ExtrinsicDecodeError::CannotDecodePalletIndex)?;
619 let call_index: u8 =
620 Decode::decode(cursor).map_err(ExtrinsicDecodeError::CannotDecodeCallIndex)?;
621 let call_info = info
622 .extrinsic_call_info(pallet_index, call_index)
623 .map_err(|e| ExtrinsicDecodeError::CannotGetInfo(e.into_owned()))?;
624
625 let mut call_data = vec![];
626 for arg in call_info.args {
627 let start_idx = curr_idx(cursor);
628 decode_with_error_tracing(
629 cursor,
630 arg.id.clone(),
631 type_resolver,
632 scale_decode::visitor::IgnoreVisitor::new(),
633 )
634 .map_err(|e| ExtrinsicDecodeError::CannotDecodeCallData {
635 pallet_name: call_info.pallet_name.to_string(),
636 call_name: call_info.call_name.to_string(),
637 argument_name: arg.name.to_string(),
638 reason: e,
639 })?;
640 let end_idx = curr_idx(cursor);
641
642 call_data.push(NamedArg {
643 name: arg.name,
644 range: Range {
645 start: start_idx,
646 end: end_idx,
647 },
648 ty: arg.id,
649 })
650 }
651
652 let ext = Extrinsic {
653 compact_prefix_len,
654 version,
655 version_ty,
656 byte_len: bytes.len() as u32,
657 signature,
658 extensions,
659 pallet_name: call_info.pallet_name,
660 pallet_index,
661 pallet_index_idx,
662 call_name: call_info.call_name,
663 call_index,
664 call_data,
665 };
666
667 Ok(ext)
668}