diff --git a/crypto/src/hash.rs b/crypto/src/hash.rs index 63a6b7a7671..a32e9d9f4b4 100644 --- a/crypto/src/hash.rs +++ b/crypto/src/hash.rs @@ -183,12 +183,15 @@ impl HashOf { } } -impl IntoSchema for HashOf { +impl IntoSchema for HashOf { + fn type_name() -> String { + format!("{}::HashOf<{}>", module_path!(), T::type_name()) + } fn schema(map: &mut MetaMap) { Hash::schema(map); map.entry(Self::type_name()).or_insert_with(|| { - Metadata::TupleStruct(UnnamedFieldsMeta { + Metadata::Tuple(UnnamedFieldsMeta { types: vec![Hash::type_name()], }) }); diff --git a/crypto/src/lib.rs b/crypto/src/lib.rs index e4ae942e765..4b1d0403ec2 100644 --- a/crypto/src/lib.rs +++ b/crypto/src/lib.rs @@ -110,9 +110,9 @@ impl TryFrom for UrsaKeyGenOption { match key_gen_option { KeyGenOption::UseSeed(seed) => Ok(UrsaKeyGenOption::UseSeed(seed)), KeyGenOption::FromPrivateKey(key) => { - if key.digest_function() == Algorithm::Ed25519 - || key.digest_function() == Algorithm::Secp256k1 - { + let algorithm = key.digest_function(); + + if algorithm == Algorithm::Ed25519 || algorithm == Algorithm::Secp256k1 { return Ok(Self::FromSecretKey(UrsaPrivateKey(key.payload))); } @@ -155,7 +155,7 @@ impl KeyGenConfiguration { } /// Pair of Public and Private keys. -#[derive(Debug, Clone, PartialEq, Eq, Getters, Deserialize, Serialize)] +#[derive(Debug, Clone, PartialEq, Eq, Getters, Serialize)] #[getset(get = "pub")] pub struct KeyPair { /// Public Key. @@ -205,6 +205,11 @@ impl From for Error { impl std::error::Error for Error {} impl KeyPair { + /// Digest function + pub fn digest_function(&self) -> Algorithm { + self.private_key.digest_function() + } + /// Construct `KeyPair` pub fn new(public_key: PublicKey, private_key: PrivateKey) -> Self { Self { @@ -228,11 +233,13 @@ impl KeyPair { /// Fails if decoding fails #[cfg(feature = "std")] pub fn generate_with_configuration(configuration: KeyGenConfiguration) -> Result { + let digest_function = configuration.algorithm.to_string(); + let key_gen_option: Option = configuration .key_gen_option .map(TryInto::try_into) .transpose()?; - let (public_key, private_key) = match configuration.algorithm { + let (mut public_key, mut private_key) = match configuration.algorithm { Algorithm::Ed25519 => Ed25519Sha512.keypair(key_gen_option), Algorithm::Secp256k1 => EcdsaSecp256k1Sha256::new().keypair(key_gen_option), Algorithm::BlsNormal => BlsNormal::new().keypair(key_gen_option), @@ -241,17 +248,33 @@ impl KeyPair { Ok(Self { public_key: PublicKey { - digest_function: configuration.algorithm.to_string(), - payload: public_key.as_ref().to_vec(), + digest_function: digest_function.clone(), + payload: core::mem::take(&mut public_key.0), }, private_key: PrivateKey { - digest_function: configuration.algorithm.to_string(), - payload: private_key.as_ref().to_vec(), + digest_function, + payload: core::mem::take(&mut private_key.0), }, }) } } +impl<'de> Deserialize<'de> for KeyPair { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + #[derive(Deserialize)] + struct KeyPair { + public_key: PublicKey, + private_key: PrivateKey, + } + + let key_pair = KeyPair::deserialize(deserializer)?; + Ok(Self::new(key_pair.public_key, key_pair.private_key)) + } +} + impl From for (PublicKey, PrivateKey) { fn from(key_pair: KeyPair) -> Self { (key_pair.public_key, key_pair.private_key) @@ -316,7 +339,7 @@ impl fmt::Debug for PublicKey { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("PublicKey") .field("digest_function", &self.digest_function()) - .field("payload", &hex::encode_upper(self.payload.as_slice())) + .field("payload", &hex::encode_upper(self.payload().as_slice())) .finish() } } @@ -485,14 +508,14 @@ impl fmt::Debug for PrivateKey { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("PrivateKey") .field("digest_function", &self.digest_function()) - .field("payload", &format!("{:X?}", self.payload)) + .field("payload", &format!("{:X?}", self.payload())) .finish() } } impl fmt::Display for PrivateKey { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", hex::encode(&self.payload)) + write!(f, "{}", hex::encode(self.payload())) } } diff --git a/crypto/src/merkle.rs b/crypto/src/merkle.rs index c490131ea80..2cc16bdc5ed 100644 --- a/crypto/src/merkle.rs +++ b/crypto/src/merkle.rs @@ -1,7 +1,7 @@ //! Merkle tree implementation. #[cfg(not(feature = "std"))] -use alloc::{boxed::Box, vec, vec::Vec}; +use alloc::{boxed::Box, format, string::String, vec, vec::Vec}; #[cfg(feature = "std")] use std::collections::VecDeque; @@ -18,10 +18,16 @@ pub struct MerkleTree { } impl IntoSchema for MerkleTree { + fn type_name() -> String { + format!("{}::MerkleTree<{}>", module_path!(), T::type_name()) + } fn schema(map: &mut MetaMap) { map.entry(Self::type_name()).or_insert_with(|| { // BFS ordered list of leaf nodes - Metadata::Vec(HashOf::::type_name()) + Metadata::Vec(VecMeta { + ty: HashOf::::type_name(), + sorted: true, + }) }); if !map.contains_key(&HashOf::::type_name()) { HashOf::::schema(map); diff --git a/crypto/src/signature.rs b/crypto/src/signature.rs index 011622f32b1..d699dc2eeaa 100644 --- a/crypto/src/signature.rs +++ b/crypto/src/signature.rs @@ -54,7 +54,6 @@ pub struct Signature { /// that corresponds with the public key's digest function. public_key: PublicKey, /// Actual signature payload is placed here. - #[getset(skip)] payload: Payload, } @@ -64,13 +63,9 @@ impl Signature { /// # Errors /// Fails if signing fails #[cfg(feature = "std")] - fn new( - KeyPair { - public_key, - private_key, - }: KeyPair, - payload: &[u8], - ) -> Result { + fn new(key_pair: KeyPair, payload: &[u8]) -> Result { + let (public_key, private_key) = key_pair.into(); + let algorithm: Algorithm = public_key.digest_function(); let private_key = UrsaPrivateKey(private_key.payload); @@ -91,7 +86,7 @@ impl Signature { /// since it is not possible to validate the correctness of the conversion. /// Prefer creating new signatures with [`SignatureOf::new`] whenever possible #[inline] - #[allow(dead_code)] + #[cfg_attr(not(feature = "std"), allow(dead_code))] fn typed(self) -> SignatureOf { SignatureOf(self, PhantomData) } @@ -103,15 +98,15 @@ impl Signature { #[cfg(feature = "std")] pub fn verify(&self, payload: &[u8]) -> Result<(), Error> { let algorithm: Algorithm = self.public_key.digest_function(); - let public_key = UrsaPublicKey(self.public_key.payload.clone()); + let public_key = UrsaPublicKey(self.public_key.payload().clone()); match algorithm { - Algorithm::Ed25519 => Ed25519Sha512::new().verify(payload, &self.payload, &public_key), + Algorithm::Ed25519 => Ed25519Sha512::new().verify(payload, self.payload(), &public_key), Algorithm::Secp256k1 => { - EcdsaSecp256k1Sha256::new().verify(payload, &self.payload, &public_key) + EcdsaSecp256k1Sha256::new().verify(payload, self.payload(), &public_key) } - Algorithm::BlsSmall => BlsSmall::new().verify(payload, &self.payload, &public_key), - Algorithm::BlsNormal => BlsNormal::new().verify(payload, &self.payload, &public_key), + Algorithm::BlsSmall => BlsSmall::new().verify(payload, self.payload(), &public_key), + Algorithm::BlsNormal => BlsNormal::new().verify(payload, self.payload(), &public_key), }?; Ok(()) @@ -122,7 +117,7 @@ impl fmt::Debug for Signature { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct(core::any::type_name::()) .field("public_key", &self.public_key) - .field("signature", &hex::encode_upper(self.payload.as_slice())) + .field("signature", &hex::encode_upper(self.payload().as_slice())) .finish() } } @@ -191,12 +186,15 @@ impl Ord for SignatureOf { } } -impl IntoSchema for SignatureOf { +impl IntoSchema for SignatureOf { + fn type_name() -> String { + format!("{}::SignatureOf<{}>", module_path!(), T::type_name()) + } fn schema(map: &mut MetaMap) { Signature::schema(map); map.entry(Self::type_name()).or_insert_with(|| { - Metadata::TupleStruct(UnnamedFieldsMeta { + Metadata::Tuple(UnnamedFieldsMeta { types: vec![Signature::type_name()], }) }); @@ -273,7 +271,6 @@ impl SignatureOf { /// /// GUARANTEE 1: This container always contains at least 1 signature /// GUARANTEE 2: Each signature corresponds to a different public key -#[allow(clippy::unsafe_derive_deserialize)] #[derive(Encode, Serialize, IntoSchema)] #[serde(transparent)] // Transmute guard @@ -381,7 +378,7 @@ impl TryFrom>> for SignaturesOf { return Ok(Self { signatures: signatures .into_iter() - .map(|signature| (signature.public_key.clone(), signature)) + .map(|signature| (signature.public_key().clone(), signature)) .collect(), }); } @@ -417,7 +414,7 @@ impl SignaturesOf { /// Adds a signature. If the signature with this key was present, replaces it. pub fn insert(&mut self, signature: SignatureOf) { self.signatures - .insert(signature.public_key.clone(), signature); + .insert(signature.public_key().clone(), signature); } /// Returns signatures that have passed verification. @@ -525,7 +522,8 @@ impl fmt::Display for SignatureVerificationFail { write!( f, "Failed to verify signatures because of signature {}: {}", - self.signature.public_key, self.reason, + self.signature.public_key(), + self.reason, ) } } @@ -552,7 +550,7 @@ mod tests { let message = b"Test message to sign."; let signature = Signature::new(key_pair.clone(), message).expect("Failed to create signature."); - assert_eq!(signature.public_key, key_pair.public_key); + assert_eq!(signature.public_key(), key_pair.public_key()); assert!(signature.verify(message).is_ok()) } @@ -566,7 +564,7 @@ mod tests { let message = b"Test message to sign."; let signature = Signature::new(key_pair.clone(), message).expect("Failed to create signature."); - assert_eq!(signature.public_key, key_pair.public_key); + assert_eq!(signature.public_key(), key_pair.public_key()); assert!(signature.verify(message).is_ok()) } @@ -580,7 +578,7 @@ mod tests { let message = b"Test message to sign."; let signature = Signature::new(key_pair.clone(), message).expect("Failed to create signature."); - assert_eq!(signature.public_key, key_pair.public_key); + assert_eq!(signature.public_key(), key_pair.public_key()); assert!(signature.verify(message).is_ok()) } @@ -594,7 +592,7 @@ mod tests { let message = b"Test message to sign."; let signature = Signature::new(key_pair.clone(), message).expect("Failed to create signature."); - assert_eq!(signature.public_key, key_pair.public_key); + assert_eq!(signature.public_key(), key_pair.public_key()); assert!(signature.verify(message).is_ok()) } diff --git a/data_model/Cargo.toml b/data_model/Cargo.toml index e0ab79dc08a..43940adbeb2 100644 --- a/data_model/Cargo.toml +++ b/data_model/Cargo.toml @@ -27,14 +27,13 @@ roles = [] # Internal use only mutable_api = [] -cross_crate_testing = [] [dependencies] +iroha_data_primitives = { path = "primitives", version = "=2.0.0-pre-rc.3", default-features = false } iroha_crypto = { path = "../crypto", version = "=2.0.0-pre-rc.3", default-features = false } iroha_macro = { path = "../macro", version = "=2.0.0-pre-rc.3", default-features = false } -iroha_schema = { path = "../schema", version = "=2.0.0-pre-rc.3", default-features = false } iroha_version = { path = "../version", version = "=2.0.0-pre-rc.3", default-features = false, features = ["derive", "json", "scale"] } -iroha_data_primitives = { path = "primitives", version = "=2.0.0-pre-rc.3", default-features = false } +iroha_schema = { path = "../schema", version = "=2.0.0-pre-rc.3" } parity-scale-codec = { version = "2.3.1", default-features = false, features = ["derive"] } derive_more = { version = "0.99.16", default-features = false, features = ["display"] } diff --git a/data_model/src/expression.rs b/data_model/src/expression.rs index 922a0816874..d75f0f4adcb 100644 --- a/data_model/src/expression.rs +++ b/data_model/src/expression.rs @@ -59,7 +59,10 @@ impl> EvaluatesTo { } } -impl> IntoSchema for EvaluatesTo { +impl> IntoSchema for EvaluatesTo { + fn type_name() -> String { + format!("{}::EvaluatesTo<{}>", module_path!(), V::type_name()) + } fn schema(map: &mut MetaMap) { ExpressionBox::schema(map); diff --git a/data_model/src/role.rs b/data_model/src/role.rs index 5e47f52d58f..9f0d312299d 100644 --- a/data_model/src/role.rs +++ b/data_model/src/role.rs @@ -1,11 +1,10 @@ //! Structures, traits and impls related to `Role`s. #[cfg(not(feature = "std"))] -use alloc::{boxed::Box, collections::btree_set, string::String}; -use core::fmt; +use alloc::{collections::btree_set, format, string::String, vec::Vec}; +use core::{fmt, str::FromStr}; #[cfg(feature = "std")] use std::collections::btree_set; -use std::str::FromStr; use getset::Getters; use iroha_schema::IntoSchema; diff --git a/schema/bin/src/lib.rs b/schema/bin/src/lib.rs index 9d7d5e4810d..5e413701b9f 100644 --- a/schema/bin/src/lib.rs +++ b/schema/bin/src/lib.rs @@ -56,33 +56,84 @@ mod tests { // By default `PhantomData` wrapped types schema will not be included const SCHEMALESS_TYPES: Vec<&str> = vec![]; + fn is_const_generic(generic: &str) -> bool { + generic.parse::().is_ok() + } + + fn get_subtypes(schema: &Metadata) -> Vec<&str> { + match schema { + Metadata::Enum(EnumMeta { variants }) => variants + .iter() + .map(|v| &v.ty) + .filter_map(Option::as_ref) + .map(String::as_str) + .collect(), + Metadata::Struct(NamedFieldsMeta { declarations }) => { + declarations.iter().map(|d| d.ty.as_str()).collect() + } + Metadata::Tuple(UnnamedFieldsMeta { types }) => { + types.iter().map(String::as_str).collect() + } + Metadata::Result(ResultMeta { ok, err }) => vec![ok, err], + Metadata::Map(MapMeta { key, value, .. }) => vec![key, value], + Metadata::Option(ty) + | Metadata::Array(ArrayMeta { ty, .. }) + | Metadata::Vec(VecMeta { ty, .. }) => { + vec![ty] + } + Metadata::String | Metadata::Bool | Metadata::FixedPoint(_) | Metadata::Int(_) => { + vec![] + } + } + } + // For `PhantomData` wrapped types schemas aren't expanded recursively. // This test ensures that schemas for those types are present as well. + #[allow(clippy::string_slice)] // NOTE: There are no non-ascii characters in source code. fn find_missing_type_params(schemas: &MetaMap) -> HashMap<&str, Vec<&str>> { let mut missing_schemas = HashMap::new(); for type_name in schemas.keys() { - // Missing `PhantomData` schemas - let params_list_start = type_name.find('<'); - let params_list_end = type_name.rfind('>'); - - if let (Some(start), Some(end)) = (params_list_start, params_list_end) { - #[allow(clippy::string_slice)] // We don't have non-ascii characters in source code. - for generic in type_name[1 + start..end].split(',') { - let gen = generic.trim(); - - // This is const generic - if gen.parse::().is_ok() { - continue; + if let (Some(mut start), Some(end)) = (type_name.find('<'), type_name.rfind('>')) { + start += 1; + + let mut angle_bracket_diff = 0_u8; + for (i, c) in type_name[start..end].chars().enumerate() { + if c == '<' { + angle_bracket_diff += 1_u8; } + if c == '>' { + angle_bracket_diff -= 1_u8; + } + + if c == ',' && angle_bracket_diff == 0_u8 { + let generic = type_name[start..(start + i)].trim(); + + start += i + 1; + if !is_const_generic(generic) { + continue; + } - if !SCHEMALESS_TYPES.contains(&gen) && !schemas.contains_key(gen) { - missing_schemas - .entry(type_name.as_str()) - .or_insert_with(Vec::new) - .push(gen); + if !SCHEMALESS_TYPES.contains(&generic) && !schemas.contains_key(generic) { + missing_schemas + .entry(type_name.as_str()) + .or_insert_with(Vec::new) + .push(generic); + } } } + + let generic = type_name[start..end].trim(); + if !generic.is_empty() + && !is_const_generic(generic) + && !SCHEMALESS_TYPES.contains(&generic) + && !schemas.contains_key(generic) + { + missing_schemas + .entry(type_name.as_str()) + .or_insert_with(Vec::new) + .push(generic); + } } } @@ -93,32 +144,9 @@ mod tests { let mut missing_schemas = HashMap::new(); for (type_name, schema) in schemas { - let types: Vec<&str> = match schema { - Metadata::Enum(EnumMeta { variants }) => variants - .iter() - .map(|v| &v.ty) - .filter_map(Option::as_ref) - .map(String::as_str) - .collect(), - Metadata::Struct(NamedFieldsMeta { declarations }) => { - declarations.iter().map(|d| d.ty.as_str()).collect() - } - Metadata::TupleStruct(UnnamedFieldsMeta { types }) => { - types.iter().map(String::as_str).collect() - } - Metadata::Result(ResultMeta { ok, err }) => vec![ok, err], - Metadata::Map(MapMeta { key, value }) => vec![key, value], - Metadata::Option(ty) - | Metadata::Array(ArrayMeta { ty, .. }) - | Metadata::Vec(ty) => { - vec![ty] - } - Metadata::String | Metadata::Bool | Metadata::FixedPoint(_) | Metadata::Int(_) => { - vec![] - } - }; + let subtypes = get_subtypes(schema); - for ty in types { + for ty in subtypes { if !schemas.contains_key(ty) { missing_schemas .entry(type_name.as_str()) @@ -144,11 +172,4 @@ mod tests { assert!(missing_schemas.is_empty()); } - - #[test] - fn no_alloc_prefix() { - assert!(build_schemas() - .keys() - .all(|type_name| !type_name.starts_with("alloc"))); - } } diff --git a/schema/derive/src/lib.rs b/schema/derive/src/lib.rs index c380a073941..0e500933dd7 100644 --- a/schema/derive/src/lib.rs +++ b/schema/derive/src/lib.rs @@ -104,7 +104,7 @@ fn metadata(data: &Data) -> TokenStream2 { fields: Fields::Unit, .. }) => { - let expr = syn::parse2(quote! {iroha_schema::Metadata::TupleStruct( + let expr = syn::parse2(quote! {iroha_schema::Metadata::Tuple( iroha_schema::UnnamedFieldsMeta { types: Vec::new() } @@ -135,7 +135,7 @@ fn metadata_for_tuplestructs(fields: &FieldsUnnamed) -> (Vec, Expr) { .map(|field| field.ty) .map(|ty| quote! { <#ty as iroha_schema::IntoSchema>::type_name()}); let expr = syn::parse2(quote! { - iroha_schema::Metadata::TupleStruct( + iroha_schema::Metadata::Tuple( iroha_schema::UnnamedFieldsMeta { types: { let mut types = Vec::new(); diff --git a/schema/src/lib.rs b/schema/src/lib.rs index 0805de15db9..caebcc6c9dc 100644 --- a/schema/src/lib.rs +++ b/schema/src/lib.rs @@ -1,12 +1,11 @@ //! Module for schematizing rust types in other languages for translation. -#![allow(clippy::expect_used)] #![no_std] extern crate alloc; use alloc::{ - borrow::ToOwned as _, + boxed::Box, collections::{btree_map::BTreeMap, btree_set::BTreeSet}, format, string::String, @@ -24,14 +23,8 @@ pub type MetaMap = BTreeMap; /// `IntoSchema` trait pub trait IntoSchema { /// Returns unique type name. - /// WARN: `core::any::type_name` is compiler related, so is not unique. - /// I guess we should change it somehow later - // TODO: Should return &str if possible - fn type_name() -> String { - core::any::type_name::() - .replace("alloc::string::String", "String") - .replace("alloc::vec::Vec", "Vec") - } + // TODO: Should return &str if possible or be immutable string + fn type_name() -> String; /// Returns info about current type. Will return map from type names to its metadata fn get_schema() -> MetaMap { @@ -56,9 +49,9 @@ pub trait DecimalPlacesAware { pub enum Metadata { /// Structure with named fields Struct(NamedFieldsMeta), - /// Structure with unnamed fields - TupleStruct(UnnamedFieldsMeta), - /// Enumeration + /// Unnamed structure + Tuple(UnnamedFieldsMeta), + /// Enum Enum(EnumMeta), /// Integer Int(IntMode), @@ -71,8 +64,8 @@ pub enum Metadata { /// Array Array(ArrayMeta), /// Vector with type - Vec(String), - /// Map + Vec(VecMeta), + /// Associative array Map(MapMeta), /// Option with type Option(String), @@ -87,6 +80,17 @@ pub struct ArrayMeta { pub ty: String, /// Length pub len: u64, + /// Order elements + pub sorted: bool, +} + +/// Array metadata +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)] +pub struct VecMeta { + /// Type + pub ty: String, + /// Order elements + pub sorted: bool, } /// Named fields @@ -94,7 +98,6 @@ pub struct ArrayMeta { pub struct NamedFieldsMeta { /// Fields pub declarations: Vec, - //todo add collection of properties meta defined in struct } /// Field @@ -111,7 +114,6 @@ pub struct Declaration { pub struct UnnamedFieldsMeta { /// Field types pub types: Vec, - // TODO: add collection of properties meta defined in struct } /// Enum metadata @@ -130,7 +132,6 @@ pub struct EnumVariant { pub discriminant: u8, /// Its type pub ty: Option, - //todo add collection of properties meta defined in enum variant } /// Result variant @@ -148,6 +149,8 @@ pub struct MapMeta { pub key: String, /// Value type pub value: String, + /// Order key-value pairs by key + pub sorted_by_key: bool, } /// Integer mode @@ -171,10 +174,10 @@ pub struct FixedMeta { } macro_rules! impl_schema_int { - ($($t:ty,)*) => {$( + ($($t:ty),*) => {$( impl IntoSchema for $t { fn type_name() -> String { - core::any::type_name::().to_owned() + String::from(stringify!($t)) } fn schema(map: &mut MetaMap) { let _ = map.entry(Self::type_name()).or_insert( @@ -194,7 +197,7 @@ macro_rules! impl_schema_int { )*}; } -impl_schema_int!(u128, u64, u32, u16, u8, i128, i64, i32, i16, i8,); +impl_schema_int!(u128, u64, u32, u16, u8, i128, i64, i32, i16, i8); impl IntoSchema for fixnum::FixedPoint { fn type_name() -> String { @@ -222,7 +225,7 @@ impl DecimalPlacesAware for fixnum::typenum::U9 { impl IntoSchema for String { fn type_name() -> String { - "String".to_owned() + String::from("String") } fn schema(map: &mut MetaMap) { let _ = map.entry(Self::type_name()).or_insert(Metadata::String); @@ -231,7 +234,7 @@ impl IntoSchema for String { impl IntoSchema for bool { fn type_name() -> String { - core::any::type_name::().to_owned() + String::from("bool") } fn schema(map: &mut MetaMap) { let _ = map.entry(Self::type_name()).or_insert(Metadata::Bool); @@ -243,9 +246,12 @@ impl IntoSchema for Vec { format!("Vec<{}>", T::type_name()) } fn schema(map: &mut MetaMap) { - let _ = map - .entry(Self::type_name()) - .or_insert_with(|| Metadata::Vec(T::type_name())); + let _ = map.entry(Self::type_name()).or_insert_with(|| { + Metadata::Vec(VecMeta { + ty: T::type_name(), + sorted: false, + }) + }); if !map.contains_key(&T::type_name()) { T::schema(map); } @@ -266,7 +272,7 @@ impl IntoSchema for Option { } } -impl IntoSchema for alloc::boxed::Box { +impl IntoSchema for Box { fn type_name() -> String { T::type_name() } @@ -298,15 +304,17 @@ impl IntoSchema for Result { impl IntoSchema for BTreeMap { fn type_name() -> String { - format!("BTreeMap<{}, {}>", K::type_name(), V::type_name()) + format!("Map<{}, {}>", K::type_name(), V::type_name(),) } fn schema(map: &mut MetaMap) { - let _ = map.entry(Self::type_name()).or_insert_with(|| { + map.entry(Self::type_name()).or_insert_with(|| { Metadata::Map(MapMeta { key: K::type_name(), value: V::type_name(), + sorted_by_key: true, }) }); + if !map.contains_key(&K::type_name()) { K::schema(map); } @@ -316,28 +324,32 @@ impl IntoSchema for BTreeMap { } } -impl IntoSchema for BTreeSet { +impl IntoSchema for BTreeSet { fn type_name() -> String { - format!("BTreeSet<{}>", V::type_name()) + format!("Vec<{}>", K::type_name()) } fn schema(map: &mut MetaMap) { - map.entry(Self::type_name()) - .or_insert_with(|| Metadata::Vec(V::type_name())); - if !map.contains_key(&V::type_name()) { - Vec::::schema(map) + map.entry(Self::type_name()).or_insert_with(|| { + Metadata::Vec(VecMeta { + ty: K::type_name(), + sorted: true, + }) + }); + if !map.contains_key(&K::type_name()) { + K::schema(map) } } } impl IntoSchema for core::time::Duration { fn type_name() -> String { - core::any::type_name::().to_owned() + String::from("Duration") } // Look at: // https://docs.rs/parity-scale-codec/2.1.1/src/parity_scale_codec/codec.rs.html#1182-1192 fn schema(map: &mut MetaMap) { let _ = map.entry(Self::type_name()).or_insert_with(|| { - Metadata::TupleStruct(UnnamedFieldsMeta { + Metadata::Tuple(UnnamedFieldsMeta { types: vec![u64::type_name(), u32::type_name()], }) }); @@ -357,9 +369,11 @@ impl IntoSchema for [T; L] { fn schema(map: &mut MetaMap) { let _ = map.entry(Self::type_name()).or_insert_with(|| { + #[allow(clippy::expect_used)] Metadata::Array(ArrayMeta { ty: T::type_name(), len: L.try_into().expect("usize should always fit in u64"), + sorted: false, }) }); if !map.contains_key(&T::type_name()) { @@ -368,42 +382,6 @@ impl IntoSchema for [T; L] { } } -macro_rules! impl_schema_tuple { - ($( ( $($id:ident),* ) ),* ) => {$( - impl<$($id: IntoSchema),*> IntoSchema for ($($id),*) { - fn type_name() -> String { - format!("({})", vec![$($id::type_name()),*].join(", ")) - } - - fn schema(map: &mut MetaMap) { - let _ = map.entry(Self::type_name()).or_insert_with(|| { - Metadata::TupleStruct(UnnamedFieldsMeta { - types: vec![$($id::type_name()),*], - }) - }); - $( - if !map.contains_key(& $id::type_name()) { - $id::schema(map); - } - )* - } - } - )*}; -} - -impl_schema_tuple!( - (A0, A1), - (A0, A1, A2), - (A0, A1, A2, A3), - (A0, A1, A2, A3, A4), - (A0, A1, A2, A3, A4, A5), - (A0, A1, A2, A3, A4, A5, A6), - (A0, A1, A2, A3, A4, A5, A6, A7), - (A0, A1, A2, A3, A4, A5, A6, A7, A8), - (A0, A1, A2, A3, A4, A5, A6, A7, A8, A9), - (A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10) -); - pub mod prelude { //! Exports common types. diff --git a/schema/tests/struct_with_named_fields.rs b/schema/tests/struct_with_named_fields.rs index f23b6ad5ecb..ff409d3ed96 100644 --- a/schema/tests/struct_with_named_fields.rs +++ b/schema/tests/struct_with_named_fields.rs @@ -36,7 +36,13 @@ fn named_fields() { let expected = vec![ ("String".to_owned(), String), - ("Vec".to_owned(), Vec("String".to_owned())), + ( + "Vec".to_owned(), + Vec(VecMeta { + ty: "String".to_owned(), + sorted: false, + }), + ), ("i32".to_owned(), Int(FixedWidth)), ( "struct_with_named_fields::Command".to_owned(), diff --git a/schema/tests/struct_with_unnamed_fields.rs b/schema/tests/struct_with_unnamed_fields.rs index 231ddfb45bc..a488d61e6e8 100644 --- a/schema/tests/struct_with_unnamed_fields.rs +++ b/schema/tests/struct_with_unnamed_fields.rs @@ -12,10 +12,16 @@ fn unnamed() { let expected = vec![ ("String".to_owned(), String), - ("Vec".to_owned(), Vec("String".to_owned())), + ( + "Vec".to_owned(), + Vec(VecMeta { + ty: "String".to_owned(), + sorted: false, + }), + ), ( "struct_with_unnamed_fields::Command".to_owned(), - TupleStruct(UnnamedFieldsMeta { + Tuple(UnnamedFieldsMeta { types: vec!["String".to_owned(), "Vec".to_owned()], }), ), diff --git a/tools/parity_scale_decoder/src/generate_map.rs b/tools/parity_scale_decoder/src/generate_map.rs index ca7257dc092..3a4576bf8de 100644 --- a/tools/parity_scale_decoder/src/generate_map.rs +++ b/tools/parity_scale_decoder/src/generate_map.rs @@ -53,8 +53,7 @@ macro_rules! generate_map { } /// Generate map with types and `dump_decoded()` ptr -#[allow(trivial_casts)] -#[allow(clippy::too_many_lines)] +#[allow(clippy::too_many_lines, trivial_casts)] pub fn generate_map() -> DumpDecodedMap { let mut map = generate_map! { Account, diff --git a/wasm/src/lib.rs b/wasm/src/lib.rs index 73007813eb6..db9f6d1a4c8 100644 --- a/wasm/src/lib.rs +++ b/wasm/src/lib.rs @@ -130,7 +130,7 @@ unsafe fn decode_with_length_prefix_from_raw(ptr: WasmUsize) -> T { let len_size_bytes = core::mem::size_of::(); #[allow(clippy::expect_used)] - let len = WasmUsize::from_be_bytes( + let len = WasmUsize::from_le_bytes( core::slice::from_raw_parts(ptr as *mut _, len_size_bytes) .try_into() .expect("Prefix length size(bytes) incorrect. This is a bug."),