mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-13 17:31:05 +00:00
Reorganising the repository - external renames and moves (#4074)
* Adding first rough ouline of the repository structure * Remove old CI stuff * add title * formatting fixes * move node-exits job's script to scripts dir * Move docs into subdir * move to bin * move maintainence scripts, configs and helpers into its own dir * add .local to ignore * move core->client * start up 'test' area * move test client * move test runtime * make test move compile * Add dependencies rule enforcement. * Fix indexing. * Update docs to reflect latest changes * Moving /srml->/paint * update docs * move client/sr-* -> primitives/ * clean old readme * remove old broken code in rhd * update lock * Step 1. * starting to untangle client * Fix after merge. * start splitting out client interfaces * move children and blockchain interfaces * Move trie and state-machine to primitives. * Fix WASM builds. * fixing broken imports * more interface moves * move backend and light to interfaces * move CallExecutor * move cli off client * moving around more interfaces * re-add consensus crates into the mix * fix subkey path * relieve client from executor * starting to pull out client from grandpa * move is_decendent_of out of client * grandpa still depends on client directly * lemme tests pass * rename srml->paint * Make it compile. * rename interfaces->client-api * Move keyring to primitives. * fixup libp2p dep * fix broken use * allow dependency enforcement to fail * move fork-tree * Moving wasm-builder * make env * move build-script-utils * fixup broken crate depdencies and names * fix imports for authority discovery * fix typo * update cargo.lock * fixing imports * Fix paths and add missing crates * re-add missing crates
This commit is contained in:
committed by
Bastian Köcher
parent
becc3b0a4f
commit
60e5011c72
@@ -0,0 +1,294 @@
|
||||
// Copyright 2018-2019 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Substrate is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Substrate changes trie configuration.
|
||||
|
||||
#[cfg(any(feature = "std", test))]
|
||||
use serde::{Serialize, Deserialize};
|
||||
use codec::{Encode, Decode};
|
||||
use num_traits::Zero;
|
||||
|
||||
/// Substrate changes trie configuration.
|
||||
#[cfg_attr(any(feature = "std", test), derive(Serialize, Deserialize))]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Default, Encode, Decode)]
|
||||
pub struct ChangesTrieConfiguration {
|
||||
/// Interval (in blocks) at which level1-digests are created. Digests are not
|
||||
/// created when this is less or equal to 1.
|
||||
pub digest_interval: u32,
|
||||
/// Maximal number of digest levels in hierarchy. 0 means that digests are not
|
||||
/// created at all (even level1 digests). 1 means only level1-digests are created.
|
||||
/// 2 means that every digest_interval^2 there will be a level2-digest, and so on.
|
||||
/// Please ensure that maximum digest interval (i.e. digest_interval^digest_levels)
|
||||
/// is within `u32` limits. Otherwise you'll never see digests covering such intervals
|
||||
/// && maximal digests interval will be truncated to the last interval that fits
|
||||
/// `u32` limits.
|
||||
pub digest_levels: u32,
|
||||
}
|
||||
|
||||
impl ChangesTrieConfiguration {
|
||||
/// Create new configuration given digest interval and levels.
|
||||
pub fn new(digest_interval: u32, digest_levels: u32) -> Self {
|
||||
Self { digest_interval, digest_levels }
|
||||
}
|
||||
|
||||
/// Is digest build enabled?
|
||||
pub fn is_digest_build_enabled(&self) -> bool {
|
||||
self.digest_interval > 1 && self.digest_levels > 0
|
||||
}
|
||||
|
||||
/// Do we need to build digest at given block?
|
||||
pub fn is_digest_build_required_at_block<Number>(
|
||||
&self,
|
||||
zero: Number,
|
||||
block: Number,
|
||||
) -> bool
|
||||
where
|
||||
Number: From<u32> + PartialEq +
|
||||
::rstd::ops::Rem<Output=Number> + ::rstd::ops::Sub<Output=Number> +
|
||||
::rstd::cmp::PartialOrd + Zero,
|
||||
{
|
||||
block > zero
|
||||
&& self.is_digest_build_enabled()
|
||||
&& ((block - zero) % self.digest_interval.into()).is_zero()
|
||||
}
|
||||
|
||||
/// Returns max digest interval. One if digests are not created at all.
|
||||
pub fn max_digest_interval(&self) -> u32 {
|
||||
if !self.is_digest_build_enabled() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// we'll get >1 loop iteration only when bad configuration parameters are selected
|
||||
let mut current_level = self.digest_levels;
|
||||
loop {
|
||||
if let Some(max_digest_interval) = self.digest_interval.checked_pow(current_level) {
|
||||
return max_digest_interval;
|
||||
}
|
||||
|
||||
current_level = current_level - 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns max level digest block number that has been created at block <= passed block number.
|
||||
///
|
||||
/// Returns None if digests are not created at all.
|
||||
pub fn prev_max_level_digest_block<Number>(
|
||||
&self,
|
||||
zero: Number,
|
||||
block: Number,
|
||||
) -> Option<Number>
|
||||
where
|
||||
Number: Clone + From<u32> + PartialOrd + PartialEq +
|
||||
::rstd::ops::Add<Output=Number> + ::rstd::ops::Sub<Output=Number> +
|
||||
::rstd::ops::Div<Output=Number> + ::rstd::ops::Mul<Output=Number> + Zero,
|
||||
{
|
||||
if block <= zero {
|
||||
return None;
|
||||
}
|
||||
|
||||
let (next_begin, next_end) = self.next_max_level_digest_range(zero.clone(), block.clone())?;
|
||||
|
||||
// if 'next' digest includes our block, then it is a also a previous digest
|
||||
if next_end == block {
|
||||
return Some(block);
|
||||
}
|
||||
|
||||
// if previous digest ends at zero block, then there are no previous digest
|
||||
let prev_end = next_begin - 1.into();
|
||||
if prev_end == zero {
|
||||
None
|
||||
} else {
|
||||
Some(prev_end)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns max level digest blocks range (inclusive) which includes passed block.
|
||||
///
|
||||
/// Returns None if digests are not created at all.
|
||||
/// It will return the first max-level digest if block is <= zero.
|
||||
pub fn next_max_level_digest_range<Number>(
|
||||
&self,
|
||||
zero: Number,
|
||||
mut block: Number,
|
||||
) -> Option<(Number, Number)>
|
||||
where
|
||||
Number: Clone + From<u32> + PartialOrd + PartialEq +
|
||||
::rstd::ops::Add<Output=Number> + ::rstd::ops::Sub<Output=Number> +
|
||||
::rstd::ops::Div<Output=Number> + ::rstd::ops::Mul<Output=Number>,
|
||||
{
|
||||
if !self.is_digest_build_enabled() {
|
||||
return None;
|
||||
}
|
||||
|
||||
if block <= zero {
|
||||
block = zero.clone() + 1.into();
|
||||
}
|
||||
|
||||
let max_digest_interval: Number = self.max_digest_interval().into();
|
||||
let max_digests_since_zero = (block.clone() - zero.clone()) / max_digest_interval.clone();
|
||||
if max_digests_since_zero == 0.into() {
|
||||
return Some((zero.clone() + 1.into(), zero + max_digest_interval));
|
||||
}
|
||||
let last_max_digest_block = zero + max_digests_since_zero * max_digest_interval.clone();
|
||||
Some(if block == last_max_digest_block {
|
||||
(block.clone() - max_digest_interval + 1.into(), block)
|
||||
} else {
|
||||
(last_max_digest_block.clone() + 1.into(), last_max_digest_block + max_digest_interval)
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns Some if digest must be built at given block number.
|
||||
/// The tuple is:
|
||||
/// (
|
||||
/// digest level
|
||||
/// digest interval (in blocks)
|
||||
/// step between blocks we're interested in when digest is built
|
||||
/// )
|
||||
pub fn digest_level_at_block<Number>(&self, zero: Number, block: Number) -> Option<(u32, u32, u32)>
|
||||
where
|
||||
Number: Clone + From<u32> + PartialEq +
|
||||
::rstd::ops::Rem<Output=Number> + ::rstd::ops::Sub<Output=Number> +
|
||||
::rstd::cmp::PartialOrd + Zero,
|
||||
{
|
||||
if !self.is_digest_build_required_at_block(zero.clone(), block.clone()) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let relative_block = block - zero;
|
||||
let mut digest_interval = self.digest_interval;
|
||||
let mut current_level = 1u32;
|
||||
let mut digest_step = 1u32;
|
||||
while current_level < self.digest_levels {
|
||||
let new_digest_interval = match digest_interval.checked_mul(self.digest_interval) {
|
||||
Some(new_digest_interval) if (relative_block.clone() % new_digest_interval.into()).is_zero()
|
||||
=> new_digest_interval,
|
||||
_ => break,
|
||||
};
|
||||
|
||||
digest_step = digest_interval;
|
||||
digest_interval = new_digest_interval;
|
||||
current_level = current_level + 1;
|
||||
}
|
||||
|
||||
Some((
|
||||
current_level,
|
||||
digest_interval,
|
||||
digest_step,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::ChangesTrieConfiguration;
|
||||
|
||||
fn config(interval: u32, levels: u32) -> ChangesTrieConfiguration {
|
||||
ChangesTrieConfiguration {
|
||||
digest_interval: interval,
|
||||
digest_levels: levels,
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_digest_build_enabled_works() {
|
||||
assert!(!config(0, 100).is_digest_build_enabled());
|
||||
assert!(!config(1, 100).is_digest_build_enabled());
|
||||
assert!(config(2, 100).is_digest_build_enabled());
|
||||
assert!(!config(100, 0).is_digest_build_enabled());
|
||||
assert!(config(100, 1).is_digest_build_enabled());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_digest_build_required_at_block_works() {
|
||||
fn test_with_zero(zero: u64) {
|
||||
assert!(!config(8, 4).is_digest_build_required_at_block(zero, zero + 0u64));
|
||||
assert!(!config(8, 4).is_digest_build_required_at_block(zero, zero + 1u64));
|
||||
assert!(!config(8, 4).is_digest_build_required_at_block(zero, zero + 2u64));
|
||||
assert!(!config(8, 4).is_digest_build_required_at_block(zero, zero + 4u64));
|
||||
assert!(config(8, 4).is_digest_build_required_at_block(zero, zero + 8u64));
|
||||
assert!(!config(8, 4).is_digest_build_required_at_block(zero, zero + 9u64));
|
||||
assert!(config(8, 4).is_digest_build_required_at_block(zero, zero + 64u64));
|
||||
assert!(config(8, 4).is_digest_build_required_at_block(zero, zero + 64u64));
|
||||
assert!(config(8, 4).is_digest_build_required_at_block(zero, zero + 512u64));
|
||||
assert!(config(8, 4).is_digest_build_required_at_block(zero, zero + 4096u64));
|
||||
assert!(!config(8, 4).is_digest_build_required_at_block(zero, zero + 4103u64));
|
||||
assert!(config(8, 4).is_digest_build_required_at_block(zero, zero + 4104u64));
|
||||
assert!(!config(8, 4).is_digest_build_required_at_block(zero, zero + 4108u64));
|
||||
}
|
||||
|
||||
test_with_zero(0);
|
||||
test_with_zero(8);
|
||||
test_with_zero(17);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn digest_level_at_block_works() {
|
||||
fn test_with_zero(zero: u64) {
|
||||
assert_eq!(config(8, 4).digest_level_at_block(zero, zero + 0u64), None);
|
||||
assert_eq!(config(8, 4).digest_level_at_block(zero, zero + 7u64), None);
|
||||
assert_eq!(config(8, 4).digest_level_at_block(zero, zero + 63u64), None);
|
||||
assert_eq!(config(8, 4).digest_level_at_block(zero, zero + 8u64), Some((1, 8, 1)));
|
||||
assert_eq!(config(8, 4).digest_level_at_block(zero, zero + 64u64), Some((2, 64, 8)));
|
||||
assert_eq!(config(8, 4).digest_level_at_block(zero, zero + 512u64), Some((3, 512, 64)));
|
||||
assert_eq!(config(8, 4).digest_level_at_block(zero, zero + 4096u64), Some((4, 4096, 512)));
|
||||
assert_eq!(config(8, 4).digest_level_at_block(zero, zero + 4112u64), Some((1, 8, 1)));
|
||||
}
|
||||
|
||||
test_with_zero(0);
|
||||
test_with_zero(8);
|
||||
test_with_zero(17);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn max_digest_interval_works() {
|
||||
assert_eq!(config(0, 0).max_digest_interval(), 1);
|
||||
assert_eq!(config(2, 2).max_digest_interval(), 4);
|
||||
assert_eq!(config(8, 4).max_digest_interval(), 4096);
|
||||
assert_eq!(config(::std::u32::MAX, 1024).max_digest_interval(), ::std::u32::MAX);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn next_max_level_digest_range_works() {
|
||||
assert_eq!(config(0, 0).next_max_level_digest_range(0u64, 16), None);
|
||||
assert_eq!(config(1, 1).next_max_level_digest_range(0u64, 16), None);
|
||||
assert_eq!(config(2, 1).next_max_level_digest_range(0u64, 16), Some((15, 16)));
|
||||
assert_eq!(config(4, 1).next_max_level_digest_range(0u64, 16), Some((13, 16)));
|
||||
assert_eq!(config(32, 1).next_max_level_digest_range(0u64, 16), Some((1, 32)));
|
||||
assert_eq!(config(2, 3).next_max_level_digest_range(0u64, 10), Some((9, 16)));
|
||||
assert_eq!(config(2, 3).next_max_level_digest_range(0u64, 8), Some((1, 8)));
|
||||
assert_eq!(config(2, 1).next_max_level_digest_range(1u64, 1), Some((2, 3)));
|
||||
assert_eq!(config(2, 2).next_max_level_digest_range(7u64, 9), Some((8, 11)));
|
||||
|
||||
assert_eq!(config(2, 2).next_max_level_digest_range(7u64, 5), Some((8, 11)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn prev_max_level_digest_block_works() {
|
||||
assert_eq!(config(0, 0).prev_max_level_digest_block(0u64, 16), None);
|
||||
assert_eq!(config(1, 1).prev_max_level_digest_block(0u64, 16), None);
|
||||
assert_eq!(config(2, 1).prev_max_level_digest_block(0u64, 16), Some(16));
|
||||
assert_eq!(config(4, 1).prev_max_level_digest_block(0u64, 16), Some(16));
|
||||
assert_eq!(config(4, 2).prev_max_level_digest_block(0u64, 16), Some(16));
|
||||
assert_eq!(config(4, 2).prev_max_level_digest_block(0u64, 17), Some(16));
|
||||
assert_eq!(config(4, 2).prev_max_level_digest_block(0u64, 33), Some(32));
|
||||
assert_eq!(config(32, 1).prev_max_level_digest_block(0u64, 16), None);
|
||||
assert_eq!(config(2, 3).prev_max_level_digest_block(0u64, 10), Some(8));
|
||||
assert_eq!(config(2, 3).prev_max_level_digest_block(0u64, 8), Some(8));
|
||||
assert_eq!(config(2, 2).prev_max_level_digest_block(7u64, 8), None);
|
||||
|
||||
assert_eq!(config(2, 2).prev_max_level_digest_block(7u64, 5), None);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,616 @@
|
||||
// Copyright 2017-2019 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Substrate is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// tag::description[]
|
||||
//! Simple ECDSA API.
|
||||
// end::description[]
|
||||
|
||||
#[cfg(feature = "full_crypto")]
|
||||
use rstd::vec::Vec;
|
||||
|
||||
use rstd::cmp::Ordering;
|
||||
use codec::{Encode, Decode};
|
||||
|
||||
#[cfg(feature = "full_crypto")]
|
||||
use core::convert::{TryFrom, TryInto};
|
||||
#[cfg(feature = "std")]
|
||||
use substrate_bip39::seed_from_entropy;
|
||||
#[cfg(feature = "std")]
|
||||
use bip39::{Mnemonic, Language, MnemonicType};
|
||||
#[cfg(feature = "full_crypto")]
|
||||
use crate::{hashing::blake2_256, crypto::{Pair as TraitPair, DeriveJunction, SecretStringError}};
|
||||
#[cfg(feature = "std")]
|
||||
use crate::crypto::Ss58Codec;
|
||||
#[cfg(feature = "std")]
|
||||
use serde::{de, Serializer, Serialize, Deserializer, Deserialize};
|
||||
use crate::crypto::{Public as TraitPublic, UncheckedFrom, CryptoType, Derive};
|
||||
#[cfg(feature = "full_crypto")]
|
||||
use secp256k1::{PublicKey, SecretKey};
|
||||
|
||||
/// A secret seed (which is bytewise essentially equivalent to a SecretKey).
|
||||
///
|
||||
/// We need it as a different type because `Seed` is expected to be AsRef<[u8]>.
|
||||
#[cfg(feature = "full_crypto")]
|
||||
type Seed = [u8; 32];
|
||||
|
||||
/// The ECDSA 33-byte compressed public key.
|
||||
#[derive(Clone, Encode, Decode)]
|
||||
pub struct Public(pub [u8; 33]);
|
||||
|
||||
impl PartialOrd for Public {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for Public {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
self.0[..].cmp(&other.0[..])
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Public {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
&self.0[..] == &other.0[..]
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Public {}
|
||||
|
||||
impl Default for Public {
|
||||
fn default() -> Self {
|
||||
Public([0u8; 33])
|
||||
}
|
||||
}
|
||||
|
||||
/// A key pair.
|
||||
#[cfg(feature = "full_crypto")]
|
||||
#[derive(Clone)]
|
||||
pub struct Pair {
|
||||
public: PublicKey,
|
||||
secret: SecretKey,
|
||||
}
|
||||
|
||||
impl AsRef<[u8; 33]> for Public {
|
||||
fn as_ref(&self) -> &[u8; 33] {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<[u8]> for Public {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
&self.0[..]
|
||||
}
|
||||
}
|
||||
|
||||
impl AsMut<[u8]> for Public {
|
||||
fn as_mut(&mut self) -> &mut [u8] {
|
||||
&mut self.0[..]
|
||||
}
|
||||
}
|
||||
|
||||
impl rstd::convert::TryFrom<&[u8]> for Public {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(data: &[u8]) -> Result<Self, Self::Error> {
|
||||
if data.len() == 33 {
|
||||
let mut inner = [0u8; 33];
|
||||
inner.copy_from_slice(data);
|
||||
Ok(Public(inner))
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Public> for [u8; 33] {
|
||||
fn from(x: Public) -> Self {
|
||||
x.0
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "full_crypto")]
|
||||
impl From<Pair> for Public {
|
||||
fn from(x: Pair) -> Self {
|
||||
x.public()
|
||||
}
|
||||
}
|
||||
|
||||
impl UncheckedFrom<[u8; 33]> for Public {
|
||||
fn unchecked_from(x: [u8; 33]) -> Self {
|
||||
Public(x)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl std::fmt::Display for Public {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(f, "{}", self.to_ss58check())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl std::fmt::Debug for Public {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
let s = self.to_ss58check();
|
||||
write!(f, "{} ({}...)", crate::hexdisplay::HexDisplay::from(&&self.0[..]), &s[0..8])
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl Serialize for Public {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
|
||||
serializer.serialize_str(&self.to_ss58check())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<'de> Deserialize<'de> for Public {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de> {
|
||||
Public::from_ss58check(&String::deserialize(deserializer)?)
|
||||
.map_err(|e| de::Error::custom(format!("{:?}", e)))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "full_crypto")]
|
||||
impl rstd::hash::Hash for Public {
|
||||
fn hash<H: rstd::hash::Hasher>(&self, state: &mut H) {
|
||||
self.0.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
/// A signature (a 512-bit value).
|
||||
#[derive(Encode, Decode)]
|
||||
pub struct Signature([u8; 65]);
|
||||
|
||||
impl rstd::convert::TryFrom<&[u8]> for Signature {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(data: &[u8]) -> Result<Self, Self::Error> {
|
||||
if data.len() == 65 {
|
||||
let mut inner = [0u8; 65];
|
||||
inner.copy_from_slice(data);
|
||||
Ok(Signature(inner))
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Signature {
|
||||
fn clone(&self) -> Self {
|
||||
let mut r = [0u8; 65];
|
||||
r.copy_from_slice(&self.0[..]);
|
||||
Signature(r)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Signature {
|
||||
fn default() -> Self {
|
||||
Signature([0u8; 65])
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Signature {
|
||||
fn eq(&self, b: &Self) -> bool {
|
||||
self.0[..] == b.0[..]
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Signature {}
|
||||
|
||||
impl From<Signature> for [u8; 65] {
|
||||
fn from(v: Signature) -> [u8; 65] {
|
||||
v.0
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<[u8; 65]> for Signature {
|
||||
fn as_ref(&self) -> &[u8; 65] {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<[u8]> for Signature {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
&self.0[..]
|
||||
}
|
||||
}
|
||||
|
||||
impl AsMut<[u8]> for Signature {
|
||||
fn as_mut(&mut self) -> &mut [u8] {
|
||||
&mut self.0[..]
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl std::fmt::Debug for Signature {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(f, "{}", crate::hexdisplay::HexDisplay::from(&self.0))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "full_crypto")]
|
||||
impl rstd::hash::Hash for Signature {
|
||||
fn hash<H: rstd::hash::Hasher>(&self, state: &mut H) {
|
||||
rstd::hash::Hash::hash(&self.0[..], state);
|
||||
}
|
||||
}
|
||||
|
||||
impl Signature {
|
||||
/// A new instance from the given 65-byte `data`.
|
||||
///
|
||||
/// NOTE: No checking goes on to ensure this is a real signature. Only use it if
|
||||
/// you are certain that the array actually is a signature. GIGO!
|
||||
pub fn from_raw(data: [u8; 65]) -> Signature {
|
||||
Signature(data)
|
||||
}
|
||||
|
||||
/// Recover the public key from this signature and a message.
|
||||
#[cfg(feature = "full_crypto")]
|
||||
pub fn recover<M: AsRef<[u8]>>(&self, message: M) -> Option<Public> {
|
||||
let message = secp256k1::Message::parse(&blake2_256(message.as_ref()));
|
||||
let sig: (_, _) = self.try_into().ok()?;
|
||||
secp256k1::recover(&message, &sig.0, &sig.1).ok()
|
||||
.map(|recovered| Public(recovered.serialize_compressed()))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "full_crypto")]
|
||||
impl From<(secp256k1::Signature, secp256k1::RecoveryId)> for Signature {
|
||||
fn from(x: (secp256k1::Signature, secp256k1::RecoveryId)) -> Signature {
|
||||
let mut r = Self::default();
|
||||
r.0[0..64].copy_from_slice(&x.0.serialize()[..]);
|
||||
r.0[64] = x.1.serialize();
|
||||
r
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "full_crypto")]
|
||||
impl<'a> TryFrom<&'a Signature> for (secp256k1::Signature, secp256k1::RecoveryId) {
|
||||
type Error = ();
|
||||
fn try_from(x: &'a Signature) -> Result<(secp256k1::Signature, secp256k1::RecoveryId), Self::Error> {
|
||||
Ok((
|
||||
secp256k1::Signature::parse_slice(&x.0[0..64]).expect("hardcoded to 64 bytes; qed"),
|
||||
secp256k1::RecoveryId::parse(x.0[64]).map_err(|_| ())?,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
/// An error type for SS58 decoding.
|
||||
#[cfg(feature = "std")]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
|
||||
pub enum PublicError {
|
||||
/// Bad alphabet.
|
||||
BadBase58,
|
||||
/// Bad length.
|
||||
BadLength,
|
||||
/// Unknown version.
|
||||
UnknownVersion,
|
||||
/// Invalid checksum.
|
||||
InvalidChecksum,
|
||||
}
|
||||
|
||||
impl Public {
|
||||
/// A new instance from the given 33-byte `data`.
|
||||
///
|
||||
/// NOTE: No checking goes on to ensure this is a real public key. Only use it if
|
||||
/// you are certain that the array actually is a pubkey. GIGO!
|
||||
pub fn from_raw(data: [u8; 33]) -> Self {
|
||||
Public(data)
|
||||
}
|
||||
|
||||
/// Return a slice filled with raw data.
|
||||
pub fn as_array_ref(&self) -> &[u8; 33] {
|
||||
self.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl TraitPublic for Public {
|
||||
/// A new instance from the given slice that should be 33 bytes long.
|
||||
///
|
||||
/// NOTE: No checking goes on to ensure this is a real public key. Only use it if
|
||||
/// you are certain that the array actually is a pubkey. GIGO!
|
||||
fn from_slice(data: &[u8]) -> Self {
|
||||
let mut r = [0u8; 33];
|
||||
r.copy_from_slice(data);
|
||||
Public(r)
|
||||
}
|
||||
}
|
||||
|
||||
impl Derive for Public {}
|
||||
|
||||
/// Derive a single hard junction.
|
||||
#[cfg(feature = "full_crypto")]
|
||||
fn derive_hard_junction(secret_seed: &Seed, cc: &[u8; 32]) -> Seed {
|
||||
("Secp256k1HDKD", secret_seed, cc).using_encoded(|data| {
|
||||
let mut res = [0u8; 32];
|
||||
res.copy_from_slice(blake2_rfc::blake2b::blake2b(32, &[], data).as_bytes());
|
||||
res
|
||||
})
|
||||
}
|
||||
|
||||
/// An error when deriving a key.
|
||||
#[cfg(feature = "full_crypto")]
|
||||
pub enum DeriveError {
|
||||
/// A soft key was found in the path (and is unsupported).
|
||||
SoftKeyInPath,
|
||||
}
|
||||
|
||||
#[cfg(feature = "full_crypto")]
|
||||
impl TraitPair for Pair {
|
||||
type Public = Public;
|
||||
type Seed = Seed;
|
||||
type Signature = Signature;
|
||||
type DeriveError = DeriveError;
|
||||
|
||||
/// Generate new secure (random) key pair and provide the recovery phrase.
|
||||
///
|
||||
/// You can recover the same key later with `from_phrase`.
|
||||
#[cfg(feature = "std")]
|
||||
fn generate_with_phrase(password: Option<&str>) -> (Pair, String, Seed) {
|
||||
let mnemonic = Mnemonic::new(MnemonicType::Words12, Language::English);
|
||||
let phrase = mnemonic.phrase();
|
||||
let (pair, seed) = Self::from_phrase(phrase, password)
|
||||
.expect("All phrases generated by Mnemonic are valid; qed");
|
||||
(
|
||||
pair,
|
||||
phrase.to_owned(),
|
||||
seed,
|
||||
)
|
||||
}
|
||||
|
||||
/// Generate key pair from given recovery phrase and password.
|
||||
#[cfg(feature = "std")]
|
||||
fn from_phrase(phrase: &str, password: Option<&str>) -> Result<(Pair, Seed), SecretStringError> {
|
||||
let big_seed = seed_from_entropy(
|
||||
Mnemonic::from_phrase(phrase, Language::English)
|
||||
.map_err(|_| SecretStringError::InvalidPhrase)?.entropy(),
|
||||
password.unwrap_or(""),
|
||||
).map_err(|_| SecretStringError::InvalidSeed)?;
|
||||
let mut seed = Seed::default();
|
||||
seed.copy_from_slice(&big_seed[0..32]);
|
||||
Self::from_seed_slice(&big_seed[0..32]).map(|x| (x, seed))
|
||||
}
|
||||
|
||||
/// Make a new key pair from secret seed material.
|
||||
///
|
||||
/// You should never need to use this; generate(), generate_with_phrase
|
||||
fn from_seed(seed: &Seed) -> Pair {
|
||||
Self::from_seed_slice(&seed[..]).expect("seed has valid length; qed")
|
||||
}
|
||||
|
||||
/// Make a new key pair from secret seed material. The slice must be 32 bytes long or it
|
||||
/// will return `None`.
|
||||
///
|
||||
/// You should never need to use this; generate(), generate_with_phrase
|
||||
fn from_seed_slice(seed_slice: &[u8]) -> Result<Pair, SecretStringError> {
|
||||
let secret = SecretKey::parse_slice(seed_slice)
|
||||
.map_err(|_| SecretStringError::InvalidSeedLength)?;
|
||||
let public = PublicKey::from_secret_key(&secret);
|
||||
Ok(Pair{ secret, public })
|
||||
}
|
||||
|
||||
/// Derive a child key from a series of given junctions.
|
||||
fn derive<Iter: Iterator<Item=DeriveJunction>>(&self,
|
||||
path: Iter,
|
||||
_seed: Option<Seed>
|
||||
) -> Result<(Pair, Option<Seed>), DeriveError> {
|
||||
let mut acc = self.secret.serialize();
|
||||
for j in path {
|
||||
match j {
|
||||
DeriveJunction::Soft(_cc) => return Err(DeriveError::SoftKeyInPath),
|
||||
DeriveJunction::Hard(cc) => acc = derive_hard_junction(&acc, &cc),
|
||||
}
|
||||
}
|
||||
Ok((Self::from_seed(&acc), Some(acc)))
|
||||
}
|
||||
|
||||
/// Get the public key.
|
||||
fn public(&self) -> Public {
|
||||
Public(self.public.serialize_compressed())
|
||||
}
|
||||
|
||||
/// Sign a message.
|
||||
fn sign(&self, message: &[u8]) -> Signature {
|
||||
let message = secp256k1::Message::parse(&blake2_256(message));
|
||||
secp256k1::sign(&message, &self.secret).into()
|
||||
}
|
||||
|
||||
/// Verify a signature on a message. Returns true if the signature is good.
|
||||
fn verify<M: AsRef<[u8]>>(sig: &Self::Signature, message: M, pubkey: &Self::Public) -> bool {
|
||||
let message = secp256k1::Message::parse(&blake2_256(message.as_ref()));
|
||||
let sig: (_, _) = match sig.try_into() { Ok(x) => x, _ => return false };
|
||||
match secp256k1::recover(&message, &sig.0, &sig.1) {
|
||||
Ok(actual) => &pubkey.0[..] == &actual.serialize_compressed()[..],
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Verify a signature on a message. Returns true if the signature is good.
|
||||
///
|
||||
/// This doesn't use the type system to ensure that `sig` and `pubkey` are the correct
|
||||
/// size. Use it only if you're coming from byte buffers and need the speed.
|
||||
fn verify_weak<P: AsRef<[u8]>, M: AsRef<[u8]>>(sig: &[u8], message: M, pubkey: P) -> bool {
|
||||
let message = secp256k1::Message::parse(&blake2_256(message.as_ref()));
|
||||
if sig.len() != 65 { return false }
|
||||
let ri = match secp256k1::RecoveryId::parse(sig[64]) { Ok(x) => x, _ => return false };
|
||||
let sig = match secp256k1::Signature::parse_slice(&sig[0..64]) { Ok(x) => x, _ => return false };
|
||||
match secp256k1::recover(&message, &sig, &ri) {
|
||||
Ok(actual) => pubkey.as_ref() == &actual.serialize_compressed()[..],
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Return a vec filled with raw data.
|
||||
fn to_raw_vec(&self) -> Vec<u8> {
|
||||
self.seed().to_vec()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "full_crypto")]
|
||||
impl Pair {
|
||||
/// Get the seed for this key.
|
||||
pub fn seed(&self) -> Seed {
|
||||
self.secret.serialize()
|
||||
}
|
||||
|
||||
/// Exactly as `from_string` except that if no matches are found then, the the first 32
|
||||
/// characters are taken (padded with spaces as necessary) and used as the MiniSecretKey.
|
||||
#[cfg(feature = "std")]
|
||||
pub fn from_legacy_string(s: &str, password_override: Option<&str>) -> Pair {
|
||||
Self::from_string(s, password_override).unwrap_or_else(|_| {
|
||||
let mut padded_seed: Seed = [' ' as u8; 32];
|
||||
let len = s.len().min(32);
|
||||
padded_seed[..len].copy_from_slice(&s.as_bytes()[..len]);
|
||||
Self::from_seed(&padded_seed)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl CryptoType for Public {
|
||||
#[cfg(feature="full_crypto")]
|
||||
type Pair = Pair;
|
||||
}
|
||||
|
||||
impl CryptoType for Signature {
|
||||
#[cfg(feature="full_crypto")]
|
||||
type Pair = Pair;
|
||||
}
|
||||
|
||||
#[cfg(feature="full_crypto")]
|
||||
impl CryptoType for Pair {
|
||||
type Pair = Pair;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use hex_literal::hex;
|
||||
use crate::crypto::DEV_PHRASE;
|
||||
|
||||
#[test]
|
||||
fn default_phrase_should_be_used() {
|
||||
assert_eq!(
|
||||
Pair::from_string("//Alice///password", None).unwrap().public(),
|
||||
Pair::from_string(&format!("{}//Alice", DEV_PHRASE), Some("password")).unwrap().public(),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn seed_and_derive_should_work() {
|
||||
let seed = hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60");
|
||||
let pair = Pair::from_seed(&seed);
|
||||
assert_eq!(pair.seed(), seed);
|
||||
let path = vec![DeriveJunction::Hard([0u8; 32])];
|
||||
let derived = pair.derive(path.into_iter(), None).ok().unwrap();
|
||||
assert_eq!(
|
||||
derived.0.seed(),
|
||||
hex!("b8eefc4937200a8382d00050e050ced2d4ab72cc2ef1b061477afb51564fdd61")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_vector_should_work() {
|
||||
let pair = Pair::from_seed(
|
||||
&hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60")
|
||||
);
|
||||
let public = pair.public();
|
||||
assert_eq!(public, Public::from_raw(
|
||||
hex!("028db55b05db86c0b1786ca49f095d76344c9e6056b2f02701a7e7f3c20aabfd91")
|
||||
));
|
||||
let message = b"";
|
||||
let signature = hex!("3dde91174bd9359027be59a428b8146513df80a2a3c7eda2194f64de04a69ab97b753169e94db6ffd50921a2668a48b94ca11e3d32c1ff19cfe88890aa7e8f3c00");
|
||||
let signature = Signature::from_raw(signature);
|
||||
assert!(&pair.sign(&message[..]) == &signature);
|
||||
assert!(Pair::verify(&signature, &message[..], &public));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_vector_by_string_should_work() {
|
||||
let pair = Pair::from_string(
|
||||
"0x9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60",
|
||||
None
|
||||
).unwrap();
|
||||
let public = pair.public();
|
||||
assert_eq!(public, Public::from_raw(
|
||||
hex!("028db55b05db86c0b1786ca49f095d76344c9e6056b2f02701a7e7f3c20aabfd91")
|
||||
));
|
||||
let message = b"";
|
||||
let signature = hex!("3dde91174bd9359027be59a428b8146513df80a2a3c7eda2194f64de04a69ab97b753169e94db6ffd50921a2668a48b94ca11e3d32c1ff19cfe88890aa7e8f3c00");
|
||||
let signature = Signature::from_raw(signature);
|
||||
assert!(&pair.sign(&message[..]) == &signature);
|
||||
assert!(Pair::verify(&signature, &message[..], &public));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn generated_pair_should_work() {
|
||||
let (pair, _) = Pair::generate();
|
||||
let public = pair.public();
|
||||
let message = b"Something important";
|
||||
let signature = pair.sign(&message[..]);
|
||||
assert!(Pair::verify(&signature, &message[..], &public));
|
||||
assert!(!Pair::verify(&signature, b"Something else", &public));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn seeded_pair_should_work() {
|
||||
let pair = Pair::from_seed(b"12345678901234567890123456789012");
|
||||
let public = pair.public();
|
||||
assert_eq!(public, Public::from_raw(
|
||||
hex!("035676109c54b9a16d271abeb4954316a40a32bcce023ac14c8e26e958aa68fba9")
|
||||
));
|
||||
let message = hex!("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000200d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000");
|
||||
let signature = pair.sign(&message[..]);
|
||||
println!("Correct signature: {:?}", signature);
|
||||
assert!(Pair::verify(&signature, &message[..], &public));
|
||||
assert!(!Pair::verify(&signature, "Other message", &public));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn generate_with_phrase_recovery_possible() {
|
||||
let (pair1, phrase, _) = Pair::generate_with_phrase(None);
|
||||
let (pair2, _) = Pair::from_phrase(&phrase, None).unwrap();
|
||||
|
||||
assert_eq!(pair1.public(), pair2.public());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn generate_with_password_phrase_recovery_possible() {
|
||||
let (pair1, phrase, _) = Pair::generate_with_phrase(Some("password"));
|
||||
let (pair2, _) = Pair::from_phrase(&phrase, Some("password")).unwrap();
|
||||
|
||||
assert_eq!(pair1.public(), pair2.public());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn password_does_something() {
|
||||
let (pair1, phrase, _) = Pair::generate_with_phrase(Some("password"));
|
||||
let (pair2, _) = Pair::from_phrase(&phrase, None).unwrap();
|
||||
|
||||
assert_ne!(pair1.public(), pair2.public());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ss58check_roundtrip_works() {
|
||||
let pair = Pair::from_seed(b"12345678901234567890123456789012");
|
||||
let public = pair.public();
|
||||
let s = public.to_ss58check();
|
||||
println!("Correct: {}", s);
|
||||
let cmp = Public::from_ss58check(&s).unwrap();
|
||||
assert_eq!(cmp, public);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,646 @@
|
||||
// Copyright 2017-2019 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Substrate is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// tag::description[]
|
||||
//! Simple Ed25519 API.
|
||||
// end::description[]
|
||||
|
||||
#[cfg(feature = "full_crypto")]
|
||||
use rstd::vec::Vec;
|
||||
|
||||
use crate::{hash::H256, hash::H512};
|
||||
use codec::{Encode, Decode};
|
||||
|
||||
#[cfg(feature = "full_crypto")]
|
||||
use blake2_rfc;
|
||||
#[cfg(feature = "std")]
|
||||
use substrate_bip39::seed_from_entropy;
|
||||
#[cfg(feature = "std")]
|
||||
use bip39::{Mnemonic, Language, MnemonicType};
|
||||
#[cfg(feature = "full_crypto")]
|
||||
use crate::crypto::{Pair as TraitPair, DeriveJunction, SecretStringError};
|
||||
#[cfg(feature = "std")]
|
||||
use crate::crypto::Ss58Codec;
|
||||
#[cfg(feature = "std")]
|
||||
use serde::{de, Serializer, Serialize, Deserializer, Deserialize};
|
||||
use crate::{crypto::{Public as TraitPublic, UncheckedFrom, CryptoType, Derive}};
|
||||
use runtime_interface::pass_by::PassByInner;
|
||||
use rstd::ops::Deref;
|
||||
|
||||
/// A secret seed. It's not called a "secret key" because ring doesn't expose the secret keys
|
||||
/// of the key pair (yeah, dumb); as such we're forced to remember the seed manually if we
|
||||
/// will need it later (such as for HDKD).
|
||||
#[cfg(feature = "full_crypto")]
|
||||
type Seed = [u8; 32];
|
||||
|
||||
/// A public key.
|
||||
#[cfg_attr(feature = "full_crypto", derive(Hash))]
|
||||
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Encode, Decode, Default, PassByInner)]
|
||||
pub struct Public(pub [u8; 32]);
|
||||
|
||||
/// A key pair.
|
||||
#[cfg(feature = "full_crypto")]
|
||||
pub struct Pair(ed25519_dalek::Keypair);
|
||||
|
||||
#[cfg(feature = "full_crypto")]
|
||||
impl Clone for Pair {
|
||||
fn clone(&self) -> Self {
|
||||
Pair(ed25519_dalek::Keypair {
|
||||
public: self.0.public.clone(),
|
||||
secret: ed25519_dalek::SecretKey::from_bytes(self.0.secret.as_bytes())
|
||||
.expect("key is always the correct size; qed")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<[u8; 32]> for Public {
|
||||
fn as_ref(&self) -> &[u8; 32] {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<[u8]> for Public {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
&self.0[..]
|
||||
}
|
||||
}
|
||||
|
||||
impl AsMut<[u8]> for Public {
|
||||
fn as_mut(&mut self) -> &mut [u8] {
|
||||
&mut self.0[..]
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for Public {
|
||||
type Target = [u8];
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl rstd::convert::TryFrom<&[u8]> for Public {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(data: &[u8]) -> Result<Self, Self::Error> {
|
||||
if data.len() == 32 {
|
||||
let mut inner = [0u8; 32];
|
||||
inner.copy_from_slice(data);
|
||||
Ok(Public(inner))
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Public> for [u8; 32] {
|
||||
fn from(x: Public) -> Self {
|
||||
x.0
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "full_crypto")]
|
||||
impl From<Pair> for Public {
|
||||
fn from(x: Pair) -> Self {
|
||||
x.public()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Public> for H256 {
|
||||
fn from(x: Public) -> Self {
|
||||
x.0.into()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl std::str::FromStr for Public {
|
||||
type Err = crate::crypto::PublicError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Self::from_ss58check(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl UncheckedFrom<[u8; 32]> for Public {
|
||||
fn unchecked_from(x: [u8; 32]) -> Self {
|
||||
Public::from_raw(x)
|
||||
}
|
||||
}
|
||||
|
||||
impl UncheckedFrom<H256> for Public {
|
||||
fn unchecked_from(x: H256) -> Self {
|
||||
Public::from_h256(x)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl std::fmt::Display for Public {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(f, "{}", self.to_ss58check())
|
||||
}
|
||||
}
|
||||
|
||||
impl rstd::fmt::Debug for Public {
|
||||
#[cfg(feature = "std")]
|
||||
fn fmt(&self, f: &mut rstd::fmt::Formatter) -> rstd::fmt::Result {
|
||||
let s = self.to_ss58check();
|
||||
write!(f, "{} ({}...)", crate::hexdisplay::HexDisplay::from(&self.0), &s[0..8])
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
fn fmt(&self, _: &mut rstd::fmt::Formatter) -> rstd::fmt::Result {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl Serialize for Public {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
|
||||
serializer.serialize_str(&self.to_ss58check())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<'de> Deserialize<'de> for Public {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de> {
|
||||
Public::from_ss58check(&String::deserialize(deserializer)?)
|
||||
.map_err(|e| de::Error::custom(format!("{:?}", e)))
|
||||
}
|
||||
}
|
||||
|
||||
/// A signature (a 512-bit value).
|
||||
#[derive(Encode, Decode, PassByInner)]
|
||||
pub struct Signature(pub [u8; 64]);
|
||||
|
||||
impl rstd::convert::TryFrom<&[u8]> for Signature {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(data: &[u8]) -> Result<Self, Self::Error> {
|
||||
if data.len() == 64 {
|
||||
let mut inner = [0u8; 64];
|
||||
inner.copy_from_slice(data);
|
||||
Ok(Signature(inner))
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Signature {
|
||||
fn clone(&self) -> Self {
|
||||
let mut r = [0u8; 64];
|
||||
r.copy_from_slice(&self.0[..]);
|
||||
Signature(r)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Signature {
|
||||
fn default() -> Self {
|
||||
Signature([0u8; 64])
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Signature {
|
||||
fn eq(&self, b: &Self) -> bool {
|
||||
self.0[..] == b.0[..]
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Signature {}
|
||||
|
||||
impl From<Signature> for H512 {
|
||||
fn from(v: Signature) -> H512 {
|
||||
H512::from(v.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Signature> for [u8; 64] {
|
||||
fn from(v: Signature) -> [u8; 64] {
|
||||
v.0
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<[u8; 64]> for Signature {
|
||||
fn as_ref(&self) -> &[u8; 64] {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<[u8]> for Signature {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
&self.0[..]
|
||||
}
|
||||
}
|
||||
|
||||
impl AsMut<[u8]> for Signature {
|
||||
fn as_mut(&mut self) -> &mut [u8] {
|
||||
&mut self.0[..]
|
||||
}
|
||||
}
|
||||
|
||||
impl rstd::fmt::Debug for Signature {
|
||||
#[cfg(feature = "std")]
|
||||
fn fmt(&self, f: &mut rstd::fmt::Formatter) -> rstd::fmt::Result {
|
||||
write!(f, "{}", crate::hexdisplay::HexDisplay::from(&self.0))
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
fn fmt(&self, _: &mut rstd::fmt::Formatter) -> rstd::fmt::Result {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "full_crypto")]
|
||||
impl rstd::hash::Hash for Signature {
|
||||
fn hash<H: rstd::hash::Hasher>(&self, state: &mut H) {
|
||||
rstd::hash::Hash::hash(&self.0[..], state);
|
||||
}
|
||||
}
|
||||
|
||||
impl Signature {
|
||||
/// A new instance from the given 64-byte `data`.
|
||||
///
|
||||
/// NOTE: No checking goes on to ensure this is a real signature. Only use it if
|
||||
/// you are certain that the array actually is a signature. GIGO!
|
||||
pub fn from_raw(data: [u8; 64]) -> Signature {
|
||||
Signature(data)
|
||||
}
|
||||
|
||||
/// A new instance from the given slice that should be 64 bytes long.
|
||||
///
|
||||
/// NOTE: No checking goes on to ensure this is a real signature. Only use it if
|
||||
/// you are certain that the array actually is a signature. GIGO!
|
||||
pub fn from_slice(data: &[u8]) -> Self {
|
||||
let mut r = [0u8; 64];
|
||||
r.copy_from_slice(data);
|
||||
Signature(r)
|
||||
}
|
||||
|
||||
/// A new instance from an H512.
|
||||
///
|
||||
/// NOTE: No checking goes on to ensure this is a real signature. Only use it if
|
||||
/// you are certain that the array actually is a signature. GIGO!
|
||||
pub fn from_h512(v: H512) -> Signature {
|
||||
Signature(v.into())
|
||||
}
|
||||
}
|
||||
|
||||
/// A localized signature also contains sender information.
|
||||
#[cfg(feature = "std")]
|
||||
#[derive(PartialEq, Eq, Clone, Debug, Encode, Decode)]
|
||||
pub struct LocalizedSignature {
|
||||
/// The signer of the signature.
|
||||
pub signer: Public,
|
||||
/// The signature itself.
|
||||
pub signature: Signature,
|
||||
}
|
||||
|
||||
/// An error type for SS58 decoding.
|
||||
#[cfg(feature = "std")]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
|
||||
pub enum PublicError {
|
||||
/// Bad alphabet.
|
||||
BadBase58,
|
||||
/// Bad length.
|
||||
BadLength,
|
||||
/// Unknown version.
|
||||
UnknownVersion,
|
||||
/// Invalid checksum.
|
||||
InvalidChecksum,
|
||||
}
|
||||
|
||||
impl Public {
|
||||
/// A new instance from the given 32-byte `data`.
|
||||
///
|
||||
/// NOTE: No checking goes on to ensure this is a real public key. Only use it if
|
||||
/// you are certain that the array actually is a pubkey. GIGO!
|
||||
pub fn from_raw(data: [u8; 32]) -> Self {
|
||||
Public(data)
|
||||
}
|
||||
|
||||
/// A new instance from an H256.
|
||||
///
|
||||
/// NOTE: No checking goes on to ensure this is a real public key. Only use it if
|
||||
/// you are certain that the array actually is a pubkey. GIGO!
|
||||
pub fn from_h256(x: H256) -> Self {
|
||||
Public(x.into())
|
||||
}
|
||||
|
||||
/// Return a slice filled with raw data.
|
||||
pub fn as_array_ref(&self) -> &[u8; 32] {
|
||||
self.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl TraitPublic for Public {
|
||||
/// A new instance from the given slice that should be 32 bytes long.
|
||||
///
|
||||
/// NOTE: No checking goes on to ensure this is a real public key. Only use it if
|
||||
/// you are certain that the array actually is a pubkey. GIGO!
|
||||
fn from_slice(data: &[u8]) -> Self {
|
||||
let mut r = [0u8; 32];
|
||||
r.copy_from_slice(data);
|
||||
Public(r)
|
||||
}
|
||||
}
|
||||
|
||||
impl Derive for Public {}
|
||||
|
||||
/// Derive a single hard junction.
|
||||
#[cfg(feature = "full_crypto")]
|
||||
fn derive_hard_junction(secret_seed: &Seed, cc: &[u8; 32]) -> Seed {
|
||||
("Ed25519HDKD", secret_seed, cc).using_encoded(|data| {
|
||||
let mut res = [0u8; 32];
|
||||
res.copy_from_slice(blake2_rfc::blake2b::blake2b(32, &[], data).as_bytes());
|
||||
res
|
||||
})
|
||||
}
|
||||
|
||||
/// An error when deriving a key.
|
||||
#[cfg(feature = "full_crypto")]
|
||||
pub enum DeriveError {
|
||||
/// A soft key was found in the path (and is unsupported).
|
||||
SoftKeyInPath,
|
||||
}
|
||||
|
||||
#[cfg(feature = "full_crypto")]
|
||||
impl TraitPair for Pair {
|
||||
type Public = Public;
|
||||
type Seed = Seed;
|
||||
type Signature = Signature;
|
||||
type DeriveError = DeriveError;
|
||||
|
||||
/// Generate new secure (random) key pair and provide the recovery phrase.
|
||||
///
|
||||
/// You can recover the same key later with `from_phrase`.
|
||||
#[cfg(feature = "std")]
|
||||
fn generate_with_phrase(password: Option<&str>) -> (Pair, String, Seed) {
|
||||
let mnemonic = Mnemonic::new(MnemonicType::Words12, Language::English);
|
||||
let phrase = mnemonic.phrase();
|
||||
let (pair, seed) = Self::from_phrase(phrase, password)
|
||||
.expect("All phrases generated by Mnemonic are valid; qed");
|
||||
(
|
||||
pair,
|
||||
phrase.to_owned(),
|
||||
seed,
|
||||
)
|
||||
}
|
||||
|
||||
/// Generate key pair from given recovery phrase and password.
|
||||
#[cfg(feature = "std")]
|
||||
fn from_phrase(phrase: &str, password: Option<&str>) -> Result<(Pair, Seed), SecretStringError> {
|
||||
let big_seed = seed_from_entropy(
|
||||
Mnemonic::from_phrase(phrase, Language::English)
|
||||
.map_err(|_| SecretStringError::InvalidPhrase)?.entropy(),
|
||||
password.unwrap_or(""),
|
||||
).map_err(|_| SecretStringError::InvalidSeed)?;
|
||||
let mut seed = Seed::default();
|
||||
seed.copy_from_slice(&big_seed[0..32]);
|
||||
Self::from_seed_slice(&big_seed[0..32]).map(|x| (x, seed))
|
||||
}
|
||||
|
||||
/// Make a new key pair from secret seed material.
|
||||
///
|
||||
/// You should never need to use this; generate(), generate_with_phrasee
|
||||
fn from_seed(seed: &Seed) -> Pair {
|
||||
Self::from_seed_slice(&seed[..]).expect("seed has valid length; qed")
|
||||
}
|
||||
|
||||
/// Make a new key pair from secret seed material. The slice must be 32 bytes long or it
|
||||
/// will return `None`.
|
||||
///
|
||||
/// You should never need to use this; generate(), generate_with_phrase
|
||||
fn from_seed_slice(seed_slice: &[u8]) -> Result<Pair, SecretStringError> {
|
||||
let secret = ed25519_dalek::SecretKey::from_bytes(seed_slice)
|
||||
.map_err(|_| SecretStringError::InvalidSeedLength)?;
|
||||
let public = ed25519_dalek::PublicKey::from(secret.expand::<sha2::Sha512>());
|
||||
Ok(Pair(ed25519_dalek::Keypair { secret, public }))
|
||||
}
|
||||
|
||||
/// Derive a child key from a series of given junctions.
|
||||
fn derive<Iter: Iterator<Item=DeriveJunction>>(&self,
|
||||
path: Iter,
|
||||
_seed: Option<Seed>,
|
||||
) -> Result<(Pair, Option<Seed>), DeriveError> {
|
||||
let mut acc = self.0.secret.to_bytes();
|
||||
for j in path {
|
||||
match j {
|
||||
DeriveJunction::Soft(_cc) => return Err(DeriveError::SoftKeyInPath),
|
||||
DeriveJunction::Hard(cc) => acc = derive_hard_junction(&acc, &cc),
|
||||
}
|
||||
}
|
||||
Ok((Self::from_seed(&acc), Some(acc)))
|
||||
}
|
||||
|
||||
/// Get the public key.
|
||||
fn public(&self) -> Public {
|
||||
let mut r = [0u8; 32];
|
||||
let pk = self.0.public.as_bytes();
|
||||
r.copy_from_slice(pk);
|
||||
Public(r)
|
||||
}
|
||||
|
||||
/// Sign a message.
|
||||
fn sign(&self, message: &[u8]) -> Signature {
|
||||
let r = self.0.sign::<sha2::Sha512>(message).to_bytes();
|
||||
Signature::from_raw(r)
|
||||
}
|
||||
|
||||
/// Verify a signature on a message. Returns true if the signature is good.
|
||||
fn verify<M: AsRef<[u8]>>(sig: &Self::Signature, message: M, pubkey: &Self::Public) -> bool {
|
||||
Self::verify_weak(&sig.0[..], message.as_ref(), pubkey)
|
||||
}
|
||||
|
||||
/// Verify a signature on a message. Returns true if the signature is good.
|
||||
///
|
||||
/// This doesn't use the type system to ensure that `sig` and `pubkey` are the correct
|
||||
/// size. Use it only if you're coming from byte buffers and need the speed.
|
||||
fn verify_weak<P: AsRef<[u8]>, M: AsRef<[u8]>>(sig: &[u8], message: M, pubkey: P) -> bool {
|
||||
let public_key = match ed25519_dalek::PublicKey::from_bytes(pubkey.as_ref()) {
|
||||
Ok(pk) => pk,
|
||||
Err(_) => return false,
|
||||
};
|
||||
|
||||
let sig = match ed25519_dalek::Signature::from_bytes(sig) {
|
||||
Ok(s) => s,
|
||||
Err(_) => return false
|
||||
};
|
||||
|
||||
match public_key.verify::<sha2::Sha512>(message.as_ref(), &sig) {
|
||||
Ok(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Return a vec filled with raw data.
|
||||
fn to_raw_vec(&self) -> Vec<u8> {
|
||||
self.seed().to_vec()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "full_crypto")]
|
||||
impl Pair {
|
||||
/// Get the seed for this key.
|
||||
pub fn seed(&self) -> &Seed {
|
||||
self.0.secret.as_bytes()
|
||||
}
|
||||
|
||||
/// Exactly as `from_string` except that if no matches are found then, the the first 32
|
||||
/// characters are taken (padded with spaces as necessary) and used as the MiniSecretKey.
|
||||
#[cfg(feature = "std")]
|
||||
pub fn from_legacy_string(s: &str, password_override: Option<&str>) -> Pair {
|
||||
Self::from_string(s, password_override).unwrap_or_else(|_| {
|
||||
let mut padded_seed: Seed = [' ' as u8; 32];
|
||||
let len = s.len().min(32);
|
||||
padded_seed[..len].copy_from_slice(&s.as_bytes()[..len]);
|
||||
Self::from_seed(&padded_seed)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl CryptoType for Public {
|
||||
#[cfg(feature = "full_crypto")]
|
||||
type Pair = Pair;
|
||||
}
|
||||
|
||||
impl CryptoType for Signature {
|
||||
#[cfg(feature = "full_crypto")]
|
||||
type Pair = Pair;
|
||||
}
|
||||
|
||||
#[cfg(feature = "full_crypto")]
|
||||
impl CryptoType for Pair {
|
||||
type Pair = Pair;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use hex_literal::hex;
|
||||
use crate::crypto::DEV_PHRASE;
|
||||
|
||||
#[test]
|
||||
fn default_phrase_should_be_used() {
|
||||
assert_eq!(
|
||||
Pair::from_string("//Alice///password", None).unwrap().public(),
|
||||
Pair::from_string(&format!("{}//Alice", DEV_PHRASE), Some("password")).unwrap().public(),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn seed_and_derive_should_work() {
|
||||
let seed = hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60");
|
||||
let pair = Pair::from_seed(&seed);
|
||||
assert_eq!(pair.seed(), &seed);
|
||||
let path = vec![DeriveJunction::Hard([0u8; 32])];
|
||||
let derived = pair.derive(path.into_iter(), None).ok().unwrap().0;
|
||||
assert_eq!(
|
||||
derived.seed(),
|
||||
&hex!("ede3354e133f9c8e337ddd6ee5415ed4b4ffe5fc7d21e933f4930a3730e5b21c")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_vector_should_work() {
|
||||
let pair = Pair::from_seed(
|
||||
&hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60")
|
||||
);
|
||||
let public = pair.public();
|
||||
assert_eq!(public, Public::from_raw(
|
||||
hex!("d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a")
|
||||
));
|
||||
let message = b"";
|
||||
let signature = hex!("e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e065224901555fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b");
|
||||
let signature = Signature::from_raw(signature);
|
||||
assert!(&pair.sign(&message[..]) == &signature);
|
||||
assert!(Pair::verify(&signature, &message[..], &public));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_vector_by_string_should_work() {
|
||||
let pair = Pair::from_string(
|
||||
"0x9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60",
|
||||
None
|
||||
).unwrap();
|
||||
let public = pair.public();
|
||||
assert_eq!(public, Public::from_raw(
|
||||
hex!("d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a")
|
||||
));
|
||||
let message = b"";
|
||||
let signature = hex!("e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e065224901555fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b");
|
||||
let signature = Signature::from_raw(signature);
|
||||
assert!(&pair.sign(&message[..]) == &signature);
|
||||
assert!(Pair::verify(&signature, &message[..], &public));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn generated_pair_should_work() {
|
||||
let (pair, _) = Pair::generate();
|
||||
let public = pair.public();
|
||||
let message = b"Something important";
|
||||
let signature = pair.sign(&message[..]);
|
||||
assert!(Pair::verify(&signature, &message[..], &public));
|
||||
assert!(!Pair::verify(&signature, b"Something else", &public));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn seeded_pair_should_work() {
|
||||
let pair = Pair::from_seed(b"12345678901234567890123456789012");
|
||||
let public = pair.public();
|
||||
assert_eq!(public, Public::from_raw(
|
||||
hex!("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee")
|
||||
));
|
||||
let message = hex!("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000200d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000");
|
||||
let signature = pair.sign(&message[..]);
|
||||
println!("Correct signature: {:?}", signature);
|
||||
assert!(Pair::verify(&signature, &message[..], &public));
|
||||
assert!(!Pair::verify(&signature, "Other message", &public));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn generate_with_phrase_recovery_possible() {
|
||||
let (pair1, phrase, _) = Pair::generate_with_phrase(None);
|
||||
let (pair2, _) = Pair::from_phrase(&phrase, None).unwrap();
|
||||
|
||||
assert_eq!(pair1.public(), pair2.public());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn generate_with_password_phrase_recovery_possible() {
|
||||
let (pair1, phrase, _) = Pair::generate_with_phrase(Some("password"));
|
||||
let (pair2, _) = Pair::from_phrase(&phrase, Some("password")).unwrap();
|
||||
|
||||
assert_eq!(pair1.public(), pair2.public());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn password_does_something() {
|
||||
let (pair1, phrase, _) = Pair::generate_with_phrase(Some("password"));
|
||||
let (pair2, _) = Pair::from_phrase(&phrase, None).unwrap();
|
||||
|
||||
assert_ne!(pair1.public(), pair2.public());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ss58check_roundtrip_works() {
|
||||
let pair = Pair::from_seed(b"12345678901234567890123456789012");
|
||||
let public = pair.public();
|
||||
let s = public.to_ss58check();
|
||||
println!("Correct: {}", s);
|
||||
let cmp = Public::from_ss58check(&s).unwrap();
|
||||
assert_eq!(cmp, public);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
// Copyright 2017-2019 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Substrate is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! A fixed hash type.
|
||||
|
||||
pub use primitive_types::{H160, H256, H512};
|
||||
|
||||
/// Hash conversion. Used to convert between unbound associated hash types in traits,
|
||||
/// implemented by the same hash type.
|
||||
/// Panics if used to convert between different hash types.
|
||||
pub fn convert_hash<H1: Default + AsMut<[u8]>, H2: AsRef<[u8]>>(src: &H2) -> H1 {
|
||||
let mut dest = H1::default();
|
||||
assert_eq!(dest.as_mut().len(), src.as_ref().len());
|
||||
dest.as_mut().copy_from_slice(src.as_ref());
|
||||
dest
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use substrate_serializer as ser;
|
||||
|
||||
#[test]
|
||||
fn test_h160() {
|
||||
let tests = vec![
|
||||
(Default::default(), "0x0000000000000000000000000000000000000000"),
|
||||
(H160::from_low_u64_be(2), "0x0000000000000000000000000000000000000002"),
|
||||
(H160::from_low_u64_be(15), "0x000000000000000000000000000000000000000f"),
|
||||
(H160::from_low_u64_be(16), "0x0000000000000000000000000000000000000010"),
|
||||
(H160::from_low_u64_be(1_000), "0x00000000000000000000000000000000000003e8"),
|
||||
(H160::from_low_u64_be(100_000), "0x00000000000000000000000000000000000186a0"),
|
||||
(H160::from_low_u64_be(u64::max_value()), "0x000000000000000000000000ffffffffffffffff"),
|
||||
];
|
||||
|
||||
for (number, expected) in tests {
|
||||
assert_eq!(format!("{:?}", expected), ser::to_string_pretty(&number));
|
||||
assert_eq!(number, ser::from_str(&format!("{:?}", expected)).unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_h256() {
|
||||
let tests = vec![
|
||||
(Default::default(), "0x0000000000000000000000000000000000000000000000000000000000000000"),
|
||||
(H256::from_low_u64_be(2), "0x0000000000000000000000000000000000000000000000000000000000000002"),
|
||||
(H256::from_low_u64_be(15), "0x000000000000000000000000000000000000000000000000000000000000000f"),
|
||||
(H256::from_low_u64_be(16), "0x0000000000000000000000000000000000000000000000000000000000000010"),
|
||||
(H256::from_low_u64_be(1_000), "0x00000000000000000000000000000000000000000000000000000000000003e8"),
|
||||
(H256::from_low_u64_be(100_000), "0x00000000000000000000000000000000000000000000000000000000000186a0"),
|
||||
(H256::from_low_u64_be(u64::max_value()), "0x000000000000000000000000000000000000000000000000ffffffffffffffff"),
|
||||
];
|
||||
|
||||
for (number, expected) in tests {
|
||||
assert_eq!(format!("{:?}", expected), ser::to_string_pretty(&number));
|
||||
assert_eq!(number, ser::from_str(&format!("{:?}", expected)).unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_invalid() {
|
||||
assert!(ser::from_str::<H256>("\"0x000000000000000000000000000000000000000000000000000000000000000\"").unwrap_err().is_data());
|
||||
assert!(ser::from_str::<H256>("\"0x000000000000000000000000000000000000000000000000000000000000000g\"").unwrap_err().is_data());
|
||||
assert!(ser::from_str::<H256>("\"0x00000000000000000000000000000000000000000000000000000000000000000\"").unwrap_err().is_data());
|
||||
assert!(ser::from_str::<H256>("\"\"").unwrap_err().is_data());
|
||||
assert!(ser::from_str::<H256>("\"0\"").unwrap_err().is_data());
|
||||
assert!(ser::from_str::<H256>("\"10\"").unwrap_err().is_data());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
// Copyright 2018-2019 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Substrate is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Substrate Blake2b Hasher implementation
|
||||
|
||||
use hash_db::Hasher;
|
||||
use hash256_std_hasher::Hash256StdHasher;
|
||||
use crate::hash::H256;
|
||||
|
||||
pub mod blake2 {
|
||||
use super::{Hasher, Hash256StdHasher, H256};
|
||||
#[cfg(feature = "std")]
|
||||
use crate::hashing::blake2_256;
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
extern "C" {
|
||||
fn ext_blake2_256(data: *const u8, len: u32, out: *mut u8);
|
||||
}
|
||||
#[cfg(not(feature = "std"))]
|
||||
fn blake2_256(data: &[u8]) -> [u8; 32] {
|
||||
let mut result: [u8; 32] = Default::default();
|
||||
unsafe {
|
||||
ext_blake2_256(data.as_ptr(), data.len() as u32, result.as_mut_ptr());
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
/// Concrete implementation of Hasher using Blake2b 256-bit hashes
|
||||
#[derive(Debug)]
|
||||
pub struct Blake2Hasher;
|
||||
|
||||
impl Hasher for Blake2Hasher {
|
||||
type Out = H256;
|
||||
type StdHasher = Hash256StdHasher;
|
||||
const LENGTH: usize = 32;
|
||||
fn hash(x: &[u8]) -> Self::Out {
|
||||
blake2_256(x).into()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
// Copyright 2017-2019 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Substrate is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Hashing functions.
|
||||
|
||||
use blake2_rfc;
|
||||
use tiny_keccak::{Hasher, Keccak};
|
||||
use twox_hash;
|
||||
|
||||
/// Do a Blake2 512-bit hash and place result in `dest`.
|
||||
pub fn blake2_512_into(data: &[u8], dest: &mut [u8; 64]) {
|
||||
dest.copy_from_slice(blake2_rfc::blake2b::blake2b(64, &[], data).as_bytes());
|
||||
}
|
||||
|
||||
/// Do a Blake2 512-bit hash and return result.
|
||||
pub fn blake2_512(data: &[u8]) -> [u8; 64] {
|
||||
let mut r = [0; 64];
|
||||
blake2_512_into(data, &mut r);
|
||||
r
|
||||
}
|
||||
|
||||
/// Do a Blake2 256-bit hash and place result in `dest`.
|
||||
pub fn blake2_256_into(data: &[u8], dest: &mut [u8; 32]) {
|
||||
dest.copy_from_slice(blake2_rfc::blake2b::blake2b(32, &[], data).as_bytes());
|
||||
}
|
||||
|
||||
/// Do a Blake2 256-bit hash and return result.
|
||||
pub fn blake2_256(data: &[u8]) -> [u8; 32] {
|
||||
let mut r = [0; 32];
|
||||
blake2_256_into(data, &mut r);
|
||||
r
|
||||
}
|
||||
|
||||
/// Do a Blake2 128-bit hash and place result in `dest`.
|
||||
pub fn blake2_128_into(data: &[u8], dest: &mut [u8; 16]) {
|
||||
dest.copy_from_slice(blake2_rfc::blake2b::blake2b(16, &[], data).as_bytes());
|
||||
}
|
||||
|
||||
/// Do a Blake2 128-bit hash and return result.
|
||||
pub fn blake2_128(data: &[u8]) -> [u8; 16] {
|
||||
let mut r = [0; 16];
|
||||
blake2_128_into(data, &mut r);
|
||||
r
|
||||
}
|
||||
|
||||
/// Do a XX 64-bit hash and place result in `dest`.
|
||||
pub fn twox_64_into(data: &[u8], dest: &mut [u8; 8]) {
|
||||
use ::core::hash::Hasher;
|
||||
let mut h0 = twox_hash::XxHash::with_seed(0);
|
||||
h0.write(data);
|
||||
let r0 = h0.finish();
|
||||
use byteorder::{ByteOrder, LittleEndian};
|
||||
LittleEndian::write_u64(&mut dest[0..8], r0);
|
||||
}
|
||||
|
||||
/// Do a XX 64-bit hash and return result.
|
||||
pub fn twox_64(data: &[u8]) -> [u8; 8] {
|
||||
let mut r: [u8; 8] = [0; 8];
|
||||
twox_64_into(data, &mut r);
|
||||
r
|
||||
}
|
||||
|
||||
/// Do a XX 128-bit hash and place result in `dest`.
|
||||
pub fn twox_128_into(data: &[u8], dest: &mut [u8; 16]) {
|
||||
use ::core::hash::Hasher;
|
||||
let mut h0 = twox_hash::XxHash::with_seed(0);
|
||||
let mut h1 = twox_hash::XxHash::with_seed(1);
|
||||
h0.write(data);
|
||||
h1.write(data);
|
||||
let r0 = h0.finish();
|
||||
let r1 = h1.finish();
|
||||
use byteorder::{ByteOrder, LittleEndian};
|
||||
LittleEndian::write_u64(&mut dest[0..8], r0);
|
||||
LittleEndian::write_u64(&mut dest[8..16], r1);
|
||||
}
|
||||
|
||||
/// Do a XX 128-bit hash and return result.
|
||||
pub fn twox_128(data: &[u8]) -> [u8; 16] {
|
||||
let mut r: [u8; 16] = [0; 16];
|
||||
twox_128_into(data, &mut r);
|
||||
r
|
||||
}
|
||||
|
||||
/// Do a XX 256-bit hash and place result in `dest`.
|
||||
pub fn twox_256_into(data: &[u8], dest: &mut [u8; 32]) {
|
||||
use ::core::hash::Hasher;
|
||||
use byteorder::{ByteOrder, LittleEndian};
|
||||
let mut h0 = twox_hash::XxHash::with_seed(0);
|
||||
let mut h1 = twox_hash::XxHash::with_seed(1);
|
||||
let mut h2 = twox_hash::XxHash::with_seed(2);
|
||||
let mut h3 = twox_hash::XxHash::with_seed(3);
|
||||
h0.write(data);
|
||||
h1.write(data);
|
||||
h2.write(data);
|
||||
h3.write(data);
|
||||
let r0 = h0.finish();
|
||||
let r1 = h1.finish();
|
||||
let r2 = h2.finish();
|
||||
let r3 = h3.finish();
|
||||
LittleEndian::write_u64(&mut dest[0..8], r0);
|
||||
LittleEndian::write_u64(&mut dest[8..16], r1);
|
||||
LittleEndian::write_u64(&mut dest[16..24], r2);
|
||||
LittleEndian::write_u64(&mut dest[24..32], r3);
|
||||
}
|
||||
|
||||
/// Do a XX 256-bit hash and return result.
|
||||
pub fn twox_256(data: &[u8]) -> [u8; 32] {
|
||||
let mut r: [u8; 32] = [0; 32];
|
||||
twox_256_into(data, &mut r);
|
||||
r
|
||||
}
|
||||
|
||||
/// Do a keccak 256 hash and return result.
|
||||
pub fn keccak_256(data: &[u8]) -> [u8; 32] {
|
||||
let mut keccak = Keccak::v256();
|
||||
keccak.update(data);
|
||||
let mut output = [0u8; 32];
|
||||
keccak.finalize(&mut output);
|
||||
output
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
// Copyright 2017-2019 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Substrate is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Wrapper type for byte collections that outputs hex.
|
||||
|
||||
/// Simple wrapper to display hex representation of bytes.
|
||||
pub struct HexDisplay<'a>(&'a [u8]);
|
||||
|
||||
impl<'a> HexDisplay<'a> {
|
||||
/// Create new instance that will display `d` as a hex string when displayed.
|
||||
pub fn from<R: AsBytesRef>(d: &'a R) -> Self { HexDisplay(d.as_bytes_ref()) }
|
||||
}
|
||||
|
||||
impl<'a> rstd::fmt::Display for HexDisplay<'a> {
|
||||
fn fmt(&self, f: &mut rstd::fmt::Formatter) -> Result<(), rstd::fmt::Error> {
|
||||
if self.0.len() < 1027 {
|
||||
for byte in self.0 {
|
||||
f.write_fmt(format_args!("{:02x}", byte))?;
|
||||
}
|
||||
} else {
|
||||
for byte in &self.0[0..512] {
|
||||
f.write_fmt(format_args!("{:02x}", byte))?;
|
||||
}
|
||||
f.write_str("...")?;
|
||||
for byte in &self.0[self.0.len() - 512..] {
|
||||
f.write_fmt(format_args!("{:02x}", byte))?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> rstd::fmt::Debug for HexDisplay<'a> {
|
||||
fn fmt(&self, f: &mut rstd::fmt::Formatter) -> Result<(), rstd::fmt::Error> {
|
||||
for byte in self.0 {
|
||||
f.write_fmt(format_args!("{:02x}", byte))?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Simple trait to transform various types to `&[u8]`
|
||||
pub trait AsBytesRef {
|
||||
/// Transform `self` into `&[u8]`.
|
||||
fn as_bytes_ref(&self) -> &[u8];
|
||||
}
|
||||
|
||||
impl<'a> AsBytesRef for &'a [u8] {
|
||||
fn as_bytes_ref(&self) -> &[u8] { self }
|
||||
}
|
||||
|
||||
impl AsBytesRef for [u8] {
|
||||
fn as_bytes_ref(&self) -> &[u8] { &self }
|
||||
}
|
||||
|
||||
impl AsBytesRef for Vec<u8> {
|
||||
fn as_bytes_ref(&self) -> &[u8] { &self }
|
||||
}
|
||||
|
||||
macro_rules! impl_non_endians {
|
||||
( $( $t:ty ),* ) => { $(
|
||||
impl AsBytesRef for $t {
|
||||
fn as_bytes_ref(&self) -> &[u8] { &self[..] }
|
||||
}
|
||||
)* }
|
||||
}
|
||||
|
||||
impl_non_endians!([u8; 1], [u8; 2], [u8; 3], [u8; 4], [u8; 5], [u8; 6], [u8; 7], [u8; 8],
|
||||
[u8; 10], [u8; 12], [u8; 14], [u8; 16], [u8; 20], [u8; 24], [u8; 28], [u8; 32], [u8; 40],
|
||||
[u8; 48], [u8; 56], [u8; 64], [u8; 65], [u8; 80], [u8; 96], [u8; 112], [u8; 128]);
|
||||
|
||||
/// Format into ASCII + # + hex, suitable for storage key preimages.
|
||||
pub fn ascii_format(asciish: &[u8]) -> String {
|
||||
let mut r = String::new();
|
||||
let mut latch = false;
|
||||
for c in asciish {
|
||||
match (latch, *c) {
|
||||
(false, 32..=127) => r.push(*c as char),
|
||||
_ => {
|
||||
if !latch {
|
||||
r.push('#');
|
||||
latch = true;
|
||||
}
|
||||
r.push_str(&format!("{:02x}", *c));
|
||||
}
|
||||
}
|
||||
}
|
||||
r
|
||||
}
|
||||
@@ -0,0 +1,311 @@
|
||||
// Copyright 2017-2019 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Substrate is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Shareable Substrate types.
|
||||
|
||||
#![warn(missing_docs)]
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
/// Initialize a key-value collection from array.
|
||||
///
|
||||
/// Creates a vector of given pairs and calls `collect` on the iterator from it.
|
||||
/// Can be used to create a `HashMap`.
|
||||
#[macro_export]
|
||||
macro_rules! map {
|
||||
($( $name:expr => $value:expr ),* $(,)? ) => (
|
||||
vec![ $( ( $name, $value ) ),* ].into_iter().collect()
|
||||
);
|
||||
}
|
||||
|
||||
use rstd::prelude::*;
|
||||
use rstd::ops::Deref;
|
||||
#[cfg(feature = "std")]
|
||||
use std::borrow::Cow;
|
||||
#[cfg(feature = "std")]
|
||||
use serde::{Serialize, Deserialize};
|
||||
#[cfg(feature = "std")]
|
||||
pub use serde;
|
||||
#[doc(hidden)]
|
||||
pub use codec::{Encode, Decode};
|
||||
|
||||
pub use substrate_debug_derive::RuntimeDebug;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub use impl_serde::serialize as bytes;
|
||||
|
||||
#[cfg(feature = "full_crypto")]
|
||||
pub mod hashing;
|
||||
#[cfg(feature = "full_crypto")]
|
||||
pub use hashing::{blake2_128, blake2_256, twox_64, twox_128, twox_256, keccak_256};
|
||||
#[cfg(feature = "std")]
|
||||
pub mod hexdisplay;
|
||||
pub mod crypto;
|
||||
|
||||
pub mod u32_trait;
|
||||
|
||||
pub mod ed25519;
|
||||
pub mod sr25519;
|
||||
pub mod ecdsa;
|
||||
pub mod hash;
|
||||
mod hasher;
|
||||
pub mod offchain;
|
||||
pub mod sandbox;
|
||||
pub mod uint;
|
||||
mod changes_trie;
|
||||
#[cfg(feature = "std")]
|
||||
pub mod traits;
|
||||
pub mod testing;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
pub use self::hash::{H160, H256, H512, convert_hash};
|
||||
pub use self::uint::U256;
|
||||
pub use changes_trie::ChangesTrieConfiguration;
|
||||
#[cfg(feature = "full_crypto")]
|
||||
pub use crypto::{DeriveJunction, Pair, Public};
|
||||
|
||||
pub use hash_db::Hasher;
|
||||
// Switch back to Blake after PoC-3 is out
|
||||
// pub use self::hasher::blake::BlakeHasher;
|
||||
pub use self::hasher::blake2::Blake2Hasher;
|
||||
|
||||
pub use primitives_storage as storage;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub use rstd;
|
||||
|
||||
/// Context for executing a call into the runtime.
|
||||
pub enum ExecutionContext {
|
||||
/// Context for general importing (including own blocks).
|
||||
Importing,
|
||||
/// Context used when syncing the blockchain.
|
||||
Syncing,
|
||||
/// Context used for block construction.
|
||||
BlockConstruction,
|
||||
/// Context used for offchain calls.
|
||||
///
|
||||
/// This allows passing offchain extension and customizing available capabilities.
|
||||
OffchainCall(Option<(Box<dyn offchain::Externalities>, offchain::Capabilities)>),
|
||||
}
|
||||
|
||||
impl ExecutionContext {
|
||||
/// Returns the capabilities of particular context.
|
||||
pub fn capabilities(&self) -> offchain::Capabilities {
|
||||
use ExecutionContext::*;
|
||||
|
||||
match self {
|
||||
Importing | Syncing | BlockConstruction =>
|
||||
offchain::Capabilities::none(),
|
||||
// Enable keystore by default for offchain calls. CC @bkchr
|
||||
OffchainCall(None) => [offchain::Capability::Keystore][..].into(),
|
||||
OffchainCall(Some((_, capabilities))) => *capabilities,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Hex-serialized shim for `Vec<u8>`.
|
||||
#[derive(PartialEq, Eq, Clone, RuntimeDebug)]
|
||||
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Hash, PartialOrd, Ord))]
|
||||
pub struct Bytes(#[cfg_attr(feature = "std", serde(with="bytes"))] pub Vec<u8>);
|
||||
|
||||
impl From<Vec<u8>> for Bytes {
|
||||
fn from(s: Vec<u8>) -> Self { Bytes(s) }
|
||||
}
|
||||
|
||||
impl From<OpaqueMetadata> for Bytes {
|
||||
fn from(s: OpaqueMetadata) -> Self { Bytes(s.0) }
|
||||
}
|
||||
|
||||
impl Deref for Bytes {
|
||||
type Target = [u8];
|
||||
fn deref(&self) -> &[u8] { &self.0[..] }
|
||||
}
|
||||
|
||||
/// Stores the encoded `RuntimeMetadata` for the native side as opaque type.
|
||||
#[derive(Encode, Decode, PartialEq)]
|
||||
pub struct OpaqueMetadata(Vec<u8>);
|
||||
|
||||
impl OpaqueMetadata {
|
||||
/// Creates a new instance with the given metadata blob.
|
||||
pub fn new(metadata: Vec<u8>) -> Self {
|
||||
OpaqueMetadata(metadata)
|
||||
}
|
||||
}
|
||||
|
||||
impl rstd::ops::Deref for OpaqueMetadata {
|
||||
type Target = Vec<u8>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
/// Something that is either a native or an encoded value.
|
||||
#[cfg(feature = "std")]
|
||||
pub enum NativeOrEncoded<R> {
|
||||
/// The native representation.
|
||||
Native(R),
|
||||
/// The encoded representation.
|
||||
Encoded(Vec<u8>)
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<R: codec::Encode> rstd::fmt::Debug for NativeOrEncoded<R> {
|
||||
fn fmt(&self, f: &mut rstd::fmt::Formatter) -> rstd::fmt::Result {
|
||||
hexdisplay::HexDisplay::from(&self.as_encoded().as_ref()).fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<R: codec::Encode> NativeOrEncoded<R> {
|
||||
/// Return the value as the encoded format.
|
||||
pub fn as_encoded(&self) -> Cow<'_, [u8]> {
|
||||
match self {
|
||||
NativeOrEncoded::Encoded(e) => Cow::Borrowed(e.as_slice()),
|
||||
NativeOrEncoded::Native(n) => Cow::Owned(n.encode()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the value as the encoded format.
|
||||
pub fn into_encoded(self) -> Vec<u8> {
|
||||
match self {
|
||||
NativeOrEncoded::Encoded(e) => e,
|
||||
NativeOrEncoded::Native(n) => n.encode(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<R: PartialEq + codec::Decode> PartialEq for NativeOrEncoded<R> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(NativeOrEncoded::Native(l), NativeOrEncoded::Native(r)) => l == r,
|
||||
(NativeOrEncoded::Native(n), NativeOrEncoded::Encoded(e)) |
|
||||
(NativeOrEncoded::Encoded(e), NativeOrEncoded::Native(n)) =>
|
||||
Some(n) == codec::Decode::decode(&mut &e[..]).ok().as_ref(),
|
||||
(NativeOrEncoded::Encoded(l), NativeOrEncoded::Encoded(r)) => l == r,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A value that is never in a native representation.
|
||||
/// This is type is useful in conjuction with `NativeOrEncoded`.
|
||||
#[cfg(feature = "std")]
|
||||
#[derive(PartialEq)]
|
||||
pub enum NeverNativeValue {}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl codec::Encode for NeverNativeValue {
|
||||
fn encode(&self) -> Vec<u8> {
|
||||
// The enum is not constructable, so this function should never be callable!
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl codec::EncodeLike for NeverNativeValue {}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl codec::Decode for NeverNativeValue {
|
||||
fn decode<I: codec::Input>(_: &mut I) -> Result<Self, codec::Error> {
|
||||
Err("`NeverNativeValue` should never be decoded".into())
|
||||
}
|
||||
}
|
||||
|
||||
/// Provide a simple 4 byte identifier for a type.
|
||||
pub trait TypeId {
|
||||
/// Simple 4 byte identifier.
|
||||
const TYPE_ID: [u8; 4];
|
||||
}
|
||||
|
||||
/// A log level matching the one from `log` crate.
|
||||
///
|
||||
/// Used internally by `runtime_io::log` method.
|
||||
#[derive(Encode, Decode, runtime_interface::pass_by::PassByEnum, Copy, Clone)]
|
||||
pub enum LogLevel {
|
||||
/// `Error` log level.
|
||||
Error = 1,
|
||||
/// `Warn` log level.
|
||||
Warn = 2,
|
||||
/// `Info` log level.
|
||||
Info = 3,
|
||||
/// `Debug` log level.
|
||||
Debug = 4,
|
||||
/// `Trace` log level.
|
||||
Trace = 5,
|
||||
}
|
||||
|
||||
impl From<u32> for LogLevel {
|
||||
fn from(val: u32) -> Self {
|
||||
match val {
|
||||
x if x == LogLevel::Warn as u32 => LogLevel::Warn,
|
||||
x if x == LogLevel::Info as u32 => LogLevel::Info,
|
||||
x if x == LogLevel::Debug as u32 => LogLevel::Debug,
|
||||
x if x == LogLevel::Trace as u32 => LogLevel::Trace,
|
||||
_ => LogLevel::Error,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<log::Level> for LogLevel {
|
||||
fn from(l: log::Level) -> Self {
|
||||
use log::Level::*;
|
||||
match l {
|
||||
Error => Self::Error,
|
||||
Warn => Self::Warn,
|
||||
Info => Self::Info,
|
||||
Debug => Self::Debug,
|
||||
Trace => Self::Trace,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<LogLevel> for log::Level {
|
||||
fn from(l: LogLevel) -> Self {
|
||||
use self::LogLevel::*;
|
||||
match l {
|
||||
Error => Self::Error,
|
||||
Warn => Self::Warn,
|
||||
Info => Self::Info,
|
||||
Debug => Self::Debug,
|
||||
Trace => Self::Trace,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Encodes the given value into a buffer and returns the pointer and the length as a single `u64`.
|
||||
///
|
||||
/// When Substrate calls into Wasm it expects a fixed signature for functions exported
|
||||
/// from the Wasm blob. The return value of this signature is always a `u64`.
|
||||
/// This `u64` stores the pointer to the encoded return value and the length of this encoded value.
|
||||
/// The low `32bits` are reserved for the pointer, followed by `32bit` for the length.
|
||||
#[cfg(not(feature = "std"))]
|
||||
pub fn to_substrate_wasm_fn_return_value(value: &impl Encode) -> u64 {
|
||||
let encoded = value.encode();
|
||||
|
||||
let ptr = encoded.as_ptr() as u64;
|
||||
let length = encoded.len() as u64;
|
||||
let res = ptr | (length << 32);
|
||||
|
||||
// Leak the output vector to avoid it being freed.
|
||||
// This is fine in a WASM context since the heap
|
||||
// will be discarded after the call.
|
||||
rstd::mem::forget(encoded);
|
||||
|
||||
res
|
||||
}
|
||||
@@ -0,0 +1,698 @@
|
||||
// Copyright 2019 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Substrate is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Offchain workers types
|
||||
|
||||
use codec::{Encode, Decode};
|
||||
use rstd::{prelude::{Vec, Box}, convert::TryFrom};
|
||||
use crate::RuntimeDebug;
|
||||
use runtime_interface::pass_by::{PassByCodec, PassByInner, PassByEnum};
|
||||
|
||||
pub use crate::crypto::KeyTypeId;
|
||||
|
||||
/// A type of supported crypto.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Encode, Decode, RuntimeDebug, PassByEnum)]
|
||||
#[repr(C)]
|
||||
pub enum StorageKind {
|
||||
/// Persistent storage is non-revertible and not fork-aware. It means that any value
|
||||
/// set by the offchain worker triggered at block `N(hash1)` is persisted even
|
||||
/// if that block is reverted as non-canonical and is available for the worker
|
||||
/// that is re-run at block `N(hash2)`.
|
||||
/// This storage can be used by offchain workers to handle forks
|
||||
/// and coordinate offchain workers running on different forks.
|
||||
PERSISTENT = 1,
|
||||
/// Local storage is revertible and fork-aware. It means that any value
|
||||
/// set by the offchain worker triggered at block `N(hash1)` is reverted
|
||||
/// if that block is reverted as non-canonical and is NOT available for the worker
|
||||
/// that is re-run at block `N(hash2)`.
|
||||
LOCAL = 2,
|
||||
}
|
||||
|
||||
impl TryFrom<u32> for StorageKind {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(kind: u32) -> Result<Self, Self::Error> {
|
||||
match kind {
|
||||
e if e == u32::from(StorageKind::PERSISTENT as u8) => Ok(StorageKind::PERSISTENT),
|
||||
e if e == u32::from(StorageKind::LOCAL as u8) => Ok(StorageKind::LOCAL),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<StorageKind> for u32 {
|
||||
fn from(c: StorageKind) -> Self {
|
||||
c as u8 as u32
|
||||
}
|
||||
}
|
||||
|
||||
/// Opaque type for offchain http requests.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, Encode, Decode, PassByInner)]
|
||||
#[cfg_attr(feature = "std", derive(Hash))]
|
||||
pub struct HttpRequestId(pub u16);
|
||||
|
||||
impl From<HttpRequestId> for u32 {
|
||||
fn from(c: HttpRequestId) -> Self {
|
||||
c.0 as u32
|
||||
}
|
||||
}
|
||||
|
||||
/// An error enum returned by some http methods.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, RuntimeDebug, Encode, Decode, PassByEnum)]
|
||||
#[repr(C)]
|
||||
pub enum HttpError {
|
||||
/// The requested action couldn't been completed within a deadline.
|
||||
DeadlineReached = 1,
|
||||
/// There was an IO Error while processing the request.
|
||||
IoError = 2,
|
||||
/// The ID of the request is invalid in this context.
|
||||
Invalid = 3,
|
||||
}
|
||||
|
||||
impl TryFrom<u32> for HttpError {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(error: u32) -> Result<Self, Self::Error> {
|
||||
match error {
|
||||
e if e == HttpError::DeadlineReached as u8 as u32 => Ok(HttpError::DeadlineReached),
|
||||
e if e == HttpError::IoError as u8 as u32 => Ok(HttpError::IoError),
|
||||
e if e == HttpError::Invalid as u8 as u32 => Ok(HttpError::Invalid),
|
||||
_ => Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<HttpError> for u32 {
|
||||
fn from(c: HttpError) -> Self {
|
||||
c as u8 as u32
|
||||
}
|
||||
}
|
||||
|
||||
/// Status of the HTTP request
|
||||
#[derive(Clone, Copy, PartialEq, Eq, RuntimeDebug, Encode, Decode, PassByCodec)]
|
||||
pub enum HttpRequestStatus {
|
||||
/// Deadline was reached while we waited for this request to finish.
|
||||
///
|
||||
/// Note the deadline is controlled by the calling part, it not necessarily
|
||||
/// means that the request has timed out.
|
||||
DeadlineReached,
|
||||
/// An error has occured during the request, for example a timeout or the
|
||||
/// remote has closed our socket.
|
||||
///
|
||||
/// The request is now considered destroyed. To retry the request you need
|
||||
/// to construct it again.
|
||||
IoError,
|
||||
/// The passed ID is invalid in this context.
|
||||
Invalid,
|
||||
/// The request has finished with given status code.
|
||||
Finished(u16),
|
||||
}
|
||||
|
||||
impl From<HttpRequestStatus> for u32 {
|
||||
fn from(status: HttpRequestStatus) -> Self {
|
||||
match status {
|
||||
HttpRequestStatus::Invalid => 0,
|
||||
HttpRequestStatus::DeadlineReached => 10,
|
||||
HttpRequestStatus::IoError => 20,
|
||||
HttpRequestStatus::Finished(code) => u32::from(code),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<u32> for HttpRequestStatus {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(status: u32) -> Result<Self, Self::Error> {
|
||||
match status {
|
||||
0 => Ok(HttpRequestStatus::Invalid),
|
||||
10 => Ok(HttpRequestStatus::DeadlineReached),
|
||||
20 => Ok(HttpRequestStatus::IoError),
|
||||
100..=999 => u16::try_from(status).map(HttpRequestStatus::Finished).map_err(|_| ()),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A blob to hold information about the local node's network state
|
||||
/// without committing to its format.
|
||||
#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, PassByCodec)]
|
||||
pub struct OpaqueNetworkState {
|
||||
/// PeerId of the local node.
|
||||
pub peer_id: OpaquePeerId,
|
||||
/// List of addresses the node knows it can be reached as.
|
||||
pub external_addresses: Vec<OpaqueMultiaddr>,
|
||||
}
|
||||
|
||||
/// Simple blob to hold a `PeerId` without committing to its format.
|
||||
#[derive(Default, Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, PassByInner)]
|
||||
pub struct OpaquePeerId(pub Vec<u8>);
|
||||
|
||||
impl OpaquePeerId {
|
||||
/// Create new `OpaquePeerId`
|
||||
pub fn new(vec: Vec<u8>) -> Self {
|
||||
OpaquePeerId(vec)
|
||||
}
|
||||
}
|
||||
|
||||
/// Simple blob to hold a `Multiaddr` without committing to its format.
|
||||
#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, PassByInner)]
|
||||
pub struct OpaqueMultiaddr(pub Vec<u8>);
|
||||
|
||||
impl OpaqueMultiaddr {
|
||||
/// Create new `OpaqueMultiaddr`
|
||||
pub fn new(vec: Vec<u8>) -> Self {
|
||||
OpaqueMultiaddr(vec)
|
||||
}
|
||||
}
|
||||
|
||||
/// Opaque timestamp type
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Default, RuntimeDebug, PassByInner, Encode, Decode)]
|
||||
pub struct Timestamp(u64);
|
||||
|
||||
/// Duration type
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Default, RuntimeDebug, PassByInner, Encode, Decode)]
|
||||
pub struct Duration(u64);
|
||||
|
||||
impl Duration {
|
||||
/// Create new duration representing given number of milliseconds.
|
||||
pub fn from_millis(millis: u64) -> Self {
|
||||
Duration(millis)
|
||||
}
|
||||
|
||||
/// Returns number of milliseconds this Duration represents.
|
||||
pub fn millis(&self) -> u64 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Timestamp {
|
||||
/// Creates new `Timestamp` given unix timestamp in miliseconds.
|
||||
pub fn from_unix_millis(millis: u64) -> Self {
|
||||
Timestamp(millis)
|
||||
}
|
||||
|
||||
/// Increase the timestamp by given `Duration`.
|
||||
pub fn add(&self, duration: Duration) -> Timestamp {
|
||||
Timestamp(self.0.saturating_add(duration.0))
|
||||
}
|
||||
|
||||
/// Decrease the timestamp by given `Duration`
|
||||
pub fn sub(&self, duration: Duration) -> Timestamp {
|
||||
Timestamp(self.0.saturating_sub(duration.0))
|
||||
}
|
||||
|
||||
/// Returns a saturated difference (Duration) between two Timestamps.
|
||||
pub fn diff(&self, other: &Self) -> Duration {
|
||||
Duration(self.0.saturating_sub(other.0))
|
||||
}
|
||||
|
||||
/// Return number of milliseconds since UNIX epoch.
|
||||
pub fn unix_millis(&self) -> u64 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
/// Execution context extra capabilities.
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
#[repr(u8)]
|
||||
pub enum Capability {
|
||||
/// Access to transaction pool.
|
||||
TransactionPool = 1,
|
||||
/// External http calls.
|
||||
Http = 2,
|
||||
/// Keystore access.
|
||||
Keystore = 4,
|
||||
/// Randomness source.
|
||||
Randomness = 8,
|
||||
/// Access to opaque network state.
|
||||
NetworkState = 16,
|
||||
/// Access to offchain worker DB (read only).
|
||||
OffchainWorkerDbRead = 32,
|
||||
/// Access to offchain worker DB (writes).
|
||||
OffchainWorkerDbWrite = 64,
|
||||
}
|
||||
|
||||
/// A set of capabilities
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub struct Capabilities(u8);
|
||||
|
||||
impl Capabilities {
|
||||
/// Return an object representing an empty set of capabilities.
|
||||
pub fn none() -> Self {
|
||||
Self(0)
|
||||
}
|
||||
|
||||
/// Return an object representing all capabilities enabled.
|
||||
pub fn all() -> Self {
|
||||
Self(u8::max_value())
|
||||
}
|
||||
|
||||
/// Return capabilities for rich offchain calls.
|
||||
///
|
||||
/// Those calls should be allowed to sign and submit transactions
|
||||
/// and access offchain workers database (but read only!).
|
||||
pub fn rich_offchain_call() -> Self {
|
||||
[
|
||||
Capability::TransactionPool,
|
||||
Capability::Keystore,
|
||||
Capability::OffchainWorkerDbRead,
|
||||
][..].into()
|
||||
}
|
||||
|
||||
/// Check if particular capability is enabled.
|
||||
pub fn has(&self, capability: Capability) -> bool {
|
||||
self.0 & capability as u8 != 0
|
||||
}
|
||||
|
||||
/// Check if this capability object represents all capabilities.
|
||||
pub fn has_all(&self) -> bool {
|
||||
self == &Capabilities::all()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a [Capability]> for Capabilities {
|
||||
fn from(list: &'a [Capability]) -> Self {
|
||||
Capabilities(list.iter().fold(0_u8, |a, b| a | *b as u8))
|
||||
}
|
||||
}
|
||||
|
||||
/// An extended externalities for offchain workers.
|
||||
pub trait Externalities: Send {
|
||||
/// Returns if the local node is a potential validator.
|
||||
///
|
||||
/// Even if this function returns `true`, it does not mean that any keys are configured
|
||||
/// and that the validator is registered in the chain.
|
||||
fn is_validator(&self) -> bool;
|
||||
/// Submit transaction.
|
||||
///
|
||||
/// The transaction will end up in the pool and be propagated to others.
|
||||
fn submit_transaction(&mut self, extrinsic: Vec<u8>) -> Result<(), ()>;
|
||||
|
||||
/// Returns information about the local node's network state.
|
||||
fn network_state(&self) -> Result<OpaqueNetworkState, ()>;
|
||||
|
||||
/// Returns current UNIX timestamp (in millis)
|
||||
fn timestamp(&mut self) -> Timestamp;
|
||||
|
||||
/// Pause the execution until `deadline` is reached.
|
||||
fn sleep_until(&mut self, deadline: Timestamp);
|
||||
|
||||
/// Returns a random seed.
|
||||
///
|
||||
/// This is a trully random non deterministic seed generated by host environment.
|
||||
/// Obviously fine in the off-chain worker context.
|
||||
fn random_seed(&mut self) -> [u8; 32];
|
||||
|
||||
/// Sets a value in the local storage.
|
||||
///
|
||||
/// Note this storage is not part of the consensus, it's only accessible by
|
||||
/// offchain worker tasks running on the same machine. It IS persisted between runs.
|
||||
fn local_storage_set(&mut self, kind: StorageKind, key: &[u8], value: &[u8]);
|
||||
|
||||
/// Sets a value in the local storage if it matches current value.
|
||||
///
|
||||
/// Since multiple offchain workers may be running concurrently, to prevent
|
||||
/// data races use CAS to coordinate between them.
|
||||
///
|
||||
/// Returns `true` if the value has been set, `false` otherwise.
|
||||
///
|
||||
/// Note this storage is not part of the consensus, it's only accessible by
|
||||
/// offchain worker tasks running on the same machine. It IS persisted between runs.
|
||||
fn local_storage_compare_and_set(
|
||||
&mut self,
|
||||
kind: StorageKind,
|
||||
key: &[u8],
|
||||
old_value: Option<&[u8]>,
|
||||
new_value: &[u8],
|
||||
) -> bool;
|
||||
|
||||
/// Gets a value from the local storage.
|
||||
///
|
||||
/// If the value does not exist in the storage `None` will be returned.
|
||||
/// Note this storage is not part of the consensus, it's only accessible by
|
||||
/// offchain worker tasks running on the same machine. It IS persisted between runs.
|
||||
fn local_storage_get(&mut self, kind: StorageKind, key: &[u8]) -> Option<Vec<u8>>;
|
||||
|
||||
/// Initiates a http request given HTTP verb and the URL.
|
||||
///
|
||||
/// Meta is a future-reserved field containing additional, parity-scale-codec encoded parameters.
|
||||
/// Returns the id of newly started request.
|
||||
///
|
||||
/// Returns an error if:
|
||||
/// - No new request identifier could be allocated.
|
||||
/// - The method or URI contain invalid characters.
|
||||
///
|
||||
fn http_request_start(
|
||||
&mut self,
|
||||
method: &str,
|
||||
uri: &str,
|
||||
meta: &[u8]
|
||||
) -> Result<HttpRequestId, ()>;
|
||||
|
||||
/// Append header to the request.
|
||||
///
|
||||
/// Calling this function multiple times with the same header name continues appending new
|
||||
/// headers. In other words, headers are never replaced.
|
||||
///
|
||||
/// Returns an error if:
|
||||
/// - The request identifier is invalid.
|
||||
/// - You have called `http_request_write_body` on that request.
|
||||
/// - The name or value contain invalid characters.
|
||||
///
|
||||
/// An error doesn't poison the request, and you can continue as if the call had never been
|
||||
/// made.
|
||||
///
|
||||
fn http_request_add_header(
|
||||
&mut self,
|
||||
request_id: HttpRequestId,
|
||||
name: &str,
|
||||
value: &str
|
||||
) -> Result<(), ()>;
|
||||
|
||||
/// Write a chunk of request body.
|
||||
///
|
||||
/// Calling this function with a non-empty slice may or may not start the
|
||||
/// HTTP request. Calling this function with an empty chunks finalizes the
|
||||
/// request and always starts it. It is no longer valid to write more data
|
||||
/// afterwards.
|
||||
/// Passing `None` as deadline blocks forever.
|
||||
///
|
||||
/// Returns an error if:
|
||||
/// - The request identifier is invalid.
|
||||
/// - `http_response_wait` has already been called on this request.
|
||||
/// - The deadline is reached.
|
||||
/// - An I/O error has happened, for example the remote has closed our
|
||||
/// request. The request is then considered invalid.
|
||||
///
|
||||
fn http_request_write_body(
|
||||
&mut self,
|
||||
request_id: HttpRequestId,
|
||||
chunk: &[u8],
|
||||
deadline: Option<Timestamp>
|
||||
) -> Result<(), HttpError>;
|
||||
|
||||
/// Block and wait for the responses for given requests.
|
||||
///
|
||||
/// Returns a vector of request statuses (the len is the same as ids).
|
||||
/// Note that if deadline is not provided the method will block indefinitely,
|
||||
/// otherwise unready responses will produce `DeadlineReached` status.
|
||||
///
|
||||
/// If a response returns an `IoError`, it is then considered destroyed.
|
||||
/// Its id is then invalid.
|
||||
///
|
||||
/// Passing `None` as deadline blocks forever.
|
||||
fn http_response_wait(
|
||||
&mut self,
|
||||
ids: &[HttpRequestId],
|
||||
deadline: Option<Timestamp>
|
||||
) -> Vec<HttpRequestStatus>;
|
||||
|
||||
/// Read all response headers.
|
||||
///
|
||||
/// Returns a vector of pairs `(HeaderKey, HeaderValue)`.
|
||||
///
|
||||
/// Dispatches the request if it hasn't been done yet. It is no longer
|
||||
/// valid to modify the headers or write data to the request.
|
||||
///
|
||||
/// Returns an empty list if the identifier is unknown/invalid, hasn't
|
||||
/// received a response, or has finished.
|
||||
fn http_response_headers(
|
||||
&mut self,
|
||||
request_id: HttpRequestId
|
||||
) -> Vec<(Vec<u8>, Vec<u8>)>;
|
||||
|
||||
/// Read a chunk of body response to given buffer.
|
||||
///
|
||||
/// Dispatches the request if it hasn't been done yet. It is no longer
|
||||
/// valid to modify the headers or write data to the request.
|
||||
///
|
||||
/// Returns the number of bytes written or an error in case a deadline
|
||||
/// is reached or server closed the connection.
|
||||
/// Passing `None` as a deadline blocks forever.
|
||||
///
|
||||
/// If `Ok(0)` or `Err(IoError)` is returned, the request is considered
|
||||
/// destroyed. Doing another read or getting the response's headers, for
|
||||
/// example, is then invalid.
|
||||
///
|
||||
/// Returns an error if:
|
||||
/// - The request identifier is invalid.
|
||||
/// - The deadline is reached.
|
||||
/// - An I/O error has happened, for example the remote has closed our
|
||||
/// request. The request is then considered invalid.
|
||||
///
|
||||
fn http_response_read_body(
|
||||
&mut self,
|
||||
request_id: HttpRequestId,
|
||||
buffer: &mut [u8],
|
||||
deadline: Option<Timestamp>
|
||||
) -> Result<usize, HttpError>;
|
||||
|
||||
}
|
||||
impl<T: Externalities + ?Sized> Externalities for Box<T> {
|
||||
fn is_validator(&self) -> bool {
|
||||
(& **self).is_validator()
|
||||
}
|
||||
|
||||
fn submit_transaction(&mut self, ex: Vec<u8>) -> Result<(), ()> {
|
||||
(&mut **self).submit_transaction(ex)
|
||||
}
|
||||
|
||||
fn network_state(&self) -> Result<OpaqueNetworkState, ()> {
|
||||
(& **self).network_state()
|
||||
}
|
||||
|
||||
fn timestamp(&mut self) -> Timestamp {
|
||||
(&mut **self).timestamp()
|
||||
}
|
||||
|
||||
fn sleep_until(&mut self, deadline: Timestamp) {
|
||||
(&mut **self).sleep_until(deadline)
|
||||
}
|
||||
|
||||
fn random_seed(&mut self) -> [u8; 32] {
|
||||
(&mut **self).random_seed()
|
||||
}
|
||||
|
||||
fn local_storage_set(&mut self, kind: StorageKind, key: &[u8], value: &[u8]) {
|
||||
(&mut **self).local_storage_set(kind, key, value)
|
||||
}
|
||||
|
||||
fn local_storage_compare_and_set(
|
||||
&mut self,
|
||||
kind: StorageKind,
|
||||
key: &[u8],
|
||||
old_value: Option<&[u8]>,
|
||||
new_value: &[u8],
|
||||
) -> bool {
|
||||
(&mut **self).local_storage_compare_and_set(kind, key, old_value, new_value)
|
||||
}
|
||||
|
||||
fn local_storage_get(&mut self, kind: StorageKind, key: &[u8]) -> Option<Vec<u8>> {
|
||||
(&mut **self).local_storage_get(kind, key)
|
||||
}
|
||||
|
||||
fn http_request_start(&mut self, method: &str, uri: &str, meta: &[u8]) -> Result<HttpRequestId, ()> {
|
||||
(&mut **self).http_request_start(method, uri, meta)
|
||||
}
|
||||
|
||||
fn http_request_add_header(&mut self, request_id: HttpRequestId, name: &str, value: &str) -> Result<(), ()> {
|
||||
(&mut **self).http_request_add_header(request_id, name, value)
|
||||
}
|
||||
|
||||
fn http_request_write_body(
|
||||
&mut self,
|
||||
request_id: HttpRequestId,
|
||||
chunk: &[u8],
|
||||
deadline: Option<Timestamp>
|
||||
) -> Result<(), HttpError> {
|
||||
(&mut **self).http_request_write_body(request_id, chunk, deadline)
|
||||
}
|
||||
|
||||
fn http_response_wait(&mut self, ids: &[HttpRequestId], deadline: Option<Timestamp>) -> Vec<HttpRequestStatus> {
|
||||
(&mut **self).http_response_wait(ids, deadline)
|
||||
}
|
||||
|
||||
fn http_response_headers(&mut self, request_id: HttpRequestId) -> Vec<(Vec<u8>, Vec<u8>)> {
|
||||
(&mut **self).http_response_headers(request_id)
|
||||
}
|
||||
|
||||
fn http_response_read_body(
|
||||
&mut self,
|
||||
request_id: HttpRequestId,
|
||||
buffer: &mut [u8],
|
||||
deadline: Option<Timestamp>
|
||||
) -> Result<usize, HttpError> {
|
||||
(&mut **self).http_response_read_body(request_id, buffer, deadline)
|
||||
}
|
||||
}
|
||||
/// An `OffchainExternalities` implementation with limited capabilities.
|
||||
pub struct LimitedExternalities<T> {
|
||||
capabilities: Capabilities,
|
||||
externalities: T,
|
||||
}
|
||||
|
||||
impl<T> LimitedExternalities<T> {
|
||||
/// Create new externalities limited to given `capabilities`.
|
||||
pub fn new(capabilities: Capabilities, externalities: T) -> Self {
|
||||
Self {
|
||||
capabilities,
|
||||
externalities,
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if given capability is allowed.
|
||||
///
|
||||
/// Panics in case it is not.
|
||||
fn check(&self, capability: Capability, name: &'static str) {
|
||||
if !self.capabilities.has(capability) {
|
||||
panic!("Accessing a forbidden API: {}. No: {:?} capability.", name, capability);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Externalities> Externalities for LimitedExternalities<T> {
|
||||
fn is_validator(&self) -> bool {
|
||||
self.check(Capability::Keystore, "is_validator");
|
||||
self.externalities.is_validator()
|
||||
}
|
||||
|
||||
fn submit_transaction(&mut self, ex: Vec<u8>) -> Result<(), ()> {
|
||||
self.check(Capability::TransactionPool, "submit_transaction");
|
||||
self.externalities.submit_transaction(ex)
|
||||
}
|
||||
|
||||
fn network_state(&self) -> Result<OpaqueNetworkState, ()> {
|
||||
self.check(Capability::NetworkState, "network_state");
|
||||
self.externalities.network_state()
|
||||
}
|
||||
|
||||
fn timestamp(&mut self) -> Timestamp {
|
||||
self.check(Capability::Http, "timestamp");
|
||||
self.externalities.timestamp()
|
||||
}
|
||||
|
||||
fn sleep_until(&mut self, deadline: Timestamp) {
|
||||
self.check(Capability::Http, "sleep_until");
|
||||
self.externalities.sleep_until(deadline)
|
||||
}
|
||||
|
||||
fn random_seed(&mut self) -> [u8; 32] {
|
||||
self.check(Capability::Randomness, "random_seed");
|
||||
self.externalities.random_seed()
|
||||
}
|
||||
|
||||
fn local_storage_set(&mut self, kind: StorageKind, key: &[u8], value: &[u8]) {
|
||||
self.check(Capability::OffchainWorkerDbWrite, "local_storage_set");
|
||||
self.externalities.local_storage_set(kind, key, value)
|
||||
}
|
||||
|
||||
fn local_storage_compare_and_set(
|
||||
&mut self,
|
||||
kind: StorageKind,
|
||||
key: &[u8],
|
||||
old_value: Option<&[u8]>,
|
||||
new_value: &[u8],
|
||||
) -> bool {
|
||||
self.check(Capability::OffchainWorkerDbWrite, "local_storage_compare_and_set");
|
||||
self.externalities.local_storage_compare_and_set(kind, key, old_value, new_value)
|
||||
}
|
||||
|
||||
fn local_storage_get(&mut self, kind: StorageKind, key: &[u8]) -> Option<Vec<u8>> {
|
||||
self.check(Capability::OffchainWorkerDbRead, "local_storage_get");
|
||||
self.externalities.local_storage_get(kind, key)
|
||||
}
|
||||
|
||||
fn http_request_start(&mut self, method: &str, uri: &str, meta: &[u8]) -> Result<HttpRequestId, ()> {
|
||||
self.check(Capability::Http, "http_request_start");
|
||||
self.externalities.http_request_start(method, uri, meta)
|
||||
}
|
||||
|
||||
fn http_request_add_header(&mut self, request_id: HttpRequestId, name: &str, value: &str) -> Result<(), ()> {
|
||||
self.check(Capability::Http, "http_request_add_header");
|
||||
self.externalities.http_request_add_header(request_id, name, value)
|
||||
}
|
||||
|
||||
fn http_request_write_body(
|
||||
&mut self,
|
||||
request_id: HttpRequestId,
|
||||
chunk: &[u8],
|
||||
deadline: Option<Timestamp>
|
||||
) -> Result<(), HttpError> {
|
||||
self.check(Capability::Http, "http_request_write_body");
|
||||
self.externalities.http_request_write_body(request_id, chunk, deadline)
|
||||
}
|
||||
|
||||
fn http_response_wait(&mut self, ids: &[HttpRequestId], deadline: Option<Timestamp>) -> Vec<HttpRequestStatus> {
|
||||
self.check(Capability::Http, "http_response_wait");
|
||||
self.externalities.http_response_wait(ids, deadline)
|
||||
}
|
||||
|
||||
fn http_response_headers(&mut self, request_id: HttpRequestId) -> Vec<(Vec<u8>, Vec<u8>)> {
|
||||
self.check(Capability::Http, "http_response_headers");
|
||||
self.externalities.http_response_headers(request_id)
|
||||
}
|
||||
|
||||
fn http_response_read_body(
|
||||
&mut self,
|
||||
request_id: HttpRequestId,
|
||||
buffer: &mut [u8],
|
||||
deadline: Option<Timestamp>
|
||||
) -> Result<usize, HttpError> {
|
||||
self.check(Capability::Http, "http_response_read_body");
|
||||
self.externalities.http_response_read_body(request_id, buffer, deadline)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
externalities::decl_extension! {
|
||||
/// The offchain extension that will be registered at the Substrate externalities.
|
||||
pub struct OffchainExt(Box<dyn Externalities>);
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl OffchainExt {
|
||||
/// Create a new instance of `Self`.
|
||||
pub fn new<O: Externalities + 'static>(offchain: O) -> Self {
|
||||
Self(Box::new(offchain))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn timestamp_ops() {
|
||||
let t = Timestamp(5);
|
||||
assert_eq!(t.add(Duration::from_millis(10)), Timestamp(15));
|
||||
assert_eq!(t.sub(Duration::from_millis(10)), Timestamp(0));
|
||||
assert_eq!(t.diff(&Timestamp(3)), Duration(2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn capabilities() {
|
||||
let none = Capabilities::none();
|
||||
let all = Capabilities::all();
|
||||
let some = Capabilities::from(&[Capability::Keystore, Capability::Randomness][..]);
|
||||
|
||||
assert!(!none.has(Capability::Keystore));
|
||||
assert!(all.has(Capability::Keystore));
|
||||
assert!(some.has(Capability::Keystore));
|
||||
assert!(!none.has(Capability::TransactionPool));
|
||||
assert!(all.has(Capability::TransactionPool));
|
||||
assert!(!some.has(Capability::TransactionPool));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
// Copyright 2018-2019 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Substrate is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Definition of a sandbox environment.
|
||||
|
||||
use codec::{Encode, Decode};
|
||||
use rstd::vec::Vec;
|
||||
|
||||
/// Error error that can be returned from host function.
|
||||
#[derive(Encode, Decode)]
|
||||
#[derive(crate::RuntimeDebug)]
|
||||
pub struct HostError;
|
||||
|
||||
/// Representation of a typed wasm value.
|
||||
#[derive(Clone, Copy, PartialEq, Encode, Decode)]
|
||||
#[derive(crate::RuntimeDebug)]
|
||||
pub enum TypedValue {
|
||||
/// Value of 32-bit signed or unsigned integer.
|
||||
#[codec(index = "1")]
|
||||
I32(i32),
|
||||
|
||||
/// Value of 64-bit signed or unsigned integer.
|
||||
#[codec(index = "2")]
|
||||
I64(i64),
|
||||
|
||||
/// Value of 32-bit IEEE 754-2008 floating point number represented as a bit pattern.
|
||||
#[codec(index = "3")]
|
||||
F32(i32),
|
||||
|
||||
/// Value of 64-bit IEEE 754-2008 floating point number represented as a bit pattern.
|
||||
#[codec(index = "4")]
|
||||
F64(i64),
|
||||
}
|
||||
|
||||
impl TypedValue {
|
||||
/// Returns `Some` if this value of type `I32`.
|
||||
pub fn as_i32(&self) -> Option<i32> {
|
||||
match *self {
|
||||
TypedValue::I32(v) => Some(v),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl From<::wasmi::RuntimeValue> for TypedValue {
|
||||
fn from(val: ::wasmi::RuntimeValue) -> TypedValue {
|
||||
use ::wasmi::RuntimeValue;
|
||||
match val {
|
||||
RuntimeValue::I32(v) => TypedValue::I32(v),
|
||||
RuntimeValue::I64(v) => TypedValue::I64(v),
|
||||
RuntimeValue::F32(v) => TypedValue::F32(v.to_bits() as i32),
|
||||
RuntimeValue::F64(v) => TypedValue::F64(v.to_bits() as i64),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl From<TypedValue> for ::wasmi::RuntimeValue {
|
||||
fn from(val: TypedValue) -> ::wasmi::RuntimeValue {
|
||||
use ::wasmi::RuntimeValue;
|
||||
use ::wasmi::nan_preserving_float::{F32, F64};
|
||||
match val {
|
||||
TypedValue::I32(v) => RuntimeValue::I32(v),
|
||||
TypedValue::I64(v) => RuntimeValue::I64(v),
|
||||
TypedValue::F32(v_bits) => RuntimeValue::F32(F32::from_bits(v_bits as u32)),
|
||||
TypedValue::F64(v_bits) => RuntimeValue::F64(F64::from_bits(v_bits as u64)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Typed value that can be returned from a function.
|
||||
///
|
||||
/// Basically a `TypedValue` plus `Unit`, for functions which return nothing.
|
||||
#[derive(Clone, Copy, PartialEq, Encode, Decode)]
|
||||
#[derive(crate::RuntimeDebug)]
|
||||
pub enum ReturnValue {
|
||||
/// For returning nothing.
|
||||
Unit,
|
||||
/// For returning some concrete value.
|
||||
Value(TypedValue),
|
||||
}
|
||||
|
||||
impl From<TypedValue> for ReturnValue {
|
||||
fn from(v: TypedValue) -> ReturnValue {
|
||||
ReturnValue::Value(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl ReturnValue {
|
||||
/// Maximum number of bytes `ReturnValue` might occupy when serialized with
|
||||
/// `Codec`.
|
||||
///
|
||||
/// Breakdown:
|
||||
/// 1 byte for encoding unit/value variant
|
||||
/// 1 byte for encoding value type
|
||||
/// 8 bytes for encoding the biggest value types available in wasm: f64, i64.
|
||||
pub const ENCODED_MAX_SIZE: usize = 10;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn return_value_encoded_max_size() {
|
||||
let encoded = ReturnValue::Value(TypedValue::I64(-1)).encode();
|
||||
assert_eq!(encoded.len(), ReturnValue::ENCODED_MAX_SIZE);
|
||||
}
|
||||
|
||||
/// Describes an entity to define or import into the environment.
|
||||
#[derive(Clone, PartialEq, Eq, Encode, Decode)]
|
||||
#[derive(crate::RuntimeDebug)]
|
||||
pub enum ExternEntity {
|
||||
/// Function that is specified by an index in a default table of
|
||||
/// a module that creates the sandbox.
|
||||
#[codec(index = "1")]
|
||||
Function(u32),
|
||||
|
||||
/// Linear memory that is specified by some identifier returned by sandbox
|
||||
/// module upon creation new sandboxed memory.
|
||||
#[codec(index = "2")]
|
||||
Memory(u32),
|
||||
}
|
||||
|
||||
/// An entry in a environment definition table.
|
||||
///
|
||||
/// Each entry has a two-level name and description of an entity
|
||||
/// being defined.
|
||||
#[derive(Clone, PartialEq, Eq, Encode, Decode)]
|
||||
#[derive(crate::RuntimeDebug)]
|
||||
pub struct Entry {
|
||||
/// Module name of which corresponding entity being defined.
|
||||
pub module_name: Vec<u8>,
|
||||
/// Field name in which corresponding entity being defined.
|
||||
pub field_name: Vec<u8>,
|
||||
/// External entity being defined.
|
||||
pub entity: ExternEntity,
|
||||
}
|
||||
|
||||
/// Definition of runtime that could be used by sandboxed code.
|
||||
#[derive(Clone, PartialEq, Eq, Encode, Decode)]
|
||||
#[derive(crate::RuntimeDebug)]
|
||||
pub struct EnvironmentDefinition {
|
||||
/// Vector of all entries in the environment definition.
|
||||
pub entries: Vec<Entry>,
|
||||
}
|
||||
|
||||
/// Constant for specifying no limit when creating a sandboxed
|
||||
/// memory instance. For FFI purposes.
|
||||
pub const MEM_UNLIMITED: u32 = -1i32 as u32;
|
||||
|
||||
/// No error happened.
|
||||
///
|
||||
/// For FFI purposes.
|
||||
pub const ERR_OK: u32 = 0;
|
||||
|
||||
/// Validation or instantiation error occurred when creating new
|
||||
/// sandboxed module instance.
|
||||
///
|
||||
/// For FFI purposes.
|
||||
pub const ERR_MODULE: u32 = -1i32 as u32;
|
||||
|
||||
/// Out-of-bounds access attempted with memory or table.
|
||||
///
|
||||
/// For FFI purposes.
|
||||
pub const ERR_OUT_OF_BOUNDS: u32 = -2i32 as u32;
|
||||
|
||||
/// Execution error occurred (typically trap).
|
||||
///
|
||||
/// For FFI purposes.
|
||||
pub const ERR_EXECUTION: u32 = -3i32 as u32;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::fmt;
|
||||
use codec::Codec;
|
||||
|
||||
fn roundtrip<S: Codec + PartialEq + fmt::Debug>(s: S) {
|
||||
let encoded = s.encode();
|
||||
assert_eq!(S::decode(&mut &encoded[..]).unwrap(), s);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn env_def_roundtrip() {
|
||||
roundtrip(EnvironmentDefinition {
|
||||
entries: vec![],
|
||||
});
|
||||
|
||||
roundtrip(EnvironmentDefinition {
|
||||
entries: vec![
|
||||
Entry {
|
||||
module_name: b"kernel"[..].into(),
|
||||
field_name: b"memory"[..].into(),
|
||||
entity: ExternEntity::Memory(1337),
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
roundtrip(EnvironmentDefinition {
|
||||
entries: vec![
|
||||
Entry {
|
||||
module_name: b"env"[..].into(),
|
||||
field_name: b"abort"[..].into(),
|
||||
entity: ExternEntity::Function(228),
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,751 @@
|
||||
// Copyright 2017-2019 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Substrate is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// tag::description[]
|
||||
//! Simple sr25519 (Schnorr-Ristretto) API.
|
||||
//!
|
||||
//! Note: `CHAIN_CODE_LENGTH` must be equal to `crate::crypto::JUNCTION_ID_LEN`
|
||||
//! for this to work.
|
||||
// end::description[]
|
||||
#[cfg(feature = "full_crypto")]
|
||||
use rstd::vec::Vec;
|
||||
#[cfg(feature = "full_crypto")]
|
||||
use schnorrkel::{signing_context, ExpansionMode, Keypair, SecretKey, MiniSecretKey, PublicKey,
|
||||
derive::{Derivation, ChainCode, CHAIN_CODE_LENGTH}
|
||||
};
|
||||
#[cfg(feature = "std")]
|
||||
use substrate_bip39::mini_secret_from_entropy;
|
||||
#[cfg(feature = "std")]
|
||||
use bip39::{Mnemonic, Language, MnemonicType};
|
||||
#[cfg(feature = "full_crypto")]
|
||||
use crate::crypto::{
|
||||
Pair as TraitPair, DeriveJunction, Infallible, SecretStringError
|
||||
};
|
||||
#[cfg(feature = "std")]
|
||||
use crate::crypto::Ss58Codec;
|
||||
|
||||
use crate::{crypto::{Public as TraitPublic, UncheckedFrom, CryptoType, Derive}};
|
||||
use crate::hash::{H256, H512};
|
||||
use codec::{Encode, Decode};
|
||||
use rstd::ops::Deref;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
|
||||
#[cfg(feature = "full_crypto")]
|
||||
use schnorrkel::keys::{MINI_SECRET_KEY_LENGTH, SECRET_KEY_LENGTH};
|
||||
use runtime_interface::pass_by::PassByInner;
|
||||
|
||||
// signing context
|
||||
#[cfg(feature = "full_crypto")]
|
||||
const SIGNING_CTX: &[u8] = b"substrate";
|
||||
|
||||
/// An Schnorrkel/Ristretto x25519 ("sr25519") public key.
|
||||
#[cfg_attr(feature = "full_crypto", derive(Hash))]
|
||||
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Encode, Decode, Default, PassByInner)]
|
||||
pub struct Public(pub [u8; 32]);
|
||||
|
||||
/// An Schnorrkel/Ristretto x25519 ("sr25519") key pair.
|
||||
#[cfg(feature = "full_crypto")]
|
||||
pub struct Pair(Keypair);
|
||||
|
||||
#[cfg(feature = "full_crypto")]
|
||||
impl Clone for Pair {
|
||||
fn clone(&self) -> Self {
|
||||
Pair(schnorrkel::Keypair {
|
||||
public: self.0.public,
|
||||
secret: schnorrkel::SecretKey::from_bytes(&self.0.secret.to_bytes()[..])
|
||||
.expect("key is always the correct size; qed")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<[u8; 32]> for Public {
|
||||
fn as_ref(&self) -> &[u8; 32] {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<[u8]> for Public {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
&self.0[..]
|
||||
}
|
||||
}
|
||||
|
||||
impl AsMut<[u8]> for Public {
|
||||
fn as_mut(&mut self) -> &mut [u8] {
|
||||
&mut self.0[..]
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for Public {
|
||||
type Target = [u8];
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Public> for [u8; 32] {
|
||||
fn from(x: Public) -> [u8; 32] {
|
||||
x.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Public> for H256 {
|
||||
fn from(x: Public) -> H256 {
|
||||
x.0.into()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl std::str::FromStr for Public {
|
||||
type Err = crate::crypto::PublicError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Self::from_ss58check(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl rstd::convert::TryFrom<&[u8]> for Public {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(data: &[u8]) -> Result<Self, Self::Error> {
|
||||
if data.len() == 32 {
|
||||
let mut inner = [0u8; 32];
|
||||
inner.copy_from_slice(data);
|
||||
Ok(Public(inner))
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl UncheckedFrom<[u8; 32]> for Public {
|
||||
fn unchecked_from(x: [u8; 32]) -> Self {
|
||||
Public::from_raw(x)
|
||||
}
|
||||
}
|
||||
|
||||
impl UncheckedFrom<H256> for Public {
|
||||
fn unchecked_from(x: H256) -> Self {
|
||||
Public::from_h256(x)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl std::fmt::Display for Public {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(f, "{}", self.to_ss58check())
|
||||
}
|
||||
}
|
||||
|
||||
impl rstd::fmt::Debug for Public {
|
||||
#[cfg(feature = "std")]
|
||||
fn fmt(&self, f: &mut rstd::fmt::Formatter) -> rstd::fmt::Result {
|
||||
let s = self.to_ss58check();
|
||||
write!(f, "{} ({}...)", crate::hexdisplay::HexDisplay::from(&self.0), &s[0..8])
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
fn fmt(&self, _: &mut rstd::fmt::Formatter) -> rstd::fmt::Result {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl Serialize for Public {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
|
||||
serializer.serialize_str(&self.to_ss58check())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<'de> Deserialize<'de> for Public {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de> {
|
||||
Public::from_ss58check(&String::deserialize(deserializer)?)
|
||||
.map_err(|e| de::Error::custom(format!("{:?}", e)))
|
||||
}
|
||||
}
|
||||
|
||||
/// An Schnorrkel/Ristretto x25519 ("sr25519") signature.
|
||||
///
|
||||
/// Instead of importing it for the local module, alias it to be available as a public type
|
||||
#[derive(Encode, Decode, PassByInner)]
|
||||
pub struct Signature(pub [u8; 64]);
|
||||
|
||||
impl rstd::convert::TryFrom<&[u8]> for Signature {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(data: &[u8]) -> Result<Self, Self::Error> {
|
||||
if data.len() == 64 {
|
||||
let mut inner = [0u8; 64];
|
||||
inner.copy_from_slice(data);
|
||||
Ok(Signature(inner))
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Signature {
|
||||
fn clone(&self) -> Self {
|
||||
let mut r = [0u8; 64];
|
||||
r.copy_from_slice(&self.0[..]);
|
||||
Signature(r)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Signature {
|
||||
fn default() -> Self {
|
||||
Signature([0u8; 64])
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Signature {
|
||||
fn eq(&self, b: &Self) -> bool {
|
||||
self.0[..] == b.0[..]
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Signature {}
|
||||
|
||||
impl From<Signature> for [u8; 64] {
|
||||
fn from(v: Signature) -> [u8; 64] {
|
||||
v.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Signature> for H512 {
|
||||
fn from(v: Signature) -> H512 {
|
||||
H512::from(v.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<[u8; 64]> for Signature {
|
||||
fn as_ref(&self) -> &[u8; 64] {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<[u8]> for Signature {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
&self.0[..]
|
||||
}
|
||||
}
|
||||
|
||||
impl AsMut<[u8]> for Signature {
|
||||
fn as_mut(&mut self) -> &mut [u8] {
|
||||
&mut self.0[..]
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "full_crypto")]
|
||||
impl From<schnorrkel::Signature> for Signature {
|
||||
fn from(s: schnorrkel::Signature) -> Signature {
|
||||
Signature(s.to_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl rstd::fmt::Debug for Signature {
|
||||
#[cfg(feature = "std")]
|
||||
fn fmt(&self, f: &mut rstd::fmt::Formatter) -> rstd::fmt::Result {
|
||||
write!(f, "{}", crate::hexdisplay::HexDisplay::from(&self.0))
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
fn fmt(&self, _: &mut rstd::fmt::Formatter) -> rstd::fmt::Result {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "full_crypto")]
|
||||
impl rstd::hash::Hash for Signature {
|
||||
fn hash<H: rstd::hash::Hasher>(&self, state: &mut H) {
|
||||
rstd::hash::Hash::hash(&self.0[..], state);
|
||||
}
|
||||
}
|
||||
|
||||
/// A localized signature also contains sender information.
|
||||
/// NOTE: Encode and Decode traits are supported in ed25519 but not possible for now here.
|
||||
#[cfg(feature = "std")]
|
||||
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||
pub struct LocalizedSignature {
|
||||
/// The signer of the signature.
|
||||
pub signer: Public,
|
||||
/// The signature itself.
|
||||
pub signature: Signature,
|
||||
}
|
||||
|
||||
impl Signature {
|
||||
/// A new instance from the given 64-byte `data`.
|
||||
///
|
||||
/// NOTE: No checking goes on to ensure this is a real signature. Only use
|
||||
/// it if you are certain that the array actually is a signature, or if you
|
||||
/// immediately verify the signature. All functions that verify signatures
|
||||
/// will fail if the `Signature` is not actually a valid signature.
|
||||
pub fn from_raw(data: [u8; 64]) -> Signature {
|
||||
Signature(data)
|
||||
}
|
||||
|
||||
/// A new instance from the given slice that should be 64 bytes long.
|
||||
///
|
||||
/// NOTE: No checking goes on to ensure this is a real signature. Only use it if
|
||||
/// you are certain that the array actually is a signature. GIGO!
|
||||
pub fn from_slice(data: &[u8]) -> Self {
|
||||
let mut r = [0u8; 64];
|
||||
r.copy_from_slice(data);
|
||||
Signature(r)
|
||||
}
|
||||
|
||||
/// A new instance from an H512.
|
||||
///
|
||||
/// NOTE: No checking goes on to ensure this is a real signature. Only use it if
|
||||
/// you are certain that the array actually is a signature. GIGO!
|
||||
pub fn from_h512(v: H512) -> Signature {
|
||||
Signature(v.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl Derive for Public {
|
||||
/// Derive a child key from a series of given junctions.
|
||||
///
|
||||
/// `None` if there are any hard junctions in there.
|
||||
#[cfg(feature = "std")]
|
||||
fn derive<Iter: Iterator<Item=DeriveJunction>>(&self, path: Iter) -> Option<Public> {
|
||||
let mut acc = PublicKey::from_bytes(self.as_ref()).ok()?;
|
||||
for j in path {
|
||||
match j {
|
||||
DeriveJunction::Soft(cc) => acc = acc.derived_key_simple(ChainCode(cc), &[]).0,
|
||||
DeriveJunction::Hard(_cc) => return None,
|
||||
}
|
||||
}
|
||||
Some(Self(acc.to_bytes()))
|
||||
}
|
||||
}
|
||||
|
||||
impl Public {
|
||||
/// A new instance from the given 32-byte `data`.
|
||||
///
|
||||
/// NOTE: No checking goes on to ensure this is a real public key. Only use it if
|
||||
/// you are certain that the array actually is a pubkey. GIGO!
|
||||
pub fn from_raw(data: [u8; 32]) -> Self {
|
||||
Public(data)
|
||||
}
|
||||
|
||||
/// A new instance from an H256.
|
||||
///
|
||||
/// NOTE: No checking goes on to ensure this is a real public key. Only use it if
|
||||
/// you are certain that the array actually is a pubkey. GIGO!
|
||||
pub fn from_h256(x: H256) -> Self {
|
||||
Public(x.into())
|
||||
}
|
||||
|
||||
/// Return a slice filled with raw data.
|
||||
pub fn as_array_ref(&self) -> &[u8; 32] {
|
||||
self.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl TraitPublic for Public {
|
||||
/// A new instance from the given slice that should be 32 bytes long.
|
||||
///
|
||||
/// NOTE: No checking goes on to ensure this is a real public key. Only use it if
|
||||
/// you are certain that the array actually is a pubkey. GIGO!
|
||||
fn from_slice(data: &[u8]) -> Self {
|
||||
let mut r = [0u8; 32];
|
||||
r.copy_from_slice(data);
|
||||
Public(r)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl From<MiniSecretKey> for Pair {
|
||||
fn from(sec: MiniSecretKey) -> Pair {
|
||||
Pair(sec.expand_to_keypair(ExpansionMode::Ed25519))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl From<SecretKey> for Pair {
|
||||
fn from(sec: SecretKey) -> Pair {
|
||||
Pair(Keypair::from(sec))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "full_crypto")]
|
||||
impl From<schnorrkel::Keypair> for Pair {
|
||||
fn from(p: schnorrkel::Keypair) -> Pair {
|
||||
Pair(p)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "full_crypto")]
|
||||
impl From<Pair> for schnorrkel::Keypair {
|
||||
fn from(p: Pair) -> schnorrkel::Keypair {
|
||||
p.0
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "full_crypto")]
|
||||
impl AsRef<schnorrkel::Keypair> for Pair {
|
||||
fn as_ref(&self) -> &schnorrkel::Keypair {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
/// Derive a single hard junction.
|
||||
#[cfg(feature = "full_crypto")]
|
||||
fn derive_hard_junction(secret: &SecretKey, cc: &[u8; CHAIN_CODE_LENGTH]) -> MiniSecretKey {
|
||||
secret.hard_derive_mini_secret_key(Some(ChainCode(cc.clone())), b"").0
|
||||
}
|
||||
|
||||
/// The raw secret seed, which can be used to recreate the `Pair`.
|
||||
#[cfg(feature = "full_crypto")]
|
||||
type Seed = [u8; MINI_SECRET_KEY_LENGTH];
|
||||
|
||||
#[cfg(feature = "full_crypto")]
|
||||
impl TraitPair for Pair {
|
||||
type Public = Public;
|
||||
type Seed = Seed;
|
||||
type Signature = Signature;
|
||||
type DeriveError = Infallible;
|
||||
|
||||
/// Make a new key pair from raw secret seed material.
|
||||
///
|
||||
/// This is generated using schnorrkel's Mini-Secret-Keys.
|
||||
///
|
||||
/// A MiniSecretKey is literally what Ed25519 calls a SecretKey, which is just 32 random bytes.
|
||||
fn from_seed(seed: &Seed) -> Pair {
|
||||
Self::from_seed_slice(&seed[..])
|
||||
.expect("32 bytes can always build a key; qed")
|
||||
}
|
||||
|
||||
/// Get the public key.
|
||||
fn public(&self) -> Public {
|
||||
let mut pk = [0u8; 32];
|
||||
pk.copy_from_slice(&self.0.public.to_bytes());
|
||||
Public(pk)
|
||||
}
|
||||
|
||||
/// Make a new key pair from secret seed material. The slice must be 32 bytes long or it
|
||||
/// will return `None`.
|
||||
///
|
||||
/// You should never need to use this; generate(), generate_with_phrase(), from_phrase()
|
||||
fn from_seed_slice(seed: &[u8]) -> Result<Pair, SecretStringError> {
|
||||
match seed.len() {
|
||||
MINI_SECRET_KEY_LENGTH => {
|
||||
Ok(Pair(
|
||||
MiniSecretKey::from_bytes(seed)
|
||||
.map_err(|_| SecretStringError::InvalidSeed)?
|
||||
.expand_to_keypair(ExpansionMode::Ed25519)
|
||||
))
|
||||
}
|
||||
SECRET_KEY_LENGTH => {
|
||||
Ok(Pair(
|
||||
SecretKey::from_bytes(seed)
|
||||
.map_err(|_| SecretStringError::InvalidSeed)?
|
||||
.to_keypair()
|
||||
))
|
||||
}
|
||||
_ => Err(SecretStringError::InvalidSeedLength)
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "std")]
|
||||
fn generate_with_phrase(password: Option<&str>) -> (Pair, String, Seed) {
|
||||
let mnemonic = Mnemonic::new(MnemonicType::Words12, Language::English);
|
||||
let phrase = mnemonic.phrase();
|
||||
let (pair, seed) = Self::from_phrase(phrase, password)
|
||||
.expect("All phrases generated by Mnemonic are valid; qed");
|
||||
(
|
||||
pair,
|
||||
phrase.to_owned(),
|
||||
seed,
|
||||
)
|
||||
}
|
||||
#[cfg(feature = "std")]
|
||||
fn from_phrase(phrase: &str, password: Option<&str>) -> Result<(Pair, Seed), SecretStringError> {
|
||||
Mnemonic::from_phrase(phrase, Language::English)
|
||||
.map_err(|_| SecretStringError::InvalidPhrase)
|
||||
.map(|m| Self::from_entropy(m.entropy(), password))
|
||||
}
|
||||
|
||||
fn derive<Iter: Iterator<Item=DeriveJunction>>(&self,
|
||||
path: Iter,
|
||||
seed: Option<Seed>,
|
||||
) -> Result<(Pair, Option<Seed>), Self::DeriveError> {
|
||||
let seed = if let Some(s) = seed {
|
||||
if let Ok(msk) = MiniSecretKey::from_bytes(&s) {
|
||||
if msk.expand(ExpansionMode::Ed25519) == self.0.secret {
|
||||
Some(msk)
|
||||
} else { None }
|
||||
} else { None }
|
||||
} else { None };
|
||||
let init = self.0.secret.clone();
|
||||
let (result, seed) = path.fold((init, seed), |(acc, acc_seed), j| match (j, acc_seed) {
|
||||
(DeriveJunction::Soft(cc), _) =>
|
||||
(acc.derived_key_simple(ChainCode(cc), &[]).0, None),
|
||||
(DeriveJunction::Hard(cc), maybe_seed) => {
|
||||
let seed = derive_hard_junction(&acc, &cc);
|
||||
(seed.expand(ExpansionMode::Ed25519), maybe_seed.map(|_| seed))
|
||||
}
|
||||
});
|
||||
Ok((Self(result.into()), seed.map(|s| MiniSecretKey::to_bytes(&s))))
|
||||
}
|
||||
|
||||
fn sign(&self, message: &[u8]) -> Signature {
|
||||
let context = signing_context(SIGNING_CTX);
|
||||
self.0.sign(context.bytes(message)).into()
|
||||
}
|
||||
|
||||
/// Verify a signature on a message. Returns true if the signature is good.
|
||||
fn verify<M: AsRef<[u8]>>(sig: &Self::Signature, message: M, pubkey: &Self::Public) -> bool {
|
||||
Self::verify_weak(&sig.0[..], message, pubkey)
|
||||
}
|
||||
|
||||
/// Verify a signature on a message. Returns true if the signature is good.
|
||||
fn verify_weak<P: AsRef<[u8]>, M: AsRef<[u8]>>(sig: &[u8], message: M, pubkey: P) -> bool {
|
||||
// Match both schnorrkel 0.1.1 and 0.8.0+ signatures, supporting both wallets
|
||||
// that have not been upgraded and those that have. To swap to 0.8.0 only,
|
||||
// create `schnorrkel::Signature` and pass that into `verify_simple`
|
||||
match PublicKey::from_bytes(pubkey.as_ref()) {
|
||||
Ok(pk) => pk.verify_simple_preaudit_deprecated(
|
||||
SIGNING_CTX, message.as_ref(), &sig,
|
||||
).is_ok(),
|
||||
Err(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Return a vec filled with raw data.
|
||||
fn to_raw_vec(&self) -> Vec<u8> {
|
||||
self.0.secret.to_bytes().to_vec()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl Pair {
|
||||
/// Make a new key pair from binary data derived from a valid seed phrase.
|
||||
///
|
||||
/// This uses a key derivation function to convert the entropy into a seed, then returns
|
||||
/// the pair generated from it.
|
||||
pub fn from_entropy(entropy: &[u8], password: Option<&str>) -> (Pair, Seed) {
|
||||
let mini_key: MiniSecretKey = mini_secret_from_entropy(entropy, password.unwrap_or(""))
|
||||
.expect("32 bytes can always build a key; qed");
|
||||
|
||||
let kp = mini_key.expand_to_keypair(ExpansionMode::Ed25519);
|
||||
(Pair(kp), mini_key.to_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl CryptoType for Public {
|
||||
#[cfg(feature = "full_crypto")]
|
||||
type Pair = Pair;
|
||||
}
|
||||
|
||||
impl CryptoType for Signature {
|
||||
#[cfg(feature = "full_crypto")]
|
||||
type Pair = Pair;
|
||||
}
|
||||
|
||||
#[cfg(feature = "full_crypto")]
|
||||
impl CryptoType for Pair {
|
||||
type Pair = Pair;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod compatibility_test {
|
||||
use super::*;
|
||||
use crate::crypto::{DEV_PHRASE};
|
||||
use hex_literal::hex;
|
||||
|
||||
// NOTE: tests to ensure addresses that are created with the `0.1.x` version (pre-audit) are
|
||||
// still functional.
|
||||
|
||||
#[test]
|
||||
fn derive_soft_known_pair_should_work() {
|
||||
let pair = Pair::from_string(&format!("{}/Alice", DEV_PHRASE), None).unwrap();
|
||||
// known address of DEV_PHRASE with 1.1
|
||||
let known = hex!("d6c71059dbbe9ad2b0ed3f289738b800836eb425544ce694825285b958ca755e");
|
||||
assert_eq!(pair.public().to_raw_vec(), known);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn derive_hard_known_pair_should_work() {
|
||||
let pair = Pair::from_string(&format!("{}//Alice", DEV_PHRASE), None).unwrap();
|
||||
// known address of DEV_PHRASE with 1.1
|
||||
let known = hex!("d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d");
|
||||
assert_eq!(pair.public().to_raw_vec(), known);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn verify_known_message_should_work() {
|
||||
let public = Public::from_raw(hex!("b4bfa1f7a5166695eb75299fd1c4c03ea212871c342f2c5dfea0902b2c246918"));
|
||||
// signature generated by the 1.1 version with the same ^^ public key.
|
||||
let signature = Signature::from_raw(hex!(
|
||||
"5a9755f069939f45d96aaf125cf5ce7ba1db998686f87f2fb3cbdea922078741a73891ba265f70c31436e18a9acd14d189d73c12317ab6c313285cd938453202"
|
||||
));
|
||||
let message = b"Verifying that I am the owner of 5G9hQLdsKQswNPgB499DeA5PkFBbgkLPJWkkS6FAM6xGQ8xD. Hash: 221455a3\n";
|
||||
assert!(Pair::verify(&signature, &message[..], &public));
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::crypto::{Ss58Codec, DEV_PHRASE, DEV_ADDRESS};
|
||||
use hex_literal::hex;
|
||||
|
||||
#[test]
|
||||
fn default_phrase_should_be_used() {
|
||||
assert_eq!(
|
||||
Pair::from_string("//Alice///password", None).unwrap().public(),
|
||||
Pair::from_string(&format!("{}//Alice", DEV_PHRASE), Some("password")).unwrap().public(),
|
||||
);
|
||||
assert_eq!(
|
||||
Pair::from_string(&format!("{}/Alice", DEV_PHRASE), None).as_ref().map(Pair::public),
|
||||
Pair::from_string("/Alice", None).as_ref().map(Pair::public)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn default_address_should_be_used() {
|
||||
assert_eq!(
|
||||
Public::from_string(&format!("{}/Alice", DEV_ADDRESS)),
|
||||
Public::from_string("/Alice")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn default_phrase_should_correspond_to_default_address() {
|
||||
assert_eq!(
|
||||
Pair::from_string(&format!("{}/Alice", DEV_PHRASE), None).unwrap().public(),
|
||||
Public::from_string(&format!("{}/Alice", DEV_ADDRESS)).unwrap(),
|
||||
);
|
||||
assert_eq!(
|
||||
Pair::from_string("/Alice", None).unwrap().public(),
|
||||
Public::from_string("/Alice").unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn derive_soft_should_work() {
|
||||
let pair = Pair::from_seed(&hex!(
|
||||
"9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"
|
||||
));
|
||||
let derive_1 = pair.derive(Some(DeriveJunction::soft(1)).into_iter(), None).unwrap().0;
|
||||
let derive_1b = pair.derive(Some(DeriveJunction::soft(1)).into_iter(), None).unwrap().0;
|
||||
let derive_2 = pair.derive(Some(DeriveJunction::soft(2)).into_iter(), None).unwrap().0;
|
||||
assert_eq!(derive_1.public(), derive_1b.public());
|
||||
assert_ne!(derive_1.public(), derive_2.public());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn derive_hard_should_work() {
|
||||
let pair = Pair::from_seed(&hex!(
|
||||
"9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"
|
||||
));
|
||||
let derive_1 = pair.derive(Some(DeriveJunction::hard(1)).into_iter(), None).unwrap().0;
|
||||
let derive_1b = pair.derive(Some(DeriveJunction::hard(1)).into_iter(), None).unwrap().0;
|
||||
let derive_2 = pair.derive(Some(DeriveJunction::hard(2)).into_iter(), None).unwrap().0;
|
||||
assert_eq!(derive_1.public(), derive_1b.public());
|
||||
assert_ne!(derive_1.public(), derive_2.public());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn derive_soft_public_should_work() {
|
||||
let pair = Pair::from_seed(&hex!(
|
||||
"9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"
|
||||
));
|
||||
let path = Some(DeriveJunction::soft(1));
|
||||
let pair_1 = pair.derive(path.clone().into_iter(), None).unwrap().0;
|
||||
let public_1 = pair.public().derive(path.into_iter()).unwrap();
|
||||
assert_eq!(pair_1.public(), public_1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn derive_hard_public_should_fail() {
|
||||
let pair = Pair::from_seed(&hex!(
|
||||
"9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"
|
||||
));
|
||||
let path = Some(DeriveJunction::hard(1));
|
||||
assert!(pair.public().derive(path.into_iter()).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sr_test_vector_should_work() {
|
||||
let pair = Pair::from_seed(&hex!(
|
||||
"9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"
|
||||
));
|
||||
let public = pair.public();
|
||||
assert_eq!(
|
||||
public,
|
||||
Public::from_raw(hex!(
|
||||
"44a996beb1eef7bdcab976ab6d2ca26104834164ecf28fb375600576fcc6eb0f"
|
||||
))
|
||||
);
|
||||
let message = b"";
|
||||
let signature = pair.sign(message);
|
||||
assert!(Pair::verify(&signature, &message[..], &public));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn generated_pair_should_work() {
|
||||
let (pair, _) = Pair::generate();
|
||||
let public = pair.public();
|
||||
let message = b"Something important";
|
||||
let signature = pair.sign(&message[..]);
|
||||
assert!(Pair::verify(&signature, &message[..], &public));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn seeded_pair_should_work() {
|
||||
let pair = Pair::from_seed(b"12345678901234567890123456789012");
|
||||
let public = pair.public();
|
||||
assert_eq!(
|
||||
public,
|
||||
Public::from_raw(hex!(
|
||||
"741c08a06f41c596608f6774259bd9043304adfa5d3eea62760bd9be97634d63"
|
||||
))
|
||||
);
|
||||
let message = hex!("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000200d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000");
|
||||
let signature = pair.sign(&message[..]);
|
||||
assert!(Pair::verify(&signature, &message[..], &public));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ss58check_roundtrip_works() {
|
||||
let (pair, _) = Pair::generate();
|
||||
let public = pair.public();
|
||||
let s = public.to_ss58check();
|
||||
println!("Correct: {}", s);
|
||||
let cmp = Public::from_ss58check(&s).unwrap();
|
||||
assert_eq!(cmp, public);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn verify_from_wasm_works() {
|
||||
// The values in this test case are compared to the output of `node-test.js` in schnorrkel-js.
|
||||
//
|
||||
// This is to make sure that the wasm library is compatible.
|
||||
let pk = Pair::from_seed(
|
||||
&hex!("0000000000000000000000000000000000000000000000000000000000000000")
|
||||
);
|
||||
let public = pk.public();
|
||||
let js_signature = Signature::from_raw(hex!(
|
||||
"28a854d54903e056f89581c691c1f7d2ff39f8f896c9e9c22475e60902cc2b3547199e0e91fa32902028f2ca2355e8cdd16cfe19ba5e8b658c94aa80f3b81a00"
|
||||
));
|
||||
assert!(Pair::verify(&js_signature, b"SUBSTRATE", &public));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,273 @@
|
||||
// Copyright 2019 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Substrate is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Types that should only be used for testing!
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use crate::{ed25519, sr25519, crypto::{Public, Pair}};
|
||||
use crate::crypto::KeyTypeId;
|
||||
|
||||
/// Key type for generic Ed25519 key.
|
||||
pub const ED25519: KeyTypeId = KeyTypeId(*b"ed25");
|
||||
/// Key type for generic Sr 25519 key.
|
||||
pub const SR25519: KeyTypeId = KeyTypeId(*b"sr25");
|
||||
|
||||
/// A keystore implementation usable in tests.
|
||||
#[cfg(feature = "std")]
|
||||
#[derive(Default)]
|
||||
pub struct KeyStore {
|
||||
/// `KeyTypeId` maps to public keys and public keys map to private keys.
|
||||
keys: std::collections::HashMap<KeyTypeId, std::collections::HashMap<Vec<u8>, String>>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl KeyStore {
|
||||
/// Creates a new instance of `Self`.
|
||||
pub fn new() -> crate::traits::BareCryptoStorePtr {
|
||||
std::sync::Arc::new(parking_lot::RwLock::new(Self::default()))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl crate::traits::BareCryptoStore for KeyStore {
|
||||
fn sr25519_public_keys(&self, id: KeyTypeId) -> Vec<sr25519::Public> {
|
||||
self.keys.get(&id)
|
||||
.map(|keys|
|
||||
keys.values()
|
||||
.map(|s| sr25519::Pair::from_string(s, None).expect("`sr25519` seed slice is valid"))
|
||||
.map(|p| p.public())
|
||||
.collect()
|
||||
)
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
fn sr25519_generate_new(
|
||||
&mut self,
|
||||
id: KeyTypeId,
|
||||
seed: Option<&str>,
|
||||
) -> Result<sr25519::Public, String> {
|
||||
match seed {
|
||||
Some(seed) => {
|
||||
let pair = sr25519::Pair::from_string(seed, None).expect("Generates an `sr25519` pair.");
|
||||
self.keys.entry(id).or_default().insert(pair.public().to_raw_vec(), seed.into());
|
||||
Ok(pair.public())
|
||||
},
|
||||
None => {
|
||||
let (pair, phrase, _) = sr25519::Pair::generate_with_phrase(None);
|
||||
self.keys.entry(id).or_default().insert(pair.public().to_raw_vec(), phrase);
|
||||
Ok(pair.public())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn sr25519_key_pair(&self, id: KeyTypeId, pub_key: &sr25519::Public) -> Option<sr25519::Pair> {
|
||||
self.keys.get(&id)
|
||||
.and_then(|inner|
|
||||
inner.get(pub_key.as_slice())
|
||||
.map(|s| sr25519::Pair::from_string(s, None).expect("`sr25519` seed slice is valid"))
|
||||
)
|
||||
}
|
||||
|
||||
fn ed25519_public_keys(&self, id: KeyTypeId) -> Vec<ed25519::Public> {
|
||||
self.keys.get(&id)
|
||||
.map(|keys|
|
||||
keys.values()
|
||||
.map(|s| ed25519::Pair::from_string(s, None).expect("`ed25519` seed slice is valid"))
|
||||
.map(|p| p.public())
|
||||
.collect()
|
||||
)
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
fn ed25519_generate_new(
|
||||
&mut self,
|
||||
id: KeyTypeId,
|
||||
seed: Option<&str>,
|
||||
) -> Result<ed25519::Public, String> {
|
||||
match seed {
|
||||
Some(seed) => {
|
||||
let pair = ed25519::Pair::from_string(seed, None).expect("Generates an `ed25519` pair.");
|
||||
self.keys.entry(id).or_default().insert(pair.public().to_raw_vec(), seed.into());
|
||||
Ok(pair.public())
|
||||
},
|
||||
None => {
|
||||
let (pair, phrase, _) = ed25519::Pair::generate_with_phrase(None);
|
||||
self.keys.entry(id).or_default().insert(pair.public().to_raw_vec(), phrase);
|
||||
Ok(pair.public())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn ed25519_key_pair(&self, id: KeyTypeId, pub_key: &ed25519::Public) -> Option<ed25519::Pair> {
|
||||
self.keys.get(&id)
|
||||
.and_then(|inner|
|
||||
inner.get(pub_key.as_slice())
|
||||
.map(|s| ed25519::Pair::from_string(s, None).expect("`ed25519` seed slice is valid"))
|
||||
)
|
||||
}
|
||||
|
||||
fn insert_unknown(&mut self, id: KeyTypeId, suri: &str, public: &[u8]) -> Result<(), ()> {
|
||||
self.keys.entry(id).or_default().insert(public.to_owned(), suri.to_string());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn password(&self) -> Option<&str> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Macro for exporting functions from wasm in with the expected signature for using it with the
|
||||
/// wasm executor. This is useful for tests where you need to call a function in wasm.
|
||||
///
|
||||
/// The input parameters are expected to be SCALE encoded and will be automatically decoded for you.
|
||||
/// The output value is also SCALE encoded when returned back to the host.
|
||||
///
|
||||
/// The functions are feature-gated with `#[cfg(not(feature = "std"))]`, so they are only available
|
||||
/// from within wasm.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use substrate_primitives::wasm_export_functions;
|
||||
///
|
||||
/// wasm_export_functions! {
|
||||
/// fn test_in_wasm(value: bool, another_value: Vec<u8>) -> bool {
|
||||
/// value && another_value.is_empty()
|
||||
/// }
|
||||
///
|
||||
/// fn without_return_value() {
|
||||
/// // do something
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! wasm_export_functions {
|
||||
(
|
||||
$(
|
||||
fn $name:ident (
|
||||
$( $arg_name:ident: $arg_ty:ty ),* $(,)?
|
||||
) $( -> $ret_ty:ty )? { $( $fn_impl:tt )* }
|
||||
)*
|
||||
) => {
|
||||
$(
|
||||
$crate::wasm_export_functions! {
|
||||
@IMPL
|
||||
fn $name (
|
||||
$( $arg_name: $arg_ty ),*
|
||||
) $( -> $ret_ty )? { $( $fn_impl )* }
|
||||
}
|
||||
)*
|
||||
};
|
||||
(@IMPL
|
||||
fn $name:ident (
|
||||
$( $arg_name:ident: $arg_ty:ty ),*
|
||||
) { $( $fn_impl:tt )* }
|
||||
) => {
|
||||
#[no_mangle]
|
||||
#[allow(unreachable_code)]
|
||||
#[cfg(not(feature = "std"))]
|
||||
pub fn $name(input_data: *mut u8, input_len: usize) -> u64 {
|
||||
let input: &[u8] = if input_len == 0 {
|
||||
&[0u8; 0]
|
||||
} else {
|
||||
unsafe {
|
||||
$crate::rstd::slice::from_raw_parts(input_data, input_len)
|
||||
}
|
||||
};
|
||||
|
||||
{
|
||||
let ($( $arg_name ),*) : ($( $arg_ty ),*) = $crate::Decode::decode(
|
||||
&mut &input[..],
|
||||
).expect("Input data is correctly encoded");
|
||||
|
||||
$( $fn_impl )*
|
||||
}
|
||||
|
||||
$crate::to_substrate_wasm_fn_return_value(&())
|
||||
}
|
||||
};
|
||||
(@IMPL
|
||||
fn $name:ident (
|
||||
$( $arg_name:ident: $arg_ty:ty ),*
|
||||
) $( -> $ret_ty:ty )? { $( $fn_impl:tt )* }
|
||||
) => {
|
||||
#[no_mangle]
|
||||
#[allow(unreachable_code)]
|
||||
#[cfg(not(feature = "std"))]
|
||||
pub fn $name(input_data: *mut u8, input_len: usize) -> u64 {
|
||||
let input: &[u8] = if input_len == 0 {
|
||||
&[0u8; 0]
|
||||
} else {
|
||||
unsafe {
|
||||
$crate::rstd::slice::from_raw_parts(input_data, input_len)
|
||||
}
|
||||
};
|
||||
|
||||
let output $( : $ret_ty )? = {
|
||||
let ($( $arg_name ),*) : ($( $arg_ty ),*) = $crate::Decode::decode(
|
||||
&mut &input[..],
|
||||
).expect("Input data is correctly encoded");
|
||||
|
||||
$( $fn_impl )*
|
||||
};
|
||||
|
||||
$crate::to_substrate_wasm_fn_return_value(&output)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::sr25519;
|
||||
use crate::testing::{ED25519, SR25519};
|
||||
|
||||
#[test]
|
||||
fn store_key_and_extract() {
|
||||
let store = KeyStore::new();
|
||||
|
||||
let public = store.write()
|
||||
.ed25519_generate_new(ED25519, None)
|
||||
.expect("Genrates key");
|
||||
|
||||
let store_key_pair = store.read()
|
||||
.ed25519_key_pair(ED25519, &public)
|
||||
.expect("Key should exists in store");
|
||||
|
||||
assert_eq!(public, store_key_pair.public());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn store_unknown_and_extract_it() {
|
||||
let store = KeyStore::new();
|
||||
|
||||
let secret_uri = "//Alice";
|
||||
let key_pair = sr25519::Pair::from_string(secret_uri, None).expect("Generates key pair");
|
||||
|
||||
store.write().insert_unknown(
|
||||
SR25519,
|
||||
secret_uri,
|
||||
key_pair.public().as_ref(),
|
||||
).expect("Inserts unknown key");
|
||||
|
||||
let store_key_pair = store.read().sr25519_key_pair(
|
||||
SR25519,
|
||||
&key_pair.public(),
|
||||
).expect("Gets key pair from keystore");
|
||||
|
||||
assert_eq!(key_pair.public(), store_key_pair.public());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
// Copyright 2017-2019 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Substrate is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Tests.
|
||||
@@ -0,0 +1,97 @@
|
||||
// Copyright 2019 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Substrate is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Shareable Substrate traits.
|
||||
|
||||
use crate::{crypto::KeyTypeId, ed25519, sr25519};
|
||||
|
||||
use std::{fmt::{Debug, Display}, panic::UnwindSafe};
|
||||
|
||||
pub use externalities::{Externalities, ExternalitiesExt};
|
||||
|
||||
/// Something that generates, stores and provides access to keys.
|
||||
pub trait BareCryptoStore: Send + Sync {
|
||||
/// Returns all sr25519 public keys for the given key type.
|
||||
fn sr25519_public_keys(&self, id: KeyTypeId) -> Vec<sr25519::Public>;
|
||||
/// Generate a new sr25519 key pair for the given key type and an optional seed.
|
||||
///
|
||||
/// If the given seed is `Some(_)`, the key pair will only be stored in memory.
|
||||
///
|
||||
/// Returns the public key of the generated key pair.
|
||||
fn sr25519_generate_new(
|
||||
&mut self,
|
||||
id: KeyTypeId,
|
||||
seed: Option<&str>,
|
||||
) -> Result<sr25519::Public, String>;
|
||||
/// Returns the sr25519 key pair for the given key type and public key combination.
|
||||
fn sr25519_key_pair(&self, id: KeyTypeId, pub_key: &sr25519::Public) -> Option<sr25519::Pair>;
|
||||
|
||||
/// Returns all ed25519 public keys for the given key type.
|
||||
fn ed25519_public_keys(&self, id: KeyTypeId) -> Vec<ed25519::Public>;
|
||||
/// Generate a new ed25519 key pair for the given key type and an optional seed.
|
||||
///
|
||||
/// If the given seed is `Some(_)`, the key pair will only be stored in memory.
|
||||
///
|
||||
/// Returns the public key of the generated key pair.
|
||||
fn ed25519_generate_new(
|
||||
&mut self,
|
||||
id: KeyTypeId,
|
||||
seed: Option<&str>,
|
||||
) -> Result<ed25519::Public, String>;
|
||||
|
||||
/// Returns the ed25519 key pair for the given key type and public key combination.
|
||||
fn ed25519_key_pair(&self, id: KeyTypeId, pub_key: &ed25519::Public) -> Option<ed25519::Pair>;
|
||||
|
||||
/// Insert a new key. This doesn't require any known of the crypto; but a public key must be
|
||||
/// manually provided.
|
||||
///
|
||||
/// Places it into the file system store.
|
||||
///
|
||||
/// `Err` if there's some sort of weird filesystem error, but should generally be `Ok`.
|
||||
fn insert_unknown(&mut self, _key_type: KeyTypeId, _suri: &str, _public: &[u8]) -> Result<(), ()>;
|
||||
|
||||
/// Get the password for this store.
|
||||
fn password(&self) -> Option<&str>;
|
||||
}
|
||||
|
||||
/// A pointer to the key store.
|
||||
pub type BareCryptoStorePtr = std::sync::Arc<parking_lot::RwLock<dyn BareCryptoStore>>;
|
||||
|
||||
externalities::decl_extension! {
|
||||
/// The keystore extension to register/retrieve from the externalities.
|
||||
pub struct KeystoreExt(BareCryptoStorePtr);
|
||||
}
|
||||
|
||||
/// Code execution engine.
|
||||
pub trait CodeExecutor: Sized + Send + Sync {
|
||||
/// Externalities error type.
|
||||
type Error: Display + Debug + Send + 'static;
|
||||
|
||||
/// Call a given method in the runtime. Returns a tuple of the result (either the output data
|
||||
/// or an execution error) together with a `bool`, which is true if native execution was used.
|
||||
fn call<
|
||||
E: Externalities,
|
||||
R: codec::Codec + PartialEq,
|
||||
NC: FnOnce() -> Result<R, String> + UnwindSafe,
|
||||
>(
|
||||
&self,
|
||||
ext: &mut E,
|
||||
method: &str,
|
||||
data: &[u8],
|
||||
use_native: bool,
|
||||
native_call: Option<NC>,
|
||||
) -> (Result<crate::NativeOrEncoded<R>, Self::Error>, bool);
|
||||
}
|
||||
@@ -0,0 +1,243 @@
|
||||
// Copyright 2017-2019 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Substrate is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! An u32 trait with "values" as impl'd types.
|
||||
|
||||
/// A u32 value, wrapped in a trait because we don't yet have const generics.
|
||||
pub trait Value {
|
||||
/// The actual value represented by the impl'ing type.
|
||||
const VALUE: u32;
|
||||
}
|
||||
|
||||
/// Type representing the value 0 for the `Value` trait.
|
||||
pub struct _0; impl Value for _0 { const VALUE: u32 = 0; }
|
||||
/// Type representing the value 1 for the `Value` trait.
|
||||
pub struct _1; impl Value for _1 { const VALUE: u32 = 1; }
|
||||
/// Type representing the value 2 for the `Value` trait.
|
||||
pub struct _2; impl Value for _2 { const VALUE: u32 = 2; }
|
||||
/// Type representing the value 3 for the `Value` trait.
|
||||
pub struct _3; impl Value for _3 { const VALUE: u32 = 3; }
|
||||
/// Type representing the value 4 for the `Value` trait.
|
||||
pub struct _4; impl Value for _4 { const VALUE: u32 = 4; }
|
||||
/// Type representing the value 5 for the `Value` trait.
|
||||
pub struct _5; impl Value for _5 { const VALUE: u32 = 5; }
|
||||
/// Type representing the value 6 for the `Value` trait.
|
||||
pub struct _6; impl Value for _6 { const VALUE: u32 = 6; }
|
||||
/// Type representing the value 7 for the `Value` trait.
|
||||
pub struct _7; impl Value for _7 { const VALUE: u32 = 7; }
|
||||
/// Type representing the value 8 for the `Value` trait.
|
||||
pub struct _8; impl Value for _8 { const VALUE: u32 = 8; }
|
||||
/// Type representing the value 9 for the `Value` trait.
|
||||
pub struct _9; impl Value for _9 { const VALUE: u32 = 9; }
|
||||
/// Type representing the value 10 for the `Value` trait.
|
||||
pub struct _10; impl Value for _10 { const VALUE: u32 = 10; }
|
||||
/// Type representing the value 11 for the `Value` trait.
|
||||
pub struct _11; impl Value for _11 { const VALUE: u32 = 11; }
|
||||
/// Type representing the value 12 for the `Value` trait.
|
||||
pub struct _12; impl Value for _12 { const VALUE: u32 = 12; }
|
||||
/// Type representing the value 13 for the `Value` trait.
|
||||
pub struct _13; impl Value for _13 { const VALUE: u32 = 13; }
|
||||
/// Type representing the value 14 for the `Value` trait.
|
||||
pub struct _14; impl Value for _14 { const VALUE: u32 = 14; }
|
||||
/// Type representing the value 15 for the `Value` trait.
|
||||
pub struct _15; impl Value for _15 { const VALUE: u32 = 15; }
|
||||
/// Type representing the value 16 for the `Value` trait.
|
||||
pub struct _16; impl Value for _16 { const VALUE: u32 = 16; }
|
||||
/// Type representing the value 17 for the `Value` trait.
|
||||
pub struct _17; impl Value for _17 { const VALUE: u32 = 17; }
|
||||
/// Type representing the value 18 for the `Value` trait.
|
||||
pub struct _18; impl Value for _18 { const VALUE: u32 = 18; }
|
||||
/// Type representing the value 19 for the `Value` trait.
|
||||
pub struct _19; impl Value for _19 { const VALUE: u32 = 19; }
|
||||
/// Type representing the value 20 for the `Value` trait.
|
||||
pub struct _20; impl Value for _20 { const VALUE: u32 = 20; }
|
||||
/// Type representing the value 21 for the `Value` trait.
|
||||
pub struct _21; impl Value for _21 { const VALUE: u32 = 21; }
|
||||
/// Type representing the value 22 for the `Value` trait.
|
||||
pub struct _22; impl Value for _22 { const VALUE: u32 = 22; }
|
||||
/// Type representing the value 23 for the `Value` trait.
|
||||
pub struct _23; impl Value for _23 { const VALUE: u32 = 23; }
|
||||
/// Type representing the value 24 for the `Value` trait.
|
||||
pub struct _24; impl Value for _24 { const VALUE: u32 = 24; }
|
||||
/// Type representing the value 25 for the `Value` trait.
|
||||
pub struct _25; impl Value for _25 { const VALUE: u32 = 25; }
|
||||
/// Type representing the value 26 for the `Value` trait.
|
||||
pub struct _26; impl Value for _26 { const VALUE: u32 = 26; }
|
||||
/// Type representing the value 27 for the `Value` trait.
|
||||
pub struct _27; impl Value for _27 { const VALUE: u32 = 27; }
|
||||
/// Type representing the value 28 for the `Value` trait.
|
||||
pub struct _28; impl Value for _28 { const VALUE: u32 = 28; }
|
||||
/// Type representing the value 29 for the `Value` trait.
|
||||
pub struct _29; impl Value for _29 { const VALUE: u32 = 29; }
|
||||
/// Type representing the value 30 for the `Value` trait.
|
||||
pub struct _30; impl Value for _30 { const VALUE: u32 = 30; }
|
||||
/// Type representing the value 31 for the `Value` trait.
|
||||
pub struct _31; impl Value for _31 { const VALUE: u32 = 31; }
|
||||
/// Type representing the value 32 for the `Value` trait.
|
||||
pub struct _32; impl Value for _32 { const VALUE: u32 = 32; }
|
||||
/// Type representing the value 33 for the `Value` trait.
|
||||
pub struct _33; impl Value for _33 { const VALUE: u32 = 33; }
|
||||
/// Type representing the value 34 for the `Value` trait.
|
||||
pub struct _34; impl Value for _34 { const VALUE: u32 = 34; }
|
||||
/// Type representing the value 35 for the `Value` trait.
|
||||
pub struct _35; impl Value for _35 { const VALUE: u32 = 35; }
|
||||
/// Type representing the value 36 for the `Value` trait.
|
||||
pub struct _36; impl Value for _36 { const VALUE: u32 = 36; }
|
||||
/// Type representing the value 37 for the `Value` trait.
|
||||
pub struct _37; impl Value for _37 { const VALUE: u32 = 37; }
|
||||
/// Type representing the value 38 for the `Value` trait.
|
||||
pub struct _38; impl Value for _38 { const VALUE: u32 = 38; }
|
||||
/// Type representing the value 39 for the `Value` trait.
|
||||
pub struct _39; impl Value for _39 { const VALUE: u32 = 39; }
|
||||
/// Type representing the value 40 for the `Value` trait.
|
||||
pub struct _40; impl Value for _40 { const VALUE: u32 = 40; }
|
||||
/// Type representing the value 41 for the `Value` trait.
|
||||
pub struct _41; impl Value for _41 { const VALUE: u32 = 41; }
|
||||
/// Type representing the value 42 for the `Value` trait.
|
||||
pub struct _42; impl Value for _42 { const VALUE: u32 = 42; }
|
||||
/// Type representing the value 43 for the `Value` trait.
|
||||
pub struct _43; impl Value for _43 { const VALUE: u32 = 43; }
|
||||
/// Type representing the value 44 for the `Value` trait.
|
||||
pub struct _44; impl Value for _44 { const VALUE: u32 = 44; }
|
||||
/// Type representing the value 45 for the `Value` trait.
|
||||
pub struct _45; impl Value for _45 { const VALUE: u32 = 45; }
|
||||
/// Type representing the value 46 for the `Value` trait.
|
||||
pub struct _46; impl Value for _46 { const VALUE: u32 = 46; }
|
||||
/// Type representing the value 47 for the `Value` trait.
|
||||
pub struct _47; impl Value for _47 { const VALUE: u32 = 47; }
|
||||
/// Type representing the value 48 for the `Value` trait.
|
||||
pub struct _48; impl Value for _48 { const VALUE: u32 = 48; }
|
||||
/// Type representing the value 49 for the `Value` trait.
|
||||
pub struct _49; impl Value for _49 { const VALUE: u32 = 49; }
|
||||
/// Type representing the value 50 for the `Value` trait.
|
||||
pub struct _50; impl Value for _50 { const VALUE: u32 = 50; }
|
||||
/// Type representing the value 51 for the `Value` trait.
|
||||
pub struct _51; impl Value for _51 { const VALUE: u32 = 51; }
|
||||
/// Type representing the value 52 for the `Value` trait.
|
||||
pub struct _52; impl Value for _52 { const VALUE: u32 = 52; }
|
||||
/// Type representing the value 53 for the `Value` trait.
|
||||
pub struct _53; impl Value for _53 { const VALUE: u32 = 53; }
|
||||
/// Type representing the value 54 for the `Value` trait.
|
||||
pub struct _54; impl Value for _54 { const VALUE: u32 = 54; }
|
||||
/// Type representing the value 55 for the `Value` trait.
|
||||
pub struct _55; impl Value for _55 { const VALUE: u32 = 55; }
|
||||
/// Type representing the value 56 for the `Value` trait.
|
||||
pub struct _56; impl Value for _56 { const VALUE: u32 = 56; }
|
||||
/// Type representing the value 57 for the `Value` trait.
|
||||
pub struct _57; impl Value for _57 { const VALUE: u32 = 57; }
|
||||
/// Type representing the value 58 for the `Value` trait.
|
||||
pub struct _58; impl Value for _58 { const VALUE: u32 = 58; }
|
||||
/// Type representing the value 59 for the `Value` trait.
|
||||
pub struct _59; impl Value for _59 { const VALUE: u32 = 59; }
|
||||
/// Type representing the value 60 for the `Value` trait.
|
||||
pub struct _60; impl Value for _60 { const VALUE: u32 = 60; }
|
||||
/// Type representing the value 61 for the `Value` trait.
|
||||
pub struct _61; impl Value for _61 { const VALUE: u32 = 61; }
|
||||
/// Type representing the value 62 for the `Value` trait.
|
||||
pub struct _62; impl Value for _62 { const VALUE: u32 = 62; }
|
||||
/// Type representing the value 63 for the `Value` trait.
|
||||
pub struct _63; impl Value for _63 { const VALUE: u32 = 63; }
|
||||
/// Type representing the value 64 for the `Value` trait.
|
||||
pub struct _64; impl Value for _64 { const VALUE: u32 = 64; }
|
||||
/// Type representing the value 65 for the `Value` trait.
|
||||
pub struct _65; impl Value for _65 { const VALUE: u32 = 65; }
|
||||
/// Type representing the value 66 for the `Value` trait.
|
||||
pub struct _66; impl Value for _66 { const VALUE: u32 = 66; }
|
||||
/// Type representing the value 67 for the `Value` trait.
|
||||
pub struct _67; impl Value for _67 { const VALUE: u32 = 67; }
|
||||
/// Type representing the value 68 for the `Value` trait.
|
||||
pub struct _68; impl Value for _68 { const VALUE: u32 = 68; }
|
||||
/// Type representing the value 69 for the `Value` trait.
|
||||
pub struct _69; impl Value for _69 { const VALUE: u32 = 69; }
|
||||
/// Type representing the value 70 for the `Value` trait.
|
||||
pub struct _70; impl Value for _70 { const VALUE: u32 = 70; }
|
||||
/// Type representing the value 71 for the `Value` trait.
|
||||
pub struct _71; impl Value for _71 { const VALUE: u32 = 71; }
|
||||
/// Type representing the value 72 for the `Value` trait.
|
||||
pub struct _72; impl Value for _72 { const VALUE: u32 = 72; }
|
||||
/// Type representing the value 73 for the `Value` trait.
|
||||
pub struct _73; impl Value for _73 { const VALUE: u32 = 73; }
|
||||
/// Type representing the value 74 for the `Value` trait.
|
||||
pub struct _74; impl Value for _74 { const VALUE: u32 = 74; }
|
||||
/// Type representing the value 75 for the `Value` trait.
|
||||
pub struct _75; impl Value for _75 { const VALUE: u32 = 75; }
|
||||
/// Type representing the value 76 for the `Value` trait.
|
||||
pub struct _76; impl Value for _76 { const VALUE: u32 = 76; }
|
||||
/// Type representing the value 77 for the `Value` trait.
|
||||
pub struct _77; impl Value for _77 { const VALUE: u32 = 77; }
|
||||
/// Type representing the value 78 for the `Value` trait.
|
||||
pub struct _78; impl Value for _78 { const VALUE: u32 = 78; }
|
||||
/// Type representing the value 79 for the `Value` trait.
|
||||
pub struct _79; impl Value for _79 { const VALUE: u32 = 79; }
|
||||
/// Type representing the value 80 for the `Value` trait.
|
||||
pub struct _80; impl Value for _80 { const VALUE: u32 = 80; }
|
||||
/// Type representing the value 81 for the `Value` trait.
|
||||
pub struct _81; impl Value for _81 { const VALUE: u32 = 81; }
|
||||
/// Type representing the value 82 for the `Value` trait.
|
||||
pub struct _82; impl Value for _82 { const VALUE: u32 = 82; }
|
||||
/// Type representing the value 83 for the `Value` trait.
|
||||
pub struct _83; impl Value for _83 { const VALUE: u32 = 83; }
|
||||
/// Type representing the value 84 for the `Value` trait.
|
||||
pub struct _84; impl Value for _84 { const VALUE: u32 = 84; }
|
||||
/// Type representing the value 85 for the `Value` trait.
|
||||
pub struct _85; impl Value for _85 { const VALUE: u32 = 85; }
|
||||
/// Type representing the value 86 for the `Value` trait.
|
||||
pub struct _86; impl Value for _86 { const VALUE: u32 = 86; }
|
||||
/// Type representing the value 87 for the `Value` trait.
|
||||
pub struct _87; impl Value for _87 { const VALUE: u32 = 87; }
|
||||
/// Type representing the value 88 for the `Value` trait.
|
||||
pub struct _88; impl Value for _88 { const VALUE: u32 = 88; }
|
||||
/// Type representing the value 89 for the `Value` trait.
|
||||
pub struct _89; impl Value for _89 { const VALUE: u32 = 89; }
|
||||
/// Type representing the value 90 for the `Value` trait.
|
||||
pub struct _90; impl Value for _90 { const VALUE: u32 = 90; }
|
||||
/// Type representing the value 91 for the `Value` trait.
|
||||
pub struct _91; impl Value for _91 { const VALUE: u32 = 91; }
|
||||
/// Type representing the value 92 for the `Value` trait.
|
||||
pub struct _92; impl Value for _92 { const VALUE: u32 = 92; }
|
||||
/// Type representing the value 93 for the `Value` trait.
|
||||
pub struct _93; impl Value for _93 { const VALUE: u32 = 93; }
|
||||
/// Type representing the value 94 for the `Value` trait.
|
||||
pub struct _94; impl Value for _94 { const VALUE: u32 = 94; }
|
||||
/// Type representing the value 95 for the `Value` trait.
|
||||
pub struct _95; impl Value for _95 { const VALUE: u32 = 95; }
|
||||
/// Type representing the value 96 for the `Value` trait.
|
||||
pub struct _96; impl Value for _96 { const VALUE: u32 = 96; }
|
||||
/// Type representing the value 97 for the `Value` trait.
|
||||
pub struct _97; impl Value for _97 { const VALUE: u32 = 97; }
|
||||
/// Type representing the value 98 for the `Value` trait.
|
||||
pub struct _98; impl Value for _98 { const VALUE: u32 = 98; }
|
||||
/// Type representing the value 99 for the `Value` trait.
|
||||
pub struct _99; impl Value for _99 { const VALUE: u32 = 99; }
|
||||
/// Type representing the value 100 for the `Value` trait.
|
||||
pub struct _100; impl Value for _100 { const VALUE: u32 = 100; }
|
||||
/// Type representing the value 112 for the `Value` trait.
|
||||
pub struct _112; impl Value for _112 { const VALUE: u32 = 112; }
|
||||
/// Type representing the value 128 for the `Value` trait.
|
||||
pub struct _128; impl Value for _128 { const VALUE: u32 = 128; }
|
||||
/// Type representing the value 160 for the `Value` trait.
|
||||
pub struct _160; impl Value for _160 { const VALUE: u32 = 160; }
|
||||
/// Type representing the value 192 for the `Value` trait.
|
||||
pub struct _192; impl Value for _192 { const VALUE: u32 = 192; }
|
||||
/// Type representing the value 224 for the `Value` trait.
|
||||
pub struct _224; impl Value for _224 { const VALUE: u32 = 224; }
|
||||
/// Type representing the value 256 for the `Value` trait.
|
||||
pub struct _256; impl Value for _256 { const VALUE: u32 = 256; }
|
||||
/// Type representing the value 384 for the `Value` trait.
|
||||
pub struct _384; impl Value for _384 { const VALUE: u32 = 384; }
|
||||
/// Type representing the value 512 for the `Value` trait.
|
||||
pub struct _512; impl Value for _512 { const VALUE: u32 = 512; }
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
// Copyright 2017-2019 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Substrate is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! An unsigned fixed-size integer.
|
||||
|
||||
pub use primitive_types::U256;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use codec::{Encode, Decode};
|
||||
use substrate_serializer as ser;
|
||||
|
||||
macro_rules! test {
|
||||
($name: ident, $test_name: ident) => {
|
||||
#[test]
|
||||
fn $test_name() {
|
||||
let tests = vec![
|
||||
($name::from(0), "0x0"),
|
||||
($name::from(1), "0x1"),
|
||||
($name::from(2), "0x2"),
|
||||
($name::from(10), "0xa"),
|
||||
($name::from(15), "0xf"),
|
||||
($name::from(15), "0xf"),
|
||||
($name::from(16), "0x10"),
|
||||
($name::from(1_000), "0x3e8"),
|
||||
($name::from(100_000), "0x186a0"),
|
||||
($name::from(u64::max_value()), "0xffffffffffffffff"),
|
||||
($name::from(u64::max_value()) + $name::from(1), "0x10000000000000000"),
|
||||
];
|
||||
|
||||
for (number, expected) in tests {
|
||||
assert_eq!(format!("{:?}", expected), ser::to_string_pretty(&number));
|
||||
assert_eq!(number, ser::from_str(&format!("{:?}", expected)).unwrap());
|
||||
}
|
||||
|
||||
// Invalid examples
|
||||
assert!(ser::from_str::<$name>("\"0x\"").unwrap_err().is_data());
|
||||
assert!(ser::from_str::<$name>("\"0xg\"").unwrap_err().is_data());
|
||||
assert!(ser::from_str::<$name>("\"\"").unwrap_err().is_data());
|
||||
assert!(ser::from_str::<$name>("\"10\"").unwrap_err().is_data());
|
||||
assert!(ser::from_str::<$name>("\"0\"").unwrap_err().is_data());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test!(U256, test_u256);
|
||||
|
||||
#[test]
|
||||
fn test_u256_codec() {
|
||||
let res1 = vec![120, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0];
|
||||
let res2 = vec![0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff];
|
||||
|
||||
assert_eq!(
|
||||
U256::from(120).encode(),
|
||||
res1);
|
||||
assert_eq!(
|
||||
U256::max_value().encode(),
|
||||
res2);
|
||||
assert_eq!(
|
||||
U256::decode(&mut &res1[..]),
|
||||
Ok(U256::from(120)));
|
||||
assert_eq!(
|
||||
U256::decode(&mut &res2[..]),
|
||||
Ok(U256::max_value()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_large_values() {
|
||||
assert_eq!(
|
||||
ser::to_string_pretty(&!U256::zero()),
|
||||
"\"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\""
|
||||
);
|
||||
assert!(
|
||||
ser::from_str::<U256>("\"0x1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\"")
|
||||
.unwrap_err()
|
||||
.is_data()
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user