Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: multisignature #174

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions for_tests/polkadot1003003_v15

Large diffs are not rendered by default.

7 changes: 2 additions & 5 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -274,11 +274,8 @@ impl From<RegistryInternalError> for MetaStructureErrorV14 {

impl From<RegistryError<()>> for MetaStructureErrorV14 {
fn from(registry_error_extrinsic: RegistryError<()>) -> Self {
if let RegistryError::Internal(internal) = registry_error_extrinsic {
MetaStructureErrorV14::ExtrinsicTypeNotResolved(internal)
} else {
unreachable!("RegistryError<()> can not have externally originated variants.")
}
let RegistryError::Internal(internal) = registry_error_extrinsic;
MetaStructureErrorV14::ExtrinsicTypeNotResolved(internal)
}
}

Expand Down
137 changes: 135 additions & 2 deletions src/special_indicators.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@
//! mentioned in metadata descriptors, rather than decoded as more generalized
//! type and cast into custom type later on.
use external_memory_tools::{AddressableBuffer, ExternalMemory};
use scale_info::{form::PortableForm, Field, Path, Type, TypeDef, Variant};
use scale_info::{form::PortableForm, Field, Path, Type, TypeDef, TypeDefPrimitive, Variant};

use crate::std::{borrow::ToOwned, string::String, vec::Vec};

use crate::cards::Info;
use crate::decoding_sci::pick_variant;
use crate::decoding_sci::{husk_type, pick_variant};
use crate::propagated::Checker;
use crate::traits::{AsMetadata, ResolveType, SignedExtensionMetadata};

/// [`Field`] `type_name` set indicating that the value *may* be
Expand All @@ -30,6 +31,24 @@ pub const BALANCE_ID_SET: &[&str] = &[
"T::Balance",
];

/// [`Field`] `type_name` set indicating that the value *may* be Ecdsa
/// signature.
///
/// If the value is array `[u8; 65]`, it will be considered Ecdsa signature.
pub const SIGNATURE_ECDSA_ID_SET: &[&str] = &["ecdsa::Signature"];

/// [`Field`] `type_name` set indicating that the value *may* be Ed25519
/// signature.
///
/// If the value is array `[u8; 64]`, it will be considered Ed25519 signature.
pub const SIGNATURE_ED25519_ID_SET: &[&str] = &["ed25519::Signature"];

/// [`Field`] `type_name` set indicating that the value *may* be Sr25519
/// signature.
///
/// If the value is array `[u8; 64]`, it will be considered Sr25519 signature.
pub const SIGNATURE_SR25519_ID_SET: &[&str] = &["sr25519::Signature"];

/// [`Field`] `name` set indicating the value *may* be nonce.
///
/// If the value is unsigned integer, it will be considered nonce.
Expand Down Expand Up @@ -76,6 +95,9 @@ pub const H256: &str = "H256";
/// [`Type`]-associated [`Path`] `ident` for [primitive_types::H512].
pub const H512: &str = "H512";

/// [`Type`]-associated [`Path`] `ident` for `sp_runtime::MultiSignature`.
pub const MULTI_SIGNATURE: &str = "MultiSignature";

/// [`Type`]-associated [`Path`] `ident` for [sp_arithmetic::Perbill].
pub const PERBILL: &str = "Perbill";

Expand Down Expand Up @@ -233,6 +255,81 @@ pub enum SpecialtyH256 {
BlockHash,
}

/// Indicator that the field would be considered a signature. Non-propagating.
#[derive(Clone, Copy, Debug)]
pub enum SignatureIndicator {
None,
Ecdsa,
Ed25519,
Sr25519,
}

impl SignatureIndicator {
/// `SignatureIndicator` for a [`Field`]. Uses `type_name`, checks signature
/// type to be an `u8` array of the known length.
pub fn from_field<E, M>(
field: &Field<PortableForm>,
ext_memory: &mut E,
registry: &M::TypeRegistry,
) -> Self
where
E: ExternalMemory,
M: AsMetadata<E>,
{
if let Ok(husked_field_ty) =
husk_type::<E, M>(&field.ty, registry, ext_memory, Checker::new())
{
// check here that the underlying type is really `[u8; LEN]` array
let array_u8_length = match husked_field_ty.ty.type_def {
TypeDef::Array(signature_array_ty) => {
let element_ty_id = signature_array_ty.type_param.id;
if let Ok(element_ty) = registry.resolve_ty(element_ty_id, ext_memory) {
if let TypeDef::Primitive(TypeDefPrimitive::U8) = element_ty.type_def {
signature_array_ty.len
} else {
return Self::None;
}
} else {
return Self::None;
}
}
_ => return Self::None,
};
match &field.type_name {
Some(type_name) => match type_name.as_str() {
a if SIGNATURE_ECDSA_ID_SET.contains(&a) => {
if array_u8_length == substrate_crypto_light::ecdsa::SIGNATURE_LEN as u32 {
Self::Ecdsa
} else {
Self::None
}
}
a if SIGNATURE_ED25519_ID_SET.contains(&a) => {
if array_u8_length == substrate_crypto_light::ed25519::SIGNATURE_LEN as u32
{
Self::Ed25519
} else {
Self::None
}
}
a if SIGNATURE_SR25519_ID_SET.contains(&a) => {
if array_u8_length == substrate_crypto_light::sr25519::SIGNATURE_LEN as u32
{
Self::Sr25519
} else {
Self::None
}
}
_ => Self::None,
},
None => Self::None,
}
} else {
Self::None
}
}
}

/// Nonbinding, propagating type specialty indicator.
///
/// Propagates during the decoding into compacts and single-field structs and
Expand Down Expand Up @@ -362,6 +459,7 @@ pub enum SpecialtyTypeHinted {
H160,
H256,
H512,
MultiSignature,
PalletSpecific(PalletSpecificItem),
Perbill,
Percent,
Expand Down Expand Up @@ -401,6 +499,7 @@ impl SpecialtyTypeHinted {
a if H160.contains(&a) => Self::H160,
H256 => Self::H256,
H512 => Self::H512,
MULTI_SIGNATURE => Self::MultiSignature,
PERBILL => Self::Perbill,
PERCENT => Self::Percent,
PERMILL => Self::Permill,
Expand Down Expand Up @@ -506,6 +605,40 @@ impl SpecialtyTypeChecked {
SpecialtyTypeHinted::H160 => Self::H160,
SpecialtyTypeHinted::H256 => Self::H256,
SpecialtyTypeHinted::H512 => Self::H512,
SpecialtyTypeHinted::MultiSignature => {
if let TypeDef::Variant(x) = &ty.type_def {
match pick_variant::<B, E>(&x.variants, data, ext_memory, *position) {
Ok(signature_variant) => {
if signature_variant.fields.len() == 1 {
match SignatureIndicator::from_field::<E, M>(
&signature_variant.fields[0],
ext_memory,
registry,
) {
SignatureIndicator::None => Self::None,
SignatureIndicator::Ecdsa => {
*position += ENUM_INDEX_ENCODED_LEN;
Self::SignatureEcdsa
}
SignatureIndicator::Ed25519 => {
*position += ENUM_INDEX_ENCODED_LEN;
Self::SignatureEd25519
}
SignatureIndicator::Sr25519 => {
*position += ENUM_INDEX_ENCODED_LEN;
Self::SignatureSr25519
}
}
} else {
Self::None
}
}
Err(_) => Self::None,
}
} else {
Self::None
}
}
SpecialtyTypeHinted::PalletSpecific(item) => {
if let TypeDef::Variant(x) = &ty.type_def {
// found specific variant corresponding to pallet,
Expand Down
5 changes: 1 addition & 4 deletions src/special_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -393,10 +393,7 @@ impl Collectable for Vec<u8> {
_ => return None,
}
}
let inner_element_info = match inner_element_info {
Some(a) => a,
None => Vec::new(),
};
let inner_element_info = inner_element_info.unwrap_or_default();
Some(Sequence::VecU8 {
sequence: out,
inner_element_info,
Expand Down
33 changes: 33 additions & 0 deletions src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1232,6 +1232,39 @@ fn unchecked_extrinsic_1() {
}
}

#[cfg(feature = "std")]
#[test]
fn unchecked_extrinsic_2() {
let data = hex::decode("3502840094af1b41d3346c8b50f9f2d229422ddbbc53e7a59df3b49abd049ff059122d6e01c240497d62b63d2e6144bd59d43f385f5d377d03c21d0643513054491cf90c67f71c5f32ae4ac37d16f55eb100dae006b774f57283d21bb7afb84c8bbfb5de873500280000000a040036988c476fff14e9885c49f938193f2fc4b54ba9e4cf673ffed3dc4e413aeb3a00").unwrap();
let metadata = metadata_v15("for_tests/polkadot1003003_v15");
let parsed = decode_as_unchecked_extrinsic(&data.as_ref(), &mut (), &metadata).unwrap();
if let UncheckedExtrinsic::Signed {
address: _,
signature,
extra: _,
call: _,
} = parsed
{
let expected_signature = ExtendedData {
data: ParsedData::SignatureSr25519(SignatureSr25519(hex::decode("c240497d62b63d2e6144bd59d43f385f5d377d03c21d0643513054491cf90c67f71c5f32ae4ac37d16f55eb100dae006b774f57283d21bb7afb84c8bbfb5de87").unwrap().try_into().unwrap())),
info: vec![
Info {
docs: "".to_string(),
path: Path::from_segments(vec![
"sp_runtime",
"MultiSignature",
])
.unwrap()
.into_portable(&mut Registry::new()),
}
]
};
assert_eq!(expected_signature, signature);
} else {
panic!("Not a signed extrinsic: {parsed:?}")
}
}

#[test]
fn tr_7() {
let data = hex::decode("a00a0304a84b841c4d9d1a179be03bb31131c14ebf6ce22233158139ae28a3dfaac5fe1560a5e9e05cd5038d248ed73e0d9808000003000000fc41b9bd8ef8fe53d58c7ea67c794c7ec9a73daf05e6d54b14ff6342c99ba64cfc41b9bd8ef8fe53d58c7ea67c794c7ec9a73daf05e6d54b14ff6342c99ba64c").unwrap();
Expand Down
1 change: 1 addition & 0 deletions src/unchecked_extrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ where

/// Decoded unchecked extrinsic.
#[derive(Debug, Eq, PartialEq)]
#[allow(clippy::large_enum_variant)]
pub enum UncheckedExtrinsic {
Signed {
address: ExtendedData,
Expand Down
Loading