From 952cc045532ff8b9bb165f2011f1baac5491af57 Mon Sep 17 00:00:00 2001 From: Giles Cope Date: Tue, 14 Sep 2021 13:06:23 +0100 Subject: [PATCH 01/28] Altered json to be more regular --- .github/workflows/ci.yml | 2 +- Cargo.toml | 5 +- ss58-registry-derive/Cargo.toml | 10 +- ss58-registry-derive/src/lib.rs | 452 +++++++++--------- .../ss58-registry.json => ss58-registry.json | 58 +-- ss58-registry/Cargo.toml | 4 +- 6 files changed, 279 insertions(+), 252 deletions(-) rename ss58-registry-derive/src/ss58-registry.json => ss58-registry.json (96%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ab5908d..a22b621 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,7 +34,7 @@ jobs: uses: actions-rs/cargo@v1.0.3 with: command: clippy - - name: cargo test --manifest-path ./ss58-registry-derive/Cargo.toml + - name: cargo test --manifest-path ./ss58-registry/Cargo.toml uses: actions-rs/cargo@v1.0.3 with: command: test diff --git a/Cargo.toml b/Cargo.toml index 8b3b15f..cefaf52 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,4 @@ [workspace] resolver = "2" -members = [ - "ss58-registry", - "ss58-registry-derive", -] +members = ["ss58-registry", "ss58-registry-derive"] diff --git a/ss58-registry-derive/Cargo.toml b/ss58-registry-derive/Cargo.toml index f1ebb8a..2e722b0 100644 --- a/ss58-registry-derive/Cargo.toml +++ b/ss58-registry-derive/Cargo.toml @@ -10,10 +10,14 @@ description = "Registry of wellknown SS58 id types" proc-macro = true [dependencies] -quote = "1.0.3" -serde = {version = "1.0", default-features = false, features = ["std", "derive"] } -serde_json = {version = "1.0", default-features = false, features = ["std"] } +quote = { version = "1.0.3", default-features = false } +serde = { version = "1.0", default-features = false, features = [ + "std", + "derive", +] } +serde_json = { version = "1.0", default-features = false, features = ["std"] } proc-macro2 = "1.0" +Inflector = { version = "0.11.4", default-features = false } [dev-dependencies] sp-debug-derive = "3.0.0" diff --git a/ss58-registry-derive/src/lib.rs b/ss58-registry-derive/src/lib.rs index 3dd05f9..3871781 100644 --- a/ss58-registry-derive/src/lib.rs +++ b/ss58-registry-derive/src/lib.rs @@ -19,7 +19,6 @@ use proc_macro::TokenStream; use quote::{format_ident, quote}; use serde::{self, Deserialize}; use std::collections::HashSet; -use std::iter::FromIterator; #[derive(Deserialize)] struct Registry { @@ -28,50 +27,34 @@ struct Registry { impl Registry { pub fn is_valid(&self) -> Result<(), String> { - let unique_ids: HashSet = self.registry.iter().map(|r| r.prefix).collect(); - if unique_ids.len() != self.registry.len() { - return Err("prefixes must be unique.".to_owned()); - } - - let unreserved_networks: Vec = self - .registry - .iter() - .filter_map(|r| r.network.clone()) - .collect(); - let unique_networks: HashSet<&String> = HashSet::from_iter(unreserved_networks.iter()); - if unique_networks.len() != unreserved_networks.len() { - return Err("networks must be unique.".to_owned()); - } + let mut used_prefixes = HashSet::::new(); + let mut used_networks = HashSet::::new(); for account_type in &self.registry { - if let Some(network) = &account_type.network { - if network.chars().any(|c| c.is_whitespace()) { - return Err(format!( - "network can not have whitespace in: {:?}", - account_type - )); - } + if !used_prefixes.insert(account_type.prefix) { + return Err(format!( + "prefixes must be unique but this account's prefix clashes: {:#?}.", + account_type + )); } - - if let Some(symbols) = &account_type.symbols { - if account_type - .decimals - .as_ref() - .filter(|decimals| symbols.len() == decimals.len()) - .is_none() - { - return Err(format!( - "decimals must be specified for each symbol: {:?}", - account_type - )); - } - } else if account_type.decimals.is_some() { + if !used_networks.insert(account_type.network.clone()) { return Err(format!( - "decimals can't be specified without symbols: {:?}", + "networks must be unique but this account's network clashes: {:#?}.", + account_type + )); + } + if account_type.network.chars().any(|c| c.is_whitespace()) { + return Err(format!( + "network can not have whitespace in: {:?}", + account_type + )); + } + if account_type.decimals.len() != account_type.symbols.len() { + return Err(format!( + "decimals must be specified for each symbol: {:?}", account_type )); } - if let Some(sig_type) = &account_type.standard_account { match sig_type.as_str() { "Sr25519"| "Ed25519" | "secp256k1" | "*25519" => {}, @@ -88,109 +71,63 @@ impl Registry { #[derive(Deserialize, Debug)] struct AccountType { prefix: u16, - network: Option, + network: String, #[serde(rename = "displayName")] display_name: String, + /// If standard account is None then the network is reserved. #[serde(rename = "standardAccount")] standard_account: Option, + symbols: Vec, + decimals: Vec, website: Option, - symbols: Option>, - decimals: Option>, } impl AccountType { fn name(&self) -> String { - let mut name = self.network.clone().unwrap_or( - if let Some(standard_account) = &self.standard_account { - format!("Bare{}", standard_account) - } else { - let name = self - .network - .as_ref() - .expect("network should not be empty if no account specified") - .to_string(); - - assert!( - name.starts_with("reserved"), - "If no account specified, network should start `reserved` not:{}", - name - ); - name - }, - ); - let is_reserved = name.starts_with("reserved"); - if name.ends_with("net") { - name.truncate(name.len() - 3); - } - // Capitalise - name.get_mut(0..1) - .expect("name should not be empty") - .make_ascii_uppercase(); - - let postfix = if is_reserved { "" } else { "Account" }; - format!("{}{}", rust_valid_id(name), postfix) + format!( + "{}Account", + inflector::cases::pascalcase::to_pascal_case(&self.network) + ) } } -fn rust_valid_id(name: String) -> String { - // TODO find function that already does this. `-` are excluded in particular. - name.chars().filter(|c| c.is_alphanumeric()).collect() -} - /// Creates the Ss58AddressFormat enum from the ss58-registry.json file #[proc_macro] pub fn ss58_registry_derive(input: TokenStream) -> TokenStream { assert!(input.is_empty(), "No arguments are expected"); - match create_ss58_registry(include_str!("ss58-registry.json")) { - Ok(result) => result, + match create_ss58_registry(include_str!("../../ss58-registry.json")) { + Ok(result) => result.into(), Err(msg) => panic!("{}", msg), } } -fn create_ss58_registry(json: &str) -> Result { +fn create_ss58_registry(json: &str) -> Result { let registry: Registry = serde_json::from_str(json).expect("valid json file"); - registry.is_valid()?; + let registry = registry.registry; + + // Variables to insert into quote template: let identifier: Vec<_> = registry - .registry .iter() .map(|r| format_ident!("{}", r.name())) .collect(); - let reserved_identifiers: Vec<_> = registry - .registry + let reserved_identifiers = registry .iter() - .filter(|r| { - r.network - .as_ref() - .filter(|r| r.starts_with("reserved")) - .is_some() - }) - .map(|r| format_ident!("{}", r.name())) - .collect(); + .filter(|r| r.standard_account.is_none()) + .map(|r| format_ident!("{}", r.name())); - let reserved_numbers: Vec<_> = registry - .registry + let reserved_numbers = registry .iter() - .filter(|r| { - r.network - .as_ref() - .filter(|r| r.starts_with("reserved")) - .is_some() - }) - .map(|r| r.prefix) - .collect(); + .filter(|r| r.standard_account.is_none()) + .map(|r| r.prefix); - let number: Vec<_> = registry.registry.iter().map(|r| r.prefix).collect(); - let count = registry.registry.len(); - let name: Vec<_> = registry - .registry - .iter() - .map(|r| r.network.clone().unwrap_or_else(|| "Bare".to_string())) - .collect(); - let desc = registry.registry.iter().map(|r| { + let count = registry.len(); + let number: Vec<_> = registry.iter().map(|r| r.prefix).collect(); + let name: Vec<_> = registry.iter().map(|r| r.network.clone()).collect(); + let desc = registry.iter().map(|r| { if let Some(website) = &r.website { format!("{} - <{}>", r.display_name, website) } else { @@ -198,139 +135,228 @@ fn create_ss58_registry(json: &str) -> Result { } }); - let output = quote! { - /// A known address (sub)format/network ID for SS58. - #[derive(Copy, Clone, PartialEq, Eq, crate::RuntimeDebug)] - pub enum Ss58AddressFormat { - #(#[doc = #desc] #identifier),*, - /// Use a manually provided numeric value as a standard identifier - Custom(u16), - } - - /// Display the name of the address format (not the description). - #[cfg(feature = "std")] - impl std::fmt::Display for Ss58AddressFormat { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - match self { - #( - Ss58AddressFormat::#identifier => write!(f, "{}", #name), - )* - Ss58AddressFormat::Custom(x) => write!(f, "{}", x), - } + Ok(quote! { + /// A known address (sub)format/network ID for SS58. + #[derive(Copy, Clone, PartialEq, Eq, crate::RuntimeDebug)] + pub enum Ss58AddressFormat { + #(#[doc = #desc] #identifier),*, + /// Use a manually provided numeric value as a standard identifier + Custom(u16), + } + /// Display the name of the address format (not the description). + #[cfg(feature = "std")] + impl std::fmt::Display for Ss58AddressFormat { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + #( + Ss58AddressFormat::#identifier => write!(f, "{}", #name), + )* + Ss58AddressFormat::Custom(x) => write!(f, "{}", x), } + } + } - /// All non-custom address formats. - static ALL_SS58_ADDRESS_FORMATS: [Ss58AddressFormat; #count] = [ - #(Ss58AddressFormat::#identifier),*, - ]; - - /// An enumeration of unique networks. - /// Some are reserved. - impl Ss58AddressFormat { - /// names of all address formats - pub fn all_names() -> &'static [&'static str] { - &[ - #(#name),*, - ] - } - /// All known address formats. - pub fn all() -> &'static [Ss58AddressFormat] { - &ALL_SS58_ADDRESS_FORMATS - } + /// All non-custom address formats. + static ALL_SS58_ADDRESS_FORMATS: [Ss58AddressFormat; #count] = [ + #(Ss58AddressFormat::#identifier),*, + ]; + + /// An enumeration of unique networks. + /// Some are reserved. + impl Ss58AddressFormat { + /// names of all address formats + pub fn all_names() -> &'static [&'static str] { + &[ + #(#name),*, + ] + } + /// All known address formats. + pub fn all() -> &'static [Ss58AddressFormat] { + &ALL_SS58_ADDRESS_FORMATS + } - /// Whether the address is custom. - pub fn is_custom(&self) -> bool { - matches!(self, Self::Custom(_)) - } + /// Whether the address is custom. + pub fn is_custom(&self) -> bool { + matches!(self, Self::Custom(_)) + } - /// Network/AddressType is reserved for future use. - pub fn is_reserved(&self) -> bool { - match self { - #(#reserved_identifiers => true),*, - Ss58AddressFormat::Custom(prefix) => { - match prefix { - #(#reserved_numbers => true),*, - _ => false, - } - }, - _ => false, - } + /// Network/AddressType is reserved for future use. + pub fn is_reserved(&self) -> bool { + match self { + #(#reserved_identifiers => true),*, + Ss58AddressFormat::Custom(prefix) => { + match prefix { + #(#reserved_numbers => true),*, + _ => false, + } + }, + _ => false, } + } + } - // /// Is this address format the current default? - // #[cfg(feature = "std")] - // pub fn is_default(&self) -> bool - // where Self: Default - // { - // // self == &Self::default() - // } + impl From for Ss58AddressFormat { + fn from(x: u8) -> Ss58AddressFormat { + Ss58AddressFormat::from(x as u16) } + } - impl From for Ss58AddressFormat { - fn from(x: u8) -> Ss58AddressFormat { - Ss58AddressFormat::from(x as u16) + impl From for u16 { + fn from(x: Ss58AddressFormat) -> u16 { + match x { + #(Ss58AddressFormat::#identifier => #number),*, + Ss58AddressFormat::Custom(n) => n, } } + } - impl From for u16 { - fn from(x: Ss58AddressFormat) -> u16 { - match x { - #(Ss58AddressFormat::#identifier => #number),*, - Ss58AddressFormat::Custom(n) => n, - } + impl From for Ss58AddressFormat { + fn from(x: u16) -> Ss58AddressFormat { + match x { + #(#number => Ss58AddressFormat::#identifier),*, + _ => Ss58AddressFormat::Custom(x), } } + } - impl From for Ss58AddressFormat { - fn from(x: u16) -> Ss58AddressFormat { - match x { - #(#number => Ss58AddressFormat::#identifier),*, - _ => Ss58AddressFormat::Custom(x), - } + /// Error encountered while parsing `Ss58AddressFormat` from &'_ str + /// unit struct for now. + #[derive(Copy, Clone, PartialEq, Eq, crate::RuntimeDebug)] + pub struct ParseError; + + impl<'a> core::convert::TryFrom<&'a str> for Ss58AddressFormat { + type Error = ParseError; + + fn try_from(x: &'a str) -> Result { + match x { + #(#name => Ok(Ss58AddressFormat::#identifier)),*, + a => a.parse::().map(Ss58AddressFormat::Custom).map_err(|_| ParseError), } } + } - /// Error encountered while parsing `Ss58AddressFormat` from &'_ str - /// unit struct for now. - #[derive(Copy, Clone, PartialEq, Eq, crate::RuntimeDebug)] - pub struct ParseError; + #[cfg(feature = "std")] + impl std::str::FromStr for Ss58AddressFormat { + type Err = ParseError; - impl<'a> core::convert::TryFrom<&'a str> for Ss58AddressFormat { - type Error = ParseError; + fn from_str(data: &str) -> Result { + core::convert::TryFrom::try_from(data) + } + } - fn try_from(x: &'a str) -> Result { - match x { - #(#name => Ok(Ss58AddressFormat::#identifier)),*, - a => a.parse::().map(Ss58AddressFormat::Custom).map_err(|_| ParseError), - } - } + #[cfg(feature = "std")] + impl std::fmt::Display for ParseError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "failed to parse network value as u16") + } + } + + #[cfg(feature = "std")] + impl From for String { + fn from(x: Ss58AddressFormat) -> String { + x.to_string() } + } + }) +} - #[cfg(feature = "std")] - impl std::str::FromStr for Ss58AddressFormat { - type Err = ParseError; +#[cfg(test)] +mod tests { + use super::create_ss58_registry; - fn from_str(data: &str) -> Result { - core::convert::TryFrom::try_from(data) + #[test] + fn normal_account() { + assert!(create_ss58_registry( + r#" + { + "registry": [ + { + "prefix": 0, + "network": "polkadot", + "displayName": "Polkadot Relay Chain", + "symbols": ["DOT"], + "decimals": [10], + "standardAccount": "*25519", + "website": "https://polkadot.network" } - } + ] + } + "# + ) + .is_ok()); + } - #[cfg(feature = "std")] - impl std::fmt::Display for ParseError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "failed to parse network value as u16") + #[test] + fn prefix_clash() { + let result = create_ss58_registry( + r#" + { + "registry": [ + { + "prefix": 0, + "network": "polkadot", + "displayName": "Polkadot Relay Chain", + "symbols": ["DOT"], + "decimals": [10], + "standardAccount": "*25519", + "website": "https://polkadot.network" + }, + { + "prefix": 0, + "network": "polkadot2", + "displayName": "Polkadot Relay Chain2", + "symbols": ["DOT2"], + "decimals": [10], + "standardAccount": "*25519", + "website": "https://polkadot2.network" } - } + ] + } + "#, + ); - #[cfg(feature = "std")] - impl From for String { - fn from(x: Ss58AddressFormat) -> String { - x.to_string() + let err_msg = &result.unwrap_err(); + assert!(err_msg.starts_with( + "prefixes must be unique but this account's prefix clashes: AccountType {" + )); + assert!(err_msg.contains("prefix: 0")); + } + + #[test] + fn network_clash() { + let result = create_ss58_registry( + r#" + { + "registry": [ + { + "prefix": 0, + "network": "polkadot", + "displayName": "Polkadot Relay Chain", + "symbols": ["DOT"], + "decimals": [10], + "standardAccount": "*25519", + "website": "https://dot.network" + }, + { + "prefix": 1, + "network": "polkadot", + "displayName": "Polkadot Relay Chain2", + "symbols": ["DOT2"], + "decimals": [10], + "standardAccount": "*25519", + "website": "https://dot2.network" } - } - }; + ] + } + "#, + ); - Ok(output.into()) + let err_msg = &result.unwrap_err(); + assert!(err_msg.starts_with( + "networks must be unique but this account's network clashes: AccountType {" + )); + assert!(err_msg.contains("polkadot")); + } } diff --git a/ss58-registry-derive/src/ss58-registry.json b/ss58-registry.json similarity index 96% rename from ss58-registry-derive/src/ss58-registry.json rename to ss58-registry.json index 9c9257b..bf1b95c 100644 --- a/ss58-registry-derive/src/ss58-registry.json +++ b/ss58-registry.json @@ -21,10 +21,10 @@ }, { "prefix": 1, - "network": null, + "network": "BareSr25519", "displayName": "Bare 32-bit Schnorr/Ristretto (S/R 25519) public key.", - "symbols": null, - "decimals": null, + "symbols": [], + "decimals": [], "standardAccount": "Sr25519", "website": null }, @@ -39,10 +39,10 @@ }, { "prefix": 3, - "network": null, + "network": "BareEd25519", "displayName": "Bare 32-bit Ed25519 public key.", - "symbols": null, - "decimals": null, + "symbols": [], + "decimals": [], "standardAccount": "Ed25519", "website": null }, @@ -50,8 +50,8 @@ "prefix": 4, "network": "katalchain", "displayName": "Katal Chain", - "symbols": null, - "decimals": null, + "symbols": [], + "decimals": [], "standardAccount": "*25519", "website": null }, @@ -167,8 +167,8 @@ "prefix": 17, "network": "dark", "displayName": "Dark Mainnet", - "symbols": null, - "decimals": null, + "symbols": [], + "decimals": [], "standardAccount": "*25519", "website": null }, @@ -221,8 +221,8 @@ "prefix": 23, "network": "shift", "displayName": "ShiftNrg", - "symbols": null, - "decimals": null, + "symbols": [], + "decimals": [], "standardAccount": "*25519", "website": null }, @@ -257,8 +257,8 @@ "prefix": 28, "network": "subsocial", "displayName": "Subsocial", - "symbols": null, - "decimals": null, + "symbols": [], + "decimals": [], "standardAccount": "*25519", "website": null }, @@ -302,8 +302,8 @@ "prefix": 33, "network": "datahighway", "displayName": "DataHighway", - "symbols": null, - "decimals": null, + "symbols": [], + "decimals": [], "standardAccount": "*25519", "website": null }, @@ -374,8 +374,8 @@ "prefix": 41, "network": "poli", "displayName": "Polimec Chain", - "symbols": null, - "decimals": null, + "symbols": [], + "decimals": [], "standardAccount": "*25519", "website": "https://polimec.io/" }, @@ -383,17 +383,17 @@ "prefix": 42, "network": "substrate", "displayName": "Substrate", - "symbols": null, - "decimals": null, + "symbols": [], + "decimals": [], "standardAccount": "*25519", "website": "https://substrate.dev/" }, { "prefix": 43, - "network": null, + "network": "BareSecp256k1", "displayName": "Bare 32-bit ECDSA SECP-256k1 public key.", - "symbols": null, - "decimals": null, + "symbols": [], + "decimals": [], "standardAccount": "secp256k1", "website": null }, @@ -419,8 +419,8 @@ "prefix": 46, "network": "reserved46", "displayName": "This prefix is reserved.", - "symbols": null, - "decimals": null, + "symbols": [], + "decimals": [], "standardAccount": null, "website": null }, @@ -428,8 +428,8 @@ "prefix": 47, "network": "reserved47", "displayName": "This prefix is reserved.", - "symbols": null, - "decimals": null, + "symbols": [], + "decimals": [], "standardAccount": null, "website": null }, @@ -572,8 +572,8 @@ "prefix": 113, "network": "integritee-incognito", "displayName": "Integritee Incognito", - "symbols": null, - "decimals": null, + "symbols": [], + "decimals": [], "standardAccount": "*25519", "website": "https://integritee.network" }, diff --git a/ss58-registry/Cargo.toml b/ss58-registry/Cargo.toml index f987a55..f753e16 100644 --- a/ss58-registry/Cargo.toml +++ b/ss58-registry/Cargo.toml @@ -9,5 +9,5 @@ default = ["std"] std = [] [dependencies] -ss58-registry-derive = { path="../ss58-registry-derive" } -sp-debug-derive = "3.0.0" \ No newline at end of file +ss58-registry-derive = { path = "../ss58-registry-derive" } +sp-debug-derive = "3.0.0" From 0769972ca598855b467d980dd2b867f0d2f1101b Mon Sep 17 00:00:00 2001 From: Giles Cope Date: Tue, 14 Sep 2021 13:36:16 +0100 Subject: [PATCH 02/28] Its nicer if this is avaialble as a const fn --- ss58-registry-derive/src/lib.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/ss58-registry-derive/src/lib.rs b/ss58-registry-derive/src/lib.rs index 3871781..9d167c4 100644 --- a/ss58-registry-derive/src/lib.rs +++ b/ss58-registry-derive/src/lib.rs @@ -205,10 +205,15 @@ fn create_ss58_registry(json: &str) -> Result impl From for u16 { fn from(x: Ss58AddressFormat) -> u16 { - match x { - #(Ss58AddressFormat::#identifier => #number),*, - Ss58AddressFormat::Custom(n) => n, - } + from_address_format(x) + } + } + + /// const function to convert Ss58AddressFormat to u16 + pub const fn from_address_format(x: Ss58AddressFormat) -> u16 { + match x { + #(Ss58AddressFormat::#identifier => #number),*, + Ss58AddressFormat::Custom(n) => n, } } From ab9fa1a2505a03c7382ba65e9705f75487d6a76e Mon Sep 17 00:00:00 2001 From: Giles Cope Date: Tue, 14 Sep 2021 14:37:46 +0100 Subject: [PATCH 03/28] Add in is_reserved() --- ss58-registry-derive/src/lib.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/ss58-registry-derive/src/lib.rs b/ss58-registry-derive/src/lib.rs index 9d167c4..f45bf50 100644 --- a/ss58-registry-derive/src/lib.rs +++ b/ss58-registry-derive/src/lib.rs @@ -89,6 +89,10 @@ impl AccountType { inflector::cases::pascalcase::to_pascal_case(&self.network) ) } + + fn is_reserved(&self) -> bool { + self.standard_account.is_none() + } } /// Creates the Ss58AddressFormat enum from the ss58-registry.json file @@ -116,12 +120,12 @@ fn create_ss58_registry(json: &str) -> Result let reserved_identifiers = registry .iter() - .filter(|r| r.standard_account.is_none()) + .filter(|r| r.is_reserved()) .map(|r| format_ident!("{}", r.name())); let reserved_numbers = registry .iter() - .filter(|r| r.standard_account.is_none()) + .filter(|r| r.is_reserved()) .map(|r| r.prefix); let count = registry.len(); From 8e0e255ebc0708b690b72d0bb622a82f68c40e4b Mon Sep 17 00:00:00 2001 From: Squirrel Date: Wed, 15 Sep 2021 10:08:05 +0100 Subject: [PATCH 04/28] Update ss58-registry-derive/src/lib.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bastian Köcher --- ss58-registry-derive/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ss58-registry-derive/src/lib.rs b/ss58-registry-derive/src/lib.rs index f45bf50..784855a 100644 --- a/ss58-registry-derive/src/lib.rs +++ b/ss58-registry-derive/src/lib.rs @@ -326,7 +326,7 @@ mod tests { "#, ); - let err_msg = &result.unwrap_err(); + let err_msg = result.unwrap_err(); assert!(err_msg.starts_with( "prefixes must be unique but this account's prefix clashes: AccountType {" )); From 726caa152bf51e27ae3bd418f3ebaf12f4d39af4 Mon Sep 17 00:00:00 2001 From: Squirrel Date: Wed, 15 Sep 2021 10:09:07 +0100 Subject: [PATCH 05/28] Update ss58-registry-derive/src/lib.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bastian Köcher --- ss58-registry-derive/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/ss58-registry-derive/src/lib.rs b/ss58-registry-derive/src/lib.rs index 784855a..4ac1401 100644 --- a/ss58-registry-derive/src/lib.rs +++ b/ss58-registry-derive/src/lib.rs @@ -69,6 +69,7 @@ impl Registry { } #[derive(Deserialize, Debug)] +#[serde(rename_all = "camelCase")] struct AccountType { prefix: u16, network: String, From a65f161b030748008e1dec4e6a680926721894ab Mon Sep 17 00:00:00 2001 From: Squirrel Date: Wed, 15 Sep 2021 10:09:19 +0100 Subject: [PATCH 06/28] Update ss58-registry-derive/src/lib.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bastian Köcher --- ss58-registry-derive/src/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/ss58-registry-derive/src/lib.rs b/ss58-registry-derive/src/lib.rs index 4ac1401..11c1fd7 100644 --- a/ss58-registry-derive/src/lib.rs +++ b/ss58-registry-derive/src/lib.rs @@ -73,10 +73,8 @@ impl Registry { struct AccountType { prefix: u16, network: String, - #[serde(rename = "displayName")] display_name: String, /// If standard account is None then the network is reserved. - #[serde(rename = "standardAccount")] standard_account: Option, symbols: Vec, decimals: Vec, From 4a87acf4a11965e31524f7906e32f96b409ed0d8 Mon Sep 17 00:00:00 2001 From: Giles Cope Date: Wed, 15 Sep 2021 17:01:50 +0100 Subject: [PATCH 07/28] proc macro => build.rs --- .github/workflows/ci.yml | 4 +- Cargo.toml | 25 +++- ss58-registry-derive/src/lib.rs => build.rs | 132 +++----------------- src/lib.rs | 23 ++++ ss58-registry-derive/Cargo.toml | 23 ---- ss58-registry-derive/tests/tests.rs | 7 -- ss58-registry/Cargo.toml | 13 -- ss58-registry/src/lib.rs | 8 -- 8 files changed, 64 insertions(+), 171 deletions(-) rename ss58-registry-derive/src/lib.rs => build.rs (70%) create mode 100644 src/lib.rs delete mode 100644 ss58-registry-derive/Cargo.toml delete mode 100644 ss58-registry-derive/tests/tests.rs delete mode 100644 ss58-registry/Cargo.toml delete mode 100644 ss58-registry/src/lib.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a22b621..508ddbe 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,7 +34,7 @@ jobs: uses: actions-rs/cargo@v1.0.3 with: command: clippy - - name: cargo test --manifest-path ./ss58-registry/Cargo.toml + - name: cargo test uses: actions-rs/cargo@v1.0.3 with: command: test @@ -56,4 +56,4 @@ jobs: uses: actions-rs/cargo@v1.0.3 with: command: build - args: --manifest-path ./ss58-registry/Cargo.toml --no-default-features --target wasm32-unknown-unknown + args: --no-default-features --target wasm32-unknown-unknown diff --git a/Cargo.toml b/Cargo.toml index cefaf52..631446f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,4 +1,23 @@ -[workspace] -resolver = "2" +[package] +name = "ss58-registry" +version = "0.0.1" +edition = "2018" +description = "Registry of wellknown SS58 id types" -members = ["ss58-registry", "ss58-registry-derive"] +[features] +default = ["std"] +std = [] + +[dependencies] +sp-debug-derive = "3.0.0" + + +[build-dependencies] +quote = { version = "1.0.3", default-features = false } +serde = { version = "1.0", default-features = false, features = [ + "std", + "derive", +] } +serde_json = { version = "1.0", default-features = false, features = ["std"] } +proc-macro2 = "1.0" +Inflector = { version = "0.11.4", default-features = false } diff --git a/ss58-registry-derive/src/lib.rs b/build.rs similarity index 70% rename from ss58-registry-derive/src/lib.rs rename to build.rs index 11c1fd7..bae5101 100644 --- a/ss58-registry-derive/src/lib.rs +++ b/build.rs @@ -15,10 +15,12 @@ //! List of wellknown SS58 account types as an enum. #![deny(missing_docs)] -use proc_macro::TokenStream; use quote::{format_ident, quote}; use serde::{self, Deserialize}; use std::collections::HashSet; +use std::env; +use std::fs; +use std::path::Path; #[derive(Deserialize)] struct Registry { @@ -94,17 +96,6 @@ impl AccountType { } } -/// Creates the Ss58AddressFormat enum from the ss58-registry.json file -#[proc_macro] -pub fn ss58_registry_derive(input: TokenStream) -> TokenStream { - assert!(input.is_empty(), "No arguments are expected"); - - match create_ss58_registry(include_str!("../../ss58-registry.json")) { - Ok(result) => result.into(), - Err(msg) => panic!("{}", msg), - } -} - fn create_ss58_registry(json: &str) -> Result { let registry: Registry = serde_json::from_str(json).expect("valid json file"); registry.is_valid()?; @@ -139,6 +130,8 @@ fn create_ss58_registry(json: &str) -> Result }); Ok(quote! { + use sp_debug_derive::RuntimeDebug; + /// A known address (sub)format/network ID for SS58. #[derive(Copy, Clone, PartialEq, Eq, crate::RuntimeDebug)] pub enum Ss58AddressFormat { @@ -188,13 +181,8 @@ fn create_ss58_registry(json: &str) -> Result /// Network/AddressType is reserved for future use. pub fn is_reserved(&self) -> bool { match self { - #(#reserved_identifiers => true),*, - Ss58AddressFormat::Custom(prefix) => { - match prefix { - #(#reserved_numbers => true),*, - _ => false, - } - }, + #(Ss58AddressFormat::#reserved_identifiers)|* => true, + Ss58AddressFormat::Custom(prefix) => matches!(prefix, #(#reserved_numbers)|*), _ => false, } } @@ -270,101 +258,15 @@ fn create_ss58_registry(json: &str) -> Result }) } -#[cfg(test)] -mod tests { - use super::create_ss58_registry; - - #[test] - fn normal_account() { - assert!(create_ss58_registry( - r#" - { - "registry": [ - { - "prefix": 0, - "network": "polkadot", - "displayName": "Polkadot Relay Chain", - "symbols": ["DOT"], - "decimals": [10], - "standardAccount": "*25519", - "website": "https://polkadot.network" - } - ] - } - "# - ) - .is_ok()); - } +fn main() { + let out_dir = env::var_os("OUT_DIR").expect("OUT_DIR should exist"); - #[test] - fn prefix_clash() { - let result = create_ss58_registry( - r#" - { - "registry": [ - { - "prefix": 0, - "network": "polkadot", - "displayName": "Polkadot Relay Chain", - "symbols": ["DOT"], - "decimals": [10], - "standardAccount": "*25519", - "website": "https://polkadot.network" - }, - { - "prefix": 0, - "network": "polkadot2", - "displayName": "Polkadot Relay Chain2", - "symbols": ["DOT2"], - "decimals": [10], - "standardAccount": "*25519", - "website": "https://polkadot2.network" - } - ] - } - "#, - ); - - let err_msg = result.unwrap_err(); - assert!(err_msg.starts_with( - "prefixes must be unique but this account's prefix clashes: AccountType {" - )); - assert!(err_msg.contains("prefix: 0")); - } + let result: String = match create_ss58_registry(include_str!("ss58-registry.json")) { + Ok(result) => result.to_string(), + Err(msg) => panic!("{}", msg), + }; - #[test] - fn network_clash() { - let result = create_ss58_registry( - r#" - { - "registry": [ - { - "prefix": 0, - "network": "polkadot", - "displayName": "Polkadot Relay Chain", - "symbols": ["DOT"], - "decimals": [10], - "standardAccount": "*25519", - "website": "https://dot.network" - }, - { - "prefix": 1, - "network": "polkadot", - "displayName": "Polkadot Relay Chain2", - "symbols": ["DOT2"], - "decimals": [10], - "standardAccount": "*25519", - "website": "https://dot2.network" - } - ] - } - "#, - ); - - let err_msg = &result.unwrap_err(); - assert!(err_msg.starts_with( - "networks must be unique but this account's network clashes: AccountType {" - )); - assert!(err_msg.contains("polkadot")); - } -} + let dest_path = Path::new(&out_dir).join("account_type_enum.rs"); + fs::write(&dest_path, result).unwrap(); + println!("cargo:rerun-if-changed=build.rs"); +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..5d46d89 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,23 @@ +// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#![warn(missing_docs)] + +//! List of wellknown SS58 account types as an enum. + +include!(concat!( + env!("OUT_DIR"), + concat!("/", "account_type_enum", ".rs") +)); diff --git a/ss58-registry-derive/Cargo.toml b/ss58-registry-derive/Cargo.toml deleted file mode 100644 index 2e722b0..0000000 --- a/ss58-registry-derive/Cargo.toml +++ /dev/null @@ -1,23 +0,0 @@ -[package] -name = "ss58-registry-derive" -version = "0.1.0" -edition = "2018" -description = "Registry of wellknown SS58 id types" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[lib] -proc-macro = true - -[dependencies] -quote = { version = "1.0.3", default-features = false } -serde = { version = "1.0", default-features = false, features = [ - "std", - "derive", -] } -serde_json = { version = "1.0", default-features = false, features = ["std"] } -proc-macro2 = "1.0" -Inflector = { version = "0.11.4", default-features = false } - -[dev-dependencies] -sp-debug-derive = "3.0.0" diff --git a/ss58-registry-derive/tests/tests.rs b/ss58-registry-derive/tests/tests.rs deleted file mode 100644 index fff230a..0000000 --- a/ss58-registry-derive/tests/tests.rs +++ /dev/null @@ -1,7 +0,0 @@ -use sp_debug_derive::RuntimeDebug; -use ss58_registry_derive::ss58_registry_derive; - -#[test] -fn test_can_construct() { - ss58_registry_derive!(); -} diff --git a/ss58-registry/Cargo.toml b/ss58-registry/Cargo.toml deleted file mode 100644 index f753e16..0000000 --- a/ss58-registry/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "ss58-registry" -version = "0.0.1" -edition = "2018" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[features] -default = ["std"] -std = [] - -[dependencies] -ss58-registry-derive = { path = "../ss58-registry-derive" } -sp-debug-derive = "3.0.0" diff --git a/ss58-registry/src/lib.rs b/ss58-registry/src/lib.rs deleted file mode 100644 index a8b934f..0000000 --- a/ss58-registry/src/lib.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![warn(missing_docs)] - -//! Example of macro with 'std' feature enabled by default. -//! and check it builds as no_std when --no-default-features. -use sp_debug_derive::RuntimeDebug; -use ss58_registry_derive::ss58_registry_derive; - -ss58_registry_derive!(); From c65db3a2f5428b99a480ad9c12865f98d36bf762 Mon Sep 17 00:00:00 2001 From: Giles Cope Date: Thu, 16 Sep 2021 13:16:24 +0100 Subject: [PATCH 08/28] O(log(n)) rather than O(n) for many methods. No way to have two instances of Ss58AddressFormat that mean the same thing but are different. (Before Custom(42) was the same as Ss58AddressFormat::Substrate but not eq.) --- Cargo.toml | 1 - build.rs | 148 +++++++++++------------------------------------------ src/lib.rs | 129 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 160 insertions(+), 118 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 631446f..ec1b114 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,6 @@ std = [] [dependencies] sp-debug-derive = "3.0.0" - [build-dependencies] quote = { version = "1.0.3", default-features = false } serde = { version = "1.0", default-features = false, features = [ diff --git a/build.rs b/build.rs index bae5101..886edb8 100644 --- a/build.rs +++ b/build.rs @@ -100,7 +100,9 @@ fn create_ss58_registry(json: &str) -> Result let registry: Registry = serde_json::from_str(json).expect("valid json file"); registry.is_valid()?; - let registry = registry.registry; + let mut registry = registry.registry; + // The names are assumed to be sorted. + registry.sort_by_key(|a| a.name()); // Variables to insert into quote template: let identifier: Vec<_> = registry @@ -113,13 +115,16 @@ fn create_ss58_registry(json: &str) -> Result .filter(|r| r.is_reserved()) .map(|r| format_ident!("{}", r.name())); - let reserved_numbers = registry - .iter() - .filter(|r| r.is_reserved()) - .map(|r| r.prefix); - let count = registry.len(); let number: Vec<_> = registry.iter().map(|r| r.prefix).collect(); + let enumeration: Vec<_> = (0..registry.len()).collect(); + + let mut prefix_to_idx: Vec<_> = number.iter().zip(enumeration).collect(); + prefix_to_idx.sort_by_key(|(prefix, _)| *prefix); + let prefix_to_idx = prefix_to_idx + .iter() + .map(|(prefix, idx)| quote! { (#prefix, #idx) }); + let name: Vec<_> = registry.iter().map(|r| r.network.clone()).collect(); let desc = registry.iter().map(|r| { if let Some(website) = &r.website { @@ -130,131 +135,40 @@ fn create_ss58_registry(json: &str) -> Result }); Ok(quote! { - use sp_debug_derive::RuntimeDebug; /// A known address (sub)format/network ID for SS58. + #[non_exhaustive] + #[repr(u16)] #[derive(Copy, Clone, PartialEq, Eq, crate::RuntimeDebug)] - pub enum Ss58AddressFormat { - #(#[doc = #desc] #identifier),*, - /// Use a manually provided numeric value as a standard identifier - Custom(u16), + pub enum KnownSs58AddressFormat { + #(#[doc = #desc] #identifier = #number),*, } - /// Display the name of the address format (not the description). - #[cfg(feature = "std")] - impl std::fmt::Display for Ss58AddressFormat { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - match self { - #( - Ss58AddressFormat::#identifier => write!(f, "{}", #name), - )* - Ss58AddressFormat::Custom(x) => write!(f, "{}", x), - } + /// All non-custom address formats (Sorted by name) + static ALL_SS58_ADDRESS_FORMATS: [KnownSs58AddressFormat; #count] = [ + #(KnownSs58AddressFormat::#identifier),*, + ]; - } - } + /// Names of all address formats (Sorted by name) + static ALL_SS58_ADDRESS_FORMAT_NAMES: [&str; #count] = [ + #(#name),*, + ]; - /// All non-custom address formats. - static ALL_SS58_ADDRESS_FORMATS: [Ss58AddressFormat; #count] = [ - #(Ss58AddressFormat::#identifier),*, + /// (Sorted) prefixes to index of ALL_SS58_ADDRESS_FORMATS + static PREFIX_TO_INDEX: [(u16, usize); #count] = [ + #(#prefix_to_idx),*, ]; - /// An enumeration of unique networks. - /// Some are reserved. impl Ss58AddressFormat { - /// names of all address formats - pub fn all_names() -> &'static [&'static str] { - &[ - #(#name),*, - ] - } - /// All known address formats. - pub fn all() -> &'static [Ss58AddressFormat] { - &ALL_SS58_ADDRESS_FORMATS - } - - /// Whether the address is custom. - pub fn is_custom(&self) -> bool { - matches!(self, Self::Custom(_)) - } - /// Network/AddressType is reserved for future use. pub fn is_reserved(&self) -> bool { - match self { - #(Ss58AddressFormat::#reserved_identifiers)|* => true, - Ss58AddressFormat::Custom(prefix) => matches!(prefix, #(#reserved_numbers)|*), - _ => false, + if let Ok(known) = KnownSs58AddressFormat::try_from(*self) { + matches!(known, #(KnownSs58AddressFormat::#reserved_identifiers)|*) + } else { + false } } } - - impl From for Ss58AddressFormat { - fn from(x: u8) -> Ss58AddressFormat { - Ss58AddressFormat::from(x as u16) - } - } - - impl From for u16 { - fn from(x: Ss58AddressFormat) -> u16 { - from_address_format(x) - } - } - - /// const function to convert Ss58AddressFormat to u16 - pub const fn from_address_format(x: Ss58AddressFormat) -> u16 { - match x { - #(Ss58AddressFormat::#identifier => #number),*, - Ss58AddressFormat::Custom(n) => n, - } - } - - impl From for Ss58AddressFormat { - fn from(x: u16) -> Ss58AddressFormat { - match x { - #(#number => Ss58AddressFormat::#identifier),*, - _ => Ss58AddressFormat::Custom(x), - } - } - } - - /// Error encountered while parsing `Ss58AddressFormat` from &'_ str - /// unit struct for now. - #[derive(Copy, Clone, PartialEq, Eq, crate::RuntimeDebug)] - pub struct ParseError; - - impl<'a> core::convert::TryFrom<&'a str> for Ss58AddressFormat { - type Error = ParseError; - - fn try_from(x: &'a str) -> Result { - match x { - #(#name => Ok(Ss58AddressFormat::#identifier)),*, - a => a.parse::().map(Ss58AddressFormat::Custom).map_err(|_| ParseError), - } - } - } - - #[cfg(feature = "std")] - impl std::str::FromStr for Ss58AddressFormat { - type Err = ParseError; - - fn from_str(data: &str) -> Result { - core::convert::TryFrom::try_from(data) - } - } - - #[cfg(feature = "std")] - impl std::fmt::Display for ParseError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "failed to parse network value as u16") - } - } - - #[cfg(feature = "std")] - impl From for String { - fn from(x: Ss58AddressFormat) -> String { - x.to_string() - } - } }) } @@ -269,4 +183,4 @@ fn main() { let dest_path = Path::new(&out_dir).join("account_type_enum.rs"); fs::write(&dest_path, result).unwrap(); println!("cargo:rerun-if-changed=build.rs"); -} \ No newline at end of file +} diff --git a/src/lib.rs b/src/lib.rs index 5d46d89..6e2ba0d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,8 +16,137 @@ #![warn(missing_docs)] //! List of wellknown SS58 account types as an enum. +use core::convert::TryFrom; +use sp_debug_derive::RuntimeDebug; include!(concat!( env!("OUT_DIR"), concat!("/", "account_type_enum", ".rs") )); + +/// Error encountered while parsing `Ss58AddressFormat` from &'_ str +/// unit struct for now. +#[derive(Copy, Clone, PartialEq, Eq, crate::RuntimeDebug)] +pub struct ParseError; + +/// A custom address format. See also KnownSs58AddressFormat +#[non_exhaustive] +#[derive(Copy, Clone, PartialEq, Eq, crate::RuntimeDebug)] +pub struct Ss58AddressFormat { + prefix: u16, +} + +/// An enumeration of unique networks. +/// Some are reserved. +impl Ss58AddressFormat { + /// names of all address formats + pub fn all_names() -> &'static [&'static str] { + &ALL_SS58_ADDRESS_FORMAT_NAMES + } + /// All known address formats. + pub fn all() -> &'static [KnownSs58AddressFormat] { + &ALL_SS58_ADDRESS_FORMATS[..] + } + + /// Whether the address is custom. + pub fn is_custom(&self) -> bool { + PREFIX_TO_INDEX + .binary_search_by_key(&self.prefix, |(prefix, _)| *prefix) + .is_err() + } +} + +/// Display the name of the address format (not the description). +#[cfg(feature = "std")] +impl std::fmt::Display for Ss58AddressFormat { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + if let Ok(lookup) = + PREFIX_TO_INDEX.binary_search_by_key(&self.prefix, |(prefix, _)| *prefix) + { + let (_, idx) = PREFIX_TO_INDEX[lookup]; + write!(f, "{}", ALL_SS58_ADDRESS_FORMAT_NAMES[idx]) + } else { + write!(f, "{}", self.prefix) + } + } +} + +impl TryFrom for KnownSs58AddressFormat { + type Error = ParseError; + + fn try_from(x: Ss58AddressFormat) -> Result { + PREFIX_TO_INDEX + .binary_search_by_key(&x.prefix, |(prefix, _)| *prefix) + .map(|lookup| { + let (_, idx) = PREFIX_TO_INDEX[lookup]; + ALL_SS58_ADDRESS_FORMATS[idx] + }) + .map_err(|_| ParseError) + } +} + +impl From for Ss58AddressFormat { + fn from(x: KnownSs58AddressFormat) -> Ss58AddressFormat { + Ss58AddressFormat { prefix: x as u16 } + } +} + +impl From for Ss58AddressFormat { + fn from(x: u8) -> Ss58AddressFormat { + Ss58AddressFormat::from(x as u16) + } +} + +impl From for u16 { + fn from(x: Ss58AddressFormat) -> u16 { + from_address_format(x) + } +} + +/// const function to convert Ss58AddressFormat to u16 +pub const fn from_address_format(x: Ss58AddressFormat) -> u16 { + x.prefix +} + +impl From for Ss58AddressFormat { + fn from(prefix: u16) -> Ss58AddressFormat { + Ss58AddressFormat { prefix } + } +} + +impl<'a> TryFrom<&'a str> for KnownSs58AddressFormat { + type Error = ParseError; + + fn try_from(x: &'a str) -> Result { + ALL_SS58_ADDRESS_FORMAT_NAMES + .binary_search(&x) + .map(|lookup| { + let (_, idx) = PREFIX_TO_INDEX[lookup]; + ALL_SS58_ADDRESS_FORMATS[idx] + }) + .map_err(|_| ParseError) + } +} + +#[cfg(feature = "std")] +impl std::fmt::Display for ParseError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "failed to parse network value as u16") + } +} + +#[cfg(feature = "std")] +impl From for String { + fn from(x: Ss58AddressFormat) -> String { + x.to_string() + } +} + +#[cfg(feature = "std")] +impl std::str::FromStr for KnownSs58AddressFormat { + type Err = ParseError; + + fn from_str(data: &str) -> Result { + TryFrom::try_from(data) + } +} From a8b5944eaded74b496399d1bbbb3d87d90bd5dad Mon Sep 17 00:00:00 2001 From: Giles Cope Date: Thu, 16 Sep 2021 13:56:42 +0100 Subject: [PATCH 09/28] Add in custom constructor --- src/lib.rs | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 6e2ba0d..dbd239d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -39,6 +39,11 @@ pub struct Ss58AddressFormat { /// An enumeration of unique networks. /// Some are reserved. impl Ss58AddressFormat { + /// Custom constructor + pub fn custom(prefix: u16) -> Self { + Ss58AddressFormat { prefix } + } + /// names of all address formats pub fn all_names() -> &'static [&'static str] { &ALL_SS58_ADDRESS_FORMAT_NAMES @@ -85,6 +90,16 @@ impl TryFrom for KnownSs58AddressFormat { } } +/// const function to convert Ss58AddressFormat to u16 +pub const fn from_address_format(x: Ss58AddressFormat) -> u16 { + x.prefix +} + +/// const function to convert Ss58AddressFormat to u16 +pub const fn from_known_address_format(x: KnownSs58AddressFormat) -> u16 { + x as u16 +} + impl From for Ss58AddressFormat { fn from(x: KnownSs58AddressFormat) -> Ss58AddressFormat { Ss58AddressFormat { prefix: x as u16 } @@ -103,17 +118,20 @@ impl From for u16 { } } -/// const function to convert Ss58AddressFormat to u16 -pub const fn from_address_format(x: Ss58AddressFormat) -> u16 { - x.prefix -} - impl From for Ss58AddressFormat { fn from(prefix: u16) -> Ss58AddressFormat { Ss58AddressFormat { prefix } } } +impl<'a> TryFrom<&'a str> for Ss58AddressFormat { + type Error = ParseError; + + fn try_from(x: &'a str) -> Result { + KnownSs58AddressFormat::try_from(x).map(|a| a.into()) + } +} + impl<'a> TryFrom<&'a str> for KnownSs58AddressFormat { type Error = ParseError; From 727a2db3807cdeb61b684d6a441bd9468a6283d1 Mon Sep 17 00:00:00 2001 From: Squirrel Date: Thu, 16 Sep 2021 14:21:22 +0100 Subject: [PATCH 10/28] Update src/lib.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bastian Köcher --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index dbd239d..7788972 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,7 +15,7 @@ #![warn(missing_docs)] -//! List of wellknown SS58 account types as an enum. +//! List of well-known SS58 account types as an enum. use core::convert::TryFrom; use sp_debug_derive::RuntimeDebug; From b1801d9a711cae967d2ce9db97bb2d3d004b374f Mon Sep 17 00:00:00 2001 From: Giles Cope Date: Thu, 16 Sep 2021 17:56:16 +0100 Subject: [PATCH 11/28] Check for valid rust idents --- Cargo.toml | 1 + build.rs | 58 ++++++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 44 insertions(+), 15 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ec1b114..0fce166 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,3 +20,4 @@ serde = { version = "1.0", default-features = false, features = [ serde_json = { version = "1.0", default-features = false, features = ["std"] } proc-macro2 = "1.0" Inflector = { version = "0.11.4", default-features = false } +unicode-xid = "0.2.2" diff --git a/build.rs b/build.rs index 886edb8..bc3324e 100644 --- a/build.rs +++ b/build.rs @@ -17,38 +17,65 @@ #![deny(missing_docs)] use quote::{format_ident, quote}; use serde::{self, Deserialize}; -use std::collections::HashSet; +use std::collections::HashMap; use std::env; use std::fs; use std::path::Path; +use unicode_xid::UnicodeXID; #[derive(Deserialize)] struct Registry { registry: Vec, } +fn is_valid_rust_identifier(id: &str) -> Result<(), String> { + if let Some(ch) = id.chars().next() { + if ch.is_xid_start() { + for ch in id.chars().skip(1) { + if !ch.is_xid_continue() { + return Err(format!("Invalid char `{}` in `{}`", ch, id)); + } + } + Ok(()) + } else { + Err(format!( + "`{}` starts with `{}` which is not valid at the start", + id, ch + )) + } + } else { + Err("empty identifier".into()) + } +} + impl Registry { pub fn is_valid(&self) -> Result<(), String> { - let mut used_prefixes = HashSet::::new(); - let mut used_networks = HashSet::::new(); - + let mut used_prefixes = HashMap::::new(); + let mut used_networks = HashMap::::new(); for account_type in &self.registry { - if !used_prefixes.insert(account_type.prefix) { + if let Some(clash) = used_prefixes.insert(account_type.prefix, (*account_type).clone()) + { return Err(format!( - "prefixes must be unique but this account's prefix clashes: {:#?}.", - account_type + "prefixes must be unique but this account's prefix:\n{:#?}\nclashed with\n{:#?}", + account_type, + clash )); } - if !used_networks.insert(account_type.network.clone()) { + if let Some(clash) = used_networks.insert(account_type.name(), account_type.clone()) { return Err(format!( - "networks must be unique but this account's network clashes: {:#?}.", - account_type + "networks must be unique but this account's network:\n{:#?}\nclashed with\n:{:#?}", + account_type, + clash )); } - if account_type.network.chars().any(|c| c.is_whitespace()) { + if account_type.network.is_empty() { + return Err("network is mandatory.".into()); + } + + if let Err(err) = is_valid_rust_identifier(&account_type.name()) { return Err(format!( - "network can not have whitespace in: {:?}", - account_type + "network not valid: {} for {:#?}", + err, account_type )); } if account_type.decimals.len() != account_type.symbols.len() { @@ -70,7 +97,7 @@ impl Registry { } } -#[derive(Deserialize, Debug)] +#[derive(Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] struct AccountType { prefix: u16, @@ -181,6 +208,7 @@ fn main() { }; let dest_path = Path::new(&out_dir).join("account_type_enum.rs"); - fs::write(&dest_path, result).unwrap(); + fs::write(&dest_path, result).unwrap_or_else(|_| panic!("failed to write to {:?}", &dest_path)); println!("cargo:rerun-if-changed=build.rs"); + println!("cargo:rerun-if-changed=ss58-registry.json"); } From 9e0c1cdd044a2e9cbc132541123d854e91950505 Mon Sep 17 00:00:00 2001 From: Giles Cope Date: Fri, 17 Sep 2021 09:03:17 +0100 Subject: [PATCH 12/28] fmt + added clover.finance (replicating https://github.com/paritytech/substrate/pull/9236 ) --- CHANGELOG.md | 4 +- Cargo.toml | 5 +- README.md | 18 +- ss58-registry.json | 1269 ++++++++++++++++++++++---------------------- 4 files changed, 651 insertions(+), 645 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8e428f5..c182d5c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,5 +2,5 @@ ## v0.1 Changes from inside substrate tree - * DEFAULT_VALUE now an AtomicU16 rather than a Mutex. Set with `set_default()` - * try_from(u16), try_from(u8) => from(u16) and from(u8) as the conversions are infallable. \ No newline at end of file +- DEFAULT_VALUE now an AtomicU16 rather than a Mutex. Set with `set_default()` +- try_from(u16), try_from(u8) => from(u16) and from(u8) as the conversions are infallable. diff --git a/Cargo.toml b/Cargo.toml index 0fce166..3747f0a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,10 +13,7 @@ sp-debug-derive = "3.0.0" [build-dependencies] quote = { version = "1.0.3", default-features = false } -serde = { version = "1.0", default-features = false, features = [ - "std", - "derive", -] } +serde = { version = "1.0", default-features = false, features = ["std", "derive"] } serde_json = { version = "1.0", default-features = false, features = ["std"] } proc-macro2 = "1.0" Inflector = { version = "0.11.4", default-features = false } diff --git a/README.md b/README.md index 8663e1a..eef50d7 100644 --- a/README.md +++ b/README.md @@ -5,15 +5,15 @@ List of wellknown [SS58](https://github.com/paritytech/substrate/wiki/External-A This is driven from the [json data file](src/ss58-registry.json) which contains entries like this: ```js - { - "prefix": 5, // unique u16 - "network": "plasm", // unique no spaces - "displayName": "Plasm Network", // - "symbols": ["PLM"], // symbol for each ballance pallet (usually one) - "decimals": [15], // decimals for each symbol listed. - "standardAccount": "*25519", // Sr25519, Ed25519 or secp256k1 - "website": "https://plasmnet.io" // website or github of network - }, +{ + "prefix": 5, // unique u16 + "network": "plasm", // unique no spaces + "displayName": "Plasm Network", // + "symbols": ["PLM"], // symbol for each ballance pallet (usually one) + "decimals": [15], // decimals for each symbol listed. + "standardAccount": "*25519", // Sr25519, Ed25519 or secp256k1 + "website": "https://plasmnet.io" // website or github of network +}, ``` (Typically used by the Polkadot, Kusama or Substrate ecosystems.) diff --git a/ss58-registry.json b/ss58-registry.json index bf1b95c..4aa71d4 100644 --- a/ss58-registry.json +++ b/ss58-registry.json @@ -1,635 +1,644 @@ { - "specification": "https://github.com/paritytech/substrate/wiki/External-Address-Format-(SS58)", - "schema": { - "prefix": "The address prefix. Must be an integer and unique.", - "network": "Unique identifier for the network that will use this prefix, string, no spaces. To integrate with CLI tools, e.g. `--network polkadot`.", - "displayName": "The name of the network that will use this prefix, in a format friendly for display.", - "symbols": "Array of symbols of any tokens the chain uses, usually 2-5 characters. Most chains will only have one. Chains that have multiple instances of the Balances pallet should order the array by instance.", - "decimals": "Array of integers representing the number of decimals that represent a single unit to the end user. Must be same length as `symbols` to represent each token's denomination.", - "standardAccount": "Signing curve for standard account. Substrate supports ed25519, sr25519, and secp256k1.", - "website": "A website or Github repo associated with the network." - }, - "registry": [ - { - "prefix": 0, - "network": "polkadot", - "displayName": "Polkadot Relay Chain", - "symbols": ["DOT"], - "decimals": [10], - "standardAccount": "*25519", - "website": "https://polkadot.network" - }, - { - "prefix": 1, - "network": "BareSr25519", - "displayName": "Bare 32-bit Schnorr/Ristretto (S/R 25519) public key.", - "symbols": [], - "decimals": [], - "standardAccount": "Sr25519", - "website": null - }, - { - "prefix": 2, - "network": "kusama", - "displayName": "Kusama Relay Chain", - "symbols": ["KSM"], - "decimals": [12], - "standardAccount": "*25519", - "website": "https://kusama.network" - }, - { - "prefix": 3, - "network": "BareEd25519", - "displayName": "Bare 32-bit Ed25519 public key.", - "symbols": [], - "decimals": [], - "standardAccount": "Ed25519", - "website": null - }, - { - "prefix": 4, - "network": "katalchain", - "displayName": "Katal Chain", - "symbols": [], - "decimals": [], - "standardAccount": "*25519", - "website": null - }, - { - "prefix": 5, - "network": "plasm", - "displayName": "Plasm Network", - "symbols": ["PLM"], - "decimals": [15], - "standardAccount": "*25519", - "website": "https://plasmnet.io" - }, - { - "prefix": 6, - "network": "bifrost", - "displayName": "Bifrost", - "symbols": ["BNC"], - "decimals": [12], - "standardAccount": "*25519", - "website": "https://bifrost.finance/" - }, - { - "prefix": 7, - "network": "edgeware", - "displayName": "Edgeware", - "symbols": ["EDG"], - "decimals": [18], - "standardAccount": "*25519", - "website": "https://edgewa.re" - }, - { - "prefix": 8, - "network": "karura", - "displayName": "Karura", - "symbols": ["KAR"], - "decimals": [12], - "standardAccount": "*25519", - "website": "https://karura.network/" - }, - { - "prefix": 9, - "network": "reynolds", - "displayName": "Laminar Reynolds Canary", - "symbols": ["REY"], - "decimals": [18], - "standardAccount": "*25519", - "website": "http://laminar.network/" - }, - { - "prefix": 10, - "network": "acala", - "displayName": "Acala", - "symbols": ["ACA"], - "decimals": [12], - "standardAccount": "*25519", - "website": "https://acala.network/" - }, - { - "prefix": 11, - "network": "laminar", - "displayName": "Laminar", - "symbols": ["LAMI"], - "decimals": [18], - "standardAccount": "*25519", - "website": "http://laminar.network/" - }, - { - "prefix": 12, - "network": "polymesh", - "displayName": "Polymesh", - "symbols": ["POLYX"], - "decimals": [6], - "standardAccount": "*25519", - "website": "https://polymath.network/" - }, - { - "prefix": 13, - "network": "integritee", - "displayName": "Integritee", - "symbols": ["TEER"], - "decimals": [12], - "standardAccount": "*25519", - "website": "https://integritee.network" - }, - { - "prefix": 14, - "network": "totem", - "displayName": "Totem", - "symbols": ["XTX"], - "decimals": [0], - "standardAccount": "*25519", - "website": "https://totemaccounting.com" - }, - { - "prefix": 15, - "network": "synesthesia", - "displayName": "Synesthesia", - "symbols": ["SYN"], - "decimals": [12], - "standardAccount": "*25519", - "website": "https://synesthesia.network/" - }, - { - "prefix": 16, - "network": "kulupu", - "displayName": "Kulupu", - "symbols": ["KLP"], - "decimals": [12], - "standardAccount": "*25519", - "website": "https://kulupu.network/" - }, - { - "prefix": 17, - "network": "dark", - "displayName": "Dark Mainnet", - "symbols": [], - "decimals": [], - "standardAccount": "*25519", - "website": null - }, - { - "prefix": 18, - "network": "darwinia", - "displayName": "Darwinia Network", - "symbols": ["RING", "KTON"], - "decimals": [9, 9], - "standardAccount": "*25519", - "website": "https://darwinia.network/" - }, - { - "prefix": 19, - "network": "geek", - "displayName": "GeekCash", - "symbols": ["GEEK"], - "decimals": [12], - "standardAccount": "*25519", - "website": "https://geekcash.org" - }, - { - "prefix": 20, - "network": "stafi", - "displayName": "Stafi", - "symbols": ["FIS"], - "decimals": [12], - "standardAccount": "*25519", - "website": "https://stafi.io" - }, - { - "prefix": 21, - "network": "dock-testnet", - "displayName": "Dock Testnet", - "symbols": ["DCK"], - "decimals": [6], - "standardAccount": "*25519", - "website": "https://dock.io" - }, - { - "prefix": 22, - "network": "dock-mainnet", - "displayName": "Dock Mainnet", - "symbols": ["DCK"], - "decimals": [6], - "standardAccount": "*25519", - "website": "https://dock.io" - }, - { - "prefix": 23, - "network": "shift", - "displayName": "ShiftNrg", - "symbols": [], - "decimals": [], - "standardAccount": "*25519", - "website": null - }, - { - "prefix": 24, - "network": "zero", - "displayName": "ZERO", - "symbols": ["PLAY"], - "decimals": [18], - "standardAccount": "*25519", - "website": "https://zero.io" - }, - { - "prefix": 25, - "network": "zero-alphaville", - "displayName": "ZERO Alphaville", - "symbols": ["PLAY"], - "decimals": [18], - "standardAccount": "*25519", - "website": "https://zero.io" - }, - { - "prefix": 26, - "network": "jupiter", - "displayName": "Jupiter", - "symbols": ["jDOT"], - "decimals": [10], - "standardAccount": "*25519", - "website": "https://jupiter.patract.io" - }, - { - "prefix": 28, - "network": "subsocial", - "displayName": "Subsocial", - "symbols": [], - "decimals": [], - "standardAccount": "*25519", - "website": null - }, - { - "prefix": 29, - "network": "cord", - "displayName": "Dhiway CORD Network", - "symbols": ["DCU"], - "decimals": [18], - "standardAccount": "*25519", - "website": "https://dhiway.com/" - }, - { - "prefix": 30, - "network": "phala", - "displayName": "Phala Network", - "symbols": ["PHA"], - "decimals": [12], - "standardAccount": "*25519", - "website": "https://phala.network" - }, - { - "prefix": 31, - "network": "litentry", - "displayName": "Litentry Network", - "symbols": ["LIT"], - "decimals": [12], - "standardAccount": "*25519", - "website": "https://litentry.com/" - }, - { - "prefix": 32, - "network": "robonomics", - "displayName": "Robonomics", - "symbols": ["XRT"], - "decimals": [9], - "standardAccount": "*25519", - "website": "https://robonomics.network" - }, - { - "prefix": 33, - "network": "datahighway", - "displayName": "DataHighway", - "symbols": [], - "decimals": [], - "standardAccount": "*25519", - "website": null - }, - { - "prefix": 34, - "network": "ares", - "displayName": "Ares Protocol", - "symbols": ["ARES"], - "decimals": [12], - "standardAccount": "*25519", - "website": "https://www.aresprotocol.com/" - }, - { - "prefix": 35, - "network": "vln", - "displayName": "Valiu Liquidity Network", - "symbols": ["USDv"], - "decimals": [15], - "standardAccount": "*25519", - "website": "https://valiu.com/" - }, - { - "prefix": 36, - "network": "centrifuge", - "displayName": "Centrifuge Chain", - "symbols": ["CFG"], - "decimals": [18], - "standardAccount": "*25519", - "website": "https://centrifuge.io/" - }, - { - "prefix": 37, - "network": "nodle", - "displayName": "Nodle Chain", - "symbols": ["NODL"], - "decimals": [18], - "standardAccount": "*25519", - "website": "https://nodle.io/" - }, - { - "prefix": 38, - "network": "kilt", - "displayName": "KILT Chain", - "symbols": ["KILT"], - "decimals": [18], - "standardAccount": "*25519", - "website": "https://kilt.io/" - }, - { - "prefix": 39, - "network": "mathchain", - "displayName": "MathChain mainnet", - "symbols": ["MATH"], - "decimals": [18], - "standardAccount": "*25519", - "website": "https://mathwallet.org" - }, - { - "prefix": 40, - "network": "mathchain-testnet", - "displayName": "MathChain testnet", - "symbols": ["MATH"], - "decimals": [18], - "standardAccount": "*25519", - "website": "https://mathwallet.org" - }, - { - "prefix": 41, - "network": "poli", - "displayName": "Polimec Chain", - "symbols": [], - "decimals": [], - "standardAccount": "*25519", - "website": "https://polimec.io/" - }, - { - "prefix": 42, - "network": "substrate", - "displayName": "Substrate", - "symbols": [], - "decimals": [], - "standardAccount": "*25519", - "website": "https://substrate.dev/" - }, - { - "prefix": 43, - "network": "BareSecp256k1", - "displayName": "Bare 32-bit ECDSA SECP-256k1 public key.", - "symbols": [], - "decimals": [], - "standardAccount": "secp256k1", - "website": null - }, - { - "prefix": 44, - "network": "chainx", - "displayName": "ChainX", - "symbols": ["PCX"], - "decimals": [8], - "standardAccount": "*25519", - "website": "https://chainx.org/" - }, - { - "prefix": 45, - "network": "uniarts", - "displayName": "UniArts Network", - "symbols": ["UART", "UINK"], - "decimals": [12, 12], - "standardAccount": "*25519", - "website": "https://uniarts.me" - }, - { - "prefix": 46, - "network": "reserved46", - "displayName": "This prefix is reserved.", - "symbols": [], - "decimals": [], - "standardAccount": null, - "website": null - }, - { - "prefix": 47, - "network": "reserved47", - "displayName": "This prefix is reserved.", - "symbols": [], - "decimals": [], - "standardAccount": null, - "website": null - }, - { - "prefix": 48, - "network": "neatcoin", - "displayName": "Neatcoin Mainnet", - "symbols": ["NEAT"], - "decimals": [12], - "standardAccount": "*25519", - "website": "https://neatcoin.org" - }, - { - "prefix": 49, - "network": "picasso", - "displayName": "Picasso", - "symbols": ["PICA"], - "decimals": [12], - "standardAccount": "*25519", - "website": "https://picasso.composable.finance" - }, - { - "prefix": 50, - "network": "composable", - "displayName": "Composable", - "symbols": ["LAYR"], - "decimals": [12], - "standardAccount": "*25519", - "website": "https://composable.finance" - }, - { - "prefix": 63, - "network": "hydradx", - "displayName": "HydraDX", - "symbols": ["HDX"], - "decimals": [12], - "standardAccount": "*25519", - "website": "https://hydradx.io" - }, - { - "prefix": 65, - "network": "aventus", - "displayName": "AvN Mainnet", - "symbols": ["AVT"], - "decimals": [18], - "standardAccount": "*25519", - "website": "https://aventus.io" - }, - { - "prefix": 66, - "network": "crust", - "displayName": "Crust Network", - "symbols": ["CRU"], - "decimals": [12], - "standardAccount": "*25519", - "website": "https://crust.network" - }, - { - "prefix": 67, - "network": "equilibrium", - "displayName": "Equilibrium Network", - "symbols": ["Unknown", "USD", "EQ", "ETH", "BTC", "EOS", "DOT", "CRV"], - "decimals": [0,9,9,9,9,9,9,9], - "standardAccount": "*25519", - "website": "https://equilibrium.io" - }, - { - "prefix": 69, - "network": "sora", - "displayName": "SORA Network", - "symbols": ["XOR"], - "decimals": [18], - "standardAccount": "*25519", - "website": "https://sora.org" + "specification": "https://github.com/paritytech/substrate/wiki/External-Address-Format-(SS58)", + "schema": { + "prefix": "The address prefix. Must be an integer and unique.", + "network": "Unique identifier for the network that will use this prefix, string, no spaces. To integrate with CLI tools, e.g. `--network polkadot`.", + "displayName": "The name of the network that will use this prefix, in a format friendly for display.", + "symbols": "Array of symbols of any tokens the chain uses, usually 2-5 characters. Most chains will only have one. Chains that have multiple instances of the Balances pallet should order the array by instance.", + "decimals": "Array of integers representing the number of decimals that represent a single unit to the end user. Must be same length as `symbols` to represent each token's denomination.", + "standardAccount": "Signing curve for standard account. Substrate supports ed25519, sr25519, and secp256k1.", + "website": "A website or Github repo associated with the network." + }, + "registry": [ + { + "prefix": 0, + "network": "polkadot", + "displayName": "Polkadot Relay Chain", + "symbols": ["DOT"], + "decimals": [10], + "standardAccount": "*25519", + "website": "https://polkadot.network" + }, + { + "prefix": 1, + "network": "BareSr25519", + "displayName": "Bare 32-bit Schnorr/Ristretto (S/R 25519) public key.", + "symbols": [], + "decimals": [], + "standardAccount": "Sr25519", + "website": null + }, + { + "prefix": 2, + "network": "kusama", + "displayName": "Kusama Relay Chain", + "symbols": ["KSM"], + "decimals": [12], + "standardAccount": "*25519", + "website": "https://kusama.network" + }, + { + "prefix": 3, + "network": "BareEd25519", + "displayName": "Bare 32-bit Ed25519 public key.", + "symbols": [], + "decimals": [], + "standardAccount": "Ed25519", + "website": null + }, + { + "prefix": 4, + "network": "katalchain", + "displayName": "Katal Chain", + "symbols": [], + "decimals": [], + "standardAccount": "*25519", + "website": null + }, + { + "prefix": 5, + "network": "plasm", + "displayName": "Plasm Network", + "symbols": ["PLM"], + "decimals": [15], + "standardAccount": "*25519", + "website": "https://plasmnet.io" + }, + { + "prefix": 6, + "network": "bifrost", + "displayName": "Bifrost", + "symbols": ["BNC"], + "decimals": [12], + "standardAccount": "*25519", + "website": "https://bifrost.finance/" + }, + { + "prefix": 7, + "network": "edgeware", + "displayName": "Edgeware", + "symbols": ["EDG"], + "decimals": [18], + "standardAccount": "*25519", + "website": "https://edgewa.re" + }, + { + "prefix": 8, + "network": "karura", + "displayName": "Karura", + "symbols": ["KAR"], + "decimals": [12], + "standardAccount": "*25519", + "website": "https://karura.network/" + }, + { + "prefix": 9, + "network": "reynolds", + "displayName": "Laminar Reynolds Canary", + "symbols": ["REY"], + "decimals": [18], + "standardAccount": "*25519", + "website": "http://laminar.network/" + }, + { + "prefix": 10, + "network": "acala", + "displayName": "Acala", + "symbols": ["ACA"], + "decimals": [12], + "standardAccount": "*25519", + "website": "https://acala.network/" + }, + { + "prefix": 11, + "network": "laminar", + "displayName": "Laminar", + "symbols": ["LAMI"], + "decimals": [18], + "standardAccount": "*25519", + "website": "http://laminar.network/" + }, + { + "prefix": 12, + "network": "polymesh", + "displayName": "Polymesh", + "symbols": ["POLYX"], + "decimals": [6], + "standardAccount": "*25519", + "website": "https://polymath.network/" + }, + { + "prefix": 13, + "network": "integritee", + "displayName": "Integritee", + "symbols": ["TEER"], + "decimals": [12], + "standardAccount": "*25519", + "website": "https://integritee.network" + }, + { + "prefix": 14, + "network": "totem", + "displayName": "Totem", + "symbols": ["XTX"], + "decimals": [0], + "standardAccount": "*25519", + "website": "https://totemaccounting.com" + }, + { + "prefix": 15, + "network": "synesthesia", + "displayName": "Synesthesia", + "symbols": ["SYN"], + "decimals": [12], + "standardAccount": "*25519", + "website": "https://synesthesia.network/" + }, + { + "prefix": 16, + "network": "kulupu", + "displayName": "Kulupu", + "symbols": ["KLP"], + "decimals": [12], + "standardAccount": "*25519", + "website": "https://kulupu.network/" + }, + { + "prefix": 17, + "network": "dark", + "displayName": "Dark Mainnet", + "symbols": [], + "decimals": [], + "standardAccount": "*25519", + "website": null + }, + { + "prefix": 18, + "network": "darwinia", + "displayName": "Darwinia Network", + "symbols": ["RING", "KTON"], + "decimals": [9, 9], + "standardAccount": "*25519", + "website": "https://darwinia.network/" + }, + { + "prefix": 19, + "network": "geek", + "displayName": "GeekCash", + "symbols": ["GEEK"], + "decimals": [12], + "standardAccount": "*25519", + "website": "https://geekcash.org" + }, + { + "prefix": 20, + "network": "stafi", + "displayName": "Stafi", + "symbols": ["FIS"], + "decimals": [12], + "standardAccount": "*25519", + "website": "https://stafi.io" + }, + { + "prefix": 21, + "network": "dock-testnet", + "displayName": "Dock Testnet", + "symbols": ["DCK"], + "decimals": [6], + "standardAccount": "*25519", + "website": "https://dock.io" + }, + { + "prefix": 22, + "network": "dock-mainnet", + "displayName": "Dock Mainnet", + "symbols": ["DCK"], + "decimals": [6], + "standardAccount": "*25519", + "website": "https://dock.io" + }, + { + "prefix": 23, + "network": "shift", + "displayName": "ShiftNrg", + "symbols": [], + "decimals": [], + "standardAccount": "*25519", + "website": null + }, + { + "prefix": 24, + "network": "zero", + "displayName": "ZERO", + "symbols": ["PLAY"], + "decimals": [18], + "standardAccount": "*25519", + "website": "https://zero.io" + }, + { + "prefix": 25, + "network": "zero-alphaville", + "displayName": "ZERO Alphaville", + "symbols": ["PLAY"], + "decimals": [18], + "standardAccount": "*25519", + "website": "https://zero.io" + }, + { + "prefix": 26, + "network": "jupiter", + "displayName": "Jupiter", + "symbols": ["jDOT"], + "decimals": [10], + "standardAccount": "*25519", + "website": "https://jupiter.patract.io" + }, + { + "prefix": 28, + "network": "subsocial", + "displayName": "Subsocial", + "symbols": [], + "decimals": [], + "standardAccount": "*25519", + "website": null + }, + { + "prefix": 29, + "network": "cord", + "displayName": "Dhiway CORD Network", + "symbols": ["DCU"], + "decimals": [18], + "standardAccount": "*25519", + "website": "https://dhiway.com/" + }, + { + "prefix": 30, + "network": "phala", + "displayName": "Phala Network", + "symbols": ["PHA"], + "decimals": [12], + "standardAccount": "*25519", + "website": "https://phala.network" + }, + { + "prefix": 31, + "network": "litentry", + "displayName": "Litentry Network", + "symbols": ["LIT"], + "decimals": [12], + "standardAccount": "*25519", + "website": "https://litentry.com/" + }, + { + "prefix": 32, + "network": "robonomics", + "displayName": "Robonomics", + "symbols": ["XRT"], + "decimals": [9], + "standardAccount": "*25519", + "website": "https://robonomics.network" + }, + { + "prefix": 33, + "network": "datahighway", + "displayName": "DataHighway", + "symbols": [], + "decimals": [], + "standardAccount": "*25519", + "website": null + }, + { + "prefix": 34, + "network": "ares", + "displayName": "Ares Protocol", + "symbols": ["ARES"], + "decimals": [12], + "standardAccount": "*25519", + "website": "https://www.aresprotocol.com/" + }, + { + "prefix": 35, + "network": "vln", + "displayName": "Valiu Liquidity Network", + "symbols": ["USDv"], + "decimals": [15], + "standardAccount": "*25519", + "website": "https://valiu.com/" + }, + { + "prefix": 36, + "network": "centrifuge", + "displayName": "Centrifuge Chain", + "symbols": ["CFG"], + "decimals": [18], + "standardAccount": "*25519", + "website": "https://centrifuge.io/" + }, + { + "prefix": 37, + "network": "nodle", + "displayName": "Nodle Chain", + "symbols": ["NODL"], + "decimals": [18], + "standardAccount": "*25519", + "website": "https://nodle.io/" + }, + { + "prefix": 38, + "network": "kilt", + "displayName": "KILT Chain", + "symbols": ["KILT"], + "decimals": [18], + "standardAccount": "*25519", + "website": "https://kilt.io/" + }, + { + "prefix": 39, + "network": "mathchain", + "displayName": "MathChain mainnet", + "symbols": ["MATH"], + "decimals": [18], + "standardAccount": "*25519", + "website": "https://mathwallet.org" + }, + { + "prefix": 40, + "network": "mathchain-testnet", + "displayName": "MathChain testnet", + "symbols": ["MATH"], + "decimals": [18], + "standardAccount": "*25519", + "website": "https://mathwallet.org" + }, + { + "prefix": 41, + "network": "poli", + "displayName": "Polimec Chain", + "symbols": [], + "decimals": [], + "standardAccount": "*25519", + "website": "https://polimec.io/" + }, + { + "prefix": 42, + "network": "substrate", + "displayName": "Substrate", + "symbols": [], + "decimals": [], + "standardAccount": "*25519", + "website": "https://substrate.dev/" + }, + { + "prefix": 43, + "network": "BareSecp256k1", + "displayName": "Bare 32-bit ECDSA SECP-256k1 public key.", + "symbols": [], + "decimals": [], + "standardAccount": "secp256k1", + "website": null + }, + { + "prefix": 44, + "network": "chainx", + "displayName": "ChainX", + "symbols": ["PCX"], + "decimals": [8], + "standardAccount": "*25519", + "website": "https://chainx.org/" + }, + { + "prefix": 45, + "network": "uniarts", + "displayName": "UniArts Network", + "symbols": ["UART", "UINK"], + "decimals": [12, 12], + "standardAccount": "*25519", + "website": "https://uniarts.me" + }, + { + "prefix": 46, + "network": "reserved46", + "displayName": "This prefix is reserved.", + "symbols": [], + "decimals": [], + "standardAccount": null, + "website": null + }, + { + "prefix": 47, + "network": "reserved47", + "displayName": "This prefix is reserved.", + "symbols": [], + "decimals": [], + "standardAccount": null, + "website": null + }, + { + "prefix": 48, + "network": "neatcoin", + "displayName": "Neatcoin Mainnet", + "symbols": ["NEAT"], + "decimals": [12], + "standardAccount": "*25519", + "website": "https://neatcoin.org" + }, + { + "prefix": 49, + "network": "picasso", + "displayName": "Picasso", + "symbols": ["PICA"], + "decimals": [12], + "standardAccount": "*25519", + "website": "https://picasso.composable.finance" + }, + { + "prefix": 50, + "network": "composable", + "displayName": "Composable", + "symbols": ["LAYR"], + "decimals": [12], + "standardAccount": "*25519", + "website": "https://composable.finance" + }, + { + "prefix": 63, + "network": "hydradx", + "displayName": "HydraDX", + "symbols": ["HDX"], + "decimals": [12], + "standardAccount": "*25519", + "website": "https://hydradx.io" + }, + { + "prefix": 65, + "network": "aventus", + "displayName": "AvN Mainnet", + "symbols": ["AVT"], + "decimals": [18], + "standardAccount": "*25519", + "website": "https://aventus.io" + }, + { + "prefix": 66, + "network": "crust", + "displayName": "Crust Network", + "symbols": ["CRU"], + "decimals": [12], + "standardAccount": "*25519", + "website": "https://crust.network" + }, + { + "prefix": 67, + "network": "equilibrium", + "displayName": "Equilibrium Network", + "symbols": ["Unknown", "USD", "EQ", "ETH", "BTC", "EOS", "DOT", "CRV"], + "decimals": [0, 9, 9, 9, 9, 9, 9, 9], + "standardAccount": "*25519", + "website": "https://equilibrium.io" + }, + { + "prefix": 69, + "network": "sora", + "displayName": "SORA Network", + "symbols": ["XOR"], + "decimals": [18], + "standardAccount": "*25519", + "website": "https://sora.org" }, { "prefix": 73, - "network": "zeitgeist", - "displayName": "Zeitgeist", - "symbols": ["ZTG"], - "decimals": [10], - "standardAccount": "*25519", - "website": "https://zeitgeist.pm" - }, - { - "prefix": 77, - "network": "manta", - "displayName": "Manta network", - "symbols": ["MA"], - "decimals": [12], - "standardAccount": "*25519", - "website": "https://manta.network" - }, - { - "prefix": 78, - "network": "calamari", - "displayName": "Calamari: Manta Canary Network", - "symbols": ["KMA"], - "decimals": [12], - "standardAccount": "*25519", - "website": "https://manta.network" - }, - { - "prefix": 98, - "network": "polkasmith", - "displayName": "PolkaSmith Canary Network", - "symbols": ["PKS"], - "decimals": [18], - "standardAccount": "*25519", - "website": "https://polkafoundry.com" - }, - { - "prefix": 99, - "network": "polkafoundry", - "displayName": "PolkaFoundry Network", - "symbols": ["PKF"], - "decimals": [18], - "standardAccount": "*25519", - "website": "https://polkafoundry.com" - }, - { - "prefix": 101, - "network": "origintrail-parachain", - "displayName": "OriginTrail Parachain", - "symbols": ["TRAC"], - "decimals": [18], - "standardAccount": "secp256k1", - "website": "https://origintrail.io" - }, - { - "prefix": 110, - "network": "heiko", - "displayName": "Heiko", - "symbols": ["HKO"], - "decimals": [12], - "standardAccount": "*25519", - "website": "https://parallel.fi/" - }, - { - "prefix": 113, - "network": "integritee-incognito", - "displayName": "Integritee Incognito", - "symbols": [], - "decimals": [], - "standardAccount": "*25519", - "website": "https://integritee.network" - }, - { - "prefix": 136, - "network": "altair", - "displayName": "Altair", - "symbols": ["AIR"], - "decimals": [18], - "standardAccount": "*25519", - "website": "https://centrifuge.io/" - }, - { - "prefix": 172, - "network": "parallel", - "displayName": "Parallel", - "symbols": ["PARA"], - "decimals": [12], - "standardAccount": "*25519", - "website": "https://parallel.fi/" - }, - { - "prefix": 252, - "network": "social-network", - "displayName": "Social Network", - "symbols": ["NET"], - "decimals": [18], - "standardAccount": "*25519", - "website": "https://social.network" - }, - { - "prefix": 1284, - "network": "moonbeam", - "displayName": "Moonbeam", - "symbols": ["GLMR"], - "decimals": [18], - "standardAccount": "secp256k1", - "website": "https://moonbeam.network" - }, - { - "prefix": 1285, - "network": "moonriver", - "displayName": "Moonriver", - "symbols": ["MOVR"], - "decimals": [18], - "standardAccount": "secp256k1", - "website": "https://moonbeam.network" - }, - { - "prefix": 10041, - "network": "basilisk", - "displayName": "Basilisk", - "symbols": ["BSX"], - "decimals": [12], - "standardAccount": "*25519", - "website": "https://bsx.fi" - } - ] + "network": "zeitgeist", + "displayName": "Zeitgeist", + "symbols": ["ZTG"], + "decimals": [10], + "standardAccount": "*25519", + "website": "https://zeitgeist.pm" + }, + { + "prefix": 77, + "network": "manta", + "displayName": "Manta network", + "symbols": ["MA"], + "decimals": [12], + "standardAccount": "*25519", + "website": "https://manta.network" + }, + { + "prefix": 78, + "network": "calamari", + "displayName": "Calamari: Manta Canary Network", + "symbols": ["KMA"], + "decimals": [12], + "standardAccount": "*25519", + "website": "https://manta.network" + }, + { + "prefix": 98, + "network": "polkasmith", + "displayName": "PolkaSmith Canary Network", + "symbols": ["PKS"], + "decimals": [18], + "standardAccount": "*25519", + "website": "https://polkafoundry.com" + }, + { + "prefix": 99, + "network": "polkafoundry", + "displayName": "PolkaFoundry Network", + "symbols": ["PKF"], + "decimals": [18], + "standardAccount": "*25519", + "website": "https://polkafoundry.com" + }, + { + "prefix": 101, + "network": "origintrail-parachain", + "displayName": "OriginTrail Parachain", + "symbols": ["TRAC"], + "decimals": [18], + "standardAccount": "secp256k1", + "website": "https://origintrail.io" + }, + { + "prefix": 110, + "network": "heiko", + "displayName": "Heiko", + "symbols": ["HKO"], + "decimals": [12], + "standardAccount": "*25519", + "website": "https://parallel.fi/" + }, + { + "prefix": 113, + "network": "integritee-incognito", + "displayName": "Integritee Incognito", + "symbols": [], + "decimals": [], + "standardAccount": "*25519", + "website": "https://integritee.network" + }, + { + "prefix": 128, + "network": "clover", + "displayName": "Clover Finance", + "symbols": ["CLV"], + "decimals": [18], + "standardAccount": "*25519", + "website": "https://clover.finance" + }, + { + "prefix": 136, + "network": "altair", + "displayName": "Altair", + "symbols": ["AIR"], + "decimals": [18], + "standardAccount": "*25519", + "website": "https://centrifuge.io/" + }, + { + "prefix": 172, + "network": "parallel", + "displayName": "Parallel", + "symbols": ["PARA"], + "decimals": [12], + "standardAccount": "*25519", + "website": "https://parallel.fi/" + }, + { + "prefix": 252, + "network": "social-network", + "displayName": "Social Network", + "symbols": ["NET"], + "decimals": [18], + "standardAccount": "*25519", + "website": "https://social.network" + }, + { + "prefix": 1284, + "network": "moonbeam", + "displayName": "Moonbeam", + "symbols": ["GLMR"], + "decimals": [18], + "standardAccount": "secp256k1", + "website": "https://moonbeam.network" + }, + { + "prefix": 1285, + "network": "moonriver", + "displayName": "Moonriver", + "symbols": ["MOVR"], + "decimals": [18], + "standardAccount": "secp256k1", + "website": "https://moonbeam.network" + }, + { + "prefix": 10041, + "network": "basilisk", + "displayName": "Basilisk", + "symbols": ["BSX"], + "decimals": [12], + "standardAccount": "*25519", + "website": "https://bsx.fi" + } + ] } From 13df58bb55c1a768721f0ff36bee3587655abb81 Mon Sep 17 00:00:00 2001 From: Squirrel Date: Tue, 28 Sep 2021 11:44:39 +0100 Subject: [PATCH 13/28] Update src/lib.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bastian Köcher --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 7788972..c23d47f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,7 +21,7 @@ use sp_debug_derive::RuntimeDebug; include!(concat!( env!("OUT_DIR"), - concat!("/", "account_type_enum", ".rs") + "/account_type_enum.rs" )); /// Error encountered while parsing `Ss58AddressFormat` from &'_ str From ba05969fcaa80eb9a06b90eb3b7e183b6c005e10 Mon Sep 17 00:00:00 2001 From: Squirrel Date: Tue, 28 Sep 2021 11:53:40 +0100 Subject: [PATCH 14/28] Update build.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bastian Köcher --- build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.rs b/build.rs index bc3324e..82c9da2 100644 --- a/build.rs +++ b/build.rs @@ -146,7 +146,7 @@ fn create_ss58_registry(json: &str) -> Result let number: Vec<_> = registry.iter().map(|r| r.prefix).collect(); let enumeration: Vec<_> = (0..registry.len()).collect(); - let mut prefix_to_idx: Vec<_> = number.iter().zip(enumeration).collect(); + let mut prefix_to_idx: Vec<_> = number.iter().enumerate().collect(); prefix_to_idx.sort_by_key(|(prefix, _)| *prefix); let prefix_to_idx = prefix_to_idx .iter() From 4843e35cae6421df637a7457ff3d8d500aa559f6 Mon Sep 17 00:00:00 2001 From: Squirrel Date: Tue, 28 Sep 2021 12:00:17 +0100 Subject: [PATCH 15/28] Update Cargo.toml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bastian Köcher --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 3747f0a..d9e6b7e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "ss58-registry" version = "0.0.1" edition = "2018" -description = "Registry of wellknown SS58 id types" +description = "Registry of wellknown SS58 addresses" [features] default = ["std"] From 0b3ddfcb511ca6efabf320d80044bc6a8eab1442 Mon Sep 17 00:00:00 2001 From: Squirrel Date: Tue, 28 Sep 2021 12:00:26 +0100 Subject: [PATCH 16/28] Update build.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bastian Köcher --- build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.rs b/build.rs index 82c9da2..bd2ecf8 100644 --- a/build.rs +++ b/build.rs @@ -202,7 +202,7 @@ fn create_ss58_registry(json: &str) -> Result fn main() { let out_dir = env::var_os("OUT_DIR").expect("OUT_DIR should exist"); - let result: String = match create_ss58_registry(include_str!("ss58-registry.json")) { + let result = match create_ss58_registry(include_str!("ss58-registry.json")) { Ok(result) => result.to_string(), Err(msg) => panic!("{}", msg), }; From b66285e21bba778877f3e2e256cccf59014a78e8 Mon Sep 17 00:00:00 2001 From: Giles Cope Date: Tue, 28 Sep 2021 12:09:38 +0100 Subject: [PATCH 17/28] Less dependencies - yay! --- Cargo.toml | 8 ++++---- build.rs | 10 +++++----- src/lib.rs | 11 +++-------- 3 files changed, 12 insertions(+), 17 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d9e6b7e..d5ea569 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,12 +8,12 @@ description = "Registry of wellknown SS58 addresses" default = ["std"] std = [] -[dependencies] -sp-debug-derive = "3.0.0" - [build-dependencies] quote = { version = "1.0.3", default-features = false } -serde = { version = "1.0", default-features = false, features = ["std", "derive"] } +serde = { version = "1.0", default-features = false, features = [ + "std", + "derive", +] } serde_json = { version = "1.0", default-features = false, features = ["std"] } proc-macro2 = "1.0" Inflector = { version = "0.11.4", default-features = false } diff --git a/build.rs b/build.rs index bd2ecf8..c43f346 100644 --- a/build.rs +++ b/build.rs @@ -14,6 +14,7 @@ // limitations under the License. //! List of wellknown SS58 account types as an enum. +#![allow(clippy::expect_fun_call)] #![deny(missing_docs)] use quote::{format_ident, quote}; use serde::{self, Deserialize}; @@ -144,15 +145,14 @@ fn create_ss58_registry(json: &str) -> Result let count = registry.len(); let number: Vec<_> = registry.iter().map(|r| r.prefix).collect(); - let enumeration: Vec<_> = (0..registry.len()).collect(); - let mut prefix_to_idx: Vec<_> = number.iter().enumerate().collect(); + let mut prefix_to_idx: Vec<_> = number.iter().enumerate().map(|(a, b)| (b, a)).collect(); prefix_to_idx.sort_by_key(|(prefix, _)| *prefix); let prefix_to_idx = prefix_to_idx .iter() .map(|(prefix, idx)| quote! { (#prefix, #idx) }); - let name: Vec<_> = registry.iter().map(|r| r.network.clone()).collect(); + let name = registry.iter().map(|r| r.network.clone()); let desc = registry.iter().map(|r| { if let Some(website) = &r.website { format!("{} - <{}>", r.display_name, website) @@ -166,7 +166,7 @@ fn create_ss58_registry(json: &str) -> Result /// A known address (sub)format/network ID for SS58. #[non_exhaustive] #[repr(u16)] - #[derive(Copy, Clone, PartialEq, Eq, crate::RuntimeDebug)] + #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum KnownSs58AddressFormat { #(#[doc = #desc] #identifier = #number),*, } @@ -208,7 +208,7 @@ fn main() { }; let dest_path = Path::new(&out_dir).join("account_type_enum.rs"); - fs::write(&dest_path, result).unwrap_or_else(|_| panic!("failed to write to {:?}", &dest_path)); + fs::write(&dest_path, result).expect(&format!("failed to write to {:?}", &dest_path)); println!("cargo:rerun-if-changed=build.rs"); println!("cargo:rerun-if-changed=ss58-registry.json"); } diff --git a/src/lib.rs b/src/lib.rs index c23d47f..a79aef2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,26 +12,21 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. - #![warn(missing_docs)] //! List of well-known SS58 account types as an enum. use core::convert::TryFrom; -use sp_debug_derive::RuntimeDebug; -include!(concat!( - env!("OUT_DIR"), - "/account_type_enum.rs" -)); +include!(concat!(env!("OUT_DIR"), "/account_type_enum.rs")); /// Error encountered while parsing `Ss58AddressFormat` from &'_ str /// unit struct for now. -#[derive(Copy, Clone, PartialEq, Eq, crate::RuntimeDebug)] +#[derive(Copy, Clone, PartialEq, Eq, Debug)] pub struct ParseError; /// A custom address format. See also KnownSs58AddressFormat #[non_exhaustive] -#[derive(Copy, Clone, PartialEq, Eq, crate::RuntimeDebug)] +#[derive(Copy, Clone, PartialEq, Eq, Debug)] pub struct Ss58AddressFormat { prefix: u16, } From 99d6203f476279e026ed0d81659b4bf42fbc791b Mon Sep 17 00:00:00 2001 From: Giles Cope Date: Tue, 28 Sep 2021 12:20:22 +0100 Subject: [PATCH 18/28] Explain why --- build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.rs b/build.rs index c43f346..c060af9 100644 --- a/build.rs +++ b/build.rs @@ -129,7 +129,7 @@ fn create_ss58_registry(json: &str) -> Result registry.is_valid()?; let mut registry = registry.registry; - // The names are assumed to be sorted. + // Sort by name so that we can later binary search by name registry.sort_by_key(|a| a.name()); // Variables to insert into quote template: From bd9b0af94c842a63de20b51649bead07beefdefe Mon Sep 17 00:00:00 2001 From: Giles Cope Date: Tue, 28 Sep 2021 13:10:03 +0100 Subject: [PATCH 19/28] Adding in polkadex (brought in from master merge on substrate PR) --- ss58-registry.json | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ss58-registry.json b/ss58-registry.json index 4aa71d4..f8e5ceb 100644 --- a/ss58-registry.json +++ b/ss58-registry.json @@ -532,6 +532,15 @@ "standardAccount": "*25519", "website": "https://manta.network" }, + { + "prefix": 88, + "network": "polkadex", + "displayName": "Polkadex Mainnet", + "symbols": ["PDEX"], + "decimals": [12], + "standardAccount": "*25519", + "website": "https://polkadex.trade" + }, { "prefix": 98, "network": "polkasmith", From 9817131f32b43e07c722e3b4ba10664a4cbc2b45 Mon Sep 17 00:00:00 2001 From: Giles Cope Date: Tue, 28 Sep 2021 13:16:36 +0100 Subject: [PATCH 20/28] We can use earlier version. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index d5ea569..1e03fda 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,4 +17,4 @@ serde = { version = "1.0", default-features = false, features = [ serde_json = { version = "1.0", default-features = false, features = ["std"] } proc-macro2 = "1.0" Inflector = { version = "0.11.4", default-features = false } -unicode-xid = "0.2.2" +unicode-xid = "0.2.0" From 30009c9dd5cb4b3e780d6a3c195ba3e57e09d326 Mon Sep 17 00:00:00 2001 From: Squirrel Date: Wed, 29 Sep 2021 11:36:29 +0100 Subject: [PATCH 21/28] Update build.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bastian Köcher --- build.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/build.rs b/build.rs index c060af9..605cbae 100644 --- a/build.rs +++ b/build.rs @@ -14,8 +14,6 @@ // limitations under the License. //! List of wellknown SS58 account types as an enum. -#![allow(clippy::expect_fun_call)] -#![deny(missing_docs)] use quote::{format_ident, quote}; use serde::{self, Deserialize}; use std::collections::HashMap; From d6216651d9d3a1a134ea78152130bad85e2454e8 Mon Sep 17 00:00:00 2001 From: Giles Cope Date: Thu, 30 Sep 2021 18:42:45 +0100 Subject: [PATCH 22/28] Added tests, benches, fixed bug. --- CHANGELOG.md | 1 - benches/benches.rs | 84 +++++++++++++++++++++++++++++++++++++++++++ build.rs | 79 ++++++++++++++++++++++++++++------------ src/lib.rs | 89 +++++++++++++++++++++++++++++++++------------- 4 files changed, 205 insertions(+), 48 deletions(-) create mode 100644 benches/benches.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index c182d5c..ad7cc0d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,5 +2,4 @@ ## v0.1 Changes from inside substrate tree -- DEFAULT_VALUE now an AtomicU16 rather than a Mutex. Set with `set_default()` - try_from(u16), try_from(u8) => from(u16) and from(u8) as the conversions are infallable. diff --git a/benches/benches.rs b/benches/benches.rs new file mode 100644 index 0000000..b8ed928 --- /dev/null +++ b/benches/benches.rs @@ -0,0 +1,84 @@ +#![feature(bench_black_box)] +#![feature(test)] +extern crate test; +use std::hint::black_box; + +use ss58_registry; +use test::Bencher; +static BENCH_SIZE: u16 = 100; +use ss58_registry::{from_address_format, Ss58AddressFormat, Ss58AddressFormatRegistry}; +use std::convert::TryInto; + +#[bench] +fn new(b: &mut Bencher) { + b.iter(|| { + for i in 0..BENCH_SIZE { + let _ = ss58_registry::Ss58AddressFormat::custom(black_box(i)); + } + }) +} + +#[bench] +fn is_custom(b: &mut Bencher) { + let v: Vec = (0..BENCH_SIZE) + .map(|i| ss58_registry::Ss58AddressFormat::custom(i)) + .collect(); + b.iter(|| { + for i in v.iter() { + let _ = i.is_custom(); + } + }) +} + +#[bench] +fn is_reserved(b: &mut Bencher) { + let v: Vec = (0..BENCH_SIZE) + .map(|i| ss58_registry::Ss58AddressFormat::custom(i)) + .collect(); + b.iter(|| { + for i in v.iter() { + let _ = i.is_reserved(); + } + }) +} + +#[bench] +fn to_string(b: &mut Bencher) { + let v: Vec = (0..BENCH_SIZE) + .map(|i| ss58_registry::Ss58AddressFormat::custom(i)) + .collect(); + b.iter(|| { + for i in v.iter() { + let _ = i.to_string(); + } + }) +} + +#[bench] +fn known_to_prefix(b: &mut Bencher) { + b.iter(|| { + for i in ss58_registry::Ss58AddressFormat::all() { + let i: Ss58AddressFormat = (*i).into(); + let _ii: u16 = from_address_format(i); + } + }) +} + +#[bench] +fn name_to_enum(b: &mut Bencher) { + b.iter(|| { + for name in ss58_registry::Ss58AddressFormat::all_names() { + let _: Ss58AddressFormatRegistry = (*name).try_into().expect(&format!("{}", name)); + } + }) +} + +#[bench] +fn prefix_to_known(b: &mut Bencher) { + b.iter(|| { + for i in 0_u16..100 { + let i: Ss58AddressFormat = i.into(); + let _: Result = i.try_into(); + } + }) +} diff --git a/build.rs b/build.rs index 605cbae..28f43e1 100644 --- a/build.rs +++ b/build.rs @@ -1,4 +1,4 @@ -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -122,13 +122,35 @@ impl AccountType { } } +fn consecutive_runs(data: &[u16]) -> (Vec, Vec) { + let mut slice_start = 0_u16; + let (mut starts, mut ends) = (Vec::new(), Vec::new()); + for i in 1..data.len() { + if data[i - 1] + 1 != data[i] { + starts.push(slice_start); + ends.push(data[(i - 1)]); + slice_start = data[i]; + } + } + if !data.is_empty() { + starts.push(slice_start); + ends.push(data[data.len() - 1]); + } + (starts, ends) +} + fn create_ss58_registry(json: &str) -> Result { - let registry: Registry = serde_json::from_str(json).expect("valid json file"); + let registry: Registry = + serde_json::from_str(json).map_err(|e| format!("json parsing error: {}", e))?; registry.is_valid()?; let mut registry = registry.registry; - // Sort by name so that we can later binary search by name - registry.sort_by_key(|a| a.name()); + + let mut ordered_prefixes = registry.iter().map(|i| i.prefix).collect::>(); + ordered_prefixes.sort_unstable(); + + // Sort by name so that we can later binary search by network + registry.sort_by_key(|a| a.network.clone()); // Variables to insert into quote template: let identifier: Vec<_> = registry @@ -136,15 +158,15 @@ fn create_ss58_registry(json: &str) -> Result .map(|r| format_ident!("{}", r.name())) .collect(); - let reserved_identifiers = registry + let reserved_prefixes = registry .iter() .filter(|r| r.is_reserved()) - .map(|r| format_ident!("{}", r.name())); + .map(|r| r.prefix); let count = registry.len(); - let number: Vec<_> = registry.iter().map(|r| r.prefix).collect(); + let prefix: Vec<_> = registry.iter().map(|r| r.prefix).collect(); - let mut prefix_to_idx: Vec<_> = number.iter().enumerate().map(|(a, b)| (b, a)).collect(); + let mut prefix_to_idx: Vec<_> = prefix.iter().enumerate().map(|(a, b)| (b, a)).collect(); prefix_to_idx.sort_by_key(|(prefix, _)| *prefix); let prefix_to_idx = prefix_to_idx .iter() @@ -159,22 +181,23 @@ fn create_ss58_registry(json: &str) -> Result } }); - Ok(quote! { + let (prefix_starts, prefix_ends) = consecutive_runs(ordered_prefixes.as_slice()); + Ok(quote! { /// A known address (sub)format/network ID for SS58. #[non_exhaustive] #[repr(u16)] #[derive(Copy, Clone, PartialEq, Eq, Debug)] - pub enum KnownSs58AddressFormat { - #(#[doc = #desc] #identifier = #number),*, + pub enum Ss58AddressFormatRegistry { + #(#[doc = #desc] #identifier = #prefix),*, } - /// All non-custom address formats (Sorted by name) - static ALL_SS58_ADDRESS_FORMATS: [KnownSs58AddressFormat; #count] = [ - #(KnownSs58AddressFormat::#identifier),*, + /// All non-custom address formats (Sorted by network) + static ALL_SS58_ADDRESS_FORMATS: [Ss58AddressFormatRegistry; #count] = [ + #(Ss58AddressFormatRegistry::#identifier),*, ]; - /// Names of all address formats (Sorted by name) + /// Names of all address formats (Sorted by network) static ALL_SS58_ADDRESS_FORMAT_NAMES: [&str; #count] = [ #(#name),*, ]; @@ -187,17 +210,23 @@ fn create_ss58_registry(json: &str) -> Result impl Ss58AddressFormat { /// Network/AddressType is reserved for future use. pub fn is_reserved(&self) -> bool { - if let Ok(known) = KnownSs58AddressFormat::try_from(*self) { - matches!(known, #(KnownSs58AddressFormat::#reserved_identifiers)|*) - } else { - false - } + self.prefix > 16384 || matches!(self.prefix, #(#reserved_prefixes)|*) + } + + /// A custom format is one that is not already known. + pub fn is_custom(&self) -> bool { + // A match is faster than bin search + // as most hits will be in the first group. + !matches!(self.prefix, #(#prefix_starts..=#prefix_ends)|*) } } }) } fn main() { + println!("cargo:rerun-if-changed=build.rs"); + println!("cargo:rerun-if-changed=ss58-registry.json"); + let out_dir = env::var_os("OUT_DIR").expect("OUT_DIR should exist"); let result = match create_ss58_registry(include_str!("ss58-registry.json")) { @@ -206,7 +235,11 @@ fn main() { }; let dest_path = Path::new(&out_dir).join("account_type_enum.rs"); - fs::write(&dest_path, result).expect(&format!("failed to write to {:?}", &dest_path)); - println!("cargo:rerun-if-changed=build.rs"); - println!("cargo:rerun-if-changed=ss58-registry.json"); + if let Err(err) = fs::write(&dest_path, result) { + eprintln!( + "failed to write generated code to {:?}: {}", + &dest_path, err + ); + std::process::exit(-1); + } } diff --git a/src/lib.rs b/src/lib.rs index a79aef2..0cca45e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -24,7 +24,7 @@ include!(concat!(env!("OUT_DIR"), "/account_type_enum.rs")); #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub struct ParseError; -/// A custom address format. See also KnownSs58AddressFormat +/// A custom address format. See also Ss58AddressFormatRegistry #[non_exhaustive] #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub struct Ss58AddressFormat { @@ -35,6 +35,7 @@ pub struct Ss58AddressFormat { /// Some are reserved. impl Ss58AddressFormat { /// Custom constructor + #[inline] pub fn custom(prefix: u16) -> Self { Ss58AddressFormat { prefix } } @@ -44,15 +45,8 @@ impl Ss58AddressFormat { &ALL_SS58_ADDRESS_FORMAT_NAMES } /// All known address formats. - pub fn all() -> &'static [KnownSs58AddressFormat] { - &ALL_SS58_ADDRESS_FORMATS[..] - } - - /// Whether the address is custom. - pub fn is_custom(&self) -> bool { - PREFIX_TO_INDEX - .binary_search_by_key(&self.prefix, |(prefix, _)| *prefix) - .is_err() + pub fn all() -> &'static [Ss58AddressFormatRegistry] { + &ALL_SS58_ADDRESS_FORMATS } } @@ -71,10 +65,21 @@ impl std::fmt::Display for Ss58AddressFormat { } } -impl TryFrom for KnownSs58AddressFormat { +#[cfg(feature = "std")] +impl std::fmt::Display for Ss58AddressFormatRegistry { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + let lookup = PREFIX_TO_INDEX + .binary_search_by_key(&from_known_address_format(*self), |(prefix, _)| *prefix) + .expect("always be found"); + let (_, idx) = PREFIX_TO_INDEX[lookup]; + write!(f, "{}", ALL_SS58_ADDRESS_FORMAT_NAMES[idx]) + } +} + +impl TryFrom for Ss58AddressFormatRegistry { type Error = ParseError; - fn try_from(x: Ss58AddressFormat) -> Result { + fn try_from(x: Ss58AddressFormat) -> Result { PREFIX_TO_INDEX .binary_search_by_key(&x.prefix, |(prefix, _)| *prefix) .map(|lookup| { @@ -91,29 +96,32 @@ pub const fn from_address_format(x: Ss58AddressFormat) -> u16 { } /// const function to convert Ss58AddressFormat to u16 -pub const fn from_known_address_format(x: KnownSs58AddressFormat) -> u16 { +pub const fn from_known_address_format(x: Ss58AddressFormatRegistry) -> u16 { x as u16 } -impl From for Ss58AddressFormat { - fn from(x: KnownSs58AddressFormat) -> Ss58AddressFormat { +impl From for Ss58AddressFormat { + fn from(x: Ss58AddressFormatRegistry) -> Ss58AddressFormat { Ss58AddressFormat { prefix: x as u16 } } } impl From for Ss58AddressFormat { + #[inline] fn from(x: u8) -> Ss58AddressFormat { Ss58AddressFormat::from(x as u16) } } impl From for u16 { + #[inline] fn from(x: Ss58AddressFormat) -> u16 { from_address_format(x) } } impl From for Ss58AddressFormat { + #[inline] fn from(prefix: u16) -> Ss58AddressFormat { Ss58AddressFormat { prefix } } @@ -123,20 +131,17 @@ impl<'a> TryFrom<&'a str> for Ss58AddressFormat { type Error = ParseError; fn try_from(x: &'a str) -> Result { - KnownSs58AddressFormat::try_from(x).map(|a| a.into()) + Ss58AddressFormatRegistry::try_from(x).map(|a| a.into()) } } -impl<'a> TryFrom<&'a str> for KnownSs58AddressFormat { +impl<'a> TryFrom<&'a str> for Ss58AddressFormatRegistry { type Error = ParseError; - fn try_from(x: &'a str) -> Result { + fn try_from(x: &'a str) -> Result { ALL_SS58_ADDRESS_FORMAT_NAMES .binary_search(&x) - .map(|lookup| { - let (_, idx) = PREFIX_TO_INDEX[lookup]; - ALL_SS58_ADDRESS_FORMATS[idx] - }) + .map(|lookup| ALL_SS58_ADDRESS_FORMATS[lookup]) .map_err(|_| ParseError) } } @@ -156,10 +161,46 @@ impl From for String { } #[cfg(feature = "std")] -impl std::str::FromStr for KnownSs58AddressFormat { +impl std::str::FromStr for Ss58AddressFormatRegistry { type Err = ParseError; fn from_str(data: &str) -> Result { TryFrom::try_from(data) } } + +#[cfg(test)] +mod tests { + use super::{Ss58AddressFormat, Ss58AddressFormatRegistry}; + use std::convert::TryInto; + + #[test] + fn is_reserved() { + let reserved: Ss58AddressFormat = Ss58AddressFormatRegistry::Reserved46Account.into(); + assert!(reserved.is_reserved()); + + let not_reserved: Ss58AddressFormat = Ss58AddressFormatRegistry::PolkadexAccount.into(); + assert!(!not_reserved.is_reserved()); + + assert!(!Ss58AddressFormat::custom(100).is_reserved()); + } + + #[test] + fn is_custom() { + assert!(Ss58AddressFormat::custom(432).is_custom()); + + let reserved: Ss58AddressFormat = Ss58AddressFormatRegistry::Reserved46Account.into(); + assert!(!reserved.is_custom()); + + let not_reserved: Ss58AddressFormat = Ss58AddressFormatRegistry::PolkadexAccount.into(); + assert!(!not_reserved.is_custom()); + } + + #[test] + fn enum_to_name_and_back() { + for name in Ss58AddressFormat::all_names() { + let val: Ss58AddressFormatRegistry = (*name).try_into().expect(&format!("{}", name)); + assert_eq!(name, &val.to_string()); + } + } +} From cfc01702d7985cf15811722afd6b96507cdf64b4 Mon Sep 17 00:00:00 2001 From: Squirrel Date: Fri, 1 Oct 2021 05:45:33 +0100 Subject: [PATCH 23/28] Update src/lib.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bastian Köcher --- src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 0cca45e..3fe3ca1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,7 +25,6 @@ include!(concat!(env!("OUT_DIR"), "/account_type_enum.rs")); pub struct ParseError; /// A custom address format. See also Ss58AddressFormatRegistry -#[non_exhaustive] #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub struct Ss58AddressFormat { prefix: u16, From 818f2b89b2b7b9d198bc60f91181f37df714ddd4 Mon Sep 17 00:00:00 2001 From: Squirrel Date: Fri, 1 Oct 2021 05:45:54 +0100 Subject: [PATCH 24/28] Update build.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bastian Köcher --- build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.rs b/build.rs index 28f43e1..8d54294 100644 --- a/build.rs +++ b/build.rs @@ -15,7 +15,7 @@ //! List of wellknown SS58 account types as an enum. use quote::{format_ident, quote}; -use serde::{self, Deserialize}; +use serde::Deserialize; use std::collections::HashMap; use std::env; use std::fs; From b1a33f72471594ed80b5f08a5bc03dca626ef14b Mon Sep 17 00:00:00 2001 From: Giles Cope Date: Fri, 1 Oct 2021 06:14:50 +0100 Subject: [PATCH 25/28] Use substrate rustfmt rules --- benches/benches.rs | 89 ++++++------ build.rs | 349 +++++++++++++++++++++------------------------ rustfmt.toml | 23 +++ src/lib.rs | 224 ++++++++++++++--------------- 4 files changed, 341 insertions(+), 344 deletions(-) create mode 100644 rustfmt.toml diff --git a/benches/benches.rs b/benches/benches.rs index b8ed928..9b4784a 100644 --- a/benches/benches.rs +++ b/benches/benches.rs @@ -11,74 +11,71 @@ use std::convert::TryInto; #[bench] fn new(b: &mut Bencher) { - b.iter(|| { - for i in 0..BENCH_SIZE { - let _ = ss58_registry::Ss58AddressFormat::custom(black_box(i)); - } - }) + b.iter(|| { + for i in 0..BENCH_SIZE { + let _ = ss58_registry::Ss58AddressFormat::custom(black_box(i)); + } + }) } #[bench] fn is_custom(b: &mut Bencher) { - let v: Vec = (0..BENCH_SIZE) - .map(|i| ss58_registry::Ss58AddressFormat::custom(i)) - .collect(); - b.iter(|| { - for i in v.iter() { - let _ = i.is_custom(); - } - }) + let v: Vec = + (0..BENCH_SIZE).map(|i| ss58_registry::Ss58AddressFormat::custom(i)).collect(); + b.iter(|| { + for i in v.iter() { + let _ = i.is_custom(); + } + }) } #[bench] fn is_reserved(b: &mut Bencher) { - let v: Vec = (0..BENCH_SIZE) - .map(|i| ss58_registry::Ss58AddressFormat::custom(i)) - .collect(); - b.iter(|| { - for i in v.iter() { - let _ = i.is_reserved(); - } - }) + let v: Vec = + (0..BENCH_SIZE).map(|i| ss58_registry::Ss58AddressFormat::custom(i)).collect(); + b.iter(|| { + for i in v.iter() { + let _ = i.is_reserved(); + } + }) } #[bench] fn to_string(b: &mut Bencher) { - let v: Vec = (0..BENCH_SIZE) - .map(|i| ss58_registry::Ss58AddressFormat::custom(i)) - .collect(); - b.iter(|| { - for i in v.iter() { - let _ = i.to_string(); - } - }) + let v: Vec = + (0..BENCH_SIZE).map(|i| ss58_registry::Ss58AddressFormat::custom(i)).collect(); + b.iter(|| { + for i in v.iter() { + let _ = i.to_string(); + } + }) } #[bench] fn known_to_prefix(b: &mut Bencher) { - b.iter(|| { - for i in ss58_registry::Ss58AddressFormat::all() { - let i: Ss58AddressFormat = (*i).into(); - let _ii: u16 = from_address_format(i); - } - }) + b.iter(|| { + for i in ss58_registry::Ss58AddressFormat::all() { + let i: Ss58AddressFormat = (*i).into(); + let _ii: u16 = from_address_format(i); + } + }) } #[bench] fn name_to_enum(b: &mut Bencher) { - b.iter(|| { - for name in ss58_registry::Ss58AddressFormat::all_names() { - let _: Ss58AddressFormatRegistry = (*name).try_into().expect(&format!("{}", name)); - } - }) + b.iter(|| { + for name in ss58_registry::Ss58AddressFormat::all_names() { + let _: Ss58AddressFormatRegistry = (*name).try_into().expect(&format!("{}", name)); + } + }) } #[bench] fn prefix_to_known(b: &mut Bencher) { - b.iter(|| { - for i in 0_u16..100 { - let i: Ss58AddressFormat = i.into(); - let _: Result = i.try_into(); - } - }) + b.iter(|| { + for i in 0_u16..100 { + let i: Ss58AddressFormat = i.into(); + let _: Result = i.try_into(); + } + }) } diff --git a/build.rs b/build.rs index 8d54294..fda1d11 100644 --- a/build.rs +++ b/build.rs @@ -16,230 +16,207 @@ //! List of wellknown SS58 account types as an enum. use quote::{format_ident, quote}; use serde::Deserialize; -use std::collections::HashMap; -use std::env; -use std::fs; -use std::path::Path; +use std::{collections::HashMap, env, fs, path::Path}; use unicode_xid::UnicodeXID; #[derive(Deserialize)] struct Registry { - registry: Vec, + registry: Vec, } fn is_valid_rust_identifier(id: &str) -> Result<(), String> { - if let Some(ch) = id.chars().next() { - if ch.is_xid_start() { - for ch in id.chars().skip(1) { - if !ch.is_xid_continue() { - return Err(format!("Invalid char `{}` in `{}`", ch, id)); - } - } - Ok(()) - } else { - Err(format!( - "`{}` starts with `{}` which is not valid at the start", - id, ch - )) - } - } else { - Err("empty identifier".into()) - } + if let Some(ch) = id.chars().next() { + if ch.is_xid_start() { + for ch in id.chars().skip(1) { + if !ch.is_xid_continue() { + return Err(format!("Invalid char `{}` in `{}`", ch, id)) + } + } + Ok(()) + } else { + Err(format!("`{}` starts with `{}` which is not valid at the start", id, ch)) + } + } else { + Err("empty identifier".into()) + } } impl Registry { - pub fn is_valid(&self) -> Result<(), String> { - let mut used_prefixes = HashMap::::new(); - let mut used_networks = HashMap::::new(); - for account_type in &self.registry { - if let Some(clash) = used_prefixes.insert(account_type.prefix, (*account_type).clone()) - { - return Err(format!( + pub fn is_valid(&self) -> Result<(), String> { + let mut used_prefixes = HashMap::::new(); + let mut used_networks = HashMap::::new(); + for account_type in &self.registry { + if let Some(clash) = used_prefixes.insert(account_type.prefix, (*account_type).clone()) + { + return Err(format!( "prefixes must be unique but this account's prefix:\n{:#?}\nclashed with\n{:#?}", account_type, clash )); - } - if let Some(clash) = used_networks.insert(account_type.name(), account_type.clone()) { - return Err(format!( + } + if let Some(clash) = used_networks.insert(account_type.name(), account_type.clone()) { + return Err(format!( "networks must be unique but this account's network:\n{:#?}\nclashed with\n:{:#?}", account_type, clash )); - } - if account_type.network.is_empty() { - return Err("network is mandatory.".into()); - } - - if let Err(err) = is_valid_rust_identifier(&account_type.name()) { - return Err(format!( - "network not valid: {} for {:#?}", - err, account_type - )); - } - if account_type.decimals.len() != account_type.symbols.len() { - return Err(format!( - "decimals must be specified for each symbol: {:?}", - account_type - )); - } - if let Some(sig_type) = &account_type.standard_account { - match sig_type.as_str() { + } + if account_type.network.is_empty() { + return Err("network is mandatory.".into()) + } + + if let Err(err) = is_valid_rust_identifier(&account_type.name()) { + return Err(format!("network not valid: {} for {:#?}", err, account_type)) + } + if account_type.decimals.len() != account_type.symbols.len() { + return Err(format!( + "decimals must be specified for each symbol: {:?}", + account_type + )) + } + if let Some(sig_type) = &account_type.standard_account { + match sig_type.as_str() { "Sr25519"| "Ed25519" | "secp256k1" | "*25519" => {}, _ => { return Err(format!("Unknown sig type in standardAccount: expected one of Sr25519, Ed25519, secp256k1, *25519: {:?}", account_type)) } } - } - } - Ok(()) - } + } + } + Ok(()) + } } #[derive(Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] struct AccountType { - prefix: u16, - network: String, - display_name: String, - /// If standard account is None then the network is reserved. - standard_account: Option, - symbols: Vec, - decimals: Vec, - website: Option, + prefix: u16, + network: String, + display_name: String, + /// If standard account is None then the network is reserved. + standard_account: Option, + symbols: Vec, + decimals: Vec, + website: Option, } impl AccountType { - fn name(&self) -> String { - format!( - "{}Account", - inflector::cases::pascalcase::to_pascal_case(&self.network) - ) - } - - fn is_reserved(&self) -> bool { - self.standard_account.is_none() - } + fn name(&self) -> String { + format!("{}Account", inflector::cases::pascalcase::to_pascal_case(&self.network)) + } + + fn is_reserved(&self) -> bool { + self.standard_account.is_none() + } } fn consecutive_runs(data: &[u16]) -> (Vec, Vec) { - let mut slice_start = 0_u16; - let (mut starts, mut ends) = (Vec::new(), Vec::new()); - for i in 1..data.len() { - if data[i - 1] + 1 != data[i] { - starts.push(slice_start); - ends.push(data[(i - 1)]); - slice_start = data[i]; - } - } - if !data.is_empty() { - starts.push(slice_start); - ends.push(data[data.len() - 1]); - } - (starts, ends) + let mut slice_start = 0_u16; + let (mut starts, mut ends) = (Vec::new(), Vec::new()); + for i in 1..data.len() { + if data[i - 1] + 1 != data[i] { + starts.push(slice_start); + ends.push(data[(i - 1)]); + slice_start = data[i]; + } + } + if !data.is_empty() { + starts.push(slice_start); + ends.push(data[data.len() - 1]); + } + (starts, ends) } fn create_ss58_registry(json: &str) -> Result { - let registry: Registry = - serde_json::from_str(json).map_err(|e| format!("json parsing error: {}", e))?; - registry.is_valid()?; - - let mut registry = registry.registry; - - let mut ordered_prefixes = registry.iter().map(|i| i.prefix).collect::>(); - ordered_prefixes.sort_unstable(); - - // Sort by name so that we can later binary search by network - registry.sort_by_key(|a| a.network.clone()); - - // Variables to insert into quote template: - let identifier: Vec<_> = registry - .iter() - .map(|r| format_ident!("{}", r.name())) - .collect(); - - let reserved_prefixes = registry - .iter() - .filter(|r| r.is_reserved()) - .map(|r| r.prefix); - - let count = registry.len(); - let prefix: Vec<_> = registry.iter().map(|r| r.prefix).collect(); - - let mut prefix_to_idx: Vec<_> = prefix.iter().enumerate().map(|(a, b)| (b, a)).collect(); - prefix_to_idx.sort_by_key(|(prefix, _)| *prefix); - let prefix_to_idx = prefix_to_idx - .iter() - .map(|(prefix, idx)| quote! { (#prefix, #idx) }); - - let name = registry.iter().map(|r| r.network.clone()); - let desc = registry.iter().map(|r| { - if let Some(website) = &r.website { - format!("{} - <{}>", r.display_name, website) - } else { - r.display_name.clone() - } - }); - - let (prefix_starts, prefix_ends) = consecutive_runs(ordered_prefixes.as_slice()); - - Ok(quote! { - /// A known address (sub)format/network ID for SS58. - #[non_exhaustive] - #[repr(u16)] - #[derive(Copy, Clone, PartialEq, Eq, Debug)] - pub enum Ss58AddressFormatRegistry { - #(#[doc = #desc] #identifier = #prefix),*, - } - - /// All non-custom address formats (Sorted by network) - static ALL_SS58_ADDRESS_FORMATS: [Ss58AddressFormatRegistry; #count] = [ - #(Ss58AddressFormatRegistry::#identifier),*, - ]; - - /// Names of all address formats (Sorted by network) - static ALL_SS58_ADDRESS_FORMAT_NAMES: [&str; #count] = [ - #(#name),*, - ]; - - /// (Sorted) prefixes to index of ALL_SS58_ADDRESS_FORMATS - static PREFIX_TO_INDEX: [(u16, usize); #count] = [ - #(#prefix_to_idx),*, - ]; - - impl Ss58AddressFormat { - /// Network/AddressType is reserved for future use. - pub fn is_reserved(&self) -> bool { - self.prefix > 16384 || matches!(self.prefix, #(#reserved_prefixes)|*) - } - - /// A custom format is one that is not already known. - pub fn is_custom(&self) -> bool { - // A match is faster than bin search - // as most hits will be in the first group. - !matches!(self.prefix, #(#prefix_starts..=#prefix_ends)|*) - } - } - }) + let registry: Registry = + serde_json::from_str(json).map_err(|e| format!("json parsing error: {}", e))?; + registry.is_valid()?; + + let mut registry = registry.registry; + + let mut ordered_prefixes = registry.iter().map(|i| i.prefix).collect::>(); + ordered_prefixes.sort_unstable(); + + // Sort by name so that we can later binary search by network + registry.sort_by_key(|a| a.network.clone()); + + // Variables to insert into quote template: + let identifier: Vec<_> = registry.iter().map(|r| format_ident!("{}", r.name())).collect(); + + let reserved_prefixes = registry.iter().filter(|r| r.is_reserved()).map(|r| r.prefix); + + let count = registry.len(); + let prefix: Vec<_> = registry.iter().map(|r| r.prefix).collect(); + + let mut prefix_to_idx: Vec<_> = prefix.iter().enumerate().map(|(a, b)| (b, a)).collect(); + prefix_to_idx.sort_by_key(|(prefix, _)| *prefix); + let prefix_to_idx = prefix_to_idx.iter().map(|(prefix, idx)| quote! { (#prefix, #idx) }); + + let name = registry.iter().map(|r| r.network.clone()); + let desc = registry.iter().map(|r| { + if let Some(website) = &r.website { + format!("{} - <{}>", r.display_name, website) + } else { + r.display_name.clone() + } + }); + + let (prefix_starts, prefix_ends) = consecutive_runs(ordered_prefixes.as_slice()); + + Ok(quote! { + /// A known address (sub)format/network ID for SS58. + #[non_exhaustive] + #[repr(u16)] + #[derive(Copy, Clone, PartialEq, Eq, Debug)] + pub enum Ss58AddressFormatRegistry { + #(#[doc = #desc] #identifier = #prefix),*, + } + + /// All non-custom address formats (Sorted by network) + static ALL_SS58_ADDRESS_FORMATS: [Ss58AddressFormatRegistry; #count] = [ + #(Ss58AddressFormatRegistry::#identifier),*, + ]; + + /// Names of all address formats (Sorted by network) + static ALL_SS58_ADDRESS_FORMAT_NAMES: [&str; #count] = [ + #(#name),*, + ]; + + /// (Sorted) prefixes to index of ALL_SS58_ADDRESS_FORMATS + static PREFIX_TO_INDEX: [(u16, usize); #count] = [ + #(#prefix_to_idx),*, + ]; + + impl Ss58AddressFormat { + /// Network/AddressType is reserved for future use. + pub fn is_reserved(&self) -> bool { + self.prefix > 16384 || matches!(self.prefix, #(#reserved_prefixes)|*) + } + + /// A custom format is one that is not already known. + pub fn is_custom(&self) -> bool { + // A match is faster than bin search + // as most hits will be in the first group. + !matches!(self.prefix, #(#prefix_starts..=#prefix_ends)|*) + } + } + }) } fn main() { - println!("cargo:rerun-if-changed=build.rs"); - println!("cargo:rerun-if-changed=ss58-registry.json"); - - let out_dir = env::var_os("OUT_DIR").expect("OUT_DIR should exist"); - - let result = match create_ss58_registry(include_str!("ss58-registry.json")) { - Ok(result) => result.to_string(), - Err(msg) => panic!("{}", msg), - }; - - let dest_path = Path::new(&out_dir).join("account_type_enum.rs"); - if let Err(err) = fs::write(&dest_path, result) { - eprintln!( - "failed to write generated code to {:?}: {}", - &dest_path, err - ); - std::process::exit(-1); - } + println!("cargo:rerun-if-changed=build.rs"); + println!("cargo:rerun-if-changed=ss58-registry.json"); + + let out_dir = env::var_os("OUT_DIR").expect("OUT_DIR should exist"); + + let result = match create_ss58_registry(include_str!("ss58-registry.json")) { + Ok(result) => result.to_string(), + Err(msg) => panic!("{}", msg), + }; + + let dest_path = Path::new(&out_dir).join("account_type_enum.rs"); + if let Err(err) = fs::write(&dest_path, result) { + eprintln!("failed to write generated code to {:?}: {}", &dest_path, err); + std::process::exit(-1); + } } diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..f4d7ad6 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,23 @@ +# Basic +hard_tabs = true +max_width = 100 +use_small_heuristics = "Max" +# Imports +imports_granularity = "Crate" +reorder_imports = true +# Consistency +newline_style = "Unix" +# Format comments +comment_width = 100 +wrap_comments = true +# Misc +chain_width = 80 +spaces_around_ranges = false +binop_separator = "Back" +reorder_impl_items = false +match_arm_leading_pipes = "Preserve" +match_arm_blocks = false +match_block_trailing_comma = true +trailing_comma = "Vertical" +trailing_semicolon = false +use_field_init_shorthand = true \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 3fe3ca1..adc4ac4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,179 +27,179 @@ pub struct ParseError; /// A custom address format. See also Ss58AddressFormatRegistry #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub struct Ss58AddressFormat { - prefix: u16, + prefix: u16, } /// An enumeration of unique networks. /// Some are reserved. impl Ss58AddressFormat { - /// Custom constructor - #[inline] - pub fn custom(prefix: u16) -> Self { - Ss58AddressFormat { prefix } - } - - /// names of all address formats - pub fn all_names() -> &'static [&'static str] { - &ALL_SS58_ADDRESS_FORMAT_NAMES - } - /// All known address formats. - pub fn all() -> &'static [Ss58AddressFormatRegistry] { - &ALL_SS58_ADDRESS_FORMATS - } + /// Custom constructor + #[inline] + pub fn custom(prefix: u16) -> Self { + Ss58AddressFormat { prefix } + } + + /// names of all address formats + pub fn all_names() -> &'static [&'static str] { + &ALL_SS58_ADDRESS_FORMAT_NAMES + } + /// All known address formats. + pub fn all() -> &'static [Ss58AddressFormatRegistry] { + &ALL_SS58_ADDRESS_FORMATS + } } /// Display the name of the address format (not the description). #[cfg(feature = "std")] impl std::fmt::Display for Ss58AddressFormat { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - if let Ok(lookup) = - PREFIX_TO_INDEX.binary_search_by_key(&self.prefix, |(prefix, _)| *prefix) - { - let (_, idx) = PREFIX_TO_INDEX[lookup]; - write!(f, "{}", ALL_SS58_ADDRESS_FORMAT_NAMES[idx]) - } else { - write!(f, "{}", self.prefix) - } - } + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + if let Ok(lookup) = + PREFIX_TO_INDEX.binary_search_by_key(&self.prefix, |(prefix, _)| *prefix) + { + let (_, idx) = PREFIX_TO_INDEX[lookup]; + write!(f, "{}", ALL_SS58_ADDRESS_FORMAT_NAMES[idx]) + } else { + write!(f, "{}", self.prefix) + } + } } #[cfg(feature = "std")] impl std::fmt::Display for Ss58AddressFormatRegistry { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - let lookup = PREFIX_TO_INDEX - .binary_search_by_key(&from_known_address_format(*self), |(prefix, _)| *prefix) - .expect("always be found"); - let (_, idx) = PREFIX_TO_INDEX[lookup]; - write!(f, "{}", ALL_SS58_ADDRESS_FORMAT_NAMES[idx]) - } + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + let lookup = PREFIX_TO_INDEX + .binary_search_by_key(&from_known_address_format(*self), |(prefix, _)| *prefix) + .expect("always be found"); + let (_, idx) = PREFIX_TO_INDEX[lookup]; + write!(f, "{}", ALL_SS58_ADDRESS_FORMAT_NAMES[idx]) + } } impl TryFrom for Ss58AddressFormatRegistry { - type Error = ParseError; + type Error = ParseError; - fn try_from(x: Ss58AddressFormat) -> Result { - PREFIX_TO_INDEX - .binary_search_by_key(&x.prefix, |(prefix, _)| *prefix) - .map(|lookup| { - let (_, idx) = PREFIX_TO_INDEX[lookup]; - ALL_SS58_ADDRESS_FORMATS[idx] - }) - .map_err(|_| ParseError) - } + fn try_from(x: Ss58AddressFormat) -> Result { + PREFIX_TO_INDEX + .binary_search_by_key(&x.prefix, |(prefix, _)| *prefix) + .map(|lookup| { + let (_, idx) = PREFIX_TO_INDEX[lookup]; + ALL_SS58_ADDRESS_FORMATS[idx] + }) + .map_err(|_| ParseError) + } } /// const function to convert Ss58AddressFormat to u16 pub const fn from_address_format(x: Ss58AddressFormat) -> u16 { - x.prefix + x.prefix } /// const function to convert Ss58AddressFormat to u16 pub const fn from_known_address_format(x: Ss58AddressFormatRegistry) -> u16 { - x as u16 + x as u16 } impl From for Ss58AddressFormat { - fn from(x: Ss58AddressFormatRegistry) -> Ss58AddressFormat { - Ss58AddressFormat { prefix: x as u16 } - } + fn from(x: Ss58AddressFormatRegistry) -> Ss58AddressFormat { + Ss58AddressFormat { prefix: x as u16 } + } } impl From for Ss58AddressFormat { - #[inline] - fn from(x: u8) -> Ss58AddressFormat { - Ss58AddressFormat::from(x as u16) - } + #[inline] + fn from(x: u8) -> Ss58AddressFormat { + Ss58AddressFormat::from(x as u16) + } } impl From for u16 { - #[inline] - fn from(x: Ss58AddressFormat) -> u16 { - from_address_format(x) - } + #[inline] + fn from(x: Ss58AddressFormat) -> u16 { + from_address_format(x) + } } impl From for Ss58AddressFormat { - #[inline] - fn from(prefix: u16) -> Ss58AddressFormat { - Ss58AddressFormat { prefix } - } + #[inline] + fn from(prefix: u16) -> Ss58AddressFormat { + Ss58AddressFormat { prefix } + } } impl<'a> TryFrom<&'a str> for Ss58AddressFormat { - type Error = ParseError; + type Error = ParseError; - fn try_from(x: &'a str) -> Result { - Ss58AddressFormatRegistry::try_from(x).map(|a| a.into()) - } + fn try_from(x: &'a str) -> Result { + Ss58AddressFormatRegistry::try_from(x).map(|a| a.into()) + } } impl<'a> TryFrom<&'a str> for Ss58AddressFormatRegistry { - type Error = ParseError; + type Error = ParseError; - fn try_from(x: &'a str) -> Result { - ALL_SS58_ADDRESS_FORMAT_NAMES - .binary_search(&x) - .map(|lookup| ALL_SS58_ADDRESS_FORMATS[lookup]) - .map_err(|_| ParseError) - } + fn try_from(x: &'a str) -> Result { + ALL_SS58_ADDRESS_FORMAT_NAMES + .binary_search(&x) + .map(|lookup| ALL_SS58_ADDRESS_FORMATS[lookup]) + .map_err(|_| ParseError) + } } #[cfg(feature = "std")] impl std::fmt::Display for ParseError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "failed to parse network value as u16") - } + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "failed to parse network value as u16") + } } #[cfg(feature = "std")] impl From for String { - fn from(x: Ss58AddressFormat) -> String { - x.to_string() - } + fn from(x: Ss58AddressFormat) -> String { + x.to_string() + } } #[cfg(feature = "std")] impl std::str::FromStr for Ss58AddressFormatRegistry { - type Err = ParseError; + type Err = ParseError; - fn from_str(data: &str) -> Result { - TryFrom::try_from(data) - } + fn from_str(data: &str) -> Result { + TryFrom::try_from(data) + } } #[cfg(test)] mod tests { - use super::{Ss58AddressFormat, Ss58AddressFormatRegistry}; - use std::convert::TryInto; - - #[test] - fn is_reserved() { - let reserved: Ss58AddressFormat = Ss58AddressFormatRegistry::Reserved46Account.into(); - assert!(reserved.is_reserved()); - - let not_reserved: Ss58AddressFormat = Ss58AddressFormatRegistry::PolkadexAccount.into(); - assert!(!not_reserved.is_reserved()); - - assert!(!Ss58AddressFormat::custom(100).is_reserved()); - } - - #[test] - fn is_custom() { - assert!(Ss58AddressFormat::custom(432).is_custom()); - - let reserved: Ss58AddressFormat = Ss58AddressFormatRegistry::Reserved46Account.into(); - assert!(!reserved.is_custom()); - - let not_reserved: Ss58AddressFormat = Ss58AddressFormatRegistry::PolkadexAccount.into(); - assert!(!not_reserved.is_custom()); - } - - #[test] - fn enum_to_name_and_back() { - for name in Ss58AddressFormat::all_names() { - let val: Ss58AddressFormatRegistry = (*name).try_into().expect(&format!("{}", name)); - assert_eq!(name, &val.to_string()); - } - } + use super::{Ss58AddressFormat, Ss58AddressFormatRegistry}; + use std::convert::TryInto; + + #[test] + fn is_reserved() { + let reserved: Ss58AddressFormat = Ss58AddressFormatRegistry::Reserved46Account.into(); + assert!(reserved.is_reserved()); + + let not_reserved: Ss58AddressFormat = Ss58AddressFormatRegistry::PolkadexAccount.into(); + assert!(!not_reserved.is_reserved()); + + assert!(!Ss58AddressFormat::custom(100).is_reserved()); + } + + #[test] + fn is_custom() { + assert!(Ss58AddressFormat::custom(432).is_custom()); + + let reserved: Ss58AddressFormat = Ss58AddressFormatRegistry::Reserved46Account.into(); + assert!(!reserved.is_custom()); + + let not_reserved: Ss58AddressFormat = Ss58AddressFormatRegistry::PolkadexAccount.into(); + assert!(!not_reserved.is_custom()); + } + + #[test] + fn enum_to_name_and_back() { + for name in Ss58AddressFormat::all_names() { + let val: Ss58AddressFormatRegistry = (*name).try_into().expect(&format!("{}", name)); + assert_eq!(name, &val.to_string()); + } + } } From dfde1ad432b850ceb9a1ef40b6fa4db80530c1a1 Mon Sep 17 00:00:00 2001 From: Giles Cope Date: Fri, 1 Oct 2021 06:25:25 +0100 Subject: [PATCH 26/28] Make error handling regular --- build.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/build.rs b/build.rs index fda1d11..d7f24fa 100644 --- a/build.rs +++ b/build.rs @@ -211,7 +211,10 @@ fn main() { let result = match create_ss58_registry(include_str!("ss58-registry.json")) { Ok(result) => result.to_string(), - Err(msg) => panic!("{}", msg), + Err(msg) => { + eprintln!("failed to generate code from json: {}", &msg); + std::process::exit(-1); + }, }; let dest_path = Path::new(&out_dir).join("account_type_enum.rs"); From f239923aa43749c5d6e85d038007c8317875acb3 Mon Sep 17 00:00:00 2001 From: Giles Cope Date: Sun, 3 Oct 2021 17:29:30 +0100 Subject: [PATCH 27/28] substrate is on nightly --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 508ddbe..72070b5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,7 +21,7 @@ jobs: uses: actions-rs/toolchain@v1.0.7 with: profile: minimal - toolchain: stable + toolchain: nightly override: true components: clippy, rustfmt From 1d175887d651ff2948136597656b752950e67233 Mon Sep 17 00:00:00 2001 From: Giles Cope Date: Mon, 4 Oct 2021 09:59:28 +0100 Subject: [PATCH 28/28] Use stable sort because it doesn't make too much difference. --- build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.rs b/build.rs index d7f24fa..8cedbc7 100644 --- a/build.rs +++ b/build.rs @@ -135,7 +135,7 @@ fn create_ss58_registry(json: &str) -> Result let mut registry = registry.registry; let mut ordered_prefixes = registry.iter().map(|i| i.prefix).collect::>(); - ordered_prefixes.sort_unstable(); + ordered_prefixes.sort(); // Sort by name so that we can later binary search by network registry.sort_by_key(|a| a.network.clone());