mod decode_storage;
mod decode_value;
mod extrinsic_bytes;
use crate::metadata::Metadata;
use crate::value::Value;
use crate::TypeId;
use codec::{Compact, Decode};
use extrinsic_bytes::{AllExtrinsicBytes, ExtrinsicBytesError};
use serde::Serialize;
use sp_runtime::{AccountId32, MultiAddress, MultiSignature};
use std::borrow::Cow;
pub use decode_value::DecodeValueError;
pub use decode_storage::{
StorageDecodeError, StorageDecoder, StorageEntry, StorageEntryType, StorageHasher, StorageMapKey,
};
#[derive(Clone, Debug, thiserror::Error)]
pub enum DecodeError {
#[error("Failed to parse the provided vector of extrinsics: {0}")]
UnexpectedExtrinsicsShape(#[from] ExtrinsicBytesError),
#[error("Failed to decode: {0}")]
CodecError(#[from] codec::Error),
#[error("Failed to decode type: {0}")]
DecodeValueError(#[from] DecodeValueError),
#[error("Failed to decode: expected more data")]
EarlyEof(&'static str),
#[error("Failed to decode extrinsics: {0} bytes of the input were not consumed")]
ExcessBytes(usize),
#[error("Failed to decode unsupported extrinsic version '{0}'")]
CannotDecodeExtrinsicVersion(u8),
#[error("Cannot find call corresponding to extrinsic with pallet index {0} and call index {1}")]
CannotFindCall(u8, u8),
#[error("Failed to decode extrinsic: cannot find type ID {0}")]
CannotFindType(u32),
}
pub fn decode_value_by_id<'a, Id: Into<TypeId>>(
metadata: &'a Metadata,
ty: Id,
data: &mut &[u8],
) -> Result<Value<TypeId>, DecodeValueError> {
decode_value::decode_value_by_id(data, ty, metadata.types())
}
pub fn decode_storage(metadata: &Metadata) -> StorageDecoder {
decode_storage::StorageDecoder::generate_from_metadata(metadata)
}
pub fn decode_extrinsics<'a>(
metadata: &'a Metadata,
data: &mut &[u8],
) -> Result<Vec<Extrinsic<'a>>, (Vec<Extrinsic<'a>>, DecodeError)> {
let extrinsic_bytes = AllExtrinsicBytes::new(*data).map_err(|e| (Vec::new(), e.into()))?;
log::trace!("Decoding {} Total Extrinsics.", extrinsic_bytes.len());
let mut out = Vec::with_capacity(extrinsic_bytes.len());
let mut extrinsics_iter = extrinsic_bytes.iter();
for res in &mut extrinsics_iter {
let single_extrinsic = match res {
Ok(bytes) => bytes,
Err(e) => return Err((out, e.into())),
};
log::trace!("Extrinsic:{:?}", single_extrinsic.bytes());
let bytes = &mut single_extrinsic.bytes();
let ext = match decode_unwrapped_extrinsic(metadata, bytes) {
Ok(ext) => ext,
Err(e) => return Err((out, e)),
};
if !bytes.is_empty() {
return Err((out, DecodeError::ExcessBytes(bytes.len())));
}
out.push(ext);
}
*data = extrinsics_iter.remaining_bytes();
Ok(out)
}
pub fn decode_extrinsic<'a>(metadata: &'a Metadata, data: &mut &[u8]) -> Result<Extrinsic<'a>, DecodeError> {
let _len = <Compact<u32>>::decode(data)?;
decode_unwrapped_extrinsic(metadata, data)
}
pub fn decode_unwrapped_extrinsic<'a>(metadata: &'a Metadata, data: &mut &[u8]) -> Result<Extrinsic<'a>, DecodeError> {
if data.is_empty() {
return Err(DecodeError::EarlyEof("unwrapped extrinsic byte length should be > 0"));
}
let is_signed = data[0] & 0b1000_0000 != 0;
let version = data[0] & 0b0111_1111;
*data = &data[1..];
if version != 4 {
return Err(DecodeError::CannotDecodeExtrinsicVersion(version));
}
let signature = match is_signed {
true => Some(decode_signature(metadata, data)?),
false => None,
};
let call_data = decode_call_data(metadata, data)?;
Ok(Extrinsic { call_data, signature })
}
pub fn decode_call_data<'a>(metadata: &'a Metadata, data: &mut &[u8]) -> Result<CallData<'a>, DecodeError> {
if data.len() < 2 {
return Err(DecodeError::EarlyEof("expected at least 2 more bytes for the pallet/call index"));
}
let pallet_index = u8::decode(data)?;
let call_index = u8::decode(data)?;
log::trace!("pallet index: {}, call index: {}", pallet_index, call_index);
let (pallet_name, variant) = match metadata.call_variant_by_enum_index(pallet_index, call_index) {
Some(call) => call,
None => return Err(DecodeError::CannotFindCall(pallet_index, call_index)),
};
let arguments = variant
.fields()
.iter()
.map(|field| {
let id = field.ty().id();
decode_value_by_id(metadata, TypeId::from_u32(id), data).map_err(DecodeError::DecodeValueError)
})
.collect::<Result<Vec<_>, _>>()?;
Ok(CallData { pallet_name: Cow::Borrowed(pallet_name), ty: Cow::Borrowed(variant), arguments })
}
pub fn decode_signer_payload<'a>(metadata: &'a Metadata, data: &mut &[u8]) -> Result<SignerPayload<'a>, DecodeError> {
let call_data = decode_call_data(metadata, data)?;
let signed_extensions = decode_signed_extensions(metadata, data)?;
let additional_signed = decode_additional_signed(metadata, data)?;
let extensions = signed_extensions
.into_iter()
.zip(additional_signed)
.map(|((name, extension), (_, additional))| (name, SignedExtensionWithAdditional { additional, extension }))
.collect();
Ok(SignerPayload { call_data, extensions })
}
pub fn decode_signature<'a>(metadata: &'a Metadata, data: &mut &[u8]) -> Result<ExtrinsicSignature<'a>, DecodeError> {
let address = <MultiAddress<AccountId32, u32>>::decode(data)?;
let signature = MultiSignature::decode(data)?;
let extensions = decode_signed_extensions(metadata, data)?;
Ok(ExtrinsicSignature { address, signature, extensions })
}
#[allow(clippy::type_complexity)]
pub fn decode_signed_extensions<'a>(
metadata: &'a Metadata,
data: &mut &[u8],
) -> Result<Vec<(Cow<'a, str>, Value<TypeId>)>, DecodeError> {
metadata
.extrinsic()
.signed_extensions()
.iter()
.map(|ext| {
let val = decode_value_by_id(metadata, &ext.ty, data)?;
let name = Cow::Borrowed(&*ext.identifier);
Ok((name, val))
})
.collect()
}
#[allow(clippy::type_complexity)]
pub fn decode_additional_signed<'a>(
metadata: &'a Metadata,
data: &mut &[u8],
) -> Result<Vec<(Cow<'a, str>, Value<TypeId>)>, DecodeError> {
metadata
.extrinsic()
.signed_extensions()
.iter()
.map(|ext| {
let val = decode_value_by_id(metadata, &ext.additional_signed, data)?;
let name = Cow::Borrowed(&*ext.identifier);
Ok((name, val))
})
.collect()
}
#[derive(Serialize, Debug, Clone, PartialEq)]
pub struct CallData<'a> {
#[serde(borrow)]
pub pallet_name: Cow<'a, str>,
pub ty: Cow<'a, scale_info::Variant<scale_info::form::PortableForm>>,
pub arguments: Vec<Value<TypeId>>,
}
impl<'a> CallData<'a> {
pub fn into_owned(self) -> CallData<'static> {
CallData {
pallet_name: Cow::Owned(self.pallet_name.into_owned()),
ty: Cow::Owned(self.ty.into_owned()),
arguments: self.arguments,
}
}
}
#[derive(Serialize, Debug, Clone, PartialEq)]
pub struct Extrinsic<'a> {
#[serde(borrow)]
pub call_data: CallData<'a>,
#[serde(borrow)]
pub signature: Option<ExtrinsicSignature<'a>>,
}
impl<'a> Extrinsic<'a> {
pub fn into_owned(self) -> Extrinsic<'static> {
Extrinsic { call_data: self.call_data.into_owned(), signature: self.signature.map(|s| s.into_owned()) }
}
}
#[derive(Serialize, Debug, Clone, PartialEq)]
pub struct ExtrinsicSignature<'a> {
#[serde(with = "desub_common::RemoteAddress")]
pub address: MultiAddress<AccountId32, u32>,
pub signature: MultiSignature,
#[serde(borrow)]
pub extensions: Vec<(Cow<'a, str>, Value<TypeId>)>,
}
impl<'a> ExtrinsicSignature<'a> {
pub fn into_owned(self) -> ExtrinsicSignature<'static> {
ExtrinsicSignature {
address: self.address,
signature: self.signature,
extensions: self.extensions.into_iter().map(|(k, v)| (Cow::Owned(k.into_owned()), v)).collect(),
}
}
}
#[derive(Serialize, Debug, Clone, PartialEq)]
pub struct SignerPayload<'a> {
#[serde(borrow)]
pub call_data: CallData<'a>,
pub extensions: Vec<(Cow<'a, str>, SignedExtensionWithAdditional)>,
}
impl<'a> SignerPayload<'a> {
pub fn into_owned(self) -> SignerPayload<'static> {
SignerPayload {
call_data: self.call_data.into_owned(),
extensions: self.extensions.into_iter().map(|(k, v)| (Cow::Owned(k.into_owned()), v)).collect(),
}
}
}
#[derive(Serialize, Debug, Clone, PartialEq)]
pub struct SignedExtensionWithAdditional {
pub extension: Value<TypeId>,
pub additional: Value<TypeId>,
}