Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions core/primitives/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ hex = { version = "0.3", optional = true }
regex = { version = "1.1", optional = true }
num-traits = { version = "0.2", default-features = false }
zeroize = { version = "0.9.2", default-features = false }
lazy_static = { version = "1.3", optional = true }
parking_lot = { version = "0.8", optional = true }

[dev-dependencies]
substrate-serializer = { path = "../serializer" }
Expand All @@ -47,6 +49,8 @@ bench = false
default = ["std"]
std = [
"wasmi",
"lazy_static",
"parking_lot",
"primitive-types/std",
"primitive-types/serde",
"primitive-types/byteorder",
Expand Down
115 changes: 105 additions & 10 deletions core/primitives/src/crypto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
//! Cryptographic utilities.
// end::description[]

#[cfg(feature = "std")]
use std::convert::{TryFrom, TryInto};
#[cfg(feature = "std")]
use parking_lot::Mutex;
#[cfg(feature = "std")]
use rand::{RngCore, rngs::OsRng};
#[cfg(feature = "std")]
Expand Down Expand Up @@ -243,12 +247,23 @@ pub enum PublicError {
#[cfg(feature = "std")]
pub trait Ss58Codec: Sized {
/// Some if the string is a properly encoded SS58Check address.
fn from_ss58check(s: &str) -> Result<Self, PublicError>;
fn from_ss58check(s: &str) -> Result<Self, PublicError> {
Self::from_ss58check_with_version(s)
.and_then(|(r, v)| match v {
Ss58AddressFormat::SubstrateAccountDirect => Ok(r),
v if v == *DEFAULT_VERSION.lock() => Ok(r),
_ => Err(PublicError::UnknownVersion),
})
}
/// Some if the string is a properly encoded SS58Check address.
fn from_ss58check_with_version(s: &str) -> Result<(Self, Ss58AddressFormat), PublicError>;
/// Some if the string is a properly encoded SS58Check address, optionally with
/// a derivation path following.
fn from_string(s: &str) -> Result<Self, PublicError> { Self::from_ss58check(s) }
/// Return the ss58-check string for this key.
fn to_ss58check(&self) -> String;
fn to_ss58check_with_version(&self, version: Ss58AddressFormat) -> String;
/// Return the ss58-check string for this key.
fn to_ss58check(&self) -> String { self.to_ss58check_with_version(*DEFAULT_VERSION.lock()) }
}

#[cfg(feature = "std")]
Expand All @@ -273,31 +288,111 @@ fn ss58hash(data: &[u8]) -> blake2_rfc::blake2b::Blake2bResult {
context.finalize()
}

#[cfg(feature = "std")]
lazy_static::lazy_static! {
static ref DEFAULT_VERSION: Mutex<Ss58AddressFormat>
= Mutex::new(Ss58AddressFormat::SubstrateAccountDirect);
}

/// A known address (sub)format/network ID for SS58.
#[cfg(feature = "std")]
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum Ss58AddressFormat {
/// Any Substrate network, direct checksum, standard account (*25519).
SubstrateAccountDirect,
/// Polkadot Relay-chain, direct checksum, standard account (*25519).
PolkadotAccountDirect,
/// Kusama Relay-chain, direct checksum, standard account (*25519).
KusamaAccountDirect,
/// Override with a manually provided numeric value.
Override(u8),
}

#[cfg(feature = "std")]
impl From<Ss58AddressFormat> for u8 {
fn from(x: Ss58AddressFormat) -> u8 {
match x {
Ss58AddressFormat::SubstrateAccountDirect => 42,
Ss58AddressFormat::PolkadotAccountDirect => 0,
Ss58AddressFormat::KusamaAccountDirect => 4,
Ss58AddressFormat::Override(n) => n,
}
}
}

#[cfg(feature = "std")]
impl TryFrom<u8> for Ss58AddressFormat {
type Error = ();
fn try_from(x: u8) -> Result<Ss58AddressFormat, ()> {
match x {
42 => Ok(Ss58AddressFormat::SubstrateAccountDirect),
0 => Ok(Ss58AddressFormat::PolkadotAccountDirect),
2 => Ok(Ss58AddressFormat::KusamaAccountDirect),
_ => Err(()),
}
}
}

#[cfg(feature = "std")]
impl<'a> TryFrom<&'a str> for Ss58AddressFormat {
type Error = ();
fn try_from(x: &'a str) -> Result<Ss58AddressFormat, ()> {
match x {
"substrate" => Ok(Ss58AddressFormat::SubstrateAccountDirect),
"polkadot" => Ok(Ss58AddressFormat::PolkadotAccountDirect),
"kusama" => Ok(Ss58AddressFormat::KusamaAccountDirect),
a => a.parse::<u8>().map(Ss58AddressFormat::Override).map_err(|_| ()),
}
}
}

#[cfg(feature = "std")]
impl From<Ss58AddressFormat> for &'static str {
fn from(x: Ss58AddressFormat) -> &'static str {
match x {
Ss58AddressFormat::SubstrateAccountDirect => "substrate",
Ss58AddressFormat::PolkadotAccountDirect => "polkadot",
Ss58AddressFormat::KusamaAccountDirect => "kusama",
Ss58AddressFormat::Override(_) => "(override)",
}
}
}

/// 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.
///
/// Current known "versions" are:
/// - 0 direct (payload) checksum for 32-byte *25519 Polkadot addresses.
/// - 2 direct (payload) checksum for 32-byte *25519 Polkadot Milestone 'K' addresses.
/// - 42 direct (payload) checksum for 32-byte *25519 addresses on any Substrate-based network.
#[cfg(feature = "std")]
pub fn set_default_ss58_version(version: Ss58AddressFormat) {
*DEFAULT_VERSION.lock() = version
}

#[cfg(feature = "std")]
impl<T: AsMut<[u8]> + AsRef<[u8]> + Default + Derive> Ss58Codec for T {
fn from_ss58check(s: &str) -> Result<Self, PublicError> {
fn from_ss58check_with_version(s: &str) -> Result<(Self, Ss58AddressFormat), PublicError> {
let mut res = T::default();
let len = res.as_mut().len();
let d = s.from_base58().map_err(|_| PublicError::BadBase58)?; // failure here would be invalid encoding.
if d.len() != len + 3 {
// Invalid length.
return Err(PublicError::BadLength);
}
if d[0] != 42 {
// Invalid version.
return Err(PublicError::UnknownVersion);
}
let ver = d[0].try_into().map_err(|_: ()| PublicError::UnknownVersion)?;

if d[len+1..len+3] != ss58hash(&d[0..len+1]).as_bytes()[0..2] {
// Invalid checksum.
return Err(PublicError::InvalidChecksum);
}
res.as_mut().copy_from_slice(&d[1..len+1]);
Ok(res)
Ok((res, ver))
}

fn to_ss58check(&self) -> String {
let mut v = vec![42u8];
fn to_ss58check_with_version(&self, version: Ss58AddressFormat) -> String {
let mut v = vec![version.into()];
v.extend(self.as_ref());
let r = ss58hash(&v);
v.extend(&r.as_bytes()[0..2]);
Expand Down
59 changes: 45 additions & 14 deletions core/sr-primitives/src/generic/checked_extrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,46 +17,77 @@
//! Generic implementation of an extrinsic that has passed the verification
//! stage.

use crate::traits::{self, Member, SimpleArithmetic, MaybeDisplay};
use rstd::result::Result;
use crate::traits::{
self, Member, MaybeDisplay, SignedExtension, DispatchError, Dispatchable, DispatchResult,
ValidateUnsigned
};
use crate::weights::{Weighable, Weight};
use crate::transaction_validity::TransactionValidity;

/// Definition of something that the external world might want to say; its
/// existence implies that it has been checked and is good, particularly with
/// regards to the signature.
#[derive(PartialEq, Eq, Clone)]
#[cfg_attr(feature = "std", derive(Debug))]
pub struct CheckedExtrinsic<AccountId, Index, Call> {
pub struct CheckedExtrinsic<AccountId, Call, Extra> {
/// Who this purports to be from and the number of extrinsics have come before
/// from the same signer, if anyone (note this is not a signature).
pub signed: Option<(AccountId, Index)>,
pub signed: Option<(AccountId, Extra)>,

/// The function that should be called.
pub function: Call,
}

impl<AccountId, Index, Call> traits::Applyable for CheckedExtrinsic<AccountId, Index, Call>
impl<AccountId, Call, Extra, Origin> traits::Applyable
for
CheckedExtrinsic<AccountId, Call, Extra>
where
AccountId: Member + MaybeDisplay,
Index: Member + MaybeDisplay + SimpleArithmetic,
Call: Member,
Call: Member + Dispatchable<Origin=Origin>,
Extra: SignedExtension<AccountId=AccountId>,
Origin: From<Option<AccountId>>,
{
type Index = Index;
type AccountId = AccountId;
type Call = Call;

fn index(&self) -> Option<&Self::Index> {
self.signed.as_ref().map(|x| &x.1)
}
type Call = Call;

fn sender(&self) -> Option<&Self::AccountId> {
self.signed.as_ref().map(|x| &x.0)
}

fn deconstruct(self) -> (Self::Call, Option<Self::AccountId>) {
(self.function, self.signed.map(|x| x.0))
fn validate<U: ValidateUnsigned<Call=Self::Call>>(&self,
weight: crate::weights::Weight,
) -> TransactionValidity {
if let Some((ref id, ref extra)) = self.signed {
Extra::validate(extra, id, weight).into()
} else {
match Extra::validate_unsigned(weight) {
Ok(extra) => match U::validate_unsigned(&self.function) {
TransactionValidity::Valid(v) =>
TransactionValidity::Valid(v.combine_with(extra)),
x => x,
},
x => x.into(),
}
}
}

fn dispatch(self,
weight: crate::weights::Weight,
) -> Result<DispatchResult, DispatchError> {
let maybe_who = if let Some((id, extra)) = self.signed {
Extra::pre_dispatch(extra, &id, weight)?;
Some(id)
} else {
Extra::pre_dispatch_unsigned(weight)?;
None
};
Ok(self.function.dispatch(Origin::from(maybe_who)))
}
}

impl<AccountId, Index, Call> Weighable for CheckedExtrinsic<AccountId, Index, Call>
impl<AccountId, Call, Extra> Weighable for CheckedExtrinsic<AccountId, Call, Extra>
where
Call: Weighable,
{
Expand Down
4 changes: 0 additions & 4 deletions core/sr-primitives/src/generic/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@
// end::description[]

mod unchecked_extrinsic;
mod unchecked_mortal_extrinsic;
mod unchecked_mortal_compact_extrinsic;
mod era;
mod checked_extrinsic;
mod header;
Expand All @@ -30,8 +28,6 @@ mod digest;
mod tests;

pub use self::unchecked_extrinsic::UncheckedExtrinsic;
pub use self::unchecked_mortal_extrinsic::UncheckedMortalExtrinsic;
pub use self::unchecked_mortal_compact_extrinsic::UncheckedMortalCompactExtrinsic;
pub use self::era::{Era, Phase};
pub use self::checked_extrinsic::CheckedExtrinsic;
pub use self::header::Header;
Expand Down
Loading