Switch to using ss58-registry crate (#9755)

* Switch to using ss58-registry crate
* Custom(42) is now eq to Substrate

Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>

Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com>
This commit is contained in:
Squirrel
2021-10-12 09:54:40 +01:00
committed by GitHub
parent 8f8b08871f
commit 98c157886c
7 changed files with 74 additions and 304 deletions
+15
View File
@@ -9269,6 +9269,7 @@ dependencies = [
"sp-serializer",
"sp-std",
"sp-storage",
"ss58-registry",
"substrate-bip39",
"thiserror",
"tiny-bip39",
@@ -9783,6 +9784,20 @@ version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
[[package]]
name = "ss58-registry"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef2413ecc7946ca99368862851dc1359f1477bc654ecfb135cf3efcb85ceca5f"
dependencies = [
"Inflector",
"proc-macro2",
"quote",
"serde",
"serde_json",
"unicode-xid",
]
[[package]]
name = "stable_deref_trait"
version = "1.2.0"
+7 -4
View File
@@ -23,7 +23,10 @@ use crate::{
};
use serde_json::json;
use sp_core::{
crypto::{ExposeSecret, SecretString, Ss58AddressFormat, Ss58Codec, Zeroize},
crypto::{
unwrap_or_default_ss58_version, ExposeSecret, SecretString, Ss58AddressFormat, Ss58Codec,
Zeroize,
},
hexdisplay::HexDisplay,
Pair,
};
@@ -72,7 +75,7 @@ pub fn print_from_uri<Pair>(
let password = password.as_ref().map(|s| s.expose_secret().as_str());
if let Ok((pair, seed)) = Pair::from_phrase(uri, password.clone()) {
let public_key = pair.public();
let network_override = network_override.unwrap_or_default();
let network_override = unwrap_or_default_ss58_version(network_override);
match output {
OutputType::Json => {
@@ -108,7 +111,7 @@ pub fn print_from_uri<Pair>(
}
} else if let Ok((pair, seed)) = Pair::from_string_with_seed(uri, password.clone()) {
let public_key = pair.public();
let network_override = network_override.unwrap_or_default();
let network_override = unwrap_or_default_ss58_version(network_override);
match output {
OutputType::Json => {
@@ -198,7 +201,7 @@ where
let public_key = Pair::Public::try_from(&public)
.map_err(|_| "Failed to construct public key from given hex")?;
let network_override = network_override.unwrap_or_default();
let network_override = unwrap_or_default_ss58_version(network_override);
match output {
OutputType::Json => {
+14 -6
View File
@@ -22,7 +22,7 @@ use crate::{
error, utils, with_crypto_scheme, CryptoSchemeFlag, NetworkSchemeFlag, OutputTypeFlag,
};
use rand::{rngs::OsRng, RngCore};
use sp_core::crypto::{Ss58AddressFormat, Ss58Codec};
use sp_core::crypto::{unwrap_or_default_ss58_version, Ss58AddressFormat, Ss58Codec};
use sp_runtime::traits::IdentifyAccount;
use structopt::StructOpt;
use utils::print_from_uri;
@@ -53,7 +53,10 @@ impl VanityCmd {
pub fn run(&self) -> error::Result<()> {
let formated_seed = with_crypto_scheme!(
self.crypto_scheme.scheme,
generate_key(&self.pattern, self.network_scheme.network.clone().unwrap_or_default()),
generate_key(
&self.pattern,
unwrap_or_default_ss58_version(self.network_scheme.network)
),
)?;
with_crypto_scheme!(
@@ -159,7 +162,10 @@ fn assert_non_empty_string(pattern: &str) -> Result<String, &'static str> {
#[cfg(test)]
mod tests {
use super::*;
use sp_core::{crypto::Ss58Codec, sr25519, Pair};
use sp_core::{
crypto::{default_ss58_version, Ss58AddressFormatRegistry, Ss58Codec},
sr25519, Pair,
};
use structopt::StructOpt;
#[cfg(feature = "bench")]
use test::Bencher;
@@ -172,7 +178,7 @@ mod tests {
#[test]
fn test_generation_with_single_char() {
let seed = generate_key::<sr25519::Pair>("ab", Default::default()).unwrap();
let seed = generate_key::<sr25519::Pair>("ab", default_ss58_version()).unwrap();
assert!(sr25519::Pair::from_seed_slice(&hex::decode(&seed[2..]).unwrap())
.unwrap()
.public()
@@ -182,11 +188,13 @@ mod tests {
#[test]
fn generate_key_respects_network_override() {
let seed = generate_key::<sr25519::Pair>("ab", Ss58AddressFormat::PolkadotAccount).unwrap();
let seed =
generate_key::<sr25519::Pair>("ab", Ss58AddressFormatRegistry::PolkadotAccount.into())
.unwrap();
assert!(sr25519::Pair::from_seed_slice(&hex::decode(&seed[2..]).unwrap())
.unwrap()
.public()
.to_ss58check_with_version(Ss58AddressFormat::PolkadotAccount)
.to_ss58check_with_version(Ss58AddressFormatRegistry::PolkadotAccount.into())
.contains("ab"));
}
+1 -1
View File
@@ -66,7 +66,7 @@ hex = { version = "0.4", default-features = false, optional = true }
twox-hash = { version = "1.6.1", default-features = false, optional = true }
libsecp256k1 = { version = "0.6", default-features = false, features = ["hmac", "static-context"], optional = true }
merlin = { version = "2.0", default-features = false, optional = true }
ss58-registry = "1.0.0"
sp-runtime-interface = { version = "4.0.0-dev", default-features = false, path = "../runtime-interface" }
[dev-dependencies]
+26 -283
View File
@@ -26,8 +26,6 @@ use crate::{ed25519, sr25519};
use base58::{FromBase58, ToBase58};
use codec::{Decode, Encode, MaxEncodedLen};
#[cfg(feature = "std")]
use parking_lot::Mutex;
#[cfg(feature = "std")]
use rand::{rngs::OsRng, RngCore};
#[cfg(feature = "std")]
use regex::Regex;
@@ -38,14 +36,15 @@ pub use secrecy::ExposeSecret;
#[cfg(feature = "std")]
pub use secrecy::SecretString;
use sp_runtime_interface::pass_by::PassByInner;
#[cfg(feature = "std")]
use sp_std::convert::TryInto;
#[doc(hidden)]
pub use sp_std::ops::Deref;
use sp_std::{convert::TryFrom, hash::Hash, str, vec::Vec};
/// Trait to zeroize a memory buffer.
pub use zeroize::Zeroize;
#[cfg(feature = "full_crypto")]
pub use ss58_registry::{from_known_address_format, Ss58AddressFormat, Ss58AddressFormatRegistry};
/// The root phrase for our publicly known keys.
pub const DEV_PHRASE: &str =
"bottom drive obey lake curtain smoke basket hold race lonely fit walk";
@@ -227,7 +226,7 @@ pub trait Ss58Codec: Sized + AsMut<[u8]> + AsRef<[u8]> + Default {
/// A format filterer, can be used to ensure that `from_ss58check` family only decode for
/// allowed identifiers. By default just refuses the two reserved identifiers.
fn format_is_allowed(f: Ss58AddressFormat) -> bool {
!matches!(f, Ss58AddressFormat::Reserved46 | Ss58AddressFormat::Reserved47)
!f.is_reserved()
}
/// Some if the string is a properly encoded SS58Check address.
@@ -235,7 +234,7 @@ pub trait Ss58Codec: Sized + AsMut<[u8]> + AsRef<[u8]> + Default {
fn from_ss58check(s: &str) -> Result<Self, PublicError> {
Self::from_ss58check_with_version(s).and_then(|(r, v)| match v {
v if !v.is_custom() => Ok(r),
v if v == *DEFAULT_VERSION.lock() => Ok(r),
v if v == default_ss58_version() => Ok(r),
_ => Err(PublicError::UnknownVersion),
})
}
@@ -270,7 +269,7 @@ pub trait Ss58Codec: Sized + AsMut<[u8]> + AsRef<[u8]> + Default {
if data.len() != prefix_len + body_len + CHECKSUM_LEN {
return Err(PublicError::BadLength)
}
let format = ident.try_into().map_err(|_: ()| PublicError::UnknownVersion)?;
let format = ident.into();
if !Self::format_is_allowed(format) {
return Err(PublicError::FormatNotAllowed)
}
@@ -291,7 +290,7 @@ pub trait Ss58Codec: Sized + AsMut<[u8]> + AsRef<[u8]> + Default {
fn from_string(s: &str) -> Result<Self, PublicError> {
Self::from_string_with_version(s).and_then(|(r, v)| match v {
v if !v.is_custom() => Ok(r),
v if v == *DEFAULT_VERSION.lock() => Ok(r),
v if v == default_ss58_version() => Ok(r),
_ => Err(PublicError::UnknownVersion),
})
}
@@ -322,7 +321,7 @@ pub trait Ss58Codec: Sized + AsMut<[u8]> + AsRef<[u8]> + Default {
/// Return the ss58-check string for this key.
#[cfg(feature = "std")]
fn to_ss58check(&self) -> String {
self.to_ss58check_with_version(*DEFAULT_VERSION.lock())
self.to_ss58check_with_version(default_ss58_version())
}
/// Some if the string is a properly encoded SS58Check address, optionally with
@@ -355,286 +354,30 @@ fn ss58hash(data: &[u8]) -> blake2_rfc::blake2b::Blake2bResult {
context.finalize()
}
/// Default prefix number
#[cfg(feature = "std")]
lazy_static::lazy_static! {
static ref DEFAULT_VERSION: Mutex<Ss58AddressFormat>
= Mutex::new(Ss58AddressFormat::SubstrateAccount);
}
#[cfg(feature = "full_crypto")]
macro_rules! ss58_address_format {
( $( $identifier:tt => ($number:expr, $name:expr, $desc:tt) )* ) => (
/// 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),
}
#[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),
}
}
}
static ALL_SS58_ADDRESS_FORMATS: [Ss58AddressFormat; 0 $(+ { let _ = $number; 1})*] = [
$(Ss58AddressFormat::$identifier),*,
];
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(_))
}
}
impl TryFrom<u8> for Ss58AddressFormat {
type Error = ();
fn try_from(x: u8) -> Result<Ss58AddressFormat, ()> {
Ss58AddressFormat::try_from(x as u16)
}
}
impl From<Ss58AddressFormat> for u16 {
fn from(x: Ss58AddressFormat) -> u16 {
match x {
$(Ss58AddressFormat::$identifier => $number),*,
Ss58AddressFormat::Custom(n) => n,
}
}
}
impl TryFrom<u16> for Ss58AddressFormat {
type Error = ();
fn try_from(x: u16) -> Result<Ss58AddressFormat, ()> {
match x {
$($number => Ok(Ss58AddressFormat::$identifier)),*,
_ => Ok(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> TryFrom<&'a str> for Ss58AddressFormat {
type Error = ParseError;
fn try_from(x: &'a str) -> Result<Ss58AddressFormat, Self::Error> {
match x {
$($name => Ok(Ss58AddressFormat::$identifier)),*,
a => a.parse::<u16>().map(Ss58AddressFormat::Custom).map_err(|_| ParseError),
}
}
}
#[cfg(feature = "std")]
impl std::str::FromStr for Ss58AddressFormat {
type Err = ParseError;
fn from_str(data: &str) -> Result<Self, Self::Err> {
Self::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 u8")
}
}
#[cfg(feature = "std")]
impl Default for Ss58AddressFormat {
fn default() -> Self {
*DEFAULT_VERSION.lock()
}
}
#[cfg(feature = "std")]
impl From<Ss58AddressFormat> for String {
fn from(x: Ss58AddressFormat) -> String {
x.to_string()
}
}
)
}
#[cfg(feature = "full_crypto")]
ss58_address_format!(
PolkadotAccount =>
(0, "polkadot", "Polkadot Relay-chain, standard account (*25519).")
BareSr25519 =>
(1, "sr25519", "Bare 32-bit Schnorr/Ristretto 25519 (S/R 25519) key.")
KusamaAccount =>
(2, "kusama", "Kusama Relay-chain, standard account (*25519).")
BareEd25519 =>
(3, "ed25519", "Bare 32-bit Edwards Ed25519 key.")
KatalChainAccount =>
(4, "katalchain", "Katal Chain, standard account (*25519).")
PlasmAccount =>
(5, "plasm", "Plasm Network, standard account (*25519).")
BifrostAccount =>
(6, "bifrost", "Bifrost mainnet, direct checksum, standard account (*25519).")
EdgewareAccount =>
(7, "edgeware", "Edgeware mainnet, standard account (*25519).")
KaruraAccount =>
(8, "karura", "Acala Karura canary network, standard account (*25519).")
ReynoldsAccount =>
(9, "reynolds", "Laminar Reynolds canary network, standard account (*25519).")
AcalaAccount =>
(10, "acala", "Acala mainnet, standard account (*25519).")
LaminarAccount =>
(11, "laminar", "Laminar mainnet, standard account (*25519).")
PolymathAccount =>
(12, "polymath", "Polymath network, standard account (*25519).")
SubstraTeeAccount =>
(13, "substratee", "Any SubstraTEE off-chain network private account (*25519).")
TotemAccount =>
(14, "totem", "Any Totem Live Accounting network standard account (*25519).")
SynesthesiaAccount =>
(15, "synesthesia", "Synesthesia mainnet, standard account (*25519).")
KulupuAccount =>
(16, "kulupu", "Kulupu mainnet, standard account (*25519).")
DarkAccount =>
(17, "dark", "Dark mainnet, standard account (*25519).")
DarwiniaAccount =>
(18, "darwinia", "Darwinia Chain mainnet, standard account (*25519).")
GeekAccount =>
(19, "geek", "GeekCash mainnet, standard account (*25519).")
StafiAccount =>
(20, "stafi", "Stafi mainnet, standard account (*25519).")
DockTestAccount =>
(21, "dock-testnet", "Dock testnet, standard account (*25519).")
DockMainAccount =>
(22, "dock-mainnet", "Dock mainnet, standard account (*25519).")
ShiftNrg =>
(23, "shift", "ShiftNrg mainnet, standard account (*25519).")
ZeroAccount =>
(24, "zero", "ZERO mainnet, standard account (*25519).")
AlphavilleAccount =>
(25, "alphaville", "ZERO testnet, standard account (*25519).")
JupiterAccount =>
(26, "jupiter", "Jupiter testnet, standard account (*25519).")
SubsocialAccount =>
(28, "subsocial", "Subsocial network, standard account (*25519).")
DhiwayAccount =>
(29, "cord", "Dhiway CORD network, standard account (*25519).")
PhalaAccount =>
(30, "phala", "Phala Network, standard account (*25519).")
LitentryAccount =>
(31, "litentry", "Litentry Network, standard account (*25519).")
RobonomicsAccount =>
(32, "robonomics", "Any Robonomics network standard account (*25519).")
DataHighwayAccount =>
(33, "datahighway", "DataHighway mainnet, standard account (*25519).")
AresAccount =>
(34, "ares", "Ares Protocol, standard account (*25519).")
ValiuAccount =>
(35, "vln", "Valiu Liquidity Network mainnet, standard account (*25519).")
CentrifugeAccount =>
(36, "centrifuge", "Centrifuge Chain mainnet, standard account (*25519).")
NodleAccount =>
(37, "nodle", "Nodle Chain mainnet, standard account (*25519).")
KiltAccount =>
(38, "kilt", "KILT Chain mainnet, standard account (*25519).")
PolimecAccount =>
(41, "poli", "Polimec Chain mainnet, standard account (*25519).")
SubstrateAccount =>
(42, "substrate", "Any Substrate network, standard account (*25519).")
BareSecp256k1 =>
(43, "secp256k1", "Bare ECDSA SECP256k1 key.")
ChainXAccount =>
(44, "chainx", "ChainX mainnet, standard account (*25519).")
UniartsAccount =>
(45, "uniarts", "UniArts Chain mainnet, standard account (*25519).")
Reserved46 =>
(46, "reserved46", "Reserved for future use (46).")
Reserved47 =>
(47, "reserved47", "Reserved for future use (47).")
NeatcoinAccount =>
(48, "neatcoin", "Neatcoin mainnet, standard account (*25519).")
PicassoAccount =>
(49, "picasso", "Composable Canary Network, standard account (*25519).")
ComposableAccount =>
(50, "composable", "Composable mainnet, standard account (*25519).")
HydraDXAccount =>
(63, "hydradx", "HydraDX standard account (*25519).")
AventusAccount =>
(65, "aventus", "Aventus Chain mainnet, standard account (*25519).")
CrustAccount =>
(66, "crust", "Crust Network, standard account (*25519).")
EquilibriumAccount =>
(67, "equilibrium", "Equilibrium Network, standard account (*25519).")
SoraAccount =>
(69, "sora", "SORA Network, standard account (*25519).")
ZeitgeistAccount =>
(73, "zeitgeist", "Zeitgeist network, standard account (*25519).")
MantaAccount =>
(77, "manta", "Manta Network, standard account (*25519).")
CalamariAccount =>
(78, "calamari", "Manta Canary Network, standard account (*25519).")
Polkadex =>
(88, "polkadex", "Polkadex Mainnet, standard account (*25519).")
PolkaSmith =>
(98, "polkasmith", "PolkaSmith Canary Network, standard account (*25519).")
PolkaFoundry =>
(99, "polkafoundry", "PolkaFoundry Network, standard account (*25519).")
OriginTrailAccount =>
(101, "origintrail-parachain", "OriginTrail Parachain, ethereumm account (ECDSA).")
HeikoAccount =>
(110, "heiko", "Heiko, session key (*25519).")
CloverAccount =>
(128, "clover", "Clover Finance, standard account (*25519).")
ParallelAccount =>
(172, "parallel", "Parallel, session key (*25519).")
SocialAccount =>
(252, "social-network", "Social Network, standard account (*25519).")
Moonbeam =>
(1284, "moonbeam", "Moonbeam, session key (*25519).")
Moonriver =>
(1285, "moonriver", "Moonriver, session key (*25519).")
Automata =>
(2349, "automata", "Automata mainnet standard account (*25519).")
BasiliskAccount =>
(10041, "basilisk", "Basilisk standard account (*25519).")
ContextFree =>
(11820, "contextfree", "Automata ContextFree standard account (*25519).")
// Note: 16384 and above are reserved.
static DEFAULT_VERSION: core::sync::atomic::AtomicU16 = std::sync::atomic::AtomicU16::new(
from_known_address_format(Ss58AddressFormatRegistry::SubstrateAccount),
);
/// Returns default ss58 format used by the current active process.
#[cfg(feature = "std")]
pub fn default_ss58_version() -> Ss58AddressFormat {
DEFAULT_VERSION.load(std::sync::atomic::Ordering::Relaxed).into()
}
/// Returns either the input address format or the default.
#[cfg(feature = "std")]
pub fn unwrap_or_default_ss58_version(network: Option<Ss58AddressFormat>) -> Ss58AddressFormat {
network.unwrap_or_else(default_ss58_version)
}
/// Set the default "version" (actually, this is a bit of a misnomer and the version byte is
/// typically used not just to encode format/version but also network identity) that is used for
/// encoding and decoding SS58 addresses. If an unknown version is provided then it fails.
///
/// See `ss58_address_format!` for all current known "versions".
/// encoding and decoding SS58 addresses.
#[cfg(feature = "std")]
pub fn set_default_ss58_version(version: Ss58AddressFormat) {
*DEFAULT_VERSION.lock() = version
pub fn set_default_ss58_version(new_default: Ss58AddressFormat) {
DEFAULT_VERSION.store(new_default.into(), std::sync::atomic::Ordering::Relaxed);
}
#[cfg(feature = "std")]
+9 -8
View File
@@ -640,7 +640,10 @@ impl CryptoType for Pair {
mod test {
use super::*;
use crate::{
crypto::{set_default_ss58_version, PublicError, DEV_PHRASE},
crypto::{
set_default_ss58_version, PublicError, Ss58AddressFormat, Ss58AddressFormatRegistry,
DEV_PHRASE,
},
keccak_256,
};
use hex_literal::hex;
@@ -772,26 +775,24 @@ mod test {
#[test]
fn ss58check_format_check_works() {
use crate::crypto::Ss58AddressFormat;
let pair = Pair::from_seed(b"12345678901234567890123456789012");
let public = pair.public();
let format = Ss58AddressFormat::Reserved46;
let format = Ss58AddressFormatRegistry::Reserved46Account.into();
let s = public.to_ss58check_with_version(format);
assert_eq!(Public::from_ss58check_with_version(&s), Err(PublicError::FormatNotAllowed));
}
#[test]
fn ss58check_full_roundtrip_works() {
use crate::crypto::Ss58AddressFormat;
let pair = Pair::from_seed(b"12345678901234567890123456789012");
let public = pair.public();
let format = Ss58AddressFormat::PolkadotAccount;
let format = Ss58AddressFormatRegistry::PolkadotAccount.into();
let s = public.to_ss58check_with_version(format);
let (k, f) = Public::from_ss58check_with_version(&s).unwrap();
assert_eq!(k, public);
assert_eq!(f, format);
let format = Ss58AddressFormat::Custom(64);
let format = Ss58AddressFormat::custom(64);
let s = public.to_ss58check_with_version(format);
let (k, f) = Public::from_ss58check_with_version(&s).unwrap();
assert_eq!(k, public);
@@ -805,10 +806,10 @@ mod test {
if std::env::var("RUN_CUSTOM_FORMAT_TEST") == Ok("1".into()) {
use crate::crypto::Ss58AddressFormat;
// temp save default format version
let default_format = Ss58AddressFormat::default();
let default_format = crate::crypto::default_ss58_version();
// set current ss58 version is custom "200" `Ss58AddressFormat::Custom(200)`
set_default_ss58_version(Ss58AddressFormat::Custom(200));
set_default_ss58_version(Ss58AddressFormat::custom(200));
// custom addr encoded by version 200
let addr = "4pbsSkWcBaYoFHrKJZp5fDVUKbqSYD9dhZZGvpp3vQ5ysVs5ybV";
Public::from_ss58check(&addr).unwrap();
@@ -22,7 +22,7 @@ use sc_cli::{
utils::print_from_uri, with_crypto_scheme, CryptoSchemeFlag, Error, KeystoreParams,
OutputTypeFlag,
};
use sp_core::crypto::{Ss58AddressFormat, Ss58Codec};
use sp_core::crypto::{unwrap_or_default_ss58_version, Ss58AddressFormat, Ss58Codec};
use sp_runtime::traits::AccountIdConversion;
use std::convert::{TryFrom, TryInto};
use structopt::StructOpt;
@@ -78,7 +78,7 @@ impl PalletIdCmd {
with_crypto_scheme!(
self.crypto_scheme.scheme,
print_from_uri(
&account_id.to_ss58check_with_version(self.network.clone().unwrap_or_default()),
&account_id.to_ss58check_with_version(unwrap_or_default_ss58_version(self.network)),
password,
self.network,
self.output_scheme.output_type.clone()