1use crate::methods::extrinsic_type_info::ExtrinsicInfoError;
17use crate::methods::extrinsic_type_info::ExtrinsicTypeInfo;
18use crate::utils::{decode_with_error_tracing, DecodeErrorTrace};
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("The extrinsic type 0b{extrinsic_type:02b} is not supported (given extrinsic version {version}).")]
46 ExtrinsicTypeNotSupported { version: u8, extrinsic_type: u8 },
47 #[error("Cannot get extrinsic info:\n\n{0}")]
48 CannotGetInfo(ExtrinsicInfoError<'static>),
49 #[error("Cannot decode signature:\n\n{0}")]
50 CannotDecodeSignature(DecodeErrorTrace),
51 #[error("Cannot decode pallet index byte:\n\n{0}")]
52 CannotDecodePalletIndex(parity_scale_codec::Error),
53 #[error("Cannot decode call index byte:\n\n{0}")]
54 CannotDecodeCallIndex(parity_scale_codec::Error),
55 #[error("Cannot decode transaction extensions version byte:\n\n{0}")]
56 CannotDecodeExtensionsVersion(parity_scale_codec::Error),
57 #[error("Cannot decode call data for argument {argument_name} in {pallet_name}.{call_name}:\n\n{reason}")]
58 CannotDecodeCallData {
59 pallet_name: String,
60 call_name: String,
61 argument_name: String,
62 reason: DecodeErrorTrace,
63 },
64}
65
66pub type ExtrinsicOwned<TypeId> = Extrinsic<'static, TypeId>;
70
71#[derive(Clone, Debug)]
73pub struct Extrinsic<'info, TypeId> {
74 compact_prefix_len: u8,
75 version: u8,
76 version_ty: ExtrinsicType,
77 byte_len: u32,
78 signature: Option<ExtrinsicSignature<TypeId>>,
79 extensions: Option<ExtrinsicExtensions<'info, TypeId>>,
80 pallet_name: Cow<'info, str>,
81 pallet_index: u8,
82 pallet_index_idx: u32,
83 call_name: Cow<'info, str>,
84 call_index: u8,
85 call_data: Vec<NamedArg<'info, TypeId>>,
86}
87
88impl<'info, TypeId> Extrinsic<'info, TypeId> {
89 pub fn into_owned(self) -> ExtrinsicOwned<TypeId> {
92 Extrinsic {
93 compact_prefix_len: self.compact_prefix_len,
94 version: self.version,
95 version_ty: self.version_ty,
96 byte_len: self.byte_len,
97 signature: self.signature,
98 extensions: self.extensions.map(|e| e.into_owned()),
99 pallet_name: Cow::Owned(self.pallet_name.into_owned()),
100 pallet_index: self.pallet_index,
101 pallet_index_idx: self.pallet_index_idx,
102 call_name: Cow::Owned(self.call_name.into_owned()),
103 call_index: self.call_index,
104 call_data: self.call_data.into_iter().map(|e| e.into_owned()).collect(),
105 }
106 }
107
108 pub fn version(&self) -> u8 {
110 self.version
111 }
112
113 pub fn ty(&self) -> ExtrinsicType {
115 self.version_ty
116 }
117
118 #[allow(clippy::len_without_is_empty)]
120 pub fn len(&self) -> usize {
121 self.byte_len as usize
122 }
123
124 pub fn pallet_name(&self) -> &str {
126 &self.pallet_name
127 }
128
129 pub fn pallet_index(&self) -> u8 {
131 self.pallet_index
132 }
133
134 pub fn call_name(&self) -> &str {
136 &self.call_name
137 }
138
139 pub fn call_index(&self) -> u8 {
141 self.call_index
142 }
143
144 pub fn is_signed(&self) -> bool {
146 self.signature.is_some()
147 }
148
149 pub fn signature_payload(&self) -> Option<&ExtrinsicSignature<TypeId>> {
152 self.signature.as_ref()
153 }
154
155 pub fn transaction_extension_payload(&self) -> Option<&ExtrinsicExtensions<'info, TypeId>> {
158 self.extensions.as_ref()
159 }
160
161 pub fn call_data(&self) -> impl ExactSizeIterator<Item = &NamedArg<'info, TypeId>> {
163 self.call_data.iter()
164 }
165
166 pub fn call_data_range(&self) -> Range<usize> {
169 let start = self.pallet_index_idx as usize;
170 let end = self
171 .call_data()
172 .map(|a| a.range.end as usize)
173 .max()
174 .unwrap_or(start);
175
176 Range { start, end }
177 }
178
179 pub fn call_data_args_range(&self) -> Range<usize> {
182 let start = (self.pallet_index_idx + 2) as usize;
183 let end = self
184 .call_data()
185 .map(|a| a.range.end as usize)
186 .max()
187 .unwrap_or(start);
188
189 Range { start, end }
190 }
191
192 pub fn map_type_id<NewTypeId, F>(self, mut f: F) -> Extrinsic<'info, NewTypeId>
194 where
195 F: FnMut(TypeId) -> NewTypeId,
196 {
197 Extrinsic {
198 compact_prefix_len: self.compact_prefix_len,
199 version: self.version,
200 version_ty: self.version_ty,
201 byte_len: self.byte_len,
202 signature: self.signature.map(|s| s.map_type_id(&mut f)),
203 extensions: self.extensions.map(|e| e.map_type_id(&mut f)),
204 pallet_name: self.pallet_name,
205 pallet_index: self.pallet_index,
206 pallet_index_idx: self.pallet_index_idx,
207 call_name: self.call_name,
208 call_index: self.call_index,
209 call_data: self
210 .call_data
211 .into_iter()
212 .map(|s| s.map_type_id(&mut f))
213 .collect(),
214 }
215 }
216}
217
218#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
220pub enum ExtrinsicType {
221 Bare,
223 General,
225 Signed,
227}
228
229#[derive(Clone, Debug)]
231pub struct ExtrinsicSignature<TypeId> {
232 address_start_idx: u32,
235 address_end_idx: u32,
236 signature_end_idx: u32,
237 address_ty: TypeId,
243 signature_ty: TypeId,
244}
245
246impl<TypeId> ExtrinsicSignature<TypeId> {
247 pub fn address_range(&self) -> Range<usize> {
249 Range {
250 start: self.address_start_idx as usize,
251 end: self.address_end_idx as usize,
252 }
253 }
254
255 pub fn address_type(&self) -> &TypeId {
257 &self.address_ty
258 }
259
260 pub fn signature_range(&self) -> Range<usize> {
262 Range {
263 start: self.address_end_idx as usize,
264 end: self.signature_end_idx as usize,
265 }
266 }
267
268 pub fn signature_type(&self) -> &TypeId {
270 &self.signature_ty
271 }
272
273 pub fn map_type_id<NewTypeId, F>(self, mut f: F) -> ExtrinsicSignature<NewTypeId>
275 where
276 F: FnMut(TypeId) -> NewTypeId,
277 {
278 ExtrinsicSignature {
279 address_start_idx: self.address_start_idx,
280 address_end_idx: self.address_end_idx,
281 signature_end_idx: self.signature_end_idx,
282 address_ty: f(self.address_ty),
283 signature_ty: f(self.signature_ty),
284 }
285 }
286}
287
288#[derive(Clone, Debug)]
290pub struct ExtrinsicExtensions<'info, TypeId> {
291 transaction_extensions_version: u8,
292 transaction_extensions: Vec<NamedArg<'info, TypeId>>,
293}
294
295impl<'info, TypeId> ExtrinsicExtensions<'info, TypeId> {
296 pub fn into_owned(self) -> ExtrinsicExtensions<'static, TypeId> {
298 ExtrinsicExtensions {
299 transaction_extensions_version: self.transaction_extensions_version,
300 transaction_extensions: self
301 .transaction_extensions
302 .into_iter()
303 .map(|e| e.into_owned())
304 .collect(),
305 }
306 }
307
308 pub fn version(&self) -> u8 {
310 self.transaction_extensions_version
311 }
312
313 pub fn iter(&self) -> impl ExactSizeIterator<Item = &NamedArg<'info, TypeId>> {
315 self.transaction_extensions.iter()
316 }
317
318 pub fn range(&self) -> Range<usize> {
321 let start = self
322 .iter()
323 .map(|a| a.range.start as usize)
324 .min()
325 .unwrap_or(0);
326 let end = self
327 .iter()
328 .map(|a| a.range.end as usize)
329 .max()
330 .unwrap_or(start);
331
332 Range { start, end }
333 }
334
335 pub fn map_type_id<NewTypeId, F>(self, mut f: F) -> ExtrinsicExtensions<'info, NewTypeId>
337 where
338 F: FnMut(TypeId) -> NewTypeId,
339 {
340 ExtrinsicExtensions {
341 transaction_extensions_version: self.transaction_extensions_version,
342 transaction_extensions: self
343 .transaction_extensions
344 .into_iter()
345 .map(|s| s.map_type_id(&mut f))
346 .collect(),
347 }
348 }
349}
350
351#[derive(Clone, Debug)]
353pub struct NamedArg<'info, TypeId> {
354 name: Cow<'info, str>,
355 range: Range<u32>,
356 ty: TypeId,
357}
358
359impl<'info, TypeId> NamedArg<'info, TypeId> {
360 pub fn map_type_id<NewTypeId, F>(self, mut f: F) -> NamedArg<'info, NewTypeId>
362 where
363 F: FnMut(TypeId) -> NewTypeId,
364 {
365 NamedArg {
366 name: self.name,
367 range: self.range,
368 ty: f(self.ty),
369 }
370 }
371}
372
373impl<TypeId> NamedArg<'_, TypeId> {
374 pub fn into_owned(self) -> NamedArg<'static, TypeId> {
376 NamedArg {
377 name: Cow::Owned(self.name.into_owned()),
378 range: self.range,
379 ty: self.ty,
380 }
381 }
382
383 pub fn name(&self) -> &str {
385 &self.name
386 }
387
388 pub fn range(&self) -> Range<usize> {
390 Range {
391 start: self.range.start as usize,
392 end: self.range.end as usize,
393 }
394 }
395
396 pub fn ty(&self) -> &TypeId {
398 &self.ty
399 }
400}
401
402pub fn decode_extrinsic<'info, Info, Resolver>(
477 cursor: &mut &[u8],
478 info: &'info Info,
479 type_resolver: &Resolver,
480) -> Result<Extrinsic<'info, Info::TypeId>, ExtrinsicDecodeError>
481where
482 Info: ExtrinsicTypeInfo,
483 Info::TypeId: core::fmt::Debug + Clone,
484 Resolver: TypeResolver<TypeId = Info::TypeId>,
485{
486 let bytes = *cursor;
487 let ext_len = Compact::<u64>::decode(cursor)
488 .map_err(|_| ExtrinsicDecodeError::CannotDecodeLength)?
489 .0 as usize;
490
491 let compact_prefix_len = (bytes.len() - cursor.len()) as u8;
492
493 if cursor.len() != ext_len {
494 return Err(ExtrinsicDecodeError::WrongLength {
495 expected_len: ext_len,
496 actual_len: cursor.len(),
497 });
498 }
499
500 if cursor.is_empty() {
501 return Err(ExtrinsicDecodeError::NotEnoughBytes);
502 }
503
504 let version = cursor[0] & 0b0011_1111;
508 let version_type = cursor[0] >> 6;
509 *cursor = &cursor[1..];
510
511 if version != 4 && version != 5 {
513 return Err(ExtrinsicDecodeError::VersionNotSupported(version));
514 }
515
516 let version_ty = match version_type {
521 0b00 => ExtrinsicType::Bare,
522 0b10 if version == 4 => ExtrinsicType::Signed,
523 0b01 if version == 5 => ExtrinsicType::General,
524 _ => {
525 return Err(ExtrinsicDecodeError::ExtrinsicTypeNotSupported {
526 version,
527 extrinsic_type: version_type,
528 })
529 }
530 };
531
532 let curr_idx = |cursor: &mut &[u8]| (bytes.len() - cursor.len()) as u32;
533
534 let signature = (version_ty == ExtrinsicType::Signed)
536 .then(|| {
537 let signature_info = info
538 .get_signature_info()
539 .map_err(|e| ExtrinsicDecodeError::CannotGetInfo(e.into_owned()))?;
540
541 let address_start_idx = curr_idx(cursor);
542 decode_with_error_tracing(
543 cursor,
544 signature_info.address_id.clone(),
545 type_resolver,
546 scale_decode::visitor::IgnoreVisitor::new(),
547 )
548 .map_err(ExtrinsicDecodeError::CannotDecodeSignature)?;
549 let address_end_idx = curr_idx(cursor);
550
551 decode_with_error_tracing(
552 cursor,
553 signature_info.signature_id.clone(),
554 type_resolver,
555 scale_decode::visitor::IgnoreVisitor::new(),
556 )
557 .map_err(ExtrinsicDecodeError::CannotDecodeSignature)?;
558 let signature_end_idx = curr_idx(cursor);
559
560 Ok(ExtrinsicSignature {
561 address_start_idx,
562 address_end_idx,
563 signature_end_idx,
564 address_ty: signature_info.address_id,
565 signature_ty: signature_info.signature_id,
566 })
567 })
568 .transpose()?;
569
570 let extension_version = (version_ty == ExtrinsicType::General)
572 .then(|| u8::decode(cursor).map_err(ExtrinsicDecodeError::CannotDecodeExtensionsVersion))
573 .transpose()?;
574
575 let extensions = (version_ty == ExtrinsicType::General || version_ty == ExtrinsicType::Signed)
577 .then(|| {
578 let extension_info = info
579 .get_extension_info(extension_version)
580 .map_err(|e| ExtrinsicDecodeError::CannotGetInfo(e.into_owned()))?;
581
582 let mut transaction_extensions = vec![];
583 for ext in extension_info.extension_ids {
584 let start_idx = curr_idx(cursor);
585 decode_with_error_tracing(
586 cursor,
587 ext.id.clone(),
588 type_resolver,
589 scale_decode::visitor::IgnoreVisitor::new(),
590 )
591 .map_err(ExtrinsicDecodeError::CannotDecodeSignature)?;
592 let end_idx = curr_idx(cursor);
593
594 transaction_extensions.push(NamedArg {
595 name: ext.name,
596 range: Range {
597 start: start_idx,
598 end: end_idx,
599 },
600 ty: ext.id,
601 });
602 }
603
604 Ok::<_, ExtrinsicDecodeError>(ExtrinsicExtensions {
605 transaction_extensions_version: extension_version.unwrap_or(0),
606 transaction_extensions,
607 })
608 })
609 .transpose()?;
610
611 let pallet_index_idx = curr_idx(cursor);
613 let pallet_index: u8 =
614 Decode::decode(cursor).map_err(ExtrinsicDecodeError::CannotDecodePalletIndex)?;
615 let call_index: u8 =
616 Decode::decode(cursor).map_err(ExtrinsicDecodeError::CannotDecodeCallIndex)?;
617 let call_info = info
618 .get_call_info(pallet_index, call_index)
619 .map_err(|e| ExtrinsicDecodeError::CannotGetInfo(e.into_owned()))?;
620
621 let mut call_data = vec![];
622 for arg in call_info.args {
623 let start_idx = curr_idx(cursor);
624 decode_with_error_tracing(
625 cursor,
626 arg.id.clone(),
627 type_resolver,
628 scale_decode::visitor::IgnoreVisitor::new(),
629 )
630 .map_err(|e| ExtrinsicDecodeError::CannotDecodeCallData {
631 pallet_name: call_info.pallet_name.to_string(),
632 call_name: call_info.call_name.to_string(),
633 argument_name: arg.name.to_string(),
634 reason: e,
635 })?;
636 let end_idx = curr_idx(cursor);
637
638 call_data.push(NamedArg {
639 name: arg.name,
640 range: Range {
641 start: start_idx,
642 end: end_idx,
643 },
644 ty: arg.id,
645 })
646 }
647
648 let ext = Extrinsic {
649 compact_prefix_len,
650 version,
651 version_ty,
652 byte_len: bytes.len() as u32,
653 signature,
654 extensions,
655 pallet_name: call_info.pallet_name,
656 pallet_index,
657 pallet_index_idx,
658 call_name: call_info.call_name,
659 call_index,
660 call_data,
661 };
662
663 Ok(ext)
664}