Overhaul crypto (Schnorr/Ristretto, HDKD, BIP39) (#1795)

* Rijig to Ristretto

* Rebuild wasm

* adds compatibility test with the wasm module

* Add Ed25519-BIP39 support

* Bump subkey version

* Update CLI output

* New keys.

* Standard phrase/password/path keys.

* Subkey uses S-URI for secrets

* Move everything to use new HDKD crypto.

* Test fixes

* Ignore old test vector.

* fix the ^^ old test vector.

* Fix tests

* Test fixes

* Cleanups

* Fix broken key conversion logic in grandpa

CC @rphmeier

* Remove legacy Keyring usage

* Traitify `Pair`

* Replace Ed25519AuthorityId with ed25519::Public

* Expunge Ed25519AuthorityId type!

* Replace Sr25519AuthorityId with sr25519::Public

* Remove dodgy crypto type-punning conversions

* Fix some tests

* Avoid trait

* Deduplicate DeriveJunction string decode

* Remove cruft code

* Fix test

* Minor removals

* Build fix

* Subkey supports sign and verify

* Inspect works for public key URIs

* Remove more crypto type-punning

* Fix typo

* Fix tests
This commit is contained in:
Gav Wood
2019-03-13 14:08:31 +01:00
committed by GitHub
parent 17f093da13
commit d7fcf5dc9d
83 changed files with 2636 additions and 1687 deletions
@@ -273,17 +273,16 @@ mod tests {
use codec::Encode;
use std::cell::RefCell;
use consensus_common::{Environment, Proposer};
use test_client::keyring::Keyring;
use test_client::{self, runtime::{Extrinsic, Transfer}};
use test_client::{self, runtime::{Extrinsic, Transfer}, AccountKeyring};
fn extrinsic(nonce: u64) -> Extrinsic {
let tx = Transfer {
amount: Default::default(),
nonce,
from: Keyring::Alice.to_raw_public().into(),
from: AccountKeyring::Alice.into(),
to: Default::default(),
};
let signature = Keyring::from_raw_public(tx.from.to_fixed_bytes()).unwrap().sign(&tx.encode()).into();
let signature = AccountKeyring::from_public(&tx.from).unwrap().sign(&tx.encode()).into();
Extrinsic::Transfer(tx, signature)
}
+4 -1
View File
@@ -63,6 +63,9 @@ use substrate_telemetry::TelemetryEndpoints;
const MAX_NODE_NAME_LENGTH: usize = 32;
/// The root phrase for our development network keys.
pub const DEV_PHRASE: &str = "bottom drive obey lake curtain smoke basket hold race lonely fit walk";
/// Executable version. Used to pass version information from the root crate.
pub struct VersionInfo {
/// Implemtation name.
@@ -387,7 +390,7 @@ where
}
if cli.shared_params.dev {
config.keys.push("Alice".into());
config.keys.push(format!("{}//Alice", DEV_PHRASE));
}
let rpc_interface: &str = if cli.rpc_external { "0.0.0.0" } else { "127.0.0.1" };
+44 -43
View File
@@ -541,6 +541,7 @@ pub(crate) mod tests {
use super::*;
type Block = RawBlock<ExtrinsicWrapper<u32>>;
type AuthorityId = AuthorityIdFor<Block>;
pub fn default_header(parent: &Hash, number: u64) -> Header {
Header {
@@ -831,10 +832,10 @@ pub(crate) mod tests {
let checks = vec![
(0, None),
(1, None),
(2, Some(vec![[1u8; 32].into()])),
(3, Some(vec![[1u8; 32].into()])),
(4, Some(vec![[1u8; 32].into(), [2u8; 32].into()])),
(5, Some(vec![[1u8; 32].into(), [2u8; 32].into()])),
(2, Some(vec![AuthorityId::from_raw([1u8; 32])])),
(3, Some(vec![AuthorityId::from_raw([1u8; 32])])),
(4, Some(vec![AuthorityId::from_raw([1u8; 32]), AuthorityId::from_raw([2u8; 32])])),
(5, Some(vec![AuthorityId::from_raw([1u8; 32]), AuthorityId::from_raw([2u8; 32])])),
(6, None),
(7, None), // block will work for 'future' block too
];
@@ -843,13 +844,13 @@ pub(crate) mod tests {
run_checks(&db, 0, &checks);
let hash1 = insert_final_block(&db, None, || default_header(&hash0, 1));
run_checks(&db, 1, &checks);
let hash2 = insert_final_block(&db, Some(vec![[1u8; 32].into()]), || default_header(&hash1, 2));
let hash2 = insert_final_block(&db, Some(vec![AuthorityId::from_raw([1u8; 32])]), || default_header(&hash1, 2));
run_checks(&db, 2, &checks);
let hash3 = insert_final_block(&db, Some(vec![[1u8; 32].into()]), || default_header(&hash2, 3));
let hash3 = insert_final_block(&db, Some(vec![AuthorityId::from_raw([1u8; 32])]), || default_header(&hash2, 3));
run_checks(&db, 3, &checks);
let hash4 = insert_final_block(&db, Some(vec![[1u8; 32].into(), [2u8; 32].into()]), || default_header(&hash3, 4));
let hash4 = insert_final_block(&db, Some(vec![AuthorityId::from_raw([1u8; 32]), AuthorityId::from_raw([2u8; 32])]), || default_header(&hash3, 4));
run_checks(&db, 4, &checks);
let hash5 = insert_final_block(&db, Some(vec![[1u8; 32].into(), [2u8; 32].into()]), || default_header(&hash4, 5));
let hash5 = insert_final_block(&db, Some(vec![AuthorityId::from_raw([1u8; 32]), AuthorityId::from_raw([2u8; 32])]), || default_header(&hash4, 5));
run_checks(&db, 5, &checks);
let hash6 = insert_final_block(&db, None, || default_header(&hash5, 6));
run_checks(&db, 7, &checks);
@@ -861,9 +862,9 @@ pub(crate) mod tests {
// some older non-best blocks are inserted
// ... -> B2(1) -> B2_1(1) -> B2_2(2)
// => the cache ignores all writes before best finalized block
let hash2_1 = insert_non_best_block(&db, Some(vec![[1u8; 32].into()]), || default_header(&hash2, 3));
let hash2_1 = insert_non_best_block(&db, Some(vec![AuthorityId::from_raw([1u8; 32])]), || default_header(&hash2, 3));
assert_eq!(None, db.cache().authorities_at(BlockId::Hash(hash2_1)));
let hash2_2 = insert_non_best_block(&db, Some(vec![[1u8; 32].into(), [2u8; 32].into()]), || default_header(&hash2_1, 4));
let hash2_2 = insert_non_best_block(&db, Some(vec![AuthorityId::from_raw([1u8; 32]), AuthorityId::from_raw([2u8; 32])]), || default_header(&hash2_1, 4));
assert_eq!(None, db.cache().authorities_at(BlockId::Hash(hash2_2)));
}
@@ -874,39 +875,39 @@ pub(crate) mod tests {
// \> B6_1_1(5)
// \> B6_1_2(6) -> B6_1_3(7)
let hash7 = insert_block(&db, Some(vec![[3u8; 32].into()]), || default_header(&hash6, 7));
let hash7 = insert_block(&db, Some(vec![AuthorityId::from_raw([3u8; 32])]), || default_header(&hash6, 7));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6)), None);
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash7)), Some(vec![[3u8; 32].into()]));
let hash8 = insert_block(&db, Some(vec![[3u8; 32].into()]), || default_header(&hash7, 8));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash7)), Some(vec![AuthorityId::from_raw([3u8; 32])]));
let hash8 = insert_block(&db, Some(vec![AuthorityId::from_raw([3u8; 32])]), || default_header(&hash7, 8));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6)), None);
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash7)), Some(vec![[3u8; 32].into()]));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash8)), Some(vec![[3u8; 32].into()]));
let hash6_1 = insert_block(&db, Some(vec![[4u8; 32].into()]), || default_header(&hash6, 7));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash7)), Some(vec![AuthorityId::from_raw([3u8; 32])]));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash8)), Some(vec![AuthorityId::from_raw([3u8; 32])]));
let hash6_1 = insert_block(&db, Some(vec![AuthorityId::from_raw([4u8; 32])]), || default_header(&hash6, 7));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6)), None);
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash7)), Some(vec![[3u8; 32].into()]));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash8)), Some(vec![[3u8; 32].into()]));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1)), Some(vec![[4u8; 32].into()]));
let hash6_1_1 = insert_non_best_block(&db, Some(vec![[5u8; 32].into()]), || default_header(&hash6_1, 8));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash7)), Some(vec![AuthorityId::from_raw([3u8; 32])]));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash8)), Some(vec![AuthorityId::from_raw([3u8; 32])]));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1)), Some(vec![AuthorityId::from_raw([4u8; 32])]));
let hash6_1_1 = insert_non_best_block(&db, Some(vec![AuthorityId::from_raw([5u8; 32])]), || default_header(&hash6_1, 8));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6)), None);
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash7)), Some(vec![[3u8; 32].into()]));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash8)), Some(vec![[3u8; 32].into()]));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1)), Some(vec![[4u8; 32].into()]));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1_1)), Some(vec![[5u8; 32].into()]));
let hash6_1_2 = insert_non_best_block(&db, Some(vec![[6u8; 32].into()]), || default_header(&hash6_1, 8));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash7)), Some(vec![AuthorityId::from_raw([3u8; 32])]));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash8)), Some(vec![AuthorityId::from_raw([3u8; 32])]));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1)), Some(vec![AuthorityId::from_raw([4u8; 32])]));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1_1)), Some(vec![AuthorityId::from_raw([5u8; 32])]));
let hash6_1_2 = insert_non_best_block(&db, Some(vec![AuthorityId::from_raw([6u8; 32])]), || default_header(&hash6_1, 8));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6)), None);
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash7)), Some(vec![[3u8; 32].into()]));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash8)), Some(vec![[3u8; 32].into()]));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1)), Some(vec![[4u8; 32].into()]));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1_1)), Some(vec![[5u8; 32].into()]));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1_2)), Some(vec![[6u8; 32].into()]));
let hash6_2 = insert_block(&db, Some(vec![[4u8; 32].into()]), || default_header(&hash6_1, 8));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash7)), Some(vec![AuthorityId::from_raw([3u8; 32])]));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash8)), Some(vec![AuthorityId::from_raw([3u8; 32])]));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1)), Some(vec![AuthorityId::from_raw([4u8; 32])]));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1_1)), Some(vec![AuthorityId::from_raw([5u8; 32])]));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1_2)), Some(vec![AuthorityId::from_raw([6u8; 32])]));
let hash6_2 = insert_block(&db, Some(vec![AuthorityId::from_raw([4u8; 32])]), || default_header(&hash6_1, 8));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6)), None);
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash7)), Some(vec![[3u8; 32].into()]));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash8)), Some(vec![[3u8; 32].into()]));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1)), Some(vec![[4u8; 32].into()]));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1_1)), Some(vec![[5u8; 32].into()]));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1_2)), Some(vec![[6u8; 32].into()]));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_2)), Some(vec![[4u8; 32].into()]));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash7)), Some(vec![AuthorityId::from_raw([3u8; 32])]));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash8)), Some(vec![AuthorityId::from_raw([3u8; 32])]));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1)), Some(vec![AuthorityId::from_raw([4u8; 32])]));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1_1)), Some(vec![AuthorityId::from_raw([5u8; 32])]));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1_2)), Some(vec![AuthorityId::from_raw([6u8; 32])]));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_2)), Some(vec![AuthorityId::from_raw([4u8; 32])]));
(hash7, hash8, hash6_1, hash6_2, hash6_1_1, hash6_1_2)
};
@@ -917,19 +918,19 @@ pub(crate) mod tests {
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6)), None);
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash7)), None);
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash8)), None);
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1)), Some(vec![[4u8; 32].into()]));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1_1)), Some(vec![[5u8; 32].into()]));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1_2)), Some(vec![[6u8; 32].into()]));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_2)), Some(vec![[4u8; 32].into()]));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1)), Some(vec![AuthorityId::from_raw([4u8; 32])]));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1_1)), Some(vec![AuthorityId::from_raw([5u8; 32])]));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1_2)), Some(vec![AuthorityId::from_raw([6u8; 32])]));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_2)), Some(vec![AuthorityId::from_raw([4u8; 32])]));
// finalize block hash6_2
db.finalize_header(BlockId::Hash(hash6_2)).unwrap();
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6)), None);
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash7)), None);
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash8)), None);
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1)), Some(vec![[4u8; 32].into()]));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1)), Some(vec![AuthorityId::from_raw([4u8; 32])]));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1_1)), None);
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1_2)), None);
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_2)), Some(vec![[4u8; 32].into()]));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_2)), Some(vec![AuthorityId::from_raw([4u8; 32])]));
}
}
+37 -38
View File
@@ -1520,11 +1520,10 @@ impl<B, E, Block, RA> backend::AuxStore for Client<B, E, Block, RA>
pub(crate) mod tests {
use std::collections::HashMap;
use super::*;
use keyring::Keyring;
use primitives::twox_128;
use runtime_primitives::traits::DigestItem as DigestItemT;
use runtime_primitives::generic::DigestItem;
use test_client::{self, TestClient};
use test_client::{self, TestClient, AccountKeyring, AuthorityKeyring};
use consensus::BlockOrigin;
use test_client::client::backend::Backend as TestBackend;
use test_client::BlockBuilderExt;
@@ -1541,10 +1540,10 @@ pub(crate) mod tests {
) {
// prepare block structure
let blocks_transfers = vec![
vec![(Keyring::Alice, Keyring::Dave), (Keyring::Bob, Keyring::Dave)],
vec![(Keyring::Charlie, Keyring::Eve)],
vec![(AccountKeyring::Alice, AccountKeyring::Dave), (AccountKeyring::Bob, AccountKeyring::Dave)],
vec![(AccountKeyring::Charlie, AccountKeyring::Eve)],
vec![],
vec![(Keyring::Alice, Keyring::Dave)],
vec![(AccountKeyring::Alice, AccountKeyring::Dave)],
];
// prepare client ang import blocks
@@ -1555,8 +1554,8 @@ pub(crate) mod tests {
let mut builder = remote_client.new_block().unwrap();
for (from, to) in block_transfers {
builder.push_transfer(Transfer {
from: from.to_raw_public().into(),
to: to.to_raw_public().into(),
from: from.into(),
to: to.into(),
amount: 1,
nonce: *nonces.entry(from).and_modify(|n| { *n = *n + 1 }).or_default(),
}).unwrap();
@@ -1571,12 +1570,12 @@ pub(crate) mod tests {
}
// prepare test cases
let alice = twox_128(&runtime::system::balance_of_key(Keyring::Alice.to_raw_public().into())).to_vec();
let bob = twox_128(&runtime::system::balance_of_key(Keyring::Bob.to_raw_public().into())).to_vec();
let charlie = twox_128(&runtime::system::balance_of_key(Keyring::Charlie.to_raw_public().into())).to_vec();
let dave = twox_128(&runtime::system::balance_of_key(Keyring::Dave.to_raw_public().into())).to_vec();
let eve = twox_128(&runtime::system::balance_of_key(Keyring::Eve.to_raw_public().into())).to_vec();
let ferdie = twox_128(&runtime::system::balance_of_key(Keyring::Ferdie.to_raw_public().into())).to_vec();
let alice = twox_128(&runtime::system::balance_of_key(AccountKeyring::Alice.into())).to_vec();
let bob = twox_128(&runtime::system::balance_of_key(AccountKeyring::Bob.into())).to_vec();
let charlie = twox_128(&runtime::system::balance_of_key(AccountKeyring::Charlie.into())).to_vec();
let dave = twox_128(&runtime::system::balance_of_key(AccountKeyring::Dave.into())).to_vec();
let eve = twox_128(&runtime::system::balance_of_key(AccountKeyring::Eve.into())).to_vec();
let ferdie = twox_128(&runtime::system::balance_of_key(AccountKeyring::Ferdie.into())).to_vec();
let test_cases = vec![
(1, 4, alice.clone(), vec![(4, 0), (1, 0)]),
(1, 3, alice.clone(), vec![(1, 0)]),
@@ -1610,14 +1609,14 @@ pub(crate) mod tests {
assert_eq!(
client.runtime_api().balance_of(
&BlockId::Number(client.info().unwrap().chain.best_number),
Keyring::Alice.to_raw_public().into()
AccountKeyring::Alice.into()
).unwrap(),
1000
);
assert_eq!(
client.runtime_api().balance_of(
&BlockId::Number(client.info().unwrap().chain.best_number),
Keyring::Ferdie.to_raw_public().into()
AccountKeyring::Ferdie.into()
).unwrap(),
0
);
@@ -1629,9 +1628,9 @@ pub(crate) mod tests {
assert_eq!(client.info().unwrap().chain.best_number, 0);
assert_eq!(client.authorities_at(&BlockId::Number(0)).unwrap(), vec![
Keyring::Alice.to_raw_public().into(),
Keyring::Bob.to_raw_public().into(),
Keyring::Charlie.to_raw_public().into()
AuthorityKeyring::Alice.into(),
AuthorityKeyring::Bob.into(),
AuthorityKeyring::Charlie.into()
]);
}
@@ -1653,8 +1652,8 @@ pub(crate) mod tests {
let mut builder = client.new_block().unwrap();
builder.push_transfer(Transfer {
from: Keyring::Alice.to_raw_public().into(),
to: Keyring::Ferdie.to_raw_public().into(),
from: AccountKeyring::Alice.into(),
to: AccountKeyring::Ferdie.into(),
amount: 42,
nonce: 0,
}).unwrap();
@@ -1666,14 +1665,14 @@ pub(crate) mod tests {
assert_eq!(
client.runtime_api().balance_of(
&BlockId::Number(client.info().unwrap().chain.best_number),
Keyring::Alice.to_raw_public().into()
AccountKeyring::Alice.into()
).unwrap(),
958
);
assert_eq!(
client.runtime_api().balance_of(
&BlockId::Number(client.info().unwrap().chain.best_number),
Keyring::Ferdie.to_raw_public().into()
AccountKeyring::Ferdie.into()
).unwrap(),
42
);
@@ -1695,15 +1694,15 @@ pub(crate) mod tests {
let mut builder = client.new_block().unwrap();
builder.push_transfer(Transfer {
from: Keyring::Alice.to_raw_public().into(),
to: Keyring::Ferdie.to_raw_public().into(),
from: AccountKeyring::Alice.into(),
to: AccountKeyring::Ferdie.into(),
amount: 42,
nonce: 0,
}).unwrap();
assert!(builder.push_transfer(Transfer {
from: Keyring::Eve.to_raw_public().into(),
to: Keyring::Alice.to_raw_public().into(),
from: AccountKeyring::Eve.into(),
to: AccountKeyring::Alice.into(),
amount: 42,
nonce: 0,
}).is_err());
@@ -1789,8 +1788,8 @@ pub(crate) mod tests {
let mut builder = client.new_block_at(&BlockId::Hash(a1.hash())).unwrap();
// this push is required as otherwise B2 has the same hash as A2 and won't get imported
builder.push_transfer(Transfer {
from: Keyring::Alice.to_raw_public().into(),
to: Keyring::Ferdie.to_raw_public().into(),
from: AccountKeyring::Alice.into(),
to: AccountKeyring::Ferdie.into(),
amount: 41,
nonce: 0,
}).unwrap();
@@ -1809,8 +1808,8 @@ pub(crate) mod tests {
let mut builder = client.new_block_at(&BlockId::Hash(b2.hash())).unwrap();
// this push is required as otherwise C3 has the same hash as B3 and won't get imported
builder.push_transfer(Transfer {
from: Keyring::Alice.to_raw_public().into(),
to: Keyring::Ferdie.to_raw_public().into(),
from: AccountKeyring::Alice.into(),
to: AccountKeyring::Ferdie.into(),
amount: 1,
nonce: 1,
}).unwrap();
@@ -1821,8 +1820,8 @@ pub(crate) mod tests {
let mut builder = client.new_block_at(&BlockId::Hash(a1.hash())).unwrap();
// this push is required as otherwise D2 has the same hash as B2 and won't get imported
builder.push_transfer(Transfer {
from: Keyring::Alice.to_raw_public().into(),
to: Keyring::Ferdie.to_raw_public().into(),
from: AccountKeyring::Alice.into(),
to: AccountKeyring::Ferdie.into(),
amount: 1,
nonce: 0,
}).unwrap();
@@ -1910,8 +1909,8 @@ pub(crate) mod tests {
let mut builder = client.new_block_at(&BlockId::Hash(a1.hash())).unwrap();
// this push is required as otherwise B2 has the same hash as A2 and won't get imported
builder.push_transfer(Transfer {
from: Keyring::Alice.to_raw_public().into(),
to: Keyring::Ferdie.to_raw_public().into(),
from: AccountKeyring::Alice.into(),
to: AccountKeyring::Ferdie.into(),
amount: 41,
nonce: 0,
}).unwrap();
@@ -1930,8 +1929,8 @@ pub(crate) mod tests {
let mut builder = client.new_block_at(&BlockId::Hash(b2.hash())).unwrap();
// this push is required as otherwise C3 has the same hash as B3 and won't get imported
builder.push_transfer(Transfer {
from: Keyring::Alice.to_raw_public().into(),
to: Keyring::Ferdie.to_raw_public().into(),
from: AccountKeyring::Alice.into(),
to: AccountKeyring::Ferdie.into(),
amount: 1,
nonce: 1,
}).unwrap();
@@ -1942,8 +1941,8 @@ pub(crate) mod tests {
let mut builder = client.new_block_at(&BlockId::Hash(a1.hash())).unwrap();
// this push is required as otherwise D2 has the same hash as B2 and won't get imported
builder.push_transfer(Transfer {
from: Keyring::Alice.to_raw_public().into(),
to: Keyring::Ferdie.to_raw_public().into(),
from: AccountKeyring::Alice.into(),
to: AccountKeyring::Ferdie.into(),
amount: 1,
nonce: 0,
}).unwrap();
+24 -18
View File
@@ -41,14 +41,16 @@ pub fn construct_genesis_block<
mod tests {
use super::*;
use parity_codec::{Encode, Decode, Joiner};
use keyring::Keyring;
use executor::{NativeExecutionDispatch, native_executor_instance};
use state_machine::{self, OverlayedChanges, ExecutionStrategy, InMemoryChangesTrieStorage};
use state_machine::backend::InMemory;
use test_client::runtime::genesismap::{GenesisConfig, additional_storage_with_genesis};
use test_client::runtime::{Hash, Transfer, Block, BlockNumber, Header, Digest, Extrinsic};
use test_client::{
runtime::genesismap::{GenesisConfig, additional_storage_with_genesis},
runtime::{Hash, Transfer, Block, BlockNumber, Header, Digest, Extrinsic},
AccountKeyring, AuthorityKeyring
};
use runtime_primitives::traits::BlakeTwo256;
use primitives::{Blake2Hasher, ed25519::{Public, Pair}};
use primitives::Blake2Hasher;
use hex::*;
native_executor_instance!(Executor, test_client::runtime::api::dispatch, test_client::runtime::native_version, include_bytes!("../../test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm"));
@@ -67,7 +69,7 @@ mod tests {
use trie::ordered_trie_root;
let transactions = txs.into_iter().map(|tx| {
let signature = Pair::from(Keyring::from_public(Public::from_raw(tx.from.to_fixed_bytes())).unwrap())
let signature = AccountKeyring::from_public(&tx.from).unwrap()
.sign(&tx.encode()).into();
Extrinsic::Transfer(tx, signature)
@@ -75,7 +77,6 @@ mod tests {
let extrinsics_root = ordered_trie_root::<Blake2Hasher, _, _>(transactions.iter().map(Encode::encode)).into();
println!("root before: {:?}", extrinsics_root);
let mut header = Header {
parent_hash,
number,
@@ -121,7 +122,6 @@ mod tests {
ExecutionStrategy::NativeElseWasm,
).unwrap();
header = Header::decode(&mut &ret_data[..]).unwrap();
println!("root after: {:?}", header.extrinsics_root);
(vec![].and(&Block { header, extrinsics: transactions }), hash)
}
@@ -133,8 +133,8 @@ mod tests {
genesis_hash,
hex!("25e5b37074063ab75c889326246640729b40d0c86932edc527bc80db0e04fe5c").into(),
vec![Transfer {
from: Keyring::One.to_raw_public().into(),
to: Keyring::Two.to_raw_public().into(),
from: AccountKeyring::One.into(),
to: AccountKeyring::Two.into(),
amount: 69,
nonce: 0,
}]
@@ -143,8 +143,10 @@ mod tests {
#[test]
fn construct_genesis_should_work_with_native() {
let mut storage = GenesisConfig::new_simple(
vec![Keyring::One.to_raw_public().into(), Keyring::Two.to_raw_public().into()], 1000
let mut storage = GenesisConfig::new(false,
vec![AuthorityKeyring::One.into(), AuthorityKeyring::Two.into()],
vec![AccountKeyring::One.into(), AccountKeyring::Two.into()],
1000
).genesis_map();
let state_root = BlakeTwo256::trie_root(storage.clone().into_iter());
let block = construct_genesis_block::<Block>(state_root);
@@ -169,8 +171,10 @@ mod tests {
#[test]
fn construct_genesis_should_work_with_wasm() {
let mut storage = GenesisConfig::new_simple(
vec![Keyring::One.to_raw_public().into(), Keyring::Two.to_raw_public().into()], 1000
let mut storage = GenesisConfig::new(false,
vec![AuthorityKeyring::One.into(), AuthorityKeyring::Two.into()],
vec![AccountKeyring::One.into(), AccountKeyring::Two.into()],
1000
).genesis_map();
let state_root = BlakeTwo256::trie_root(storage.clone().into_iter());
let block = construct_genesis_block::<Block>(state_root);
@@ -194,10 +198,11 @@ mod tests {
}
#[test]
#[should_panic]
fn construct_genesis_with_bad_transaction_should_panic() {
let mut storage = GenesisConfig::new_simple(
vec![Keyring::One.to_raw_public().into(), Keyring::Two.to_raw_public().into()], 68
let mut storage = GenesisConfig::new(false,
vec![AuthorityKeyring::One.into(), AuthorityKeyring::Two.into()],
vec![AccountKeyring::One.into(), AccountKeyring::Two.into()],
68
).genesis_map();
let state_root = BlakeTwo256::trie_root(storage.clone().into_iter());
let block = construct_genesis_block::<Block>(state_root);
@@ -208,7 +213,7 @@ mod tests {
let (b1data, _b1hash) = block1(genesis_hash, &backend);
let mut overlay = OverlayedChanges::default();
let _ = state_machine::new(
let r = state_machine::new(
&backend,
Some(&InMemoryChangesTrieStorage::new()),
&mut overlay,
@@ -217,6 +222,7 @@ mod tests {
&b1data,
).execute(
ExecutionStrategy::NativeElseWasm,
).unwrap();
);
assert!(r.is_err());
}
}
+1 -1
View File
@@ -35,7 +35,7 @@ use hash_db::Hasher;
use trie::MemoryDB;
use heapsize::HeapSizeOf;
const IN_MEMORY_EXPECT_PROOF: &'static str = "InMemory state backend has Void error type and always suceeds; qed";
const IN_MEMORY_EXPECT_PROOF: &str = "InMemory state backend has Void error type and always suceeds; qed";
/// Light client backend.
pub struct Backend<S, F, H> {
+6 -5
View File
@@ -390,12 +390,13 @@ impl<'a, H, Number, Hash> ChangesTrieRootsStorage<H> for RootsStorage<'a, Number
pub mod tests {
use futures::future::{ok, err, FutureResult};
use parking_lot::Mutex;
use keyring::Keyring;
use crate::client::tests::prepare_client_with_key_changes;
use executor::{self, NativeExecutionDispatch};
use crate::error::Error as ClientError;
use test_client::{self, TestClient, blockchain::HeaderBackend};
use test_client::runtime::{self, Hash, Block, Header};
use test_client::{
self, TestClient, blockchain::HeaderBackend, AccountKeyring,
runtime::{self, Hash, Block, Header}
};
use consensus::BlockOrigin;
use crate::in_mem::{Blockchain as InMemoryBlockchain};
@@ -583,7 +584,7 @@ pub mod tests {
// we're testing this test case here:
// (1, 4, dave.clone(), vec![(4, 0), (1, 1), (1, 0)]),
let (remote_client, remote_roots, _) = prepare_client_with_key_changes();
let dave = twox_128(&runtime::system::balance_of_key(Keyring::Dave.to_raw_public().into())).to_vec();
let dave = twox_128(&runtime::system::balance_of_key(AccountKeyring::Dave.into())).to_vec();
let dave = StorageKey(dave);
// 'fetch' changes proof from remote node:
@@ -695,7 +696,7 @@ pub mod tests {
let (remote_client, remote_roots, _) = prepare_client_with_key_changes();
let local_cht_root = cht::compute_root::<Header, Blake2Hasher, _>(
4, 0, remote_roots.iter().cloned().map(|ct| Ok(Some(ct)))).unwrap();
let dave = twox_128(&runtime::system::balance_of_key(Keyring::Dave.to_raw_public().into())).to_vec();
let dave = twox_128(&runtime::system::balance_of_key(AccountKeyring::Dave.into())).to_vec();
let dave = StorageKey(dave);
// 'fetch' changes proof from remote node:
+25 -21
View File
@@ -41,7 +41,7 @@ use runtime_primitives::{generic, generic::BlockId, Justification};
use runtime_primitives::traits::{
Block, Header, Digest, DigestItemFor, DigestItem, ProvideRuntimeApi
};
use primitives::{Ed25519AuthorityId, ed25519};
use primitives::{ed25519, Pair};
use inherents::{InherentDataProviders, InherentData, RuntimeString};
use futures::{Stream, Future, IntoFuture, future};
@@ -60,6 +60,9 @@ pub use aura_slots::SlotDuration;
pub use aura_primitives::*;
pub use consensus_common::SyncOracle;
type AuthorityId = ed25519::Public;
type Signature = ed25519::Signature;
/// A handle to the network. This is generally implemented by providing some
/// handle to a gossip service or similar.
///
@@ -73,16 +76,17 @@ pub trait Network: Clone {
}
/// Get slot author for given block along with authorities.
fn slot_author(slot_num: u64, authorities: &[Ed25519AuthorityId]) -> Option<Ed25519AuthorityId> {
fn slot_author(slot_num: u64, authorities: &[AuthorityId]) -> Option<AuthorityId> {
if authorities.is_empty() { return None }
let idx = slot_num % (authorities.len() as u64);
assert!(idx <= usize::max_value() as u64,
"It is impossible to have a vector with length beyond the address space; qed");
let current_author = *authorities.get(idx as usize)
let current_author = authorities.get(idx as usize)
.expect("authorities not empty; index constrained to list length;\
this is a valid index; qed");
this is a valid index; qed")
.clone();
Some(current_author)
}
@@ -109,22 +113,22 @@ fn inherent_to_common_error(err: RuntimeString) -> consensus_common::Error {
pub trait CompatibleDigestItem: Sized {
/// Construct a digest item which is a slot number and a signature on the
/// hash.
fn aura_seal(slot_number: u64, signature: ed25519::Signature) -> Self;
fn aura_seal(slot_number: u64, signature: Signature) -> Self;
/// If this item is an Aura seal, return the slot number and signature.
fn as_aura_seal(&self) -> Option<(u64, &ed25519::Signature)>;
fn as_aura_seal(&self) -> Option<(u64, Signature)>;
}
impl<Hash, AuthorityId> CompatibleDigestItem for generic::DigestItem<Hash, AuthorityId> {
impl<Hash, AuthorityId> CompatibleDigestItem for generic::DigestItem<Hash, AuthorityId, Signature> {
/// Construct a digest item which is a slot number and a signature on the
/// hash.
fn aura_seal(slot_number: u64, signature: ed25519::Signature) -> Self {
fn aura_seal(slot_number: u64, signature: Signature) -> Self {
generic::DigestItem::Seal(slot_number, signature)
}
/// If this item is an Aura seal, return the slot number and signature.
fn as_aura_seal(&self) -> Option<(u64, &ed25519::Signature)> {
fn as_aura_seal(&self) -> Option<(u64, Signature)> {
match self {
generic::DigestItem::Seal(slot, ref sign) => Some((*slot, sign)),
generic::DigestItem::Seal(slot, ref sig) => Some((*slot, sig.clone().into())),
_ => None
}
}
@@ -162,7 +166,7 @@ pub fn start_aura_thread<B, C, E, I, SO, Error, OnExit>(
Error: From<C::Error> + From<I::Error> + 'static,
SO: SyncOracle + Send + Sync + Clone + 'static,
OnExit: Future<Item=(), Error=()> + Send + 'static,
DigestItemFor<B>: CompatibleDigestItem + DigestItem<AuthorityId=Ed25519AuthorityId> + 'static,
DigestItemFor<B>: CompatibleDigestItem + DigestItem<AuthorityId=AuthorityId> + 'static,
Error: ::std::error::Error + Send + From<::consensus_common::Error> + 'static,
{
let worker = AuraWorker {
@@ -198,7 +202,7 @@ pub fn start_aura<B, C, E, I, SO, Error, OnExit>(
I: BlockImport<B> + Send + Sync + 'static,
Error: From<C::Error> + From<I::Error>,
SO: SyncOracle + Send + Sync + Clone,
DigestItemFor<B>: CompatibleDigestItem + DigestItem<AuthorityId=Ed25519AuthorityId>,
DigestItemFor<B>: CompatibleDigestItem + DigestItem<AuthorityId=AuthorityId>,
Error: ::std::error::Error + Send + 'static + From<::consensus_common::Error>,
OnExit: Future<Item=(), Error=()>,
{
@@ -232,7 +236,7 @@ impl<B: Block, C, E, I, Error, SO> SlotWorker<B> for AuraWorker<C, E, I, SO> whe
I: BlockImport<B> + Send + Sync + 'static,
Error: From<C::Error> + From<I::Error>,
SO: SyncOracle + Send + Clone,
DigestItemFor<B>: CompatibleDigestItem + DigestItem<AuthorityId=Ed25519AuthorityId>,
DigestItemFor<B>: CompatibleDigestItem + DigestItem<AuthorityId=AuthorityId>,
Error: ::std::error::Error + Send + 'static + From<::consensus_common::Error>,
{
type OnSlot = Box<Future<Item=(), Error=consensus_common::Error> + Send>;
@@ -387,7 +391,7 @@ impl<B: Block, C, E, I, Error, SO> SlotWorker<B> for AuraWorker<C, E, I, SO> whe
/// if it's successful, returns the pre-header, the slot number, and the signat.
//
// FIXME #1018 needs misbehavior types
fn check_header<B: Block>(slot_now: u64, mut header: B::Header, hash: B::Hash, authorities: &[Ed25519AuthorityId])
fn check_header<B: Block>(slot_now: u64, mut header: B::Header, hash: B::Hash, authorities: &[AuthorityId])
-> Result<CheckedHeader<B::Header, ed25519::Signature>, String>
where DigestItemFor<B>: CompatibleDigestItem
{
@@ -395,7 +399,7 @@ fn check_header<B: Block>(slot_now: u64, mut header: B::Header, hash: B::Hash, a
Some(x) => x,
None => return Err(format!("Header {:?} is unsealed", hash)),
};
let (slot_num, &sig) = match digest_item.as_aura_seal() {
let (slot_num, sig) = match digest_item.as_aura_seal() {
Some(x) => x,
None => return Err(format!("Header {:?} is unsealed", hash)),
};
@@ -416,7 +420,7 @@ fn check_header<B: Block>(slot_now: u64, mut header: B::Header, hash: B::Hash, a
let to_sign = (slot_num, pre_hash).encode();
let public = ed25519::Public(expected_author.0);
if ed25519::verify_strong(&sig, &to_sign[..], public) {
if ed25519::Pair::verify(&sig, &to_sign[..], public) {
Ok(CheckedHeader::Checked(header, slot_num, sig))
} else {
Err(format!("Bad signature on {:?}", hash))
@@ -555,7 +559,7 @@ impl<B: Block> ExtraVerification<B> for NothingExtra {
impl<B: Block, C, E> Verifier<B> for AuraVerifier<C, E> where
C: Authorities<B> + ProvideRuntimeApi + Send + Sync,
C::Api: BlockBuilderApi<B>,
DigestItemFor<B>: CompatibleDigestItem + DigestItem<AuthorityId=Ed25519AuthorityId>,
DigestItemFor<B>: CompatibleDigestItem + DigestItem<AuthorityId=AuthorityId>,
E: ExtraVerification<B>,
{
fn verify(
@@ -564,7 +568,7 @@ impl<B: Block, C, E> Verifier<B> for AuraVerifier<C, E> where
header: B::Header,
justification: Option<Justification>,
mut body: Option<Vec<B::Extrinsic>>,
) -> Result<(ImportBlock<B>, Option<Vec<Ed25519AuthorityId>>), String> {
) -> Result<(ImportBlock<B>, Option<Vec<AuthorityId>>), String> {
let mut inherent_data = self.inherent_data_providers.create_inherent_data().map_err(String::from)?;
let (timestamp_now, slot_now) = AuraSlotCompatible::extract_timestamp_and_slot(&inherent_data)
.map_err(|e| format!("Could not extract timestamp and slot: {:?}", e))?;
@@ -675,7 +679,7 @@ pub fn import_queue<B, C, E>(
B: Block,
C: 'static + Authorities<B> + ProvideRuntimeApi + Send + Sync,
C::Api: BlockBuilderApi<B>,
DigestItemFor<B>: CompatibleDigestItem + DigestItem<AuthorityId=Ed25519AuthorityId>,
DigestItemFor<B>: CompatibleDigestItem + DigestItem<AuthorityId=AuthorityId>,
E: 'static + ExtraVerification<B>,
{
register_aura_inherent_data_provider(&inherent_data_providers, slot_duration.get())?;
@@ -696,7 +700,7 @@ mod tests {
use network::config::ProtocolConfig;
use parking_lot::Mutex;
use tokio::runtime::current_thread;
use keyring::Keyring;
use keyring::ed25519::Keyring;
use client::BlockchainEvents;
use test_client;
@@ -711,7 +715,7 @@ mod tests {
type Proposer = DummyProposer;
type Error = Error;
fn init(&self, parent_header: &<TestBlock as BlockT>::Header, _authorities: &[Ed25519AuthorityId])
fn init(&self, parent_header: &<TestBlock as BlockT>::Header, _authorities: &[AuthorityId])
-> Result<DummyProposer, Error>
{
Ok(DummyProposer(parent_header.number + 1, self.0.clone()))
+3 -2
View File
@@ -18,6 +18,7 @@
use runtime_version::RuntimeVersion;
use error_chain::{error_chain, error_chain_processing, impl_error_chain_processed,
impl_extract_backtrace, impl_error_chain_kind};
use primitives::ed25519::{Public, Signature};
error_chain! {
errors {
@@ -52,13 +53,13 @@ error_chain! {
}
/// Error checking signature
InvalidSignature(s: ::primitives::ed25519::Signature, a: ::primitives::Ed25519AuthorityId) {
InvalidSignature(s: Signature, a: Public) {
description("Message signature is invalid"),
display("Message signature {:?} by {:?} is invalid.", s, a),
}
/// Account is not an authority.
InvalidAuthority(a: ::primitives::Ed25519AuthorityId) {
InvalidAuthority(a: Public) {
description("Message sender is not a valid authority"),
display("Message sender {:?} is not a valid authority.", a),
}
@@ -112,25 +112,25 @@ impl<AuthorityId: Eq + Clone + std::hash::Hash> OfflineTracker<AuthorityId> {
#[cfg(test)]
mod tests {
use super::*;
use primitives::Ed25519AuthorityId;
use primitives::ed25519::Public as AuthorityId;
#[test]
fn validator_offline() {
let mut tracker = OfflineTracker::<Ed25519AuthorityId>::new();
let v = [0; 32].into();
let v2 = [1; 32].into();
let v3 = [2; 32].into();
tracker.note_round_end(v, true);
tracker.note_round_end(v2, true);
tracker.note_round_end(v3, true);
let mut tracker = OfflineTracker::<AuthorityId>::new();
let v = AuthorityId::from_raw([0; 32]);
let v2 = AuthorityId::from_raw([1; 32]);
let v3 = AuthorityId::from_raw([2; 32]);
tracker.note_round_end(v.clone(), true);
tracker.note_round_end(v2.clone(), true);
tracker.note_round_end(v3.clone(), true);
let slash_time = REPORT_TIME + Duration::from_secs(5);
tracker.observed.get_mut(&v).unwrap().offline_since -= slash_time;
tracker.observed.get_mut(&v2).unwrap().offline_since -= slash_time;
assert_eq!(tracker.reports(&[v, v2, v3]), vec![0, 1]);
assert_eq!(tracker.reports(&[v.clone(), v2.clone(), v3.clone()]), vec![0, 1]);
tracker.note_new_block(&[v, v3]);
tracker.note_new_block(&[v.clone(), v3.clone()]);
assert_eq!(tracker.reports(&[v, v2, v3]), vec![0]);
}
}
+30 -30
View File
@@ -762,7 +762,7 @@ fn check_justification_signed_message<H>(
let auth_id = sig.signer.clone().into();
if !authorities.contains(&auth_id) { return None }
if ed25519::verify_strong(&sig.signature, message, &sig.signer) {
if ed25519::Pair::verify(&sig.signature, message, &sig.signer) {
Some(sig.signer.0)
} else {
None
@@ -838,7 +838,7 @@ pub fn check_vote<B: Block>(
fn check_action<B: Block>(action: Action<B, B::Hash>, parent_hash: &B::Hash, sig: &LocalizedSignature) -> Result<(), Error> {
let message = localized_encode(*parent_hash, action);
if ed25519::verify_strong(&sig.signature, &message, &sig.signer) {
if ed25519::Pair::verify(&sig.signature, &message, &sig.signer) {
Ok(())
} else {
Err(CommonErrorKind::InvalidSignature(sig.signature.into(), sig.signer.clone().into()).into())
@@ -1315,7 +1315,7 @@ mod tests {
use runtime_primitives::testing::{Block as GenericTestBlock, Header as TestHeader};
use primitives::H256;
use self::keyring::Keyring;
use keyring::AuthorityKeyring;
type TestBlock = GenericTestBlock<()>;
@@ -1420,7 +1420,7 @@ mod tests {
start_round: 0,
})),
round_timeout_multiplier: 10,
key: Arc::new(Keyring::One.into()),
key: Arc::new(AuthorityKeyring::One.into()),
factory: DummyFactory
}
}
@@ -1446,10 +1446,10 @@ mod tests {
fn future_gets_preempted() {
let client = FakeClient {
authorities: vec![
Keyring::One.to_raw_public().into(),
Keyring::Two.to_raw_public().into(),
Keyring::Alice.to_raw_public().into(),
Keyring::Eve.to_raw_public().into(),
AuthorityKeyring::One.into(),
AuthorityKeyring::Two.into(),
AuthorityKeyring::Alice.into(),
AuthorityKeyring::Eve.into(),
],
imported_heights: Mutex::new(HashSet::new()),
};
@@ -1493,17 +1493,17 @@ mod tests {
let hash = [0xff; 32].into();
let authorities = vec![
Keyring::One.to_raw_public().into(),
Keyring::Two.to_raw_public().into(),
Keyring::Alice.to_raw_public().into(),
Keyring::Eve.to_raw_public().into(),
AuthorityKeyring::One.into(),
AuthorityKeyring::Two.into(),
AuthorityKeyring::Alice.into(),
AuthorityKeyring::Eve.into(),
];
let authorities_keys = vec![
Keyring::One.into(),
Keyring::Two.into(),
Keyring::Alice.into(),
Keyring::Eve.into(),
AuthorityKeyring::One.into(),
AuthorityKeyring::Two.into(),
AuthorityKeyring::Alice.into(),
AuthorityKeyring::Eve.into(),
];
let unchecked = UncheckedJustification(rhododendron::UncheckedJustification {
@@ -1554,8 +1554,8 @@ mod tests {
let parent_hash = Default::default();
let authorities = vec![
Keyring::Alice.to_raw_public().into(),
Keyring::Eve.to_raw_public().into(),
AuthorityKeyring::Alice.into(),
AuthorityKeyring::Eve.into(),
];
let block = TestBlock {
@@ -1563,7 +1563,7 @@ mod tests {
extrinsics: Default::default()
};
let proposal = sign_message(rhododendron::Message::Propose(1, block.clone()), &Keyring::Alice.pair(), parent_hash);;
let proposal = sign_message(rhododendron::Message::Propose(1, block.clone()), &AuthorityKeyring::Alice.pair(), parent_hash);;
if let rhododendron::LocalizedMessage::Propose(proposal) = proposal {
assert!(check_proposal(&authorities, &parent_hash, &proposal).is_ok());
let mut invalid_round = proposal.clone();
@@ -1577,7 +1577,7 @@ mod tests {
}
// Not an authority
let proposal = sign_message::<TestBlock>(rhododendron::Message::Propose(1, block), &Keyring::Bob.pair(), parent_hash);;
let proposal = sign_message::<TestBlock>(rhododendron::Message::Propose(1, block), &AuthorityKeyring::Bob.pair(), parent_hash);;
if let rhododendron::LocalizedMessage::Propose(proposal) = proposal {
assert!(check_proposal(&authorities, &parent_hash, &proposal).is_err());
} else {
@@ -1591,8 +1591,8 @@ mod tests {
let hash: H256 = [0xff; 32].into();
let authorities = vec![
Keyring::Alice.to_raw_public().into(),
Keyring::Eve.to_raw_public().into(),
AuthorityKeyring::Alice.into(),
AuthorityKeyring::Eve.into(),
];
let vote = sign_message::<TestBlock>(rhododendron::Message::Vote(rhododendron::Vote::Prepare(1, hash)), &Keyring::Alice.pair(), parent_hash);;
@@ -1618,10 +1618,10 @@ mod tests {
fn drop_bft_future_does_not_deadlock() {
let client = FakeClient {
authorities: vec![
Keyring::One.to_raw_public().into(),
Keyring::Two.to_raw_public().into(),
Keyring::Alice.to_raw_public().into(),
Keyring::Eve.to_raw_public().into(),
AuthorityKeyring::One.into(),
AuthorityKeyring::Two.into(),
AuthorityKeyring::Alice.into(),
AuthorityKeyring::Eve.into(),
],
imported_heights: Mutex::new(HashSet::new()),
};
@@ -1643,10 +1643,10 @@ mod tests {
fn bft_can_build_though_skipped() {
let client = FakeClient {
authorities: vec![
Keyring::One.to_raw_public().into(),
Keyring::Two.to_raw_public().into(),
Keyring::Alice.to_raw_public().into(),
Keyring::Eve.to_raw_public().into(),
AuthorityKeyring::One.into(),
AuthorityKeyring::Two.into(),
AuthorityKeyring::Alice.into(),
AuthorityKeyring::Eve.into(),
],
imported_heights: Mutex::new(HashSet::new()),
};
@@ -74,8 +74,7 @@ pub fn evaluate_misbehavior<B: Codec, H: Codec + Copy>(
mod tests {
use super::*;
use keyring::ed25519;
use keyring::Keyring;
use keyring::AuthorityKeyring;
use rhododendron;
use runtime_primitives::testing::{H256, Block as RawBlock};
@@ -110,7 +109,7 @@ mod tests {
#[test]
fn evaluates_double_prepare() {
let key: ed25519::Pair = Keyring::One.into();
let key = AuthorityKeyring::One.pair();
let parent_hash = [0xff; 32].into();
let hash_1 = [0; 32].into();
let hash_2 = [1; 32].into();
@@ -127,7 +126,7 @@ mod tests {
// same signature twice is not misbehavior.
let signed = sign_prepare(&key, 1, hash_1, parent_hash);
assert!(evaluate_misbehavior::<Block, H256>(
assert!(!evaluate_misbehavior::<Block, H256>(
&key.public().into(),
parent_hash,
&MisbehaviorKind::BftDoublePrepare(
@@ -135,23 +134,23 @@ mod tests {
signed,
signed,
)
) == false);
));
// misbehavior has wrong target.
assert!(evaluate_misbehavior::<Block, H256>(
&Keyring::Two.to_raw_public().into(),
assert!(!evaluate_misbehavior::<Block, H256>(
&AuthorityKeyring::Two.into(),
parent_hash,
&MisbehaviorKind::BftDoublePrepare(
1,
sign_prepare(&key, 1, hash_1, parent_hash),
sign_prepare(&key, 1, hash_2, parent_hash),
)
) == false);
));
}
#[test]
fn evaluates_double_commit() {
let key: ed25519::Pair = Keyring::One.into();
let key = AuthorityKeyring::One.pair();
let parent_hash = [0xff; 32].into();
let hash_1 = [0; 32].into();
let hash_2 = [1; 32].into();
@@ -168,7 +167,7 @@ mod tests {
// same signature twice is not misbehavior.
let signed = sign_commit(&key, 1, hash_1, parent_hash);
assert!(evaluate_misbehavior::<Block, H256>(
assert!(!evaluate_misbehavior::<Block, H256>(
&key.public().into(),
parent_hash,
&MisbehaviorKind::BftDoubleCommit(
@@ -176,17 +175,17 @@ mod tests {
signed,
signed,
)
) == false);
));
// misbehavior has wrong target.
assert!(evaluate_misbehavior::<Block, H256>(
&Keyring::Two.to_raw_public().into(),
assert!(!evaluate_misbehavior::<Block, H256>(
&AuthorityKeyring::Two.into(),
parent_hash,
&MisbehaviorKind::BftDoubleCommit(
1,
sign_commit(&key, 1, hash_1, parent_hash),
sign_commit(&key, 1, hash_2, parent_hash),
)
) == false);
));
}
}
+7 -5
View File
@@ -28,7 +28,7 @@ use wasmi::memory_units::{Pages};
use state_machine::Externalities;
use crate::error::{Error, ErrorKind, Result};
use crate::wasm_utils::UserError;
use primitives::{blake2_256, twox_128, twox_256, ed25519, sr25519};
use primitives::{blake2_256, twox_128, twox_256, ed25519, sr25519, Pair};
use primitives::hexdisplay::HexDisplay;
use primitives::sandbox as sandbox_primitives;
use primitives::{H256, Blake2Hasher};
@@ -474,7 +474,7 @@ impl_function_executor!(this: FunctionExecutor<'e, E>,
this.memory.get_into(pubkey_data, &mut pubkey[..]).map_err(|_| UserError("Invalid attempt to get pubkey in ext_ed25519_verify"))?;
let msg = this.memory.get(msg_data, msg_len as usize).map_err(|_| UserError("Invalid attempt to get message in ext_ed25519_verify"))?;
Ok(if ed25519::verify(&sig, &msg, &pubkey) {
Ok(if ed25519::Pair::verify_weak(&sig, &msg, &pubkey) {
0
} else {
5
@@ -487,7 +487,7 @@ impl_function_executor!(this: FunctionExecutor<'e, E>,
this.memory.get_into(pubkey_data, &mut pubkey[..]).map_err(|_| UserError("Invalid attempt to get pubkey in ext_sr25519_verify"))?;
let msg = this.memory.get(msg_data, msg_len as usize).map_err(|_| UserError("Invalid attempt to get message in ext_sr25519_verify"))?;
Ok(if sr25519::verify(&sig, &msg, &pubkey) {
Ok(if sr25519::Pair::verify_weak(&sig, &msg, &pubkey) {
0
} else {
5
@@ -759,7 +759,9 @@ impl WasmExecutor {
#[cfg(test)]
mod tests {
use super::*;
use parity_codec::Encode;
use state_machine::TestExternalities;
use hex_literal::{hex, hex_impl};
use primitives::map;
@@ -875,7 +877,7 @@ mod tests {
fn ed25519_verify_should_work() {
let mut ext = TestExternalities::<Blake2Hasher>::default();
let test_code = include_bytes!("../wasm/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm");
let key = ed25519::Pair::from_seed(&blake2_256(b"test"));
let key = ed25519::Pair::from_seed(blake2_256(b"test"));
let sig = key.sign(b"all ok!");
let mut calldata = vec![];
calldata.extend_from_slice(key.public().as_ref());
@@ -901,7 +903,7 @@ mod tests {
fn sr25519_verify_should_work() {
let mut ext = TestExternalities::<Blake2Hasher>::default();
let test_code = include_bytes!("../wasm/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm");
let key = sr25519::Pair::from_seed(&blake2_256(b"test"));
let key = sr25519::Pair::from_seed(blake2_256(b"test"));
let sig = key.sign(b"all ok!");
let mut calldata = vec![];
calldata.extend_from_slice(key.public().as_ref());
@@ -23,17 +23,19 @@
extern crate alloc;
use parity_codec::{Encode, Decode};
use substrate_primitives::Ed25519AuthorityId;
use substrate_primitives::ed25519;
use sr_primitives::traits::{DigestFor, NumberFor};
use client::decl_runtime_apis;
use rstd::vec::Vec;
use ed25519::Public as AuthorityId;
/// A scheduled change of authority set.
#[cfg_attr(feature = "std", derive(Debug, PartialEq))]
#[derive(Clone, Encode, Decode)]
pub struct ScheduledChange<N> {
/// The new authorities after the change, along with their respective weights.
pub next_authorities: Vec<(Ed25519AuthorityId, u64)>,
pub next_authorities: Vec<(AuthorityId, u64)>,
/// The number of blocks to delay.
pub delay: N,
}
@@ -106,6 +108,6 @@ decl_runtime_apis! {
/// When called at block B, it will return the set of authorities that should be
/// used to finalize descendants of this block (B+1, B+2, ...). The block B itself
/// is finalized by the authorities from block B-1.
fn grandpa_authorities() -> Vec<(Ed25519AuthorityId, u64)>;
fn grandpa_authorities() -> Vec<(AuthorityId, u64)>;
}
}
@@ -18,7 +18,7 @@
use fork_tree::ForkTree;
use parking_lot::RwLock;
use substrate_primitives::Ed25519AuthorityId;
use substrate_primitives::ed25519;
use grandpa::VoterSet;
use parity_codec::{Encode, Decode};
use log::{debug, info};
@@ -28,6 +28,8 @@ use std::fmt::Debug;
use std::ops::Add;
use std::sync::Arc;
use ed25519::Public as AuthorityId;
/// A shared authority set.
pub(crate) struct SharedAuthoritySet<H, N> {
inner: Arc<RwLock<AuthoritySet<H, N>>>,
@@ -61,7 +63,7 @@ where N: Add<Output=N> + Ord + Clone + Debug,
}
/// Get the current authorities and their weights (for the current set ID).
pub(crate) fn current_authorities(&self) -> VoterSet<Ed25519AuthorityId> {
pub(crate) fn current_authorities(&self) -> VoterSet<AuthorityId> {
self.inner.read().current_authorities.iter().cloned().collect()
}
}
@@ -85,7 +87,7 @@ pub(crate) struct Status<H, N> {
/// A set of authorities.
#[derive(Debug, Clone, Encode, Decode, PartialEq)]
pub(crate) struct AuthoritySet<H, N> {
pub(crate) current_authorities: Vec<(Ed25519AuthorityId, u64)>,
pub(crate) current_authorities: Vec<(AuthorityId, u64)>,
pub(crate) set_id: u64,
// Tree of pending standard changes across forks. Standard changes are
// enacted on finality and must be enacted (i.e. finalized) in-order across
@@ -102,7 +104,7 @@ where H: PartialEq,
N: Ord,
{
/// Get a genesis set with given authorities.
pub(crate) fn genesis(initial: Vec<(Ed25519AuthorityId, u64)>) -> Self {
pub(crate) fn genesis(initial: Vec<(AuthorityId, u64)>) -> Self {
AuthoritySet {
current_authorities: initial,
set_id: 0,
@@ -112,7 +114,7 @@ where H: PartialEq,
}
/// Get the current set id and a reference to the current authority set.
pub(crate) fn current(&self) -> (u64, &[(Ed25519AuthorityId, u64)]) {
pub(crate) fn current(&self) -> (u64, &[(AuthorityId, u64)]) {
(self.set_id, &self.current_authorities[..])
}
}
@@ -379,7 +381,7 @@ pub(crate) enum DelayKind<N> {
#[derive(Debug, Clone, Encode, PartialEq)]
pub(crate) struct PendingChange<H, N> {
/// The new authorities and weights to apply.
pub(crate) next_authorities: Vec<(Ed25519AuthorityId, u64)>,
pub(crate) next_authorities: Vec<(AuthorityId, u64)>,
/// How deep in the chain the announcing block must be
/// before the change is applied.
pub(crate) delay: N,
@@ -509,8 +511,8 @@ mod tests {
pending_forced_changes: Vec::new(),
};
let set_a = vec![([1; 32].into(), 5)];
let set_b = vec![([2; 32].into(), 5)];
let set_a = vec![(AuthorityId([1; 32]), 5)];
let set_b = vec![(AuthorityId([2; 32]), 5)];
// two competing changes at the same height on different forks
let change_a = PendingChange {
@@ -574,8 +576,8 @@ mod tests {
pending_forced_changes: Vec::new(),
};
let set_a = vec![([1; 32].into(), 5)];
let set_c = vec![([2; 32].into(), 5)];
let set_a = vec![(AuthorityId([1; 32]), 5)];
let set_c = vec![(AuthorityId([2; 32]), 5)];
// two competing changes at the same height on different forks
let change_a = PendingChange {
@@ -640,7 +642,7 @@ mod tests {
pending_forced_changes: Vec::new(),
};
let set_a = vec![([1; 32].into(), 5)];
let set_a = vec![(AuthorityId([1; 32]), 5)];
let change_a = PendingChange {
next_authorities: set_a.clone(),
@@ -676,8 +678,8 @@ mod tests {
pending_forced_changes: Vec::new(),
};
let set_a = vec![([1; 32].into(), 5)];
let set_b = vec![([2; 32].into(), 5)];
let set_a = vec![(AuthorityId([1; 32]), 5)];
let set_b = vec![(AuthorityId([2; 32]), 5)];
let change_a = PendingChange {
next_authorities: set_a.clone(),
@@ -16,20 +16,20 @@
//! Schema for stuff in the aux-db.
use std::fmt::Debug;
use std::sync::Arc;
use parity_codec::{Encode, Decode};
use client::backend::AuxStore;
use client::error::{Result as ClientResult, Error as ClientError, ErrorKind as ClientErrorKind};
use fork_tree::ForkTree;
use grandpa::round::State as RoundState;
use substrate_primitives::Ed25519AuthorityId;
use log::{info, warn};
use crate::authorities::{AuthoritySet, SharedAuthoritySet, PendingChange, DelayKind};
use crate::consensus_changes::{SharedConsensusChanges, ConsensusChanges};
use crate::NewAuthoritySet;
use std::fmt::Debug;
use std::sync::Arc;
use substrate_primitives::ed25519::Public as AuthorityId;
const VERSION_KEY: &[u8] = b"grandpa_schema_version";
const SET_STATE_KEY: &[u8] = b"grandpa_completed_round";
@@ -61,7 +61,7 @@ type V0VoterSetState<H, N> = (u64, RoundState<H, N>);
#[derive(Debug, Clone, Encode, Decode, PartialEq)]
struct V0PendingChange<H, N> {
next_authorities: Vec<(Ed25519AuthorityId, u64)>,
next_authorities: Vec<(AuthorityId, u64)>,
delay: N,
canon_height: N,
canon_hash: H,
@@ -69,7 +69,7 @@ struct V0PendingChange<H, N> {
#[derive(Debug, Clone, Encode, Decode, PartialEq)]
struct V0AuthoritySet<H, N> {
current_authorities: Vec<(Ed25519AuthorityId, u64)>,
current_authorities: Vec<(AuthorityId, u64)>,
set_id: u64,
pending_changes: Vec<V0PendingChange<H, N>>,
}
@@ -141,7 +141,7 @@ pub(crate) fn load_persistent<B, H, N, G>(
B: AuxStore,
H: Debug + Decode + Encode + Clone + PartialEq,
N: Debug + Decode + Encode + Clone + Ord,
G: FnOnce() -> ClientResult<Vec<(Ed25519AuthorityId, u64)>>
G: FnOnce() -> ClientResult<Vec<(AuthorityId, u64)>>
{
let version: Option<u32> = load_decode(backend, VERSION_KEY)?;
let consensus_changes = load_decode(backend, CONSENSUS_CHANGES_KEY)?
@@ -25,11 +25,12 @@ use futures::prelude::*;
use futures::sync::mpsc;
use log::{debug, trace};
use parity_codec::{Encode, Decode};
use substrate_primitives::{ed25519, Ed25519AuthorityId};
use substrate_primitives::{ed25519, Pair};
use runtime_primitives::traits::Block as BlockT;
use tokio::timer::Interval;
use crate::{Error, Network, Message, SignedMessage, Commit,
CompactCommit, GossipMessage, FullCommitMessage, VoteOrPrecommitMessage};
use ed25519::{Public as AuthorityId, Signature as AuthoritySignature};
fn localized_payload<E: Encode>(round: u64, set_id: u64, message: &E) -> Vec<u8> {
(message, round, set_id).encode()
@@ -242,14 +243,14 @@ impl<B: BlockT, N: Network<B>> Network<B> for BroadcastHandle<B, N> {
// check a message.
pub(crate) fn check_message_sig<Block: BlockT>(
message: &Message<Block>,
id: &Ed25519AuthorityId,
signature: &ed25519::Signature,
id: &AuthorityId,
signature: &AuthoritySignature,
round: u64,
set_id: u64,
) -> Result<(), ()> {
let as_public = ed25519::Public::from_raw(id.0);
let as_public = AuthorityId::from_raw(id.0);
let encoded_raw = localized_payload(round, set_id, message);
if ed25519::verify_strong(signature, &encoded_raw, as_public) {
if ed25519::Pair::verify(signature, &encoded_raw, as_public) {
Ok(())
} else {
debug!(target: "afg", "Bad signature on message from {:?}", id);
@@ -261,7 +262,7 @@ pub(crate) fn check_message_sig<Block: BlockT>(
/// the output stream checks signatures also.
pub(crate) fn checked_message_stream<Block: BlockT, S>(
inner: S,
voters: Arc<VoterSet<Ed25519AuthorityId>>,
voters: Arc<VoterSet<AuthorityId>>,
)
-> impl Stream<Item=SignedMessage<Block>,Error=Error> where
S: Stream<Item=Vec<u8>,Error=()>
@@ -297,7 +298,7 @@ pub(crate) fn checked_message_stream<Block: BlockT, S>(
pub(crate) struct OutgoingMessages<Block: BlockT, N: Network<Block>> {
round: u64,
set_id: u64,
locals: Option<(Arc<ed25519::Pair>, Ed25519AuthorityId)>,
locals: Option<(Arc<ed25519::Pair>, AuthorityId)>,
sender: mpsc::UnboundedSender<SignedMessage<Block>>,
network: N,
}
@@ -309,7 +310,7 @@ impl<Block: BlockT, N: Network<Block>> Sink for OutgoingMessages<Block, N>
fn start_send(&mut self, msg: Message<Block>) -> StartSend<Message<Block>, Error> {
// when locals exist, sign messages on import
if let Some((ref pair, local_id)) = self.locals {
if let Some((ref pair, ref local_id)) = self.locals {
let encoded = localized_payload(self.round, self.set_id, &msg);
let signature = pair.sign(&encoded[..]);
@@ -317,7 +318,7 @@ impl<Block: BlockT, N: Network<Block>> Sink for OutgoingMessages<Block, N>
let signed = SignedMessage::<Block> {
message: msg,
signature,
id: local_id,
id: local_id.clone(),
};
let message = GossipMessage::VoteOrPrecommit(VoteOrPrecommitMessage::<Block> {
@@ -361,7 +362,7 @@ pub(crate) fn outgoing_messages<Block: BlockT, N: Network<Block>>(
round: u64,
set_id: u64,
local_key: Option<Arc<ed25519::Pair>>,
voters: Arc<VoterSet<Ed25519AuthorityId>>,
voters: Arc<VoterSet<AuthorityId>>,
network: N,
) -> (
impl Stream<Item=SignedMessage<Block>,Error=Error>,
@@ -369,7 +370,7 @@ pub(crate) fn outgoing_messages<Block: BlockT, N: Network<Block>>(
) {
let locals = local_key.and_then(|pair| {
let public = pair.public();
let id = Ed25519AuthorityId(public.0);
let id = AuthorityId(public.0);
if voters.contains_key(&id) {
Some((pair, id))
} else {
@@ -395,7 +396,7 @@ pub(crate) fn outgoing_messages<Block: BlockT, N: Network<Block>>(
fn check_compact_commit<Block: BlockT>(
msg: CompactCommit<Block>,
voters: &VoterSet<Ed25519AuthorityId>,
voters: &VoterSet<AuthorityId>,
) -> Option<CompactCommit<Block>> {
if msg.precommits.len() != msg.auth_data.len() || msg.precommits.is_empty() {
debug!(target: "afg", "Skipping malformed compact commit");
@@ -417,7 +418,7 @@ fn check_compact_commit<Block: BlockT>(
/// messages.
pub(crate) fn checked_commit_stream<Block: BlockT, S>(
inner: S,
voters: Arc<VoterSet<Ed25519AuthorityId>>,
voters: Arc<VoterSet<AuthorityId>>,
)
-> impl Stream<Item=(u64, CompactCommit<Block>),Error=Error> where
S: Stream<Item=Vec<u8>,Error=()>
@@ -33,7 +33,7 @@ use runtime_primitives::generic::BlockId;
use runtime_primitives::traits::{
As, Block as BlockT, Header as HeaderT, NumberFor, One, Zero,
};
use substrate_primitives::{Blake2Hasher, ed25519,Ed25519AuthorityId, H256};
use substrate_primitives::{Blake2Hasher, ed25519, H256, Pair};
use crate::{
Commit, Config, Error, Network, Precommit, Prevote,
@@ -45,6 +45,8 @@ use crate::consensus_changes::SharedConsensusChanges;
use crate::justification::GrandpaJustification;
use crate::until_imported::UntilVoteTargetImported;
use ed25519::Public as AuthorityId;
/// Data about a completed round.
pub(crate) type CompletedRound<H, N> = (u64, RoundState<H, N>);
@@ -75,7 +77,7 @@ impl<H: Clone, N: Clone> LastCompletedRound<H, N> {
/// The environment we run GRANDPA in.
pub(crate) struct Environment<B, E, Block: BlockT, N: Network<Block>, RA> {
pub(crate) inner: Arc<Client<B, E, Block, RA>>,
pub(crate) voters: Arc<VoterSet<Ed25519AuthorityId>>,
pub(crate) voters: Arc<VoterSet<AuthorityId>>,
pub(crate) config: Config,
pub(crate) authority_set: SharedAuthoritySet<Block::Hash, NumberFor<Block>>,
pub(crate) consensus_changes: SharedConsensusChanges<Block::Hash, NumberFor<Block>>,
@@ -205,7 +207,7 @@ impl<B, E, Block: BlockT<Hash=H256>, N, RA> voter::Environment<Block::Hash, Numb
NumberFor<Block>: BlockNumberOps,
{
type Timer = Box<dyn Future<Item = (), Error = Self::Error> + Send>;
type Id = Ed25519AuthorityId;
type Id = AuthorityId;
type Signature = ed25519::Signature;
// regular round message streams
@@ -42,7 +42,8 @@ use runtime_primitives::generic::BlockId;
use runtime_primitives::traits::{
NumberFor, Block as BlockT, Header as HeaderT, One,
};
use substrate_primitives::{Ed25519AuthorityId, H256};
use substrate_primitives::{ed25519, H256};
use ed25519::Public as AuthorityId;
use crate::justification::GrandpaJustification;
@@ -189,7 +190,7 @@ fn do_check_finality_proof<Block: BlockT<Hash=H256>, C, J>(
call_data: vec![],
retry_count: None,
})?;
let grandpa_authorities: Vec<(Ed25519AuthorityId, u64)> = Decode::decode(&mut &grandpa_authorities[..])
let grandpa_authorities: Vec<(AuthorityId, u64)> = Decode::decode(&mut &grandpa_authorities[..])
.ok_or_else(|| ClientErrorKind::BadJustification("failed to decode GRANDPA authorities set proof".into()))?;
// and now check justification
@@ -222,7 +223,7 @@ trait ProvableJustification<Header: HeaderT>: Encode + Decode {
fn target_block(&self) -> (Header::Number, Header::Hash);
/// Verify justification with respect to authorities set and authorities set id.
fn verify(&self, set_id: u64, authorities: &VoterSet<Ed25519AuthorityId>) -> ClientResult<()>;
fn verify(&self, set_id: u64, authorities: &VoterSet<AuthorityId>) -> ClientResult<()>;
}
impl<Block: BlockT<Hash=H256>> ProvableJustification<Block::Header> for GrandpaJustification<Block>
@@ -233,7 +234,7 @@ impl<Block: BlockT<Hash=H256>> ProvableJustification<Block::Header> for GrandpaJ
(self.commit.target_number, self.commit.target_hash)
}
fn verify(&self, set_id: u64, authorities: &VoterSet<Ed25519AuthorityId>) -> ClientResult<()> {
fn verify(&self, set_id: u64, authorities: &VoterSet<AuthorityId>) -> ClientResult<()> {
GrandpaJustification::verify(self, set_id, authorities)
}
}
@@ -253,12 +254,12 @@ mod tests {
impl ProvableJustification<Header> for ValidFinalityProof {
fn target_block(&self) -> (u64, H256) { (3, header(3).hash()) }
fn verify(&self, set_id: u64, authorities: &VoterSet<Ed25519AuthorityId>) -> ClientResult<()> {
fn verify(&self, set_id: u64, authorities: &VoterSet<AuthorityId>) -> ClientResult<()> {
assert_eq!(set_id, 1);
assert_eq!(authorities, &vec![
(Ed25519AuthorityId([1u8; 32]), 1),
(Ed25519AuthorityId([2u8; 32]), 2),
(Ed25519AuthorityId([3u8; 32]), 3),
(AuthorityId([1u8; 32]), 1),
(AuthorityId([2u8; 32]), 2),
(AuthorityId([3u8; 32]), 3),
].into_iter().collect());
Ok(())
}
@@ -387,7 +388,7 @@ mod tests {
impl ProvableJustification<Header> for InvalidFinalityProof {
fn target_block(&self) -> (u64, H256) { (3, header(3).hash()) }
fn verify(&self, _set_id: u64, _authorities: &VoterSet<Ed25519AuthorityId>) -> ClientResult<()> {
fn verify(&self, _set_id: u64, _authorities: &VoterSet<AuthorityId>) -> ClientResult<()> {
Err(ClientErrorKind::Backend("test error".into()).into())
}
}
@@ -415,9 +416,9 @@ mod tests {
.unwrap().unwrap();
assert_eq!(do_check_finality_proof::<Block, _, ValidFinalityProof>(
|_| Ok(vec![
(Ed25519AuthorityId([1u8; 32]), 1u64),
(Ed25519AuthorityId([2u8; 32]), 2u64),
(Ed25519AuthorityId([3u8; 32]), 3u64),
(AuthorityId([1u8; 32]), 1u64),
(AuthorityId([2u8; 32]), 2u64),
(AuthorityId([3u8; 32]), 3u64),
].encode()),
header(1),
(2, header(2).hash()),
@@ -36,7 +36,7 @@ use runtime_primitives::traits::{
Block as BlockT, DigestFor, DigestItemFor, DigestItem,
Header as HeaderT, NumberFor, ProvideRuntimeApi,
};
use substrate_primitives::{H256, Ed25519AuthorityId, Blake2Hasher};
use substrate_primitives::{H256, ed25519, Blake2Hasher};
use crate::{Error, CommandOrError, NewAuthoritySet, VoterCommand};
use crate::authorities::{AuthoritySet, SharedAuthoritySet, DelayKind, PendingChange};
@@ -44,6 +44,8 @@ use crate::consensus_changes::SharedConsensusChanges;
use crate::environment::{finalize_block, is_descendent_of};
use crate::justification::GrandpaJustification;
use ed25519::Public as AuthorityId;
/// A block-import handler for GRANDPA.
///
/// This scans each imported block for signals of changing authority set.
@@ -67,7 +69,7 @@ impl<B, E, Block: BlockT<Hash=H256>, RA, PRA> JustificationImport<Block>
B: Backend<Block, Blake2Hasher> + 'static,
E: CallExecutor<Block, Blake2Hasher> + 'static + Clone + Send + Sync,
DigestFor<Block>: Encode,
DigestItemFor<Block>: DigestItem<AuthorityId=Ed25519AuthorityId>,
DigestItemFor<Block>: DigestItem<AuthorityId=AuthorityId>,
RA: Send + Sync,
PRA: ProvideRuntimeApi,
PRA::Api: GrandpaApi<Block>,
@@ -161,7 +163,7 @@ impl<B, E, Block: BlockT<Hash=H256>, RA, PRA> GrandpaBlockImport<B, E, Block, RA
B: Backend<Block, Blake2Hasher> + 'static,
E: CallExecutor<Block, Blake2Hasher> + 'static + Clone + Send + Sync,
DigestFor<Block>: Encode,
DigestItemFor<Block>: DigestItem<AuthorityId=Ed25519AuthorityId>,
DigestItemFor<Block>: DigestItem<AuthorityId=AuthorityId>,
RA: Send + Sync,
PRA: ProvideRuntimeApi,
PRA::Api: GrandpaApi<Block>,
@@ -379,14 +381,14 @@ impl<B, E, Block: BlockT<Hash=H256>, RA, PRA> BlockImport<Block>
B: Backend<Block, Blake2Hasher> + 'static,
E: CallExecutor<Block, Blake2Hasher> + 'static + Clone + Send + Sync,
DigestFor<Block>: Encode,
DigestItemFor<Block>: DigestItem<AuthorityId=Ed25519AuthorityId>,
DigestItemFor<Block>: DigestItem<AuthorityId=AuthorityId>,
RA: Send + Sync,
PRA: ProvideRuntimeApi,
PRA::Api: GrandpaApi<Block>,
{
type Error = ConsensusError;
fn import_block(&self, mut block: ImportBlock<Block>, new_authorities: Option<Vec<Ed25519AuthorityId>>)
fn import_block(&self, mut block: ImportBlock<Block>, new_authorities: Option<Vec<AuthorityId>>)
-> Result<ImportResult, Self::Error>
{
let hash = block.post_header().hash();
@@ -25,11 +25,13 @@ use grandpa::VoterSet;
use grandpa::{Error as GrandpaError};
use runtime_primitives::generic::BlockId;
use runtime_primitives::traits::{NumberFor, Block as BlockT, Header as HeaderT};
use substrate_primitives::{H256, Ed25519AuthorityId, Blake2Hasher};
use substrate_primitives::{H256, ed25519, Blake2Hasher};
use crate::{Commit, Error};
use crate::communication;
use ed25519::Public as AuthorityId;
/// A GRANDPA justification for block finality, it includes a commit message and
/// an ancestry proof including all headers routing all precommit target blocks
/// to the commit target block. Due to the current voting strategy the precommit
@@ -95,7 +97,7 @@ impl<Block: BlockT<Hash=H256>> GrandpaJustification<Block> {
pub(crate) fn decode_and_verify(
encoded: Vec<u8>,
set_id: u64,
voters: &VoterSet<Ed25519AuthorityId>,
voters: &VoterSet<AuthorityId>,
) -> Result<GrandpaJustification<Block>, ClientError> where
NumberFor<Block>: grandpa::BlockNumberOps,
{
@@ -106,7 +108,7 @@ impl<Block: BlockT<Hash=H256>> GrandpaJustification<Block> {
}
/// Validate the commit and the votes' ancestry proofs.
pub(crate) fn verify(&self, set_id: u64, voters: &VoterSet<Ed25519AuthorityId>) -> Result<(), ClientError>
pub(crate) fn verify(&self, set_id: u64, voters: &VoterSet<AuthorityId>) -> Result<(), ClientError>
where
NumberFor<Block>: grandpa::BlockNumberOps,
{
+15 -13
View File
@@ -68,7 +68,7 @@ use runtime_primitives::traits::{
use fg_primitives::GrandpaApi;
use inherents::InherentDataProviders;
use runtime_primitives::generic::BlockId;
use substrate_primitives::{ed25519, H256, Ed25519AuthorityId, Blake2Hasher};
use substrate_primitives::{ed25519, H256, Blake2Hasher, Pair};
use substrate_telemetry::{telemetry, CONSENSUS_TRACE, CONSENSUS_DEBUG, CONSENSUS_WARN};
use srml_finality_tracker;
@@ -106,6 +106,8 @@ pub use finality_proof::{prove_finality, check_finality_proof};
use import::GrandpaBlockImport;
use until_imported::UntilCommitBlocksImported;
use ed25519::{Public as AuthorityId, Signature as AuthoritySignature};
#[cfg(test)]
mod tests;
@@ -118,8 +120,8 @@ pub type Message<Block> = grandpa::Message<<Block as BlockT>::Hash, NumberFor<Bl
pub type SignedMessage<Block> = grandpa::SignedMessage<
<Block as BlockT>::Hash,
NumberFor<Block>,
ed25519::Signature,
Ed25519AuthorityId,
AuthoritySignature,
AuthorityId,
>;
/// Grandpa gossip message type.
@@ -148,15 +150,15 @@ pub type Precommit<Block> = grandpa::Precommit<<Block as BlockT>::Hash, NumberFo
pub type Commit<Block> = grandpa::Commit<
<Block as BlockT>::Hash,
NumberFor<Block>,
ed25519::Signature,
Ed25519AuthorityId
AuthoritySignature,
AuthorityId
>;
/// A compact commit message for this chain's block type.
pub type CompactCommit<Block> = grandpa::CompactCommit<
<Block as BlockT>::Hash,
NumberFor<Block>,
ed25519::Signature,
Ed25519AuthorityId
AuthoritySignature,
AuthorityId
>;
/// Network level commit message with topic information.
@@ -560,7 +562,7 @@ pub(crate) struct NewAuthoritySet<H, N> {
pub(crate) canon_number: N,
pub(crate) canon_hash: H,
pub(crate) set_id: u64,
pub(crate) authorities: Vec<(Ed25519AuthorityId, u64)>,
pub(crate) authorities: Vec<(AuthorityId, u64)>,
}
/// Commands issued to the voter.
@@ -684,16 +686,16 @@ pub fn block_import<B, E, Block: BlockT<Hash=H256>, RA, PRA>(
fn committer_communication<Block: BlockT<Hash=H256>, B, E, N, RA>(
local_key: Option<Arc<ed25519::Pair>>,
set_id: u64,
voters: &Arc<VoterSet<Ed25519AuthorityId>>,
voters: &Arc<VoterSet<AuthorityId>>,
client: &Arc<Client<B, E, Block, RA>>,
network: &N,
) -> (
impl Stream<
Item = (u64, ::grandpa::CompactCommit<H256, NumberFor<Block>, ed25519::Signature, Ed25519AuthorityId>),
Item = (u64, ::grandpa::CompactCommit<H256, NumberFor<Block>, AuthoritySignature, AuthorityId>),
Error = CommandOrError<H256, NumberFor<Block>>,
>,
impl Sink<
SinkItem = (u64, ::grandpa::Commit<H256, NumberFor<Block>, ed25519::Signature, Ed25519AuthorityId>),
SinkItem = (u64, ::grandpa::Commit<H256, NumberFor<Block>, AuthoritySignature, AuthorityId>),
SinkError = CommandOrError<H256, NumberFor<Block>>,
>,
) where
@@ -702,7 +704,7 @@ fn committer_communication<Block: BlockT<Hash=H256>, B, E, N, RA>(
N: Network<Block>,
RA: Send + Sync,
NumberFor<Block>: BlockNumberOps,
DigestItemFor<Block>: DigestItem<AuthorityId=Ed25519AuthorityId>,
DigestItemFor<Block>: DigestItem<AuthorityId=AuthorityId>,
{
// verification stream
let commit_in = crate::communication::checked_commit_stream::<Block, _>(
@@ -773,7 +775,7 @@ pub fn run_grandpa<B, E, Block: BlockT<Hash=H256>, N, RA>(
N::In: Send + 'static,
NumberFor<Block>: BlockNumberOps,
DigestFor<Block>: Encode,
DigestItemFor<Block>: DigestItem<AuthorityId=Ed25519AuthorityId>,
DigestItemFor<Block>: DigestItem<AuthorityId=AuthorityId>,
RA: Send + Sync + 'static,
{
use futures::future::{self, Loop as FutureLoop};
+36 -36
View File
@@ -22,7 +22,7 @@ use network::test::{PassThroughVerifier};
use network::config::{ProtocolConfig, Roles};
use parking_lot::Mutex;
use tokio::runtime::current_thread;
use keyring::Keyring;
use keyring::AuthorityKeyring;
use client::{
BlockchainEvents, error::Result,
blockchain::Backend as BlockchainBackend,
@@ -238,13 +238,13 @@ impl Network<Block> for MessageRouting {
#[derive(Default, Clone)]
struct TestApi {
genesis_authorities: Vec<(Ed25519AuthorityId, u64)>,
genesis_authorities: Vec<(AuthorityId, u64)>,
scheduled_changes: Arc<Mutex<HashMap<Hash, ScheduledChange<BlockNumber>>>>,
forced_changes: Arc<Mutex<HashMap<Hash, (BlockNumber, ScheduledChange<BlockNumber>)>>>,
}
impl TestApi {
fn new(genesis_authorities: Vec<(Ed25519AuthorityId, u64)>) -> Self {
fn new(genesis_authorities: Vec<(AuthorityId, u64)>) -> Self {
TestApi {
genesis_authorities,
scheduled_changes: Arc::new(Mutex::new(HashMap::new())),
@@ -282,7 +282,7 @@ impl Core<Block> for RuntimeApi {
_: ExecutionContext,
_: Option<()>,
_: Vec<u8>,
) -> Result<NativeOrEncoded<Vec<Ed25519AuthorityId>>> {
) -> Result<NativeOrEncoded<Vec<AuthorityId>>> {
unimplemented!("Not required for testing!")
}
@@ -327,7 +327,7 @@ impl GrandpaApi<Block> for RuntimeApi {
_: ExecutionContext,
_: Option<()>,
_: Vec<u8>,
) -> Result<NativeOrEncoded<Vec<(Ed25519AuthorityId, u64)>>> {
) -> Result<NativeOrEncoded<Vec<(AuthorityId, u64)>>> {
if at == &BlockId::Number(0) {
Ok(self.inner.genesis_authorities.clone()).map(NativeOrEncoded::Native)
} else {
@@ -374,9 +374,9 @@ impl GrandpaApi<Block> for RuntimeApi {
const TEST_GOSSIP_DURATION: Duration = Duration::from_millis(500);
const TEST_ROUTING_INTERVAL: Duration = Duration::from_millis(50);
fn make_ids(keys: &[Keyring]) -> Vec<(Ed25519AuthorityId, u64)> {
fn make_ids(keys: &[AuthorityKeyring]) -> Vec<(AuthorityId, u64)> {
keys.iter()
.map(|key| Ed25519AuthorityId(key.to_raw_public()))
.map(|key| AuthorityId(key.to_raw_public()))
.map(|id| (id, 1))
.collect()
}
@@ -386,7 +386,7 @@ fn make_ids(keys: &[Keyring]) -> Vec<(Ed25519AuthorityId, u64)> {
fn run_to_completion_with<F: FnOnce()>(
blocks: u64,
net: Arc<Mutex<GrandpaTestNet>>,
peers: &[Keyring],
peers: &[AuthorityKeyring],
before_waiting: F,
) -> u64 {
use parking_lot::RwLock;
@@ -462,14 +462,14 @@ fn run_to_completion_with<F: FnOnce()>(
highest_finalized
}
fn run_to_completion(blocks: u64, net: Arc<Mutex<GrandpaTestNet>>, peers: &[Keyring]) -> u64 {
fn run_to_completion(blocks: u64, net: Arc<Mutex<GrandpaTestNet>>, peers: &[AuthorityKeyring]) -> u64 {
run_to_completion_with(blocks, net, peers, || {})
}
#[test]
fn finalize_3_voters_no_observers() {
let _ = env_logger::try_init();
let peers = &[Keyring::Alice, Keyring::Bob, Keyring::Charlie];
let peers = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob, AuthorityKeyring::Charlie];
let voters = make_ids(peers);
let mut net = GrandpaTestNet::new(TestApi::new(voters), 3);
@@ -491,7 +491,7 @@ fn finalize_3_voters_no_observers() {
#[test]
fn finalize_3_voters_1_observer() {
let peers = &[Keyring::Alice, Keyring::Bob, Keyring::Charlie];
let peers = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob, AuthorityKeyring::Charlie];
let voters = make_ids(peers);
let mut net = GrandpaTestNet::new(TestApi::new(voters), 4);
@@ -554,24 +554,24 @@ fn finalize_3_voters_1_observer() {
fn transition_3_voters_twice_1_observer() {
let _ = env_logger::try_init();
let peers_a = &[
Keyring::Alice,
Keyring::Bob,
Keyring::Charlie,
AuthorityKeyring::Alice,
AuthorityKeyring::Bob,
AuthorityKeyring::Charlie,
];
let peers_b = &[
Keyring::Dave,
Keyring::Eve,
Keyring::Ferdie,
AuthorityKeyring::Dave,
AuthorityKeyring::Eve,
AuthorityKeyring::Ferdie,
];
let peers_c = &[
Keyring::Alice,
Keyring::Eve,
Keyring::Two,
AuthorityKeyring::Alice,
AuthorityKeyring::Eve,
AuthorityKeyring::Two,
];
let observer = &[Keyring::One];
let observer = &[AuthorityKeyring::One];
let genesis_voters = make_ids(peers_a);
@@ -719,11 +719,11 @@ fn transition_3_voters_twice_1_observer() {
#[test]
fn justification_is_emitted_when_consensus_data_changes() {
let peers = &[Keyring::Alice, Keyring::Bob, Keyring::Charlie];
let peers = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob, AuthorityKeyring::Charlie];
let mut net = GrandpaTestNet::new(TestApi::new(make_ids(peers)), 3);
// import block#1 WITH consensus data change
let new_authorities = vec![Ed25519AuthorityId::from([42; 32])];
let new_authorities = vec![AuthorityId::from_raw([42; 32])];
net.peer(0).push_authorities_change_block(new_authorities);
net.sync();
let net = Arc::new(Mutex::new(net));
@@ -736,7 +736,7 @@ fn justification_is_emitted_when_consensus_data_changes() {
#[test]
fn justification_is_generated_periodically() {
let peers = &[Keyring::Alice, Keyring::Bob, Keyring::Charlie];
let peers = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob, AuthorityKeyring::Charlie];
let voters = make_ids(peers);
let mut net = GrandpaTestNet::new(TestApi::new(voters), 3);
@@ -775,8 +775,8 @@ fn consensus_changes_works() {
#[test]
fn sync_justifications_on_change_blocks() {
let peers_a = &[Keyring::Alice, Keyring::Bob, Keyring::Charlie];
let peers_b = &[Keyring::Alice, Keyring::Bob];
let peers_a = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob, AuthorityKeyring::Charlie];
let peers_b = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob];
let voters = make_ids(peers_b);
// 4 peers, 3 of them are authorities and participate in grandpa
@@ -825,13 +825,13 @@ fn sync_justifications_on_change_blocks() {
fn finalizes_multiple_pending_changes_in_order() {
let _ = env_logger::try_init();
let peers_a = &[Keyring::Alice, Keyring::Bob, Keyring::Charlie];
let peers_b = &[Keyring::Dave, Keyring::Eve, Keyring::Ferdie];
let peers_c = &[Keyring::Dave, Keyring::Alice, Keyring::Bob];
let peers_a = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob, AuthorityKeyring::Charlie];
let peers_b = &[AuthorityKeyring::Dave, AuthorityKeyring::Eve, AuthorityKeyring::Ferdie];
let peers_c = &[AuthorityKeyring::Dave, AuthorityKeyring::Alice, AuthorityKeyring::Bob];
let all_peers = &[
Keyring::Alice, Keyring::Bob, Keyring::Charlie,
Keyring::Dave, Keyring::Eve, Keyring::Ferdie,
AuthorityKeyring::Alice, AuthorityKeyring::Bob, AuthorityKeyring::Charlie,
AuthorityKeyring::Dave, AuthorityKeyring::Eve, AuthorityKeyring::Ferdie,
];
let genesis_voters = make_ids(peers_a);
@@ -883,7 +883,7 @@ fn finalizes_multiple_pending_changes_in_order() {
#[test]
fn doesnt_vote_on_the_tip_of_the_chain() {
let peers_a = &[Keyring::Alice, Keyring::Bob, Keyring::Charlie];
let peers_a = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob, AuthorityKeyring::Charlie];
let voters = make_ids(peers_a);
let api = TestApi::new(voters);
let mut net = GrandpaTestNet::new(api, 3);
@@ -907,8 +907,8 @@ fn doesnt_vote_on_the_tip_of_the_chain() {
#[test]
fn force_change_to_new_set() {
// two of these guys are offline.
let genesis_authorities = &[Keyring::Alice, Keyring::Bob, Keyring::Charlie, Keyring::One, Keyring::Two];
let peers_a = &[Keyring::Alice, Keyring::Bob, Keyring::Charlie];
let genesis_authorities = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob, AuthorityKeyring::Charlie, AuthorityKeyring::One, AuthorityKeyring::Two];
let peers_a = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob, AuthorityKeyring::Charlie];
let api = TestApi::new(make_ids(genesis_authorities));
let voters = make_ids(peers_a);
@@ -960,8 +960,8 @@ fn force_change_to_new_set() {
#[test]
fn allows_reimporting_change_blocks() {
let peers_a = &[Keyring::Alice, Keyring::Bob, Keyring::Charlie];
let peers_b = &[Keyring::Alice, Keyring::Bob];
let peers_a = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob, AuthorityKeyring::Charlie];
let peers_b = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob];
let voters = make_ids(peers_a);
let api = TestApi::new(voters);
let net = GrandpaTestNet::new(api.clone(), 3);
@@ -28,7 +28,7 @@ use futures::prelude::*;
use futures::stream::Fuse;
use parking_lot::Mutex;
use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, NumberFor};
use substrate_primitives::Ed25519AuthorityId;
use substrate_primitives::ed25519::Public as AuthorityId;
use tokio::timer::Interval;
use std::collections::{HashMap, VecDeque};
@@ -199,7 +199,7 @@ impl<Block: BlockT, Status, I, M> Stream for UntilImported<Block, Status, I, M>
}
}
fn warn_authority_wrong_target<H: ::std::fmt::Display>(hash: H, id: Ed25519AuthorityId) {
fn warn_authority_wrong_target<H: ::std::fmt::Display>(hash: H, id: AuthorityId) {
warn!(
target: "afg",
"Authority {:?} signed GRANDPA message with \
+31 -21
View File
@@ -19,10 +19,14 @@
use std::collections::HashMap;
use std::ops::Deref;
use lazy_static::lazy_static;
use hex_literal::{hex, hex_impl};
use substrate_primitives::ed25519::{Pair, Public, Signature};
use substrate_primitives::{ed25519::{Pair, Public, Signature}, Pair as _Pair, H256};
pub use substrate_primitives::ed25519;
/// The root phrase for our test keys.
///
/// This is the same phrase that's in node::cli, but shouldn't need to be.
pub const DEV_PHRASE: &str = "bottom drive obey lake curtain smoke basket hold race lonely fit walk";
/// Set of test accounts.
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub enum Keyring {
@@ -37,7 +41,7 @@ pub enum Keyring {
}
impl Keyring {
pub fn from_public(who: Public) -> Option<Keyring> {
pub fn from_public(who: &Public) -> Option<Keyring> {
[
Keyring::Alice,
Keyring::Bob,
@@ -49,17 +53,25 @@ impl Keyring {
Keyring::Two,
].iter()
.map(|i| *i)
.find(|&k| Public::from(k) == who)
.find(|&k| &Public::from(k) == who)
}
pub fn from_raw_public(who: [u8; 32]) -> Option<Keyring> {
Self::from_public(Public::from_raw(who))
Self::from_public(&Public::from_raw(who))
}
pub fn to_raw_public(self) -> [u8; 32] {
*Public::from(self).as_array_ref()
}
pub fn from_h256_public(who: H256) -> Option<Keyring> {
Self::from_public(&Public::from_raw(who.into()))
}
pub fn to_h256_public(self) -> H256 {
Public::from(self).as_array_ref().into()
}
pub fn to_raw_public_vec(self) -> Vec<u8> {
Public::from(self).to_raw_vec()
}
@@ -69,16 +81,8 @@ impl Keyring {
}
pub fn pair(self) -> Pair {
match self {
Keyring::Alice => Pair::from_seed(b"Alice "),
Keyring::Bob => Pair::from_seed(b"Bob "),
Keyring::Charlie => Pair::from_seed(b"Charlie "),
Keyring::Dave => Pair::from_seed(b"Dave "),
Keyring::Eve => Pair::from_seed(b"Eve "),
Keyring::Ferdie => Pair::from_seed(b"Ferdie "),
Keyring::One => Pair::from_seed(b"12345678901234567890123456789012"),
Keyring::Two => Pair::from_seed(&hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60")),
}
Pair::from_string(&format!("{}//{}", DEV_PHRASE, <&'static str>::from(self)), None)
.expect("static values are known good; qed")
}
}
@@ -91,8 +95,8 @@ impl From<Keyring> for &'static str {
Keyring::Dave => "Dave",
Keyring::Eve => "Eve",
Keyring::Ferdie => "Ferdie",
Keyring::One => "one",
Keyring::Two => "two",
Keyring::One => "One",
Keyring::Two => "Two",
}
}
}
@@ -134,6 +138,12 @@ impl From<Keyring> for [u8; 32] {
}
}
impl From<Keyring> for H256 {
fn from(k: Keyring) -> Self {
(*PUBLIC_KEYS).get(&k).unwrap().as_array_ref().into()
}
}
impl From<Keyring> for &'static [u8; 32] {
fn from(k: Keyring) -> Self {
(*PUBLIC_KEYS).get(&k).unwrap().as_array_ref()
@@ -162,12 +172,12 @@ impl Deref for Keyring {
#[cfg(test)]
mod tests {
use super::*;
use ed25519::Verifiable;
use substrate_primitives::{ed25519::Pair, Pair as _Pair};
#[test]
fn should_work() {
assert!(Keyring::Alice.sign(b"I am Alice!").verify(b"I am Alice!", Keyring::Alice));
assert!(!Keyring::Alice.sign(b"I am Alice!").verify(b"I am Bob!", Keyring::Alice));
assert!(!Keyring::Alice.sign(b"I am Alice!").verify(b"I am Alice!", Keyring::Bob));
assert!(Pair::verify(&Keyring::Alice.sign(b"I am Alice!"), b"I am Alice!", Keyring::Alice));
assert!(!Pair::verify(&Keyring::Alice.sign(b"I am Alice!"), b"I am Bob!", Keyring::Alice));
assert!(!Pair::verify(&Keyring::Alice.sign(b"I am Alice!"), b"I am Alice!", Keyring::Bob));
}
}
+12 -4
View File
@@ -22,7 +22,15 @@ pub mod sr25519;
/// Test account crypto for ed25519.
pub mod ed25519;
/// The Ed25519 keyring.
///
/// This is deprecated: use `ed25519::Keyring` instead.
pub use ed25519::Keyring;
/// Convenience export: Sr25519's Keyring is exposed as `AccountKeyring`,
/// since it tends to be used for accounts.
pub use sr25519::Keyring as AccountKeyring;
/// Convenience export: Ed25519's Keyring is exposed as `AuthorityKeyring`,
/// since it tends to be used for authorities (session keys &c.).
pub use ed25519::Keyring as AuthorityKeyring;
pub mod test {
/// The keyring for use with accounts when using the test runtime.
pub use super::ed25519::Keyring as AccountKeyring;
}
+31 -21
View File
@@ -19,10 +19,14 @@
use std::collections::HashMap;
use std::ops::Deref;
use lazy_static::lazy_static;
use hex_literal::{hex, hex_impl};
use substrate_primitives::sr25519::{Pair, Public, Signature};
use substrate_primitives::{sr25519::{Pair, Public, Signature}, Pair as _Pair, H256};
pub use substrate_primitives::sr25519;
/// The root phrase for our test keys.
///
/// This is the same phrase that's in node::cli, but shouldn't need to be.
pub const DEV_PHRASE: &str = "bottom drive obey lake curtain smoke basket hold race lonely fit walk";
/// Set of test accounts.
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub enum Keyring {
@@ -37,7 +41,7 @@ pub enum Keyring {
}
impl Keyring {
pub fn from_public(who: Public) -> Option<Keyring> {
pub fn from_public(who: &Public) -> Option<Keyring> {
[
Keyring::Alice,
Keyring::Bob,
@@ -49,17 +53,25 @@ impl Keyring {
Keyring::Two,
].iter()
.map(|i| *i)
.find(|&k| Public::from(k) == who)
.find(|&k| &Public::from(k) == who)
}
pub fn from_raw_public(who: [u8; 32]) -> Option<Keyring> {
Self::from_public(Public::from_raw(who))
Self::from_public(&Public::from_raw(who))
}
pub fn to_raw_public(self) -> [u8; 32] {
*Public::from(self).as_array_ref()
}
pub fn from_h256_public(who: H256) -> Option<Keyring> {
Self::from_public(&Public::from_raw(who.into()))
}
pub fn to_h256_public(self) -> H256 {
Public::from(self).as_array_ref().into()
}
pub fn to_raw_public_vec(self) -> Vec<u8> {
Public::from(self).to_raw_vec()
}
@@ -69,16 +81,8 @@ impl Keyring {
}
pub fn pair(self) -> Pair {
match self {
Keyring::Alice => Pair::from_seed(b"Alice "),
Keyring::Bob => Pair::from_seed(b"Bob "),
Keyring::Charlie => Pair::from_seed(b"Charlie "),
Keyring::Dave => Pair::from_seed(b"Dave "),
Keyring::Eve => Pair::from_seed(b"Eve "),
Keyring::Ferdie => Pair::from_seed(b"Ferdie "),
Keyring::One => Pair::from_seed(b"12345678901234567890123456789012"),
Keyring::Two => Pair::from_seed(&hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60")),
}
Pair::from_string(&format!("{}//{}", DEV_PHRASE, <&'static str>::from(self)), None)
.expect("static values are known good; qed")
}
}
@@ -91,8 +95,8 @@ impl From<Keyring> for &'static str {
Keyring::Dave => "Dave",
Keyring::Eve => "Eve",
Keyring::Ferdie => "Ferdie",
Keyring::One => "one",
Keyring::Two => "two",
Keyring::One => "One",
Keyring::Two => "Two",
}
}
}
@@ -134,6 +138,12 @@ impl From<Keyring> for [u8; 32] {
}
}
impl From<Keyring> for H256 {
fn from(k: Keyring) -> Self {
(*PUBLIC_KEYS).get(&k).unwrap().as_array_ref().into()
}
}
impl From<Keyring> for &'static [u8; 32] {
fn from(k: Keyring) -> Self {
(*PUBLIC_KEYS).get(&k).unwrap().as_array_ref()
@@ -162,12 +172,12 @@ impl Deref for Keyring {
#[cfg(test)]
mod tests {
use super::*;
use sr25519::Verifiable;
use substrate_primitives::{sr25519::Pair, Pair as _Pair};
#[test]
fn should_work() {
assert!(Keyring::Alice.sign(b"I am Alice!").verify(b"I am Alice!", Keyring::Alice));
assert!(!Keyring::Alice.sign(b"I am Alice!").verify(b"I am Bob!", Keyring::Alice));
assert!(!Keyring::Alice.sign(b"I am Alice!").verify(b"I am Alice!", Keyring::Bob));
assert!(Pair::verify(&Keyring::Alice.sign(b"I am Alice!"), b"I am Alice!", Keyring::Alice));
assert!(!Pair::verify(&Keyring::Alice.sign(b"I am Alice!"), b"I am Bob!", Keyring::Alice));
assert!(!Pair::verify(&Keyring::Alice.sign(b"I am Alice!"), b"I am Alice!", Keyring::Bob));
}
}
+24 -157
View File
@@ -24,13 +24,11 @@ use std::collections::HashMap;
use std::path::PathBuf;
use std::fs::{self, File};
use std::io::{self, Write};
use std::num::NonZeroU32;
use serde_derive::{Serialize, Deserialize};
use error_chain::{error_chain, error_chain_processing, impl_error_chain_processed,
use error_chain::{bail, error_chain, error_chain_processing, impl_error_chain_processed,
impl_extract_backtrace, impl_error_chain_kind};
use substrate_primitives::{hashing::blake2_256, ed25519::{Pair, Public, PKCS_LEN}};
use substrate_primitives::{ed25519::{Pair, Public}, Pair as _Pair};
pub use crypto::KEY_ITERATIONS;
@@ -45,99 +43,21 @@ error_chain! {
description("Invalid password"),
display("Invalid password"),
}
InvalidPKCS8 {
description("Invalid PKCS#8 data"),
display("Invalid PKCS#8 data"),
InvalidPhrase {
description("Invalid recovery phrase (BIP39) data"),
display("Invalid recovery phrase (BIP39) data"),
}
InvalidSeed {
description("Invalid seed"),
display("Invalid seed"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct InvalidPassword;
#[derive(Serialize, Deserialize)]
struct EncryptedKey {
mac: [u8; 32],
salt: [u8; 32],
ciphertext: Vec<u8>, // FIXME: switch to fixed-size when serde supports
iv: [u8; 16],
iterations: NonZeroU32,
}
impl EncryptedKey {
fn encrypt(plain: &[u8; PKCS_LEN], password: &str, iterations: NonZeroU32) -> Self {
use rand::{Rng, rngs::OsRng};
let mut rng = OsRng::new().expect("OS Randomness available on all supported platforms; qed");
let salt: [u8; 32] = rng.gen();
let iv: [u8; 16] = rng.gen();
// two parts of derived key
// DK = [ DK[0..15] DK[16..31] ] = [derived_left_bits, derived_right_bits]
let (derived_left_bits, derived_right_bits) = crypto::derive_key_iterations(password.as_bytes(), &salt, iterations);
// preallocated (on-stack in case of `Secret`) buffer to hold cipher
// length = length(plain) as we are using CTR-approach
let mut ciphertext = vec![0; PKCS_LEN];
// aes-128-ctr with initial vector of iv
crypto::aes::encrypt_128_ctr(&derived_left_bits, &iv, plain, &mut *ciphertext)
.expect("input lengths of key and iv are both 16; qed");
// Blake2_256(DK[16..31] ++ <ciphertext>), where DK[16..31] - derived_right_bits
let mac = blake2_256(&crypto::derive_mac(&derived_right_bits, &*ciphertext));
EncryptedKey {
salt,
iv,
mac,
iterations,
ciphertext,
}
}
fn decrypt(&self, password: &str) -> Result<[u8; PKCS_LEN]> {
let (derived_left_bits, derived_right_bits) =
crypto::derive_key_iterations(password.as_bytes(), &self.salt, self.iterations);
let mac = blake2_256(&crypto::derive_mac(&derived_right_bits, &self.ciphertext));
if subtle::ConstantTimeEq::ct_eq(&mac[..], &self.mac[..]).unwrap_u8() != 1 {
return Err(ErrorKind::InvalidPassword.into());
}
let mut plain = [0; PKCS_LEN];
crypto::aes::decrypt_128_ctr(&derived_left_bits, &self.iv, &self.ciphertext, &mut plain[..])
.expect("input lengths of key and iv are both 16; qed");
Ok(plain)
}
}
type Seed = [u8; 32];
/// Key store.
pub struct Store {
path: PathBuf,
additional: HashMap<Public, Seed>,
}
pub fn pad_seed(seed: &str) -> Seed {
let mut s: [u8; 32] = [' ' as u8; 32];
let was_hex = if seed.len() == 66 && &seed[0..2] == "0x" {
if let Ok(d) = hex::decode(&seed[2..]) {
s.copy_from_slice(&d);
true
} else { false }
} else { false };
if !was_hex {
let len = ::std::cmp::min(32, seed.len());
&mut s[..len].copy_from_slice(&seed.as_bytes()[..len]);
}
s
additional: HashMap<Public, Pair>,
}
impl Store {
@@ -149,44 +69,36 @@ impl Store {
/// Generate a new key, placing it into the store.
pub fn generate(&self, password: &str) -> Result<Pair> {
let (pair, pkcs_bytes) = Pair::generate_with_pkcs8();
let key_file = EncryptedKey::encrypt(
&pkcs_bytes,
password,
NonZeroU32::new(KEY_ITERATIONS as u32).expect("KEY_ITERATIONS is not zero; QED")
);
let (pair, phrase) = Pair::generate_with_phrase(Some(password));
let mut file = File::create(self.key_file_path(&pair.public()))?;
::serde_json::to_writer(&file, &key_file)?;
::serde_json::to_writer(&file, &phrase)?;
file.flush()?;
Ok(pair)
}
/// Create a new key from seed. Do not place it into the store.
/// Only the first 32 bytes of the sead are used. This is meant to be used for testing only.
// FIXME: remove this - https://github.com/paritytech/substrate/issues/1063
pub fn generate_from_seed(&mut self, seed: &str) -> Result<Pair> {
let padded_seed = pad_seed(seed);
let pair = Pair::from_seed(&padded_seed);
self.additional.insert(pair.public(), padded_seed);
let pair = Pair::from_string(seed, None)
.map_err(|_| Error::from(ErrorKind::InvalidSeed))?;
self.additional.insert(pair.public(), pair.clone());
Ok(pair)
}
/// Load a key file with given public key.
pub fn load(&self, public: &Public, password: &str) -> Result<Pair> {
if let Some(ref seed) = self.additional.get(public) {
let pair = Pair::from_seed(seed);
return Ok(pair);
if let Some(pair) = self.additional.get(public) {
return Ok(pair.clone());
}
let path = self.key_file_path(public);
let file = File::open(path)?;
let encrypted_key: EncryptedKey = ::serde_json::from_reader(&file)?;
let pkcs_bytes = encrypted_key.decrypt(password)?;
Pair::from_pkcs8(&pkcs_bytes[..]).map_err(|_| ErrorKind::InvalidPKCS8.into())
let phrase: String = ::serde_json::from_reader(&file)?;
let pair = Pair::from_phrase(&phrase, Some(password))
.map_err(|_| Error::from(ErrorKind::InvalidPhrase))?;
if &pair.public() != public {
bail!(ErrorKind::InvalidPassword);
}
Ok(pair)
}
/// Get public keys of all stored keys.
@@ -227,42 +139,6 @@ mod tests {
use super::*;
use tempdir::TempDir;
#[test]
fn encrypt_and_decrypt() {
let plain = [1; PKCS_LEN];
let encrypted_key = EncryptedKey::encrypt(&plain, "thepassword", NonZeroU32::new(KEY_ITERATIONS as u32).expect("KEY_ITERATIONS is not zero; QED"));
let decrypted_key = encrypted_key.decrypt("thepassword").unwrap();
assert_eq!(&plain[..], &decrypted_key[..]);
}
#[test]
fn decrypt_wrong_password_fails() {
let plain = [1; PKCS_LEN];
let encrypted_key = EncryptedKey::encrypt(
&plain,
"thepassword",
NonZeroU32::new(KEY_ITERATIONS as u32).expect("KEY_ITERATIONS is not zero; QED")
);
assert!(encrypted_key.decrypt("thepassword2").is_err());
}
#[test]
fn decrypt_wrong_iterations_fails() {
let plain = [1; PKCS_LEN];
let mut encrypted_key = EncryptedKey::encrypt(
&plain,
"thepassword",
NonZeroU32::new(KEY_ITERATIONS as u32).expect("KEY_ITERATIONS is not zero; QED")
);
encrypted_key.iterations = NonZeroU32::new(encrypted_key.iterations.get() - 64).unwrap();
assert!(encrypted_key.decrypt("thepassword").is_err());
}
#[test]
fn basic_store() {
let temp_dir = TempDir::new("keystore").unwrap();
@@ -285,16 +161,7 @@ mod tests {
let temp_dir = TempDir::new("keystore").unwrap();
let mut store = Store::open(temp_dir.path().to_owned()).unwrap();
let pair = store.generate_from_seed("0x1").unwrap();
assert_eq!("5GqhgbUd2S9uc5Tm7hWhw29Tw2jBnuHshmTV1fDF4V1w3G2z", pair.public().to_ss58check());
let pair = store.generate_from_seed("0x3d97c819d68f9bafa7d6e79cb991eebcd77d966c5334c0b94d9e1fa7ad0869dc").unwrap();
assert_eq!("5DKUrgFqCPV8iAXx9sjy1nyBygQCeiUYRFWurZGhnrn3HBL8", pair.public().to_ss58check());
let pair = store.generate_from_seed("12345678901234567890123456789022").unwrap();
assert_eq!("5DscZvfjnM5im7oKRXXP9xtCG1SEwfMb8J5eGLmw5EHhoHR3", pair.public().to_ss58check());
let pair = store.generate_from_seed("1").unwrap();
assert_eq!("5DYnksEZFc7kgtfyNM1xK2eBtW142gZ3Ho3NQubrF2S6B2fq", pair.public().to_ss58check());
}
}
+6 -7
View File
@@ -39,19 +39,18 @@ use crate::consensus_gossip::ConsensusGossip;
use crossbeam_channel::{self as channel, Sender, select};
use futures::Future;
use futures::sync::{mpsc, oneshot};
use keyring::Keyring;
use crate::message::{Message, ConsensusEngineId};
use network_libp2p::{NodeIndex, ProtocolId, PeerId};
use parity_codec::Encode;
use parking_lot::{Mutex, RwLock};
use primitives::{H256, Ed25519AuthorityId};
use primitives::{H256, ed25519::Public as AuthorityId};
use crate::protocol::{ConnectedPeer, Context, FromNetworkMsg, Protocol, ProtocolMsg};
use runtime_primitives::generic::BlockId;
use runtime_primitives::traits::{AuthorityIdFor, Block as BlockT, Digest, DigestItem, Header, NumberFor};
use runtime_primitives::Justification;
use crate::service::{network_channel, NetworkChan, NetworkLink, NetworkMsg, NetworkPort, TransactionPool};
use crate::specialization::NetworkSpecialization;
use test_client;
use test_client::{self, AccountKeyring};
pub use test_client::runtime::{Block, Extrinsic, Hash, Transfer};
pub use test_client::TestClient;
@@ -458,12 +457,12 @@ impl<D, S: NetworkSpecialization<Block> + Clone> Peer<D, S> {
if with_tx {
self.generate_blocks_at(at, count, BlockOrigin::File, |mut builder| {
let transfer = Transfer {
from: Keyring::Alice.to_raw_public().into(),
to: Keyring::Alice.to_raw_public().into(),
from: AccountKeyring::Alice.into(),
to: AccountKeyring::Alice.into(),
amount: 1,
nonce,
};
let signature = Keyring::from_raw_public(transfer.from.to_fixed_bytes()).unwrap().sign(&transfer.encode()).into();
let signature = AccountKeyring::from_public(&transfer.from).unwrap().sign(&transfer.encode()).into();
builder.push(Extrinsic::Transfer(transfer, signature)).unwrap();
nonce = nonce + 1;
builder.bake().unwrap()
@@ -473,7 +472,7 @@ impl<D, S: NetworkSpecialization<Block> + Clone> Peer<D, S> {
}
}
pub fn push_authorities_change_block(&self, new_authorities: Vec<Ed25519AuthorityId>) -> H256 {
pub fn push_authorities_change_block(&self, new_authorities: Vec<AuthorityId>) -> H256 {
self.generate_blocks(1, BlockOrigin::File, |mut builder| {
builder.push(Extrinsic::AuthoritiesChange(new_authorities.clone())).unwrap();
builder.bake().unwrap()
+4
View File
@@ -27,6 +27,8 @@ rand = { version = "0.6", optional = true }
sha2 = { version = "0.8", optional = true }
substrate-bip39 = { git = "https://github.com/paritytech/substrate-bip39", optional = true }
tiny-bip39 = { version = "0.6.0", optional = true }
hex = { version = "0.3", optional = true }
regex = {version = "1.1", optional = true }
[dev-dependencies]
substrate-serializer = { path = "../serializer" }
@@ -55,6 +57,7 @@ std = [
"ring",
"untrusted",
"hex-literal",
"hex",
"base58",
"substrate-bip39",
"tiny-bip39",
@@ -63,4 +66,5 @@ std = [
"rand",
"sha2",
"schnorrkel",
"regex",
]
@@ -1,96 +0,0 @@
// 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/>.
#[cfg(feature = "std")]
use serde::{Serialize, Serializer, Deserialize, Deserializer};
use parity_codec::{Encode, Decode};
use crate::H256;
/// An identifier for an authority in the consensus algorithm. The same size as ed25519::Public.
#[derive(Clone, Copy, PartialEq, Eq, Default, Encode, Decode)]
pub struct Ed25519AuthorityId(pub [u8; 32]);
#[cfg(feature = "std")]
impl ::std::fmt::Display for Ed25519AuthorityId {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
write!(f, "{}", crate::ed25519::Public(self.0).to_ss58check())
}
}
#[cfg(feature = "std")]
impl ::std::fmt::Debug for Ed25519AuthorityId {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
let h = format!("{}", crate::hexdisplay::HexDisplay::from(&self.0));
write!(f, "{} ({}…{})", crate::ed25519::Public(self.0).to_ss58check(), &h[0..8], &h[60..])
}
}
#[cfg(feature = "std")]
impl ::std::hash::Hash for Ed25519AuthorityId {
fn hash<H: ::std::hash::Hasher>(&self, state: &mut H) {
self.0.hash(state);
}
}
impl AsRef<[u8; 32]> for Ed25519AuthorityId {
fn as_ref(&self) -> &[u8; 32] {
&self.0
}
}
impl AsRef<[u8]> for Ed25519AuthorityId {
fn as_ref(&self) -> &[u8] {
&self.0[..]
}
}
impl Into<[u8; 32]> for Ed25519AuthorityId {
fn into(self) -> [u8; 32] {
self.0
}
}
impl From<[u8; 32]> for Ed25519AuthorityId {
fn from(a: [u8; 32]) -> Self {
Ed25519AuthorityId(a)
}
}
impl AsRef<Ed25519AuthorityId> for Ed25519AuthorityId {
fn as_ref(&self) -> &Ed25519AuthorityId {
&self
}
}
impl Into<H256> for Ed25519AuthorityId {
fn into(self) -> H256 {
self.0.into()
}
}
#[cfg(feature = "std")]
impl Serialize for Ed25519AuthorityId {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
crate::ed25519::serialize(&self, serializer)
}
}
#[cfg(feature = "std")]
impl<'de> Deserialize<'de> for Ed25519AuthorityId {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de> {
crate::ed25519::deserialize(deserializer)
}
}
+486
View File
@@ -0,0 +1,486 @@
// 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[]
//! Cryptographic utilities.
// end::description[]
#[cfg(feature = "std")]
use parity_codec::{Encode, Decode};
#[cfg(feature = "std")]
use regex::Regex;
#[cfg(feature = "std")]
use base58::{FromBase58, ToBase58};
/// The infallible type.
#[derive(Debug)]
pub enum Infallible {}
/// The length of the junction identifier. Note that this is also referred to as the
/// `CHAIN_CODE_LENGTH` in the context of Schnorrkel.
#[cfg(feature = "std")]
pub const JUNCTION_ID_LEN: usize = 32;
/// Similar to `From`, except that the onus is on the part of the caller to ensure
/// that data passed in makes sense. Basically, you're not guaranteed to get anything
/// sensible out.
pub trait UncheckedFrom<T> {
/// Convert from an instance of `T` to Self. This is not guaranteed to be
/// whatever counts as a valid instance of `T` and it's up to the caller to
/// ensure that it makes sense.
fn unchecked_from(t: T) -> Self;
}
/// The counterpart to `UncheckedFrom`.
pub trait UncheckedInto<T> {
/// The counterpart to `unchecked_from`.
fn unchecked_into(self) -> T;
}
impl<S, T: UncheckedFrom<S>> UncheckedInto<T> for S {
fn unchecked_into(self) -> T {
T::unchecked_from(self)
}
}
/// An error with the interpretation of a secret.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg(feature = "std")]
pub enum SecretStringError {
/// The overall format was invalid (e.g. the seed phrase contained symbols).
InvalidFormat,
/// The seed phrase provided is not a valid BIP39 phrase.
InvalidPhrase,
/// The supplied password was invalid.
InvalidPassword,
/// The seed is invalid (bad content).
InvalidSeed,
/// The seed has an invalid length.
InvalidSeedLength,
/// The derivation path was invalid (e.g. contains soft junctions when they are not supported).
InvalidPath,
}
/// A since derivation junction description. It is the single parameter used when creating
/// a new secret key from an existing secret key and, in the case of `SoftRaw` and `SoftIndex`
/// a new public key from an existing public key.
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Encode, Decode)]
#[cfg(feature = "std")]
pub enum DeriveJunction {
/// Soft (vanilla) derivation. Public keys have a correspondent derivation.
Soft([u8; JUNCTION_ID_LEN]),
/// Hard ("hardened") derivation. Public keys do not have a correspondent derivation.
Hard([u8; JUNCTION_ID_LEN]),
}
#[cfg(feature = "std")]
impl DeriveJunction {
/// Consume self to return a soft derive junction with the same chain code.
pub fn soften(self) -> Self { DeriveJunction::Soft(self.unwrap_inner()) }
/// Consume self to return a hard derive junction with the same chain code.
pub fn harden(self) -> Self { DeriveJunction::Hard(self.unwrap_inner()) }
/// Create a new soft (vanilla) DeriveJunction from a given, encodable, value.
///
/// If you need a hard junction, use `hard()`.
pub fn soft<T: Encode>(index: T) -> Self {
let mut cc: [u8; JUNCTION_ID_LEN] = Default::default();
index.using_encoded(|data| if data.len() > JUNCTION_ID_LEN {
let hash_result = blake2_rfc::blake2b::blake2b(JUNCTION_ID_LEN, &[], data);
let hash = hash_result.as_bytes();
cc.copy_from_slice(hash);
} else {
cc[0..data.len()].copy_from_slice(data);
});
DeriveJunction::Soft(cc)
}
/// Create a new hard (hardened) DeriveJunction from a given, encodable, value.
///
/// If you need a soft junction, use `soft()`.
pub fn hard<T: Encode>(index: T) -> Self {
Self::soft(index).harden()
}
/// Consume self to return the chain code.
pub fn unwrap_inner(self) -> [u8; JUNCTION_ID_LEN] {
match self {
DeriveJunction::Hard(c) | DeriveJunction::Soft(c) => c,
}
}
/// Get a reference to the inner junction id.
pub fn inner(&self) -> &[u8; JUNCTION_ID_LEN] {
match self {
DeriveJunction::Hard(ref c) | DeriveJunction::Soft(ref c) => c,
}
}
/// Return `true` if the junction is soft.
pub fn is_soft(&self) -> bool {
match *self {
DeriveJunction::Soft(_) => true,
_ => false,
}
}
/// Return `true` if the junction is hard.
pub fn is_hard(&self) -> bool {
match *self {
DeriveJunction::Hard(_) => true,
_ => false,
}
}
}
#[cfg(feature = "std")]
impl<T: AsRef<str>> From<T> for DeriveJunction {
fn from(j: T) -> DeriveJunction {
let j = j.as_ref();
let (code, hard) = if j.starts_with("/") {
(&j[1..], true)
} else {
(j, false)
};
let res = if let Ok(n) = str::parse::<u64>(code) {
// number
DeriveJunction::soft(n)
} else {
// something else
DeriveJunction::soft(code)
};
if hard {
res.harden()
} else {
res
}
}
}
/// 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,
/// Invalid format.
InvalidFormat,
/// Invalid derivation path.
InvalidPath,
}
/// Key that can be encoded to/from SS58.
#[cfg(feature = "std")]
pub trait Ss58Codec: Sized {
/// Some if the string is a properly encoded SS58Check address.
fn from_ss58check(s: &str) -> Result<Self, PublicError>;
/// Some if the string is a properly encoded SS58Check address, optionally with
/// a derivation path following.
fn from_string(s: &str) -> Result<Self, PublicError> { Self::from_ss58check(s) }
/// Return the ss58-check string for this key.
fn to_ss58check(&self) -> String;
}
#[cfg(feature = "std")]
/// Derivable key trait.
pub trait Derive: Sized {
/// Derive a child key from a series of given junctions.
///
/// Will be `None` for public keys if there are any hard junctions in there.
fn derive<Iter: Iterator<Item=DeriveJunction>>(&self, _path: Iter) -> Option<Self> { None }
}
#[cfg(feature = "std")]
impl<T: AsMut<[u8]> + AsRef<[u8]> + Default + Derive> Ss58Codec for T {
fn from_ss58check(s: &str) -> Result<Self, PublicError> {
let mut res = T::default();
let len = res.as_mut().len();
let d = s.from_base58().map_err(|_| PublicError::BadBase58)?; // failure here would be invalid encoding.
if d.len() != len + 3 {
// Invalid length.
return Err(PublicError::BadLength);
}
if d[0] != 42 {
// Invalid version.
return Err(PublicError::UnknownVersion);
}
if d[len+1..len+3] != blake2_rfc::blake2b::blake2b(64, &[], &d[0..len+1]).as_bytes()[0..2] {
// Invalid checksum.
return Err(PublicError::InvalidChecksum);
}
res.as_mut().copy_from_slice(&d[1..len+1]);
Ok(res)
}
fn to_ss58check(&self) -> String {
let mut v = vec![42u8];
v.extend(self.as_ref());
let r = blake2_rfc::blake2b::blake2b(64, &[], &v);
v.extend(&r.as_bytes()[0..2]);
v.to_base58()
}
fn from_string(s: &str) -> Result<Self, PublicError> {
let re = Regex::new(r"^(?P<ss58>[\w\d]+)(?P<path>(//?[^/]+)*)$")
.expect("constructed from known-good static value; qed");
let cap = re.captures(s).ok_or(PublicError::InvalidFormat)?;
let re_junction = Regex::new(r"/(/?[^/]+)")
.expect("constructed from known-good static value; qed");
let path = re_junction.captures_iter(&cap["path"])
.map(|f| DeriveJunction::from(&f[1]));
Self::from_ss58check(&cap["ss58"])?.derive(path).ok_or(PublicError::InvalidPath)
}
}
/// Trait suitable for typical cryptographic PKI key pair type.
///
/// For now it just specifies how to create a key from a phrase and derivation path.
#[cfg(feature = "std")]
pub trait Pair: Sized {
/// TThe type which is used to encode a public key.
type Public;
/// The type used to (minimally) encode the data required to securely create
/// a new key pair.
type Seed;
/// The type used to represent a signature. Can be created from a key pair and a message
/// and verified with the message and a public key.
type Signature;
/// Error returned from the `derive` function.
type DeriveError;
/// Generate new secure (random) key pair.
///
/// This is only for ephemeral keys really, since you won't have access to the secret key
/// for storage. If you want a persistent key pair, use `generate_with_phrase` instead.
fn generate() -> Self;
/// Generate new secure (random) key pair and provide the recovery phrase.
///
/// You can recover the same key later with `from_phrase`.
///
/// This is generally slower than `generate()`, so prefer that unless you need to persist
/// the key from the current session.
fn generate_with_phrase(password: Option<&str>) -> (Self, String);
/// Returns the KeyPair from the English BIP39 seed `phrase`, or `None` if it's invalid.
fn from_phrase(phrase: &str, password: Option<&str>) -> Result<Self, SecretStringError>;
/// Derive a child key from a series of given junctions.
fn derive<Iter: Iterator<Item=DeriveJunction>>(&self, path: Iter) -> Result<Self, Self::DeriveError>;
/// Generate new key pair from the provided `seed`.
///
/// @WARNING: THIS WILL ONLY BE SECURE IF THE `seed` IS SECURE. If it can be guessed
/// by an attacker then they can also derive your key.
fn from_seed(seed: Self::Seed) -> Self;
/// Make a new key pair from secret seed material. The slice must be the correct size or
/// it will return `None`.
///
/// @WARNING: THIS WILL ONLY BE SECURE IF THE `seed` IS SECURE. If it can be guessed
/// by an attacker then they can also derive your key.
fn from_seed_slice(seed: &[u8]) -> Result<Self, SecretStringError>;
/// Construct a key from a phrase, password and path.
fn from_standard_components<
I: Iterator<Item=DeriveJunction>
>(phrase: &str, password: Option<&str>, path: I) -> Result<Self, SecretStringError>;
/// Sign a message.
fn sign(&self, message: &[u8]) -> Self::Signature;
/// Verify a signature on a message. Returns true if the signature is good.
fn verify<P: AsRef<Self::Public>, M: AsRef<[u8]>>(sig: &Self::Signature, message: M, pubkey: P) -> bool;
/// 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;
/// Get the public key.
fn public(&self) -> Self::Public;
/// Interprets the string `s` in order to generate a key Pair.
///
/// This takes a helper function to do the key generation from a phrase, password and
/// junction iterator.
///
/// - If `s` is a possibly `0x` prefixed 64-digit hex string, then it will be interpreted
/// directly as a `MiniSecretKey` (aka "seed" in `subkey`).
/// - If `s` is a valid BIP-39 key phrase of 12, 15, 18, 21 or 24 words, then the key will
/// be derived from it. In this case:
/// - the phrase may be followed by one or more items delimited by `/` characters.
/// - the path may be followed by `///`, in which case everything after the `///` is treated
/// as a password.
/// In this case they are interpreted as HDKD junctions; purely numeric items are interpreted as
/// integers, non-numeric items as strings. Junctions prefixed with `/` are interpreted as soft
/// junctions, and with `//` as hard junctions.
///
/// There is no correspondence mapping between SURI strings and the keys they represent.
/// Two different non-identical strings can actually lead to the same secret being derived.
/// Notably, integer junction indices may be legally prefixed with arbitrary number of zeros.
/// Similarly an empty password (ending the SURI with `///`) is perfectly valid and will generally
/// be equivalent to no password at all.
///
/// `None` is returned if no matches are found.
fn from_string(s: &str, password_override: Option<&str>) -> Result<Self, SecretStringError> {
let hex_seed = if s.starts_with("0x") {
&s[2..]
} else {
s
};
if let Ok(d) = hex::decode(hex_seed) {
if let Ok(r) = Self::from_seed_slice(&d) {
return Ok(r)
}
}
let re = Regex::new(r"^(?P<phrase>\w+( \w+)*)(?P<path>(//?[^/]+)*)(///(?P<password>.*))?$")
.expect("constructed from known-good static value; qed");
let cap = re.captures(s).ok_or(SecretStringError::InvalidFormat)?;
let re_junction = Regex::new(r"/(/?[^/]+)")
.expect("constructed from known-good static value; qed");
let path = re_junction.captures_iter(&cap["path"])
.map(|f| DeriveJunction::from(&f[1]));
Self::from_standard_components(
&cap["phrase"],
password_override.or_else(|| cap.name("password").map(|m| m.as_str())),
path,
)
}
}
#[cfg(test)]
mod tests {
use crate::DeriveJunction;
use hex_literal::{hex, hex_impl};
use super::*;
#[derive(Eq, PartialEq, Debug)]
enum TestPair {
Generated,
GeneratedWithPhrase,
GeneratedFromPhrase{phrase: String, password: Option<String>},
Standard{phrase: String, password: Option<String>, path: Vec<DeriveJunction>},
Seed(Vec<u8>),
}
impl Pair for TestPair {
type Public = ();
type Seed = ();
type Signature = ();
type DeriveError = ();
fn generate() -> Self { TestPair::Generated }
fn generate_with_phrase(_password: Option<&str>) -> (Self, String) { (TestPair::GeneratedWithPhrase, "".into()) }
fn from_phrase(phrase: &str, password: Option<&str>) -> Result<Self, SecretStringError> {
Ok(TestPair::GeneratedFromPhrase{ phrase: phrase.to_owned(), password: password.map(Into::into) })
}
fn derive<Iter: Iterator<Item=DeriveJunction>>(&self, _path: Iter) -> Result<Self, Self::DeriveError> {
Err(())
}
fn from_seed(_seed: Self::Seed) -> Self { TestPair::Seed(vec![]) }
fn sign(&self, _message: &[u8]) -> Self::Signature { () }
fn verify<P: AsRef<Self::Public>, M: AsRef<[u8]>>(_sig: &Self::Signature, _message: M, _pubkey: P) -> bool { true }
fn verify_weak<P: AsRef<[u8]>, M: AsRef<[u8]>>(_sig: &[u8], _message: M, _pubkey: P) -> bool { true }
fn public(&self) -> Self::Public { () }
fn from_standard_components<I: Iterator<Item=DeriveJunction>>(phrase: &str, password: Option<&str>, path: I) -> Result<Self, SecretStringError> {
Ok(TestPair::Standard { phrase: phrase.to_owned(), password: password.map(ToOwned::to_owned), path: path.collect() })
}
fn from_seed_slice(seed: &[u8]) -> Result<Self, SecretStringError> {
Ok(TestPair::Seed(seed.to_owned()))
}
}
#[test]
fn interpret_std_seed_should_work() {
assert_eq!(
TestPair::from_string("0x0123456789abcdef", None),
Ok(TestPair::Seed(hex!["0123456789abcdef"][..].to_owned()))
);
assert_eq!(
TestPair::from_string("0123456789abcdef", None),
Ok(TestPair::Seed(hex!["0123456789abcdef"][..].to_owned()))
);
}
#[test]
fn password_override_should_work() {
assert_eq!(
TestPair::from_string("hello world///password", None),
TestPair::from_string("hello world", Some("password")),
);
assert_eq!(
TestPair::from_string("hello world///password", None),
TestPair::from_string("hello world///other password", Some("password")),
);
}
#[test]
fn interpret_std_secret_string_should_work() {
assert_eq!(
TestPair::from_string("hello world", None),
Ok(TestPair::Standard{phrase: "hello world".to_owned(), password: None, path: vec![]})
);
assert_eq!(
TestPair::from_string("hello world/1", None),
Ok(TestPair::Standard{phrase: "hello world".to_owned(), password: None, path: vec![DeriveJunction::soft(1)]})
);
assert_eq!(
TestPair::from_string("hello world/DOT", None),
Ok(TestPair::Standard{phrase: "hello world".to_owned(), password: None, path: vec![DeriveJunction::soft("DOT")]})
);
assert_eq!(
TestPair::from_string("hello world//1", None),
Ok(TestPair::Standard{phrase: "hello world".to_owned(), password: None, path: vec![DeriveJunction::hard(1)]})
);
assert_eq!(
TestPair::from_string("hello world//DOT", None),
Ok(TestPair::Standard{phrase: "hello world".to_owned(), password: None, path: vec![DeriveJunction::hard("DOT")]})
);
assert_eq!(
TestPair::from_string("hello world//1/DOT", None),
Ok(TestPair::Standard{phrase: "hello world".to_owned(), password: None, path: vec![DeriveJunction::hard(1), DeriveJunction::soft("DOT")]})
);
assert_eq!(
TestPair::from_string("hello world//DOT/1", None),
Ok(TestPair::Standard{phrase: "hello world".to_owned(), password: None, path: vec![DeriveJunction::hard("DOT"), DeriveJunction::soft(1)]})
);
assert_eq!(
TestPair::from_string("hello world///password", None),
Ok(TestPair::Standard{phrase: "hello world".to_owned(), password: Some("password".to_owned()), path: vec![]})
);
assert_eq!(
TestPair::from_string("hello world//1/DOT///password", None),
Ok(TestPair::Standard{phrase: "hello world".to_owned(), password: Some("password".to_owned()), path: vec![DeriveJunction::hard(1), DeriveJunction::soft("DOT")]})
);
assert_eq!(
TestPair::from_string("hello world/1//DOT///password", None),
Ok(TestPair::Standard{phrase: "hello world".to_owned(), password: Some("password".to_owned()), path: vec![DeriveJunction::soft(1), DeriveJunction::hard("DOT")]})
);
}
}
+434 -187
View File
@@ -18,23 +18,241 @@
//! Simple Ed25519 API.
// end::description[]
use untrusted;
use blake2_rfc;
use ring::{rand, signature, signature::KeyPair};
use crate::{hash::H512, Ed25519AuthorityId};
use base58::{ToBase58, FromBase58};
use crate::{hash::H256, hash::H512};
use parity_codec::{Encode, Decode};
#[cfg(feature = "std")]
use serde::{de, Serializer, Deserializer, Deserialize};
use untrusted;
#[cfg(feature = "std")]
use blake2_rfc;
#[cfg(feature = "std")]
use ring::{signature, signature::KeyPair, rand::{SecureRandom, SystemRandom}};
#[cfg(feature = "std")]
use base58::{ToBase58, FromBase58};
#[cfg(feature = "std")]
use substrate_bip39::seed_from_entropy;
#[cfg(feature = "std")]
use bip39::{Mnemonic, Language, MnemonicType};
#[cfg(feature = "std")]
use crate::crypto::{Pair as TraitPair, DeriveJunction, SecretStringError, Derive};
#[cfg(feature = "std")]
use serde::{de, Serializer, Serialize, Deserializer, Deserialize};
use crate::crypto::UncheckedFrom;
/// Alias to 512-bit hash when used in the context of a signature on the relay chain.
pub type Signature = H512;
/// 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 = "std")]
type Seed = [u8; 32];
/// Length of the PKCS#8 encoding of the key.
pub const PKCS_LEN: usize = 85;
/// A public key.
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Decode, Default)]
pub struct Public(pub [u8; 32]);
/// A key pair.
#[cfg(feature = "std")]
pub struct Pair(signature::Ed25519KeyPair, Seed);
#[cfg(feature = "std")]
impl Clone for Pair {
fn clone(&self) -> Self {
Pair::from_seed(self.1.clone())
}
}
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 From<Public> for [u8; 32] {
fn from(x: Public) -> Self {
x.0
}
}
#[cfg(feature = "std")]
impl From<Pair> for Public {
fn from(x: Pair) -> Self {
x.public()
}
}
impl AsRef<Public> for Public {
fn as_ref(&self) -> &Public {
&self
}
}
impl From<Public> for H256 {
fn from(x: Public) -> Self {
x.0.into()
}
}
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())
}
}
#[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 = "std")]
impl ::std::hash::Hash for Public {
fn hash<H: ::std::hash::Hasher>(&self, state: &mut H) {
self.0.hash(state);
}
}
/// A signature (a 512-bit value).
#[derive(Encode, Decode)]
pub struct Signature(pub [u8; 64]);
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[..]
}
}
#[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 = "std")]
impl ::std::hash::Hash for Signature {
fn hash<H: ::std::hash::Hasher>(&self, state: &mut H) {
::std::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.
@@ -43,33 +261,8 @@ pub struct LocalizedSignature {
pub signature: Signature,
}
/// Verify a message without type checking the parameters' types for the right size.
/// Returns true if the signature is good.
pub fn verify<P: AsRef<[u8]>>(sig: &[u8], message: &[u8], public: P) -> bool {
let public_key = untrusted::Input::from(public.as_ref());
let msg = untrusted::Input::from(message);
let sig = untrusted::Input::from(sig);
match signature::verify(&signature::ED25519, public_key, msg, sig) {
Ok(_) => true,
_ => false,
}
}
/// A public key.
#[derive(PartialEq, Eq, Clone, Encode, Decode)]
pub struct Public(pub [u8; 32]);
/// A key pair.
pub struct Pair(signature::Ed25519KeyPair);
impl ::std::hash::Hash for Public {
fn hash<H: ::std::hash::Hasher>(&self, state: &mut H) {
self.0.hash(state);
}
}
/// An error type for SS58 decoding.
#[cfg(feature = "std")]
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
pub enum PublicError {
/// Bad alphabet.
@@ -84,17 +277,55 @@ pub enum PublicError {
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 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!
pub fn from_slice(data: &[u8]) -> Self {
let mut r = [0u8; 32];
r.copy_from_slice(data);
Public(r)
}
/// 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 `Vec<u8>` filled with raw data.
#[cfg(feature = "std")]
pub fn to_raw_vec(self) -> Vec<u8> {
let r: &[u8; 32] = self.as_ref();
r.to_vec()
}
/// Return a slice filled with raw data.
pub fn as_slice(&self) -> &[u8] {
let r: &[u8; 32] = self.as_ref();
&r[..]
}
/// Return a slice filled with raw data.
pub fn as_array_ref(&self) -> &[u8; 32] {
self.as_ref()
}
}
#[cfg(feature = "std")]
impl Derive for Public {}
#[cfg(feature = "std")]
impl Public {
/// Some if the string is a properly encoded SS58Check address.
pub fn from_ss58check(s: &str) -> Result<Self, PublicError> {
let d = s.from_base58().map_err(|_| PublicError::BadBase58)?; // failure here would be invalid encoding.
@@ -113,23 +344,6 @@ impl Public {
Ok(Self::from_slice(&d[1..33]))
}
/// Return a `Vec<u8>` filled with raw data.
pub fn to_raw_vec(self) -> Vec<u8> {
let r: &[u8; 32] = self.as_ref();
r.to_vec()
}
/// Return a slice filled with raw data.
pub fn as_slice(&self) -> &[u8] {
let r: &[u8; 32] = self.as_ref();
&r[..]
}
/// Return a slice filled with raw data.
pub fn as_array_ref(&self) -> &[u8; 32] {
self.as_ref()
}
/// Return the ss58-check string for this key.
pub fn to_ss58check(&self) -> String {
let mut v = vec![42u8];
@@ -140,178 +354,197 @@ impl Public {
}
}
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 Into<[u8; 32]> for Public {
fn into(self) -> [u8; 32] {
self.0
}
}
impl AsRef<Public> for Public {
fn as_ref(&self) -> &Public {
&self
}
}
#[cfg(feature = "std")]
impl AsRef<Pair> for Pair {
fn as_ref(&self) -> &Pair {
&self
}
}
impl Into<Ed25519AuthorityId> for Public {
fn into(self) -> Ed25519AuthorityId {
Ed25519AuthorityId(self.0)
}
/// Derive a single hard junction.
#[cfg(feature = "std")]
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
})
}
impl From<Ed25519AuthorityId> for Public {
fn from(id: Ed25519AuthorityId) -> Self {
Public(id.0)
}
/// An error when deriving a key.
#[cfg(feature = "std")]
pub enum DeriveError {
/// A soft key was found in the path (and is unsupported).
SoftKeyInPath,
}
impl ::std::fmt::Display for Public {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
write!(f, "{}", self.to_ss58check())
}
}
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])
}
}
impl Pair {
/// Generate new secure (random) key pair, yielding it and the corresponding pkcs#8 bytes.
pub fn generate_with_pkcs8() -> (Self, [u8; PKCS_LEN]) {
let rng = rand::SystemRandom::new();
let pkcs8_bytes = signature::Ed25519KeyPair::generate_pkcs8(&rng).expect("system randomness is available; qed");
let pair = Self::from_pkcs8(&pkcs8_bytes.as_ref()).expect("just-generated pkcs#8 data is valid; qed");
let mut out = [0; PKCS_LEN];
out.copy_from_slice(pkcs8_bytes.as_ref());
(pair, out)
}
#[cfg(feature = "std")]
impl TraitPair for Pair {
type Public = Public;
type Seed = Seed;
type Signature = Signature;
type DeriveError = DeriveError;
/// Generate new secure (random) key pair.
pub fn generate() -> Pair {
let (pair, _) = Self::generate_with_pkcs8();
pair
///
/// This is only for ephemeral keys really, since you won't have access to the secret key
/// for storage. If you want a persistent key pair, use `generate_with_phrase` instead.
fn generate() -> Pair {
let mut seed: Seed = Default::default();
SystemRandom::new().fill(seed.as_mut()).expect("system random source should always work! qed");
Self::from_seed(seed)
}
/// Generate from pkcs#8 bytes.
pub fn from_pkcs8(pkcs8_bytes: &[u8]) -> Result<Self, ::ring::error::KeyRejected> {
signature::Ed25519KeyPair::from_pkcs8(untrusted::Input::from(&pkcs8_bytes)).map(Pair)
/// Generate new secure (random) key pair and provide the recovery phrase.
///
/// You can recover the same key later with `from_phrase`.
fn generate_with_phrase(password: Option<&str>) -> (Pair, String) {
let mnemonic = Mnemonic::new(MnemonicType::Words12, Language::English);
let phrase = mnemonic.phrase();
(
Self::from_phrase(phrase, password).expect("All phrases generated by Mnemonic are valid; qed"),
phrase.to_owned(),
)
}
/// Make a new key pair from a seed phrase.
/// NOTE: prefer pkcs#8 unless security doesn't matter -- this is used primarily for tests.
pub fn from_seed(seed: &[u8; 32]) -> Pair {
/// Generate key pair from given recovery phrase and password.
fn from_phrase(phrase: &str, password: Option<&str>) -> Result<Pair, 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)?;
Self::from_seed_slice(&big_seed[0..32])
}
/// 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 {
let key = signature::Ed25519KeyPair::from_seed_unchecked(untrusted::Input::from(&seed[..]))
.expect("seed has valid length; qed");
Pair(key)
Pair(key, seed)
}
/// Sign a message.
pub fn sign(&self, message: &[u8]) -> Signature {
let mut r = [0u8; 64];
r.copy_from_slice(self.0.sign(message).as_ref());
Signature::from(r)
/// 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> {
if seed_slice.len() != 32 {
Err(SecretStringError::InvalidSeedLength)
} else {
let mut seed = [0u8; 32];
seed.copy_from_slice(&seed_slice);
Ok(Self::from_seed(seed))
}
}
/// Derive a child key from a series of given junctions.
fn derive<Iter: Iterator<Item=DeriveJunction>>(&self, path: Iter) -> Result<Pair, DeriveError> {
let mut acc = self.1.clone();
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))
}
/// Generate a key from the phrase, password and derivation path.
fn from_standard_components<I: Iterator<Item=DeriveJunction>>(phrase: &str, password: Option<&str>, path: I) -> Result<Pair, SecretStringError> {
Self::from_phrase(phrase, password)?.derive(path).map_err(|_| SecretStringError::InvalidPath)
}
/// Get the public key.
pub fn public(&self) -> Public {
fn public(&self) -> Public {
let mut r = [0u8; 32];
let pk = self.0.public_key().as_ref();
r.copy_from_slice(pk);
Public(r)
}
}
/// Verify a signature on a message. Returns true if the signature is good.
pub fn verify_strong<P: AsRef<Public>>(sig: &Signature, message: &[u8], pubkey: P) -> bool {
let public_key = untrusted::Input::from(&pubkey.as_ref().0[..]);
let msg = untrusted::Input::from(message);
let sig = untrusted::Input::from(&sig.as_bytes());
/// Sign a message.
fn sign(&self, message: &[u8]) -> Signature {
let mut r = [0u8; 64];
r.copy_from_slice(self.0.sign(message).as_ref());
Signature::from_raw(r)
}
match signature::verify(&signature::ED25519, public_key, msg, sig) {
Ok(_) => true,
_ => false,
/// Verify a signature on a message. Returns true if the signature is good.
fn verify<P: AsRef<Self::Public>, M: AsRef<[u8]>>(sig: &Self::Signature, message: M, pubkey: P) -> bool {
let public_key = untrusted::Input::from(&pubkey.as_ref().0[..]);
let msg = untrusted::Input::from(message.as_ref());
let sig = untrusted::Input::from(&sig.0[..]);
match signature::verify(&signature::ED25519, public_key, msg, sig) {
Ok(_) => true,
_ => 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 public_key = untrusted::Input::from(pubkey.as_ref());
let msg = untrusted::Input::from(message.as_ref());
let sig = untrusted::Input::from(sig);
match signature::verify(&signature::ED25519, public_key, msg, sig) {
Ok(_) => true,
_ => false,
}
}
}
/// Something that acts as a signature allowing a message to be verified.
pub trait Verifiable {
/// Verify something that acts like a signature.
fn verify<P: AsRef<Public>>(&self, message: &[u8], pubkey: P) -> bool;
}
impl Verifiable for Signature {
/// Verify something that acts like a signature.
fn verify<P: AsRef<Public>>(&self, message: &[u8], pubkey: P) -> bool {
verify_strong(&self, message, pubkey)
}
}
impl Verifiable for LocalizedSignature {
fn verify<P: AsRef<Public>>(&self, message: &[u8], pubkey: P) -> bool {
pubkey.as_ref() == &self.signer && self.signature.verify(message, pubkey)
}
}
/// Deserialize from `ss58` into something that can be constructed from `[u8; 32]`.
#[cfg(feature = "std")]
pub fn deserialize<'de, D, T: From<[u8; 32]>>(deserializer: D) -> Result<T, D::Error> where
D: Deserializer<'de>,
{
let ss58 = String::deserialize(deserializer)?;
Public::from_ss58check(&ss58)
.map_err(|e| de::Error::custom(format!("{:?}", e)))
.map(|v| v.0.into())
}
impl Pair {
/// Get the seed for this key.
pub fn seed(&self) -> &Seed {
&self.1
}
/// Serializes something that implements `AsRef<[u8; 32]>` into `ss58`.
#[cfg(feature = "std")]
pub fn serialize<S, T: AsRef<[u8; 32]>>(data: &T, serializer: S) -> Result<S::Ok, S::Error> where
S: Serializer,
{
serializer.serialize_str(&Public(*data.as_ref()).to_ss58check())
/// 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.
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)
})
}
}
#[cfg(test)]
mod test {
use super::*;
use hex_literal::{hex, hex_impl};
fn _test_primitives_signature_and_local_the_same() {
fn takes_two<T>(_: T, _: T) { }
takes_two(Signature::default(), crate::Signature::default())
}
use crate::Pair as _Pair;
#[test]
fn test_vector_should_work() {
let pair: Pair = Pair::from_seed(&hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"));
let pair: Pair = Pair::from_seed(hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"));
let public = pair.public();
assert_eq!(public, Public::from_raw(hex!("d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a")));
let message = b"";
let signature: Signature = hex!("e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e065224901555fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b").into();
let signature = Signature::from_raw(hex!("e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e065224901555fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b"));
assert!(&pair.sign(&message[..]) == &signature);
assert!(verify_strong(&signature, &message[..], &public));
assert!(Pair::verify(&signature, &message[..], &public));
}
#[test]
fn test_vector_by_string_should_work() {
let pair: Pair = Pair::from_string("0x9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", None).unwrap();
let public = pair.public();
assert_eq!(public, Public::from_raw(hex!("d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a")));
let message = b"";
let signature = Signature::from_raw(hex!("e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e065224901555fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b"));
assert!(&pair.sign(&message[..]) == &signature);
assert!(Pair::verify(&signature, &message[..], &public));
}
#[test]
@@ -320,33 +553,47 @@ mod test {
let public = pair.public();
let message = b"Something important";
let signature = pair.sign(&message[..]);
assert!(verify_strong(&signature, &message[..], &public));
assert!(Pair::verify(&signature, &message[..], &public));
}
#[test]
fn seeded_pair_should_work() {
use crate::hexdisplay::HexDisplay;
let pair = Pair::from_seed(b"12345678901234567890123456789012");
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: {}", HexDisplay::from(&signature.as_bytes()));
assert!(verify_strong(&signature, &message[..], &public));
println!("Correct signature: {:?}", signature);
assert!(Pair::verify(&signature, &message[..], &public));
}
#[test]
fn generate_with_pkcs8_recovery_possible() {
let (pair1, pkcs8) = Pair::generate_with_pkcs8();
let pair2 = Pair::from_pkcs8(&pkcs8).unwrap();
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 pair = Pair::from_seed(*b"12345678901234567890123456789012");
let public = pair.public();
let s = public.to_ss58check();
println!("Correct: {}", s);
+5 -9
View File
@@ -49,19 +49,17 @@ pub mod hashing;
pub use hashing::{blake2_256, twox_128, twox_256};
#[cfg(feature = "std")]
pub mod hexdisplay;
#[cfg(feature = "std")]
pub mod ed25519;
#[cfg(feature = "std")]
pub mod sr25519;
pub mod crypto;
pub mod u32_trait;
pub mod ed25519;
pub mod sr25519;
pub mod hash;
mod hasher;
pub mod sandbox;
pub mod storage;
pub mod uint;
mod authority_id;
mod changes_trie;
#[cfg(test)]
@@ -69,17 +67,15 @@ mod tests;
pub use self::hash::{H160, H256, H512, convert_hash};
pub use self::uint::U256;
pub use authority_id::Ed25519AuthorityId;
pub use changes_trie::ChangesTrieConfiguration;
#[cfg(feature = "std")]
pub use crypto::{DeriveJunction, Pair};
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;
/// A 512-bit value interpreted as a signature.
pub type Signature = hash::H512;
/// Hex-serialised shim for `Vec<u8>`.
#[derive(PartialEq, Eq, Clone)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug, Hash, PartialOrd, Ord))]
+402 -316
View File
@@ -16,136 +16,48 @@
// 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[]
use base58::{FromBase58, ToBase58};
#[cfg(feature = "std")]
use blake2_rfc;
#[cfg(feature = "std")]
use rand::rngs::OsRng;
#[cfg(feature = "std")]
use schnorrkel::{signing_context, Keypair, SecretKey, MiniSecretKey, PublicKey,
derive::{Derivation, ChainCode, CHAIN_CODE_LENGTH}
};
#[cfg(feature = "std")]
use substrate_bip39::mini_secret_from_entropy;
//use sha2::Sha512;
#[cfg(feature = "std")]
use bip39::{Mnemonic, Language, MnemonicType};
#[cfg(feature = "std")]
use crate::crypto::{Pair as TraitPair, DeriveJunction, Infallible, SecretStringError, Derive, Ss58Codec};
use crate::{hash::{H256, H512}, crypto::UncheckedFrom};
use parity_codec::{Encode, Decode};
use crate::hash::H512;
use bip39::{Mnemonic, Language};
#[cfg(feature = "std")]
use serde::{de, Deserialize, Deserializer, Serializer};
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
#[cfg(feature = "std")]
use schnorrkel::keys::MINI_SECRET_KEY_LENGTH;
// signing context
const SIGNING_CTX: &'static [u8] = b"substrate transaction";
/// An Schnorrkel/Ristretto x25519 ("sr25519") signature.
///
/// Instead of importing it for the local module, alias it to be available as a public type
pub type Signature = H512;
/// A localized signature also contains sender information.
/// NOTE: Encode and Decode traits are supported in ed25519 but not possible for now here.
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct LocalizedSignature {
/// The signer of the signature.
pub signer: Public,
/// The signature itself.
pub signature: Signature,
}
#[cfg(feature = "std")]
const SIGNING_CTX: &[u8] = b"substrate";
/// An Schnorrkel/Ristretto x25519 ("sr25519") public key.
#[derive(PartialEq, Eq, Clone, Encode, Decode)]
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Decode, Default)]
pub struct Public(pub [u8; 32]);
/// An Schnorrkel/Ristretto x25519 ("sr25519") key pair.
#[cfg(feature = "std")]
pub struct Pair(Keypair);
impl ::std::hash::Hash for Public {
fn hash<H: ::std::hash::Hasher>(&self, state: &mut H) {
self.0.hash(state);
}
}
/// An error type for SS58 decoding.
#[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`.
pub fn from_raw(data: [u8; 32]) -> Self {
Public(data)
}
/// A new instance from the given slice that should be 32 bytes long.
pub fn from_slice(data: &[u8]) -> Self {
let mut r = [0u8; 32];
r.copy_from_slice(data);
Public(r)
}
/// Some if the string is a properly encoded SS58Check address.
pub fn from_ss58check(s: &str) -> Result<Self, PublicError> {
let d = s.from_base58().map_err(|_| PublicError::BadBase58)?; // failure here would be invalid encoding.
if d.len() != 35 {
// Invalid length.
return Err(PublicError::BadLength);
}
if d[0] != 42 {
// Invalid version.
return Err(PublicError::UnknownVersion);
}
if d[33..35] != blake2_rfc::blake2b::blake2b(64, &[], &d[0..33]).as_bytes()[0..2] {
// Invalid checksum.
return Err(PublicError::InvalidChecksum);
}
Ok(Self::from_slice(&d[1..33]))
}
/// Return a `Vec<u8>` filled with raw data.
pub fn to_raw_vec(self) -> Vec<u8> {
let r: &[u8; 32] = self.as_ref();
r.to_vec()
}
/// Return a slice filled with raw data.
pub fn as_slice(&self) -> &[u8] {
let r: &[u8; 32] = self.as_ref();
&r[..]
}
/// Return a slice filled with raw data.
pub fn as_array_ref(&self) -> &[u8; 32] {
self.as_ref()
}
/// Return the ss58-check string for this key.
pub fn to_ss58check(&self) -> String {
let mut v = vec![42u8];
v.extend(self.as_slice());
let r = blake2_rfc::blake2b::blake2b(64, &[], &v);
v.extend(&r.as_bytes()[0..2]);
v.to_base58()
}
/// Derive a child key from a series of given junctions.
///
/// `None` if there are any hard junctions in there.
pub fn derive<Iter: Iterator<Item=DeriveJunction>>(&self, mut 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 AsRef<Public> for Public {
fn as_ref(&self) -> &Public {
&self
}
}
@@ -161,60 +73,44 @@ impl AsRef<[u8]> for Public {
}
}
impl Into<[u8; 32]> for Public {
fn into(self) -> [u8; 32] {
self.0
impl AsMut<[u8]> for Public {
fn as_mut(&mut self) -> &mut [u8] {
&mut self.0[..]
}
}
impl AsRef<Public> for Public {
fn as_ref(&self) -> &Public {
&self
impl From<Public> for [u8; 32] {
fn from(x: Public) -> [u8; 32] {
x.0
}
}
impl AsRef<Pair> for Pair {
fn as_ref(&self) -> &Pair {
&self
impl From<Public> for H256 {
fn from(x: Public) -> H256 {
x.0.into()
}
}
impl From<MiniSecretKey> for Pair {
fn from(sec: MiniSecretKey) -> Pair {
Pair(sec.expand_to_keypair())
impl UncheckedFrom<[u8; 32]> for Public {
fn unchecked_from(x: [u8; 32]) -> Self {
Public::from_raw(x)
}
}
impl From<SecretKey> for Pair {
fn from(sec: SecretKey) -> Pair {
Pair(Keypair::from(sec))
}
}
impl From<schnorrkel::Keypair> for Pair {
fn from(p: schnorrkel::Keypair) -> Pair {
Pair(p)
}
}
impl From<Pair> for schnorrkel::Keypair {
fn from(p: Pair) -> schnorrkel::Keypair {
p.0
}
}
impl AsRef<schnorrkel::Keypair> for Pair {
fn as_ref(&self) -> &schnorrkel::Keypair {
&self.0
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())
}
}
#[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();
@@ -222,81 +118,253 @@ impl ::std::fmt::Debug for Public {
}
}
/// A since derivation junction description. It is the single parameter used when creating
/// a new secret key from an existing secret key and, in the case of `SoftRaw` and `SoftIndex`
/// a new public key from an existing public key.
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Encode, Decode)]
pub enum DeriveJunction {
/// Soft (vanilla) derivation. Public keys have a correspondent derivation.
Soft([u8; CHAIN_CODE_LENGTH]),
/// Hard ("hardened") derivation. Public keys do not have a correspondent derivation.
Hard([u8; CHAIN_CODE_LENGTH]),
#[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())
}
}
impl DeriveJunction {
/// Consume self to return a soft derive junction with the same chain code.
pub fn soften(self) -> Self { DeriveJunction::Soft(self.unwrap_inner()) }
#[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)))
}
}
/// Consume self to return a hard derive junction with the same chain code.
pub fn harden(self) -> Self { DeriveJunction::Hard(self.unwrap_inner()) }
#[cfg(feature = "std")]
impl ::std::hash::Hash for Public {
fn hash<H: ::std::hash::Hasher>(&self, state: &mut H) {
self.0.hash(state);
}
}
/// Create a new soft (vanilla) DeriveJunction from a given, encodable, value.
/// 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)]
pub struct Signature(pub [u8; 64]);
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 = "std")]
impl From<schnorrkel::Signature> for Signature {
fn from(s: schnorrkel::Signature) -> Signature {
Signature(s.to_bytes())
}
}
#[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 = "std")]
impl ::std::hash::Hash for Signature {
fn hash<H: ::std::hash::Hasher>(&self, state: &mut H) {
::std::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`.
///
/// If you need a hard junction, use `hard()`.
pub fn soft<T: Encode>(index: T) -> Self {
let mut cc: [u8; CHAIN_CODE_LENGTH] = Default::default();
index.using_encoded(|data| if data.len() > CHAIN_CODE_LENGTH {
let hash_result = blake2_rfc::blake2b::blake2b(CHAIN_CODE_LENGTH, &[], data);
let hash = hash_result.as_bytes();
cc.copy_from_slice(hash);
} else {
cc[0..data.len()].copy_from_slice(data);
});
DeriveJunction::Soft(cc)
/// 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)
}
/// Create a new hard (hardened) DeriveJunction from a given, encodable, value.
/// A new instance from the given slice that should be 64 bytes long.
///
/// If you need a soft junction, use `soft()`.
pub fn hard<T: Encode>(index: T) -> Self {
Self::soft(index).harden()
/// 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)
}
/// Consume self to return the chain code.
pub fn unwrap_inner(self) -> [u8; CHAIN_CODE_LENGTH] {
match self {
DeriveJunction::Hard(c) | DeriveJunction::Soft(c) => c,
/// 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())
}
}
#[cfg(feature = "std")]
impl Derive for Public {
/// Derive a child key from a series of given junctions.
///
/// `None` if there are any hard junctions in there.
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)
}
/// Consume self to return the chain code.
pub fn unwrap_chain_code(self) -> ChainCode {
ChainCode(self.unwrap_inner())
/// 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!
pub fn from_slice(data: &[u8]) -> Self {
let mut r = [0u8; 32];
r.copy_from_slice(data);
Public(r)
}
/// Return a reference to the chain code.
pub fn chain_code(&self) -> ChainCode {
self.clone().unwrap_chain_code()
/// 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 `true` if the junction is soft.
pub fn is_soft(&self) -> bool {
match *self {
DeriveJunction::Soft(_) => true,
_ => false,
}
/// Return a `Vec<u8>` filled with raw data.
#[cfg(feature = "std")]
pub fn to_raw_vec(self) -> Vec<u8> {
let r: &[u8; 32] = self.as_ref();
r.to_vec()
}
/// Return `true` if the junction is hard.
pub fn is_hard(&self) -> bool {
match *self {
DeriveJunction::Hard(_) => true,
_ => false,
}
/// Return a slice filled with raw data.
pub fn as_slice(&self) -> &[u8] {
let r: &[u8; 32] = self.as_ref();
&r[..]
}
/// Return a slice filled with raw data.
pub fn as_array_ref(&self) -> &[u8; 32] {
self.as_ref()
}
}
#[cfg(feature = "std")]
impl AsRef<Pair> for Pair {
fn as_ref(&self) -> &Pair {
&self
}
}
#[cfg(feature = "std")]
impl From<MiniSecretKey> for Pair {
fn from(sec: MiniSecretKey) -> Pair {
Pair(sec.expand_to_keypair())
}
}
#[cfg(feature = "std")]
impl From<SecretKey> for Pair {
fn from(sec: SecretKey) -> Pair {
Pair(Keypair::from(sec))
}
}
#[cfg(feature = "std")]
impl From<schnorrkel::Keypair> for Pair {
fn from(p: schnorrkel::Keypair) -> Pair {
Pair(p)
}
}
#[cfg(feature = "std")]
impl From<Pair> for schnorrkel::Keypair {
fn from(p: Pair) -> schnorrkel::Keypair {
p.0
}
}
#[cfg(feature = "std")]
impl AsRef<schnorrkel::Keypair> for Pair {
fn as_ref(&self) -> &schnorrkel::Keypair {
&self.0
}
}
/// Derive a single hard junction.
#[cfg(feature = "std")]
fn derive_hard_junction(secret: &SecretKey, cc: &[u8; CHAIN_CODE_LENGTH]) -> SecretKey {
("SchnorrRistrettoHDKD", &secret.to_bytes()[..], cc).using_encoded(|data|
MiniSecretKey::from_bytes(blake2_rfc::blake2b::blake2b(32, &[], data).as_bytes())
@@ -305,173 +373,181 @@ fn derive_hard_junction(secret: &SecretKey, cc: &[u8; CHAIN_CODE_LENGTH]) -> Sec
)
}
impl Pair {
#[cfg(feature = "std")]
type Seed = [u8; MINI_SECRET_KEY_LENGTH];
#[cfg(feature = "std")]
impl TraitPair for Pair {
type Public = Public;
type Seed = Seed;
type Signature = Signature;
type DeriveError = Infallible;
/// Generate new secure (random) key pair.
pub fn generate() -> Pair {
fn generate() -> Pair {
let mut csprng: OsRng = OsRng::new().expect("os random generator works; qed");
let key_pair: Keypair = Keypair::generate(&mut csprng);
Pair(key_pair)
}
/// Make a new key pair from a seed phrase.
/// 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.
pub fn from_seed(seed: &[u8; 32]) -> Pair {
let mini_key: MiniSecretKey = MiniSecretKey::from_bytes(seed)
fn from_seed(seed: Seed) -> Pair {
let mini_key: MiniSecretKey = MiniSecretKey::from_bytes(&seed[..])
.expect("32 bytes can always build a key; qed");
let kp = mini_key.expand_to_keypair();
Pair(kp)
}
/// Make a new key pair from a seed phrase.
/// This is generated using schnorrkel's Mini-Secret-Keys.
/// A MiniSecretKey is literally what Ed25519 calls a SecretKey, which is just 32 random bytes.
/// 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> {
if seed.len() != MINI_SECRET_KEY_LENGTH {
Err(SecretStringError::InvalidSeedLength)
} else {
Ok(Pair(
MiniSecretKey::from_bytes(seed)
.map_err(|_| SecretStringError::InvalidSeed)?
.expand_to_keypair()
))
}
}
/// Generate a key from the phrase, password and derivation path.
fn from_standard_components<I: Iterator<Item=DeriveJunction>>(phrase: &str, password: Option<&str>, path: I) -> Result<Pair, SecretStringError> {
Self::from_phrase(phrase, password)?
.derive(path)
.map_err(|_| SecretStringError::InvalidPath)
}
fn generate_with_phrase(password: Option<&str>) -> (Pair, String) {
let mnemonic = Mnemonic::new(MnemonicType::Words12, Language::English);
let phrase = mnemonic.phrase();
(
Self::from_phrase(phrase, password).expect("All phrases generated by Mnemonic are valid; qed"),
phrase.to_owned(),
)
}
fn from_phrase(phrase: &str, password: Option<&str>) -> Result<Pair, 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) -> Result<Pair, Self::DeriveError> {
let init = self.0.secret.clone();
let result = path.fold(init, |acc, j| match j {
DeriveJunction::Soft(cc) => acc.derived_key_simple(ChainCode(cc), &[]).0,
DeriveJunction::Hard(cc) => derive_hard_junction(&acc, &cc),
});
Ok(Self(result.into()))
}
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<P: AsRef<Self::Public>, M: AsRef<[u8]>>(sig: &Self::Signature, message: M, pubkey: P) -> bool {
let signature: schnorrkel::Signature = match schnorrkel::Signature::from_bytes(&sig.as_ref()) {
Ok(some_signature) => some_signature,
Err(_) => return false
};
match PublicKey::from_bytes(pubkey.as_ref().as_slice()) {
Ok(pk) => pk.verify(
signing_context(SIGNING_CTX).bytes(message.as_ref()), &signature
),
Err(_) => false,
}
}
/// 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 {
let signature: schnorrkel::Signature = match schnorrkel::Signature::from_bytes(sig) {
Ok(some_signature) => some_signature,
Err(_) => return false
};
match PublicKey::from_bytes(pubkey.as_ref()) {
Ok(pk) => pk.verify(
signing_context(SIGNING_CTX).bytes(message.as_ref()), &signature
),
Err(_) => false,
}
}
}
#[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 {
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();
Pair(kp)
}
/// Returns the KeyPair from the English BIP39 seed `phrase`, or `None` if it's invalid.
pub fn from_phrase(phrase: &str, password: Option<&str>) -> Option<Pair> {
Mnemonic::from_phrase(phrase, Language::English)
.ok()
.map(|m| Self::from_entropy(m.entropy(), password))
}
/// Derive a child key from a series of given junctions.
pub fn derive<Iter: Iterator<Item=DeriveJunction>>(&self, mut path: Iter) -> Pair {
let init = self.0.secret.clone();
let result = path.fold(init, |acc, j| match j {
DeriveJunction::Soft(cc) => acc.derived_key_simple(ChainCode(cc), &[]).0,
DeriveJunction::Hard(cc) => derive_hard_junction(&acc, &cc),
});
Self(result.into())
}
/// Sign a message.
pub fn sign(&self, message: &[u8]) -> Signature {
let context = signing_context(SIGNING_CTX);
Signature::from(self.0.sign(context.bytes(message)).to_bytes())
}
/// Get the public key.
pub fn public(&self) -> Public {
let mut pk = [0u8; 32];
pk.copy_from_slice(&self.0.public.to_bytes());
Public(pk)
}
}
/// Verify a signature on a message. Returns true if the signature is good.
pub fn verify_strong<P: AsRef<Public>>(sig: &Signature, message: &[u8], pubkey: P) -> bool {
let signature: schnorrkel::Signature = match schnorrkel::Signature::from_bytes(&sig[..]) {
Ok(some_signature) => some_signature,
Err(_) => return false
};
match PublicKey::from_bytes(pubkey.as_ref().as_slice()) {
Ok(pk) => pk.verify(signing_context(SIGNING_CTX).bytes(message), &signature),
Err(_) => false,
}
}
/// Verify a message without type checking the parameters' types for the right size.
/// Returns true if both the pubkey and the signature is good.
pub fn verify<P: AsRef<[u8]>>(sig: &[u8], message: &[u8], pubkey: P) -> bool {
let signature = match schnorrkel::Signature::from_bytes(&sig[..]) {
Ok(sig) => sig,
Err(_) => return false,
};
match PublicKey::from_bytes(pubkey.as_ref()) {
Ok(pk) => pk.verify_simple(SIGNING_CTX, message, &signature),
Err(_) => false,
}
}
/// Something that acts as a signature allowing a message to be verified.
pub trait Verifiable {
/// Verify something that acts like a signature.
fn verify<P: AsRef<Public>>(&self, message: &[u8], pubkey: P) -> bool;
}
impl Verifiable for Signature {
/// Verify something that acts like a signature.
fn verify<P: AsRef<Public>>(&self, message: &[u8], pubkey: P) -> bool {
verify_strong(&self, message, pubkey)
}
}
impl Verifiable for LocalizedSignature {
fn verify<P: AsRef<Public>>(&self, message: &[u8], pubkey: P) -> bool {
pubkey.as_ref() == &self.signer && self.signature.verify(message, pubkey)
}
}
/// Deserialize from `ss58` into something that can be constructed from `[u8; 32]`.
#[cfg(feature = "std")]
pub fn deserialize<'de, D, T: From<[u8; 32]>>(deserializer: D) -> Result<T, D::Error>
where
D: Deserializer<'de>,
{
let ss58 = String::deserialize(deserializer)?;
Public::from_ss58check(&ss58)
.map_err(|e| de::Error::custom(format!("{:?}", e)))
.map(|v| v.0.into())
}
/// Serializes something that implements `AsRef<[u8; 32]>` into `ss58`.
#[cfg(feature = "std")]
pub fn serialize<S, T: AsRef<[u8; 32]>>(data: &T, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&Public(*data.as_ref()).to_ss58check())
}
#[cfg(test)]
mod test {
use super::*;
use crate::Pair as _Pair;
use hex_literal::{hex, hex_impl};
#[test]
fn derive_soft_should_work() {
let pair: Pair = Pair::from_seed(&hex!(
let pair: Pair = Pair::from_seed(hex!(
"9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"
));
let derive_1 = pair.derive(Some(DeriveJunction::soft(1)).into_iter());
let derive_1b = pair.derive(Some(DeriveJunction::soft(1)).into_iter());
let derive_2 = pair.derive(Some(DeriveJunction::soft(2)).into_iter());
let derive_1 = pair.derive(Some(DeriveJunction::soft(1)).into_iter()).unwrap();
let derive_1b = pair.derive(Some(DeriveJunction::soft(1)).into_iter()).unwrap();
let derive_2 = pair.derive(Some(DeriveJunction::soft(2)).into_iter()).unwrap();
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 = Pair::from_seed(&hex!(
let pair: Pair = Pair::from_seed(hex!(
"9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"
));
let derive_1 = pair.derive(Some(DeriveJunction::hard(1)).into_iter());
let derive_1b = pair.derive(Some(DeriveJunction::hard(1)).into_iter());
let derive_2 = pair.derive(Some(DeriveJunction::hard(2)).into_iter());
let derive_1 = pair.derive(Some(DeriveJunction::hard(1)).into_iter()).unwrap();
let derive_1b = pair.derive(Some(DeriveJunction::hard(1)).into_iter()).unwrap();
let derive_2 = pair.derive(Some(DeriveJunction::hard(2)).into_iter()).unwrap();
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 = Pair::from_seed(&hex!(
let pair: Pair = Pair::from_seed(hex!(
"9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"
));
let path = Some(DeriveJunction::soft(1));
let pair_1 = pair.derive(path.clone().into_iter());
let pair_1 = pair.derive(path.clone().into_iter()).unwrap();
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 = Pair::from_seed(&hex!(
let pair: Pair = Pair::from_seed(hex!(
"9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"
));
let path = Some(DeriveJunction::hard(1));
@@ -480,7 +556,7 @@ mod test {
#[test]
fn sr_test_vector_should_work() {
let pair: Pair = Pair::from_seed(&hex!(
let pair: Pair = Pair::from_seed(hex!(
"9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"
));
let public = pair.public();
@@ -492,8 +568,7 @@ mod test {
);
let message = b"";
let signature = pair.sign(message);
assert!(verify(&signature[..], message, &public.0));
assert!(verify_strong(&signature, &message[..], &public));
assert!(Pair::verify(&signature, &message[..], &public));
}
#[test]
@@ -502,13 +577,13 @@ mod test {
let public = pair.public();
let message = b"Something important";
let signature = pair.sign(&message[..]);
assert!(verify_strong(&signature, &message[..], &public));
assert!(Pair::verify(&signature, &message[..], &public));
}
#[test]
fn seeded_pair_should_work() {
let pair = Pair::from_seed(b"12345678901234567890123456789012");
let pair = Pair::from_seed(*b"12345678901234567890123456789012");
let public = pair.public();
assert_eq!(
public,
@@ -518,7 +593,7 @@ mod test {
);
let message = hex!("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000200d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000");
let signature = pair.sign(&message[..]);
assert!(verify_strong(&signature, &message[..], &public));
assert!(Pair::verify(&signature, &message[..], &public));
}
#[test]
@@ -537,4 +612,15 @@ mod test {
let enc = hex!["090fa15cb5b1666222fff584b4cc2b1761fe1e238346b340491b37e25ea183ff"];
assert_eq!(Public::from_ss58check(k).unwrap(), Public::from_raw(enc));
}
#[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));
}
}
+2
View File
@@ -28,7 +28,9 @@ tokio = "0.1.7"
[dev-dependencies]
assert_matches = "1.1"
futures = "0.1.17"
sr-io = { path = "../sr-io" }
test_client = { package = "substrate-test-client", path = "../test-client" }
test_runtime = { package = "substrate-test-runtime", path = "../test-runtime" }
consensus = { package = "substrate-consensus-common", path = "../consensus/common" }
rustc-hex = "2.0"
hex-literal = "0.1"
+19 -19
View File
@@ -17,27 +17,24 @@
use super::*;
use std::sync::Arc;
use hex_literal::{hex, hex_impl};
use assert_matches::assert_matches;
use parity_codec::Encode;
use transaction_pool::{
txpool::Pool,
ChainApi,
};
use primitives::H256;
use test_client::keyring::Keyring;
use test_client::runtime::{Extrinsic, Transfer};
use test_client;
use primitives::{H256, blake2_256, hexdisplay::HexDisplay};
use test_client::{self, AccountKeyring, runtime::{Extrinsic, Transfer}};
use tokio::runtime;
fn uxt(sender: Keyring, nonce: u64) -> Extrinsic {
fn uxt(sender: AccountKeyring, nonce: u64) -> Extrinsic {
let tx = Transfer {
amount: Default::default(),
nonce,
from: sender.to_raw_public().into(),
from: sender.into(),
to: Default::default(),
};
let signature = Keyring::from_raw_public(tx.from.to_fixed_bytes()).unwrap().sign(&tx.encode()).into();
let signature = AccountKeyring::from_public(&tx.from).unwrap().sign(&tx.encode()).into();
Extrinsic::Transfer(tx, signature)
}
@@ -50,14 +47,15 @@ fn submit_transaction_should_not_cause_error() {
pool: Arc::new(Pool::new(Default::default(), ChainApi::new(client))),
subscriptions: Subscriptions::new(runtime.executor()),
};
let h: H256 = hex!("81897a4890fb7554e7f77c533a865846a11583a56a8ad5e307543188d55e64f1").into();
let xt = uxt(AccountKeyring::Alice, 1).encode();
let h: H256 = blake2_256(&xt).into();
assert_matches!(
AuthorApi::submit_extrinsic(&p, uxt(Keyring::Alice, 1).encode().into()),
AuthorApi::submit_extrinsic(&p, xt.clone().into()),
Ok(h2) if h == h2
);
assert!(
AuthorApi::submit_extrinsic(&p, uxt(Keyring::Alice, 1).encode().into()).is_err()
AuthorApi::submit_extrinsic(&p, xt.into()).is_err()
);
}
@@ -70,14 +68,15 @@ fn submit_rich_transaction_should_not_cause_error() {
pool: Arc::new(Pool::new(Default::default(), ChainApi::new(client.clone()))),
subscriptions: Subscriptions::new(runtime.executor()),
};
let h: H256 = hex!("9ec8469b5dcfe29cc274ac1d07ad73d80be57566ace0fcdbe51ebcf4b51e925b").into();
let xt = uxt(AccountKeyring::Alice, 0).encode();
let h: H256 = blake2_256(&xt).into();
assert_matches!(
AuthorApi::submit_extrinsic(&p, uxt(Keyring::Alice, 0).encode().into()),
AuthorApi::submit_extrinsic(&p, xt.clone().into()),
Ok(h2) if h == h2
);
assert!(
AuthorApi::submit_extrinsic(&p, uxt(Keyring::Alice, 0).encode().into()).is_err()
AuthorApi::submit_extrinsic(&p, xt.into()).is_err()
);
}
@@ -95,7 +94,7 @@ fn should_watch_extrinsic() {
let (subscriber, id_rx, data) = ::jsonrpc_pubsub::typed::Subscriber::new_test("test");
// when
p.watch_extrinsic(Default::default(), subscriber, uxt(Keyring::Alice, 0).encode().into());
p.watch_extrinsic(Default::default(), subscriber, uxt(AccountKeyring::Alice, 0).encode().into());
// then
assert_eq!(runtime.block_on(id_rx), Ok(Ok(1.into())));
@@ -104,10 +103,10 @@ fn should_watch_extrinsic() {
let tx = Transfer {
amount: 5,
nonce: 0,
from: Keyring::Alice.to_raw_public().into(),
from: AccountKeyring::Alice.into(),
to: Default::default(),
};
let signature = Keyring::from_raw_public(tx.from.to_fixed_bytes()).unwrap().sign(&tx.encode()).into();
let signature = AccountKeyring::from_public(&tx.from).unwrap().sign(&tx.encode()).into();
Extrinsic::Transfer(tx, signature)
};
AuthorApi::submit_extrinsic(&p, replacement.encode().into()).unwrap();
@@ -116,9 +115,10 @@ fn should_watch_extrinsic() {
res,
Some(r#"{"jsonrpc":"2.0","method":"test","params":{"result":"ready","subscription":1}}"#.into())
);
let h = blake2_256(&replacement.encode());
assert_eq!(
runtime.block_on(data.into_future()).unwrap().0,
Some(r#"{"jsonrpc":"2.0","method":"test","params":{"result":{"usurped":"0x53daed816610aa6b22dedbcee43aba44a7ca7155cc71f2919c5e79ebbc7de58c"},"subscription":1}}"#.into())
Some(format!(r#"{{"jsonrpc":"2.0","method":"test","params":{{"result":{{"usurped":"0x{}"}},"subscription":1}}}}"#, HexDisplay::from(&h)))
);
}
@@ -132,7 +132,7 @@ fn should_return_pending_extrinsics() {
pool: pool.clone(),
subscriptions: Subscriptions::new(runtime.executor()),
};
let ex = uxt(Keyring::Alice, 0);
let ex = uxt(AccountKeyring::Alice, 0);
AuthorApi::submit_extrinsic(&p, ex.encode().into()).unwrap();
assert_matches!(
p.pending_extrinsics(),
+17 -14
View File
@@ -17,10 +17,10 @@
use super::*;
use self::error::{Error, ErrorKind};
use sr_io::twox_128;
use assert_matches::assert_matches;
use consensus::BlockOrigin;
use rustc_hex::FromHex;
use test_client::{self, runtime, keyring::Keyring, TestClient, BlockBuilderExt};
use test_client::{self, runtime, AccountKeyring, TestClient, BlockBuilderExt};
#[test]
fn should_return_storage() {
@@ -64,8 +64,8 @@ fn should_notify_about_storage_changes() {
let mut builder = api.client.new_block().unwrap();
builder.push_transfer(runtime::Transfer {
from: Keyring::Alice.to_raw_public().into(),
to: Keyring::Ferdie.to_raw_public().into(),
from: AccountKeyring::Alice.into(),
to: AccountKeyring::Ferdie.into(),
amount: 42,
nonce: 0,
}).unwrap();
@@ -88,8 +88,10 @@ fn should_send_initial_storage_changes_and_notifications() {
{
let api = State::new(Arc::new(test_client::new()), Subscriptions::new(remote));
let alice_balance_key = twox_128(&test_runtime::system::balance_of_key(AccountKeyring::Alice.into()));
api.subscribe_storage(Default::default(), subscriber, Some(vec![
StorageKey("a52da2b7c269da1366b3ed1cdb7299ce".from_hex().unwrap()),
StorageKey(alice_balance_key.to_vec()),
]).into());
// assert id assigned
@@ -97,8 +99,8 @@ fn should_send_initial_storage_changes_and_notifications() {
let mut builder = api.client.new_block().unwrap();
builder.push_transfer(runtime::Transfer {
from: Keyring::Alice.to_raw_public().into(),
to: Keyring::Ferdie.to_raw_public().into(),
from: AccountKeyring::Alice.into(),
to: AccountKeyring::Ferdie.into(),
amount: 42,
nonce: 0,
}).unwrap();
@@ -131,8 +133,8 @@ fn should_query_storage() {
let add_block = |nonce| {
let mut builder = client.new_block().unwrap();
builder.push_transfer(runtime::Transfer {
from: Keyring::Alice.to_raw_public().into(),
to: Keyring::Ferdie.to_raw_public().into(),
from: AccountKeyring::Alice.into(),
to: AccountKeyring::Ferdie.into(),
amount: 42,
nonce,
}).unwrap();
@@ -145,13 +147,14 @@ fn should_query_storage() {
let block2_hash = add_block(1);
let genesis_hash = client.genesis_hash();
let alice_balance_key = twox_128(&test_runtime::system::balance_of_key(AccountKeyring::Alice.into()));
let mut expected = vec![
StorageChangeSet {
block: genesis_hash,
changes: vec![
(
StorageKey("a52da2b7c269da1366b3ed1cdb7299ce".from_hex().unwrap()),
StorageKey(alice_balance_key.to_vec()),
Some(StorageData(vec![232, 3, 0, 0, 0, 0, 0, 0]))
),
],
@@ -160,7 +163,7 @@ fn should_query_storage() {
block: block1_hash,
changes: vec![
(
StorageKey("a52da2b7c269da1366b3ed1cdb7299ce".from_hex().unwrap()),
StorageKey(alice_balance_key.to_vec()),
Some(StorageData(vec![190, 3, 0, 0, 0, 0, 0, 0]))
),
],
@@ -169,7 +172,7 @@ fn should_query_storage() {
// Query changes only up to block1
let result = api.query_storage(
vec![StorageKey("a52da2b7c269da1366b3ed1cdb7299ce".from_hex().unwrap())],
vec![StorageKey(alice_balance_key.to_vec())],
genesis_hash,
Some(block1_hash).into(),
);
@@ -178,7 +181,7 @@ fn should_query_storage() {
// Query all changes
let result = api.query_storage(
vec![StorageKey("a52da2b7c269da1366b3ed1cdb7299ce".from_hex().unwrap())],
vec![StorageKey(alice_balance_key.to_vec())],
genesis_hash,
None.into(),
);
@@ -187,7 +190,7 @@ fn should_query_storage() {
block: block2_hash,
changes: vec![
(
StorageKey("a52da2b7c269da1366b3ed1cdb7299ce".from_hex().unwrap()),
StorageKey(alice_balance_key.to_vec()),
Some(StorageData(vec![148, 3, 0, 0, 0, 0, 0, 0]))
),
],
+3 -8
View File
@@ -536,12 +536,7 @@ mod tests {
use super::*;
use parity_codec::Encode;
use consensus_common::BlockOrigin;
use substrate_test_client::{
self,
TestClient,
keyring::Keyring,
runtime::{Extrinsic, Transfer},
};
use substrate_test_client::{self, TestClient, AccountKeyring, runtime::{Extrinsic, Transfer}};
#[test]
fn should_remove_transactions_from_the_pool() {
@@ -551,10 +546,10 @@ mod tests {
let transfer = Transfer {
amount: 5,
nonce: 0,
from: Keyring::Alice.to_raw_public().into(),
from: AccountKeyring::Alice.into(),
to: Default::default(),
};
let signature = Keyring::from_raw_public(transfer.from.to_fixed_bytes()).unwrap().sign(&transfer.encode()).into();
let signature = AccountKeyring::from_public(&transfer.from).unwrap().sign(&transfer.encode()).into();
Extrinsic::Transfer(transfer, signature)
};
// store the transaction in the pool
+2 -1
View File
@@ -34,6 +34,7 @@ use log::{info, warn, debug};
use futures::prelude::*;
use keystore::Store as Keystore;
use client::BlockchainEvents;
use primitives::Pair;
use runtime_primitives::generic::BlockId;
use runtime_primitives::traits::{Header, As};
use exit_future::Signal;
@@ -62,7 +63,7 @@ use components::{StartRPC, MaintainTransactionPool};
#[doc(hidden)]
pub use network::OnDemand;
const DEFAULT_PROTOCOL_ID: &'static str = "sup";
const DEFAULT_PROTOCOL_ID: &str = "sup";
/// Substrate service.
pub struct Service<Components: components::Components> {
+5 -3
View File
@@ -18,7 +18,8 @@
pub use parity_codec as codec;
// re-export hashing functions.
pub use primitives::{
blake2_256, twox_128, twox_256, ed25519, Blake2Hasher, sr25519
blake2_256, twox_128, twox_256, ed25519, Blake2Hasher, sr25519,
Pair
};
pub use tiny_keccak::keccak256 as keccak_256;
// Switch to this after PoC-3
@@ -163,6 +164,7 @@ pub fn storage_changes_root(parent_hash: [u8; 32], parent_num: u64) -> Option<H2
}
/// A trie root formed from the enumerated items.
// TODO: remove (just use `ordered_trie_root`)
pub fn enumerated_trie_root<H>(input: &[&[u8]]) -> H::Out
where
H: Hasher,
@@ -196,12 +198,12 @@ where
/// Verify a ed25519 signature.
pub fn ed25519_verify<P: AsRef<[u8]>>(sig: &[u8; 64], msg: &[u8], pubkey: P) -> bool {
ed25519::verify(sig, msg, pubkey)
ed25519::Pair::verify_weak(sig, msg, pubkey)
}
/// Verify an sr25519 signature.
pub fn sr25519_verify<P: AsRef<[u8]>>(sig: &[u8; 64], msg: &[u8], pubkey: P) -> bool {
sr25519::verify(sig, msg, pubkey)
sr25519::Pair::verify_weak(sig, msg, pubkey)
}
/// Verify and recover a SECP256k1 ECDSA signature.
@@ -24,8 +24,6 @@ use rstd::prelude::*;
use crate::codec::{Decode, Encode, Codec, Input};
use crate::traits::{self, Member, DigestItem as DigestItemT, MaybeHash};
use substrate_primitives::hash::H512 as Signature;
/// Generic header digest.
#[derive(PartialEq, Eq, Clone, Encode, Decode)]
#[cfg_attr(feature = "std", derive(Debug, Serialize))]
@@ -63,7 +61,7 @@ impl<Item> traits::Digest for Digest<Item> where
/// provide opaque access to other items.
#[derive(PartialEq, Eq, Clone)]
#[cfg_attr(feature = "std", derive(Debug))]
pub enum DigestItem<Hash, AuthorityId> {
pub enum DigestItem<Hash, AuthorityId, SealSignature> {
/// System digest item announcing that authorities set has been changed
/// in the block. Contains the new set of authorities.
AuthoritiesChange(Vec<AuthorityId>),
@@ -72,13 +70,13 @@ pub enum DigestItem<Hash, AuthorityId> {
/// trie creation.
ChangesTrieRoot(Hash),
/// Put a Seal on it
Seal(u64, Signature),
Seal(u64, SealSignature),
/// Any 'non-system' digest item, opaque to the native code.
Other(Vec<u8>),
}
#[cfg(feature = "std")]
impl<Hash: Encode, AuthorityId: Encode> ::serde::Serialize for DigestItem<Hash, AuthorityId> {
impl<Hash: Encode, AuthorityId: Encode, SealSignature: Encode> ::serde::Serialize for DigestItem<Hash, AuthorityId, SealSignature> {
fn serialize<S>(&self, seq: S) -> Result<S::Ok, S::Error> where S: ::serde::Serializer {
self.using_encoded(|bytes| {
::substrate_primitives::bytes::serialize(bytes, seq)
@@ -91,13 +89,13 @@ impl<Hash: Encode, AuthorityId: Encode> ::serde::Serialize for DigestItem<Hash,
/// final runtime implementations for encoding/decoding its log items.
#[derive(PartialEq, Eq, Clone)]
#[cfg_attr(feature = "std", derive(Debug))]
pub enum DigestItemRef<'a, Hash: 'a, AuthorityId: 'a> {
pub enum DigestItemRef<'a, Hash: 'a, AuthorityId: 'a, SealSignature: 'a> {
/// Reference to `DigestItem::AuthoritiesChange`.
AuthoritiesChange(&'a [AuthorityId]),
/// Reference to `DigestItem::ChangesTrieRoot`.
ChangesTrieRoot(&'a Hash),
/// A sealed signature for testing
Seal(&'a u64, &'a Signature),
Seal(&'a u64, &'a SealSignature),
/// Any 'non-system' digest item, opaque to the native code.
/// Reference to `DigestItem::Other`.
Other(&'a Vec<u8>),
@@ -116,7 +114,7 @@ enum DigestItemType {
Seal,
}
impl<Hash, AuthorityId> DigestItem<Hash, AuthorityId> {
impl<Hash, AuthorityId, SealSignature> DigestItem<Hash, AuthorityId, SealSignature> {
/// Returns Some if `self` is a `DigestItem::Other`.
pub fn as_other(&self) -> Option<&Vec<u8>> {
match *self {
@@ -126,7 +124,7 @@ impl<Hash, AuthorityId> DigestItem<Hash, AuthorityId> {
}
/// Returns a 'referencing view' for this digest item.
fn dref<'a>(&'a self) -> DigestItemRef<'a, Hash, AuthorityId> {
fn dref<'a>(&'a self) -> DigestItemRef<'a, Hash, AuthorityId, SealSignature> {
match *self {
DigestItem::AuthoritiesChange(ref v) => DigestItemRef::AuthoritiesChange(v),
DigestItem::ChangesTrieRoot(ref v) => DigestItemRef::ChangesTrieRoot(v),
@@ -139,7 +137,8 @@ impl<Hash, AuthorityId> DigestItem<Hash, AuthorityId> {
impl<
Hash: Codec + Member,
AuthorityId: Codec + Member + MaybeHash,
> traits::DigestItem for DigestItem<Hash, AuthorityId> {
SealSignature: Codec + Member,
> traits::DigestItem for DigestItem<Hash, AuthorityId, SealSignature> {
type Hash = Hash;
type AuthorityId = AuthorityId;
@@ -152,13 +151,13 @@ impl<
}
}
impl<Hash: Encode, AuthorityId: Encode> Encode for DigestItem<Hash, AuthorityId> {
impl<Hash: Encode, AuthorityId: Encode, SealSignature: Encode> Encode for DigestItem<Hash, AuthorityId, SealSignature> {
fn encode(&self) -> Vec<u8> {
self.dref().encode()
}
}
impl<Hash: Decode, AuthorityId: Decode> Decode for DigestItem<Hash, AuthorityId> {
impl<Hash: Decode, AuthorityId: Decode, SealSignature: Decode> Decode for DigestItem<Hash, AuthorityId, SealSignature> {
fn decode<I: Input>(input: &mut I) -> Option<Self> {
let item_type: DigestItemType = Decode::decode(input)?;
match item_type {
@@ -169,7 +168,7 @@ impl<Hash: Decode, AuthorityId: Decode> Decode for DigestItem<Hash, AuthorityId>
Decode::decode(input)?,
)),
DigestItemType::Seal => {
let vals: (u64, Signature) = Decode::decode(input)?;
let vals: (u64, SealSignature) = Decode::decode(input)?;
Some(DigestItem::Seal(vals.0, vals.1))
},
DigestItemType::Other => Some(DigestItem::Other(
@@ -179,7 +178,7 @@ impl<Hash: Decode, AuthorityId: Decode> Decode for DigestItem<Hash, AuthorityId>
}
}
impl<'a, Hash: Codec + Member, AuthorityId: Codec + Member> DigestItemRef<'a, Hash, AuthorityId> {
impl<'a, Hash: Codec + Member, AuthorityId: Codec + Member, SealSignature: Codec + Member> DigestItemRef<'a, Hash, AuthorityId, SealSignature> {
/// Cast this digest item into `AuthoritiesChange`.
pub fn as_authorities_change(&self) -> Option<&'a [AuthorityId]> {
match *self {
@@ -197,7 +196,7 @@ impl<'a, Hash: Codec + Member, AuthorityId: Codec + Member> DigestItemRef<'a, Ha
}
}
impl<'a, Hash: Encode, AuthorityId: Encode> Encode for DigestItemRef<'a, Hash, AuthorityId> {
impl<'a, Hash: Encode, AuthorityId: Encode, SealSignature: Encode> Encode for DigestItemRef<'a, Hash, AuthorityId, SealSignature> {
fn encode(&self) -> Vec<u8> {
let mut v = Vec::new();
@@ -227,6 +226,7 @@ impl<'a, Hash: Encode, AuthorityId: Encode> Encode for DigestItemRef<'a, Hash, A
#[cfg(test)]
mod tests {
use super::*;
use substrate_primitives::hash::H512 as Signature;
#[test]
fn should_serialize_digest() {
@@ -17,12 +17,12 @@
//! Tests for the generic implementations of Extrinsic/Header/Block.
use crate::codec::{Decode, Encode};
use substrate_primitives::H256;
use substrate_primitives::{H256, H512};
use super::DigestItem;
#[test]
fn system_digest_item_encoding() {
let item = DigestItem::AuthoritiesChange::<H256, u32>(vec![10, 20, 30]);
let item = DigestItem::AuthoritiesChange::<H256, u32, H512>(vec![10, 20, 30]);
let encoded = item.encode();
assert_eq!(encoded, vec![
// type = DigestItemType::AuthoritiesChange
@@ -35,13 +35,13 @@ fn system_digest_item_encoding() {
30, 0, 0, 0,
]);
let decoded: DigestItem<H256, u32> = Decode::decode(&mut &encoded[..]).unwrap();
let decoded: DigestItem<H256, u32, H512> = Decode::decode(&mut &encoded[..]).unwrap();
assert_eq!(item, decoded);
}
#[test]
fn non_system_digest_item_encoding() {
let item = DigestItem::Other::<H256, u32>(vec![10, 20, 30]);
let item = DigestItem::Other::<H256, u32, H512>(vec![10, 20, 30]);
let encoded = item.encode();
assert_eq!(encoded, vec![
// type = DigestItemType::Other
@@ -52,6 +52,6 @@ fn non_system_digest_item_encoding() {
10, 20, 30,
]);
let decoded: DigestItem<H256, u32> = Decode::decode(&mut &encoded[..]).unwrap();
let decoded: DigestItem<H256, u32, H512> = Decode::decode(&mut &encoded[..]).unwrap();
assert_eq!(item, decoded);
}
+59 -34
View File
@@ -30,7 +30,7 @@ pub use serde_derive;
pub use runtime_io::{StorageOverlay, ChildrenStorageOverlay};
use rstd::prelude::*;
use substrate_primitives::hash::{H256, H512};
use substrate_primitives::{ed25519, sr25519, hash::{H256, H512}};
use codec::{Encode, Decode};
#[cfg(feature = "std")]
@@ -251,39 +251,64 @@ impl From<codec::Compact<Perbill>> for Perbill {
}
}
/// Ed25519 signature verify.
/// Signature verify that can work with any known signature types..
#[derive(Eq, PartialEq, Clone, Encode, Decode)]
#[cfg_attr(feature = "std", derive(Debug))]
pub enum MultiSignature {
/// An Ed25519 signature.
Ed25519(ed25519::Signature),
/// An Sr25519 signature.
Sr25519(sr25519::Signature),
}
impl Default for MultiSignature {
fn default() -> Self {
MultiSignature::Ed25519(Default::default())
}
}
/// Public key for any known crypto algorithm.
#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Encode, Decode)]
#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))]
pub enum MultiSigner {
/// An Ed25519 identity.
Ed25519(ed25519::Public),
/// An Sr25519 identity.
Sr25519(sr25519::Public),
}
impl Default for MultiSigner {
fn default() -> Self {
MultiSigner::Ed25519(Default::default())
}
}
impl Verify for MultiSignature {
type Signer = MultiSigner;
fn verify<L: Lazy<[u8]>>(&self, msg: L, signer: &Self::Signer) -> bool {
match (self, signer) {
(MultiSignature::Ed25519(ref sig), &MultiSigner::Ed25519(ref who)) => sig.verify(msg, who),
(MultiSignature::Sr25519(ref sig), &MultiSigner::Sr25519(ref who)) => sig.verify(msg, who),
_ => false,
}
}
}
/// Signature verify that can work with any known signature types..
#[derive(Eq, PartialEq, Clone, Default, Encode, Decode)]
#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))]
pub struct Ed25519Signature(pub H512);
pub struct AnySignature(H512);
impl Verify for Ed25519Signature {
type Signer = H256;
fn verify<L: Lazy<[u8]>>(&self, mut msg: L, signer: &Self::Signer) -> bool {
runtime_io::ed25519_verify((self.0).as_fixed_bytes(), msg.get(), &signer.as_bytes())
}
}
impl From<H512> for Ed25519Signature {
fn from(h: H512) -> Ed25519Signature {
Ed25519Signature(h)
}
}
/// Sr25519 signature verify.
#[derive(Eq, PartialEq, Clone, Default, Encode, Decode)]
/// Public key for any known crypto algorithm.
#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Default, Encode, Decode)]
#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))]
pub struct Sr25519Signature(pub H512);
pub struct AnySigner(H256);
impl Verify for Sr25519Signature {
type Signer = H256;
fn verify<L: Lazy<[u8]>>(&self, mut msg: L, signer: &Self::Signer) -> bool {
runtime_io::sr25519_verify((self.0).as_fixed_bytes(), msg.get(), &signer.as_bytes())
}
}
impl From<H512> for Sr25519Signature {
fn from(h: H512) -> Sr25519Signature {
Sr25519Signature(h)
impl Verify for AnySignature {
type Signer = AnySigner;
fn verify<L: Lazy<[u8]>>(&self, mut msg: L, signer: &AnySigner) -> bool {
runtime_io::sr25519_verify(self.0.as_fixed_bytes(), msg.get(), &signer.0.as_bytes()) ||
runtime_io::ed25519_verify(self.0.as_fixed_bytes(), msg.get(), &signer.0.as_bytes())
}
}
@@ -581,7 +606,7 @@ impl traits::Extrinsic for OpaqueExtrinsic {
#[cfg(test)]
mod tests {
use substrate_primitives::hash::H256;
use substrate_primitives::hash::{H256, H512};
use crate::codec::{Encode, Decode};
use crate::traits::DigestItem;
@@ -616,7 +641,7 @@ mod tests {
}
impl_outer_log! {
pub enum Log(InternalLog: DigestItem<H256, u64>) for Runtime {
pub enum Log(InternalLog: DigestItem<H256, u64, H512>) for Runtime {
a(AuthoritiesChange), b()
}
}
@@ -636,16 +661,16 @@ mod tests {
assert_eq!(auth_change, decoded_auth_change);
// interpret regular item using `generic::DigestItem`
let generic_b1: super::generic::DigestItem<H256, u64> = Decode::decode(&mut &encoded_b1[..]).unwrap();
let generic_b1: super::generic::DigestItem<H256, u64, H512> = Decode::decode(&mut &encoded_b1[..]).unwrap();
match generic_b1 {
super::generic::DigestItem::Other(_) => (),
_ => panic!("unexpected generic_b1: {:?}", generic_b1),
}
// interpret system item using `generic::DigestItem`
let generic_auth_change: super::generic::DigestItem<H256, u64> = Decode::decode(&mut &encoded_auth_change[..]).unwrap();
let generic_auth_change: super::generic::DigestItem<H256, u64, H512> = Decode::decode(&mut &encoded_auth_change[..]).unwrap();
match generic_auth_change {
super::generic::DigestItem::AuthoritiesChange::<H256, u64>(authorities) => assert_eq!(authorities, vec![100, 200, 300]),
super::generic::DigestItem::AuthoritiesChange::<H256, u64, H512>(authorities) => assert_eq!(authorities, vec![100, 200, 300]),
_ => panic!("unexpected generic_auth_change: {:?}", generic_auth_change),
}
+9 -9
View File
@@ -24,30 +24,30 @@ use std::{fmt::Debug, ops::Deref, fmt};
use crate::codec::{Codec, Encode, Decode};
use crate::traits::{self, Checkable, Applyable, BlakeTwo256, Convert};
use crate::generic::DigestItem as GenDigestItem;
pub use substrate_primitives::{H256, Ed25519AuthorityId};
pub use substrate_primitives::H256;
use substrate_primitives::U256;
use substrate_primitives::ed25519::{Public as AuthorityId, Signature as AuthoritySignature};
/// Authority Id
#[derive(Default, PartialEq, Eq, Clone, Encode, Decode, Debug)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub struct UintAuthorityId(pub u64);
impl Into<Ed25519AuthorityId> for UintAuthorityId {
fn into(self) -> Ed25519AuthorityId {
impl Into<AuthorityId> for UintAuthorityId {
fn into(self) -> AuthorityId {
let bytes: [u8; 32] = U256::from(self.0).into();
Ed25519AuthorityId(bytes)
AuthorityId(bytes)
}
}
/// Converter between u64 and the AuthorityId wrapper type.
pub struct ConvertUintAuthorityId;
impl Convert<u64, UintAuthorityId> for ConvertUintAuthorityId {
fn convert(a: u64) -> UintAuthorityId {
UintAuthorityId(a)
impl Convert<u64, Option<UintAuthorityId>> for ConvertUintAuthorityId {
fn convert(a: u64) -> Option<UintAuthorityId> {
Some(UintAuthorityId(a))
}
}
/// Digest item
pub type DigestItem = GenDigestItem<H256, Ed25519AuthorityId>;
pub type DigestItem = GenDigestItem<H256, AuthorityId, AuthoritySignature>;
/// Header Digest
#[derive(Default, PartialEq, Eq, Clone, Serialize, Debug, Encode, Decode)]
+24 -9
View File
@@ -55,6 +55,20 @@ pub trait Verify {
fn verify<L: Lazy<[u8]>>(&self, msg: L, signer: &Self::Signer) -> bool;
}
impl Verify for substrate_primitives::ed25519::Signature {
type Signer = substrate_primitives::ed25519::Public;
fn verify<L: Lazy<[u8]>>(&self, mut msg: L, signer: &Self::Signer) -> bool {
runtime_io::ed25519_verify(self.as_ref(), msg.get(), signer)
}
}
impl Verify for substrate_primitives::sr25519::Signature {
type Signer = substrate_primitives::sr25519::Public;
fn verify<L: Lazy<[u8]>>(&self, mut msg: L, signer: &Self::Signer) -> bool {
runtime_io::sr25519_verify(self.as_ref(), msg.get(), signer)
}
}
/// Some sort of check on the origin is performed by this object.
pub trait EnsureOrigin<OuterOrigin> {
/// A return type.
@@ -134,6 +148,16 @@ pub trait Convert<A, B> {
fn convert(a: A) -> B;
}
impl<A, B: Default> Convert<A, B> for () {
fn convert(_: A) -> B { Default::default() }
}
/// A structure that performs identity conversion.
pub struct Identity;
impl<T> Convert<T, T> for Identity {
fn convert(a: T) -> T { a }
}
/// Simple trait similar to `Into`, except that it can be used to convert numerics between each
/// other.
pub trait As<T> {
@@ -161,15 +185,6 @@ macro_rules! impl_numerics {
impl_numerics!(u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize);
/// A structure that performs identity conversion.
pub struct Identity;
impl<T> Convert<T, T> for Identity {
fn convert(a: T) -> T { a }
}
impl<T> Convert<T, ()> for () {
fn convert(_: T) -> () { () }
}
/// A meta trait for arithmetic.
pub trait SimpleArithmetic:
Zero + One + IntegerSquareRoot + As<u64> +
+1 -1
View File
@@ -26,7 +26,7 @@ use primitives::storage::well_known_keys::is_child_storage_key;
use trie::{MemoryDB, TrieDBMut, TrieMut, default_child_trie_root, is_child_trie_key_valid};
use heapsize::HeapSizeOf;
const EXT_NOT_ALLOWED_TO_FAIL: &'static str = "Externalities not allowed to fail within runtime";
const EXT_NOT_ALLOWED_TO_FAIL: &str = "Externalities not allowed to fail within runtime";
/// Errors that can occur when interacting with the externalities.
#[derive(Debug, Copy, Clone)]
@@ -17,7 +17,7 @@
//! Block Builder extensions for tests.
use client;
use keyring;
use super::AccountKeyring;
use runtime;
use runtime_primitives::traits::ProvideRuntimeApi;
use client::block_builder::api::BlockBuilder;
@@ -38,9 +38,8 @@ impl<'a, A> BlockBuilderExt for client::block_builder::BlockBuilder<'a, runtime:
}
fn sign_tx(transfer: runtime::Transfer) -> runtime::Extrinsic {
let signature = keyring::Keyring::from_raw_public(transfer.from.to_fixed_bytes())
let signature = AccountKeyring::from_public(&transfer.from)
.unwrap()
.sign(&parity_codec::Encode::encode(&transfer))
.into();
.sign(&parity_codec::Encode::encode(&transfer));
runtime::Extrinsic::Transfer(transfer, signature)
}
+11 -6
View File
@@ -29,9 +29,9 @@ pub use client::ExecutionStrategies;
pub use client::blockchain;
pub use client::backend;
pub use executor::NativeExecutor;
pub use keyring;
pub use runtime;
pub use consensus;
pub use keyring::{AuthorityKeyring, AccountKeyring};
use std::sync::Arc;
use futures::future::FutureResult;
@@ -39,7 +39,6 @@ use primitives::Blake2Hasher;
use runtime_primitives::StorageOverlay;
use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, Hash as HashT, NumberFor};
use runtime::genesismap::{GenesisConfig, additional_storage_with_genesis};
use keyring::Keyring;
use state_machine::ExecutionStrategy;
use client::LocalCallExecutor;
@@ -165,10 +164,16 @@ pub fn new_with_backend<B>(
fn genesis_config(support_changes_trie: bool) -> GenesisConfig {
GenesisConfig::new(support_changes_trie, vec![
Keyring::Alice.to_raw_public().into(),
Keyring::Bob.to_raw_public().into(),
Keyring::Charlie.to_raw_public().into(),
], 1000)
AuthorityKeyring::Alice.into(),
AuthorityKeyring::Bob.into(),
AuthorityKeyring::Charlie.into(),
], vec![
AccountKeyring::Alice.into(),
AccountKeyring::Bob.into(),
AccountKeyring::Charlie.into(),
],
1000
)
}
fn genesis_storage(support_changes_trie: bool) -> StorageOverlay {
+19 -20
View File
@@ -20,10 +20,9 @@
#![allow(missing_docs)]
use std::sync::Arc;
use keyring::Keyring;
use consensus::BlockOrigin;
use primitives::Blake2Hasher;
use crate::TestClient;
use crate::{TestClient, AccountKeyring};
use runtime_primitives::traits::Block as BlockT;
use crate::backend;
use crate::blockchain::{Backend as BlockChainBackendT, HeaderBackend};
@@ -88,8 +87,8 @@ pub fn test_leaves_for_backend<B: 'static>(backend: Arc<B>) where
let mut builder = client.new_block_at(&BlockId::Hash(a1.hash())).unwrap();
// this push is required as otherwise B2 has the same hash as A2 and won't get imported
builder.push_transfer(Transfer {
from: Keyring::Alice.to_raw_public().into(),
to: Keyring::Ferdie.to_raw_public().into(),
from: AccountKeyring::Alice.into(),
to: AccountKeyring::Ferdie.into(),
amount: 41,
nonce: 0,
}).unwrap();
@@ -117,8 +116,8 @@ pub fn test_leaves_for_backend<B: 'static>(backend: Arc<B>) where
let mut builder = client.new_block_at(&BlockId::Hash(b2.hash())).unwrap();
// this push is required as otherwise C3 has the same hash as B3 and won't get imported
builder.push_transfer(Transfer {
from: Keyring::Alice.to_raw_public().into(),
to: Keyring::Ferdie.to_raw_public().into(),
from: AccountKeyring::Alice.into(),
to: AccountKeyring::Ferdie.into(),
amount: 1,
nonce: 1,
}).unwrap();
@@ -132,8 +131,8 @@ pub fn test_leaves_for_backend<B: 'static>(backend: Arc<B>) where
let mut builder = client.new_block_at(&BlockId::Hash(a1.hash())).unwrap();
// this push is required as otherwise D2 has the same hash as B2 and won't get imported
builder.push_transfer(Transfer {
from: Keyring::Alice.to_raw_public().into(),
to: Keyring::Ferdie.to_raw_public().into(),
from: AccountKeyring::Alice.into(),
to: AccountKeyring::Ferdie.into(),
amount: 1,
nonce: 0,
}).unwrap();
@@ -180,8 +179,8 @@ pub fn test_children_for_backend<B: 'static>(backend: Arc<B>) where
let mut builder = client.new_block_at(&BlockId::Hash(a1.hash())).unwrap();
// this push is required as otherwise B2 has the same hash as A2 and won't get imported
builder.push_transfer(Transfer {
from: Keyring::Alice.to_raw_public().into(),
to: Keyring::Ferdie.to_raw_public().into(),
from: AccountKeyring::Alice.into(),
to: AccountKeyring::Ferdie.into(),
amount: 41,
nonce: 0,
}).unwrap();
@@ -200,8 +199,8 @@ pub fn test_children_for_backend<B: 'static>(backend: Arc<B>) where
let mut builder = client.new_block_at(&BlockId::Hash(b2.hash())).unwrap();
// this push is required as otherwise C3 has the same hash as B3 and won't get imported
builder.push_transfer(Transfer {
from: Keyring::Alice.to_raw_public().into(),
to: Keyring::Ferdie.to_raw_public().into(),
from: AccountKeyring::Alice.into(),
to: AccountKeyring::Ferdie.into(),
amount: 1,
nonce: 1,
}).unwrap();
@@ -212,8 +211,8 @@ pub fn test_children_for_backend<B: 'static>(backend: Arc<B>) where
let mut builder = client.new_block_at(&BlockId::Hash(a1.hash())).unwrap();
// this push is required as otherwise D2 has the same hash as B2 and won't get imported
builder.push_transfer(Transfer {
from: Keyring::Alice.to_raw_public().into(),
to: Keyring::Ferdie.to_raw_public().into(),
from: AccountKeyring::Alice.into(),
to: AccountKeyring::Ferdie.into(),
amount: 1,
nonce: 0,
}).unwrap();
@@ -269,8 +268,8 @@ pub fn test_blockchain_query_by_number_gets_canonical<B: 'static>(backend: Arc<B
let mut builder = client.new_block_at(&BlockId::Hash(a1.hash())).unwrap();
// this push is required as otherwise B2 has the same hash as A2 and won't get imported
builder.push_transfer(Transfer {
from: Keyring::Alice.to_raw_public().into(),
to: Keyring::Ferdie.to_raw_public().into(),
from: AccountKeyring::Alice.into(),
to: AccountKeyring::Ferdie.into(),
amount: 41,
nonce: 0,
}).unwrap();
@@ -289,8 +288,8 @@ pub fn test_blockchain_query_by_number_gets_canonical<B: 'static>(backend: Arc<B
let mut builder = client.new_block_at(&BlockId::Hash(b2.hash())).unwrap();
// this push is required as otherwise C3 has the same hash as B3 and won't get imported
builder.push_transfer(Transfer {
from: Keyring::Alice.to_raw_public().into(),
to: Keyring::Ferdie.to_raw_public().into(),
from: AccountKeyring::Alice.into(),
to: AccountKeyring::Ferdie.into(),
amount: 1,
nonce: 1,
}).unwrap();
@@ -301,8 +300,8 @@ pub fn test_blockchain_query_by_number_gets_canonical<B: 'static>(backend: Arc<B
let mut builder = client.new_block_at(&BlockId::Hash(a1.hash())).unwrap();
// this push is required as otherwise D2 has the same hash as B2 and won't get imported
builder.push_transfer(Transfer {
from: Keyring::Alice.to_raw_public().into(),
to: Keyring::Ferdie.to_raw_public().into(),
from: AccountKeyring::Alice.into(),
to: AccountKeyring::Ferdie.into(),
amount: 1,
nonce: 0,
}).unwrap();
+1
View File
@@ -24,6 +24,7 @@ cfg-if = "0.1.6"
[dev-dependencies]
substrate-executor = { path = "../executor" }
substrate-test-client = { path = "../test-client" }
[features]
default = ["std"]
+8 -11
View File
@@ -18,38 +18,35 @@
use std::collections::HashMap;
use runtime_io::twox_128;
use super::AccountId;
use parity_codec::{Encode, KeyedVec, Joiner};
use primitives::{Ed25519AuthorityId, ChangesTrieConfiguration, map};
use primitives::storage::well_known_keys;
use primitives::{ChangesTrieConfiguration, map, storage::well_known_keys};
use runtime_primitives::traits::Block;
use primitives::ed25519::Public as AuthorityId;
/// Configuration of a general Substrate test genesis block.
pub struct GenesisConfig {
pub changes_trie_config: Option<ChangesTrieConfiguration>,
pub authorities: Vec<Ed25519AuthorityId>,
pub balances: Vec<(Ed25519AuthorityId, u64)>,
pub authorities: Vec<AuthorityId>,
pub balances: Vec<(AccountId, u64)>,
}
impl GenesisConfig {
pub fn new_simple(authorities: Vec<Ed25519AuthorityId>, balance: u64) -> Self {
Self::new(false, authorities, balance)
}
pub fn new(support_changes_trie: bool, authorities: Vec<Ed25519AuthorityId>, balance: u64) -> Self {
pub fn new(support_changes_trie: bool, authorities: Vec<AuthorityId>, endowed_accounts: Vec<AccountId>, balance: u64) -> Self {
GenesisConfig {
changes_trie_config: match support_changes_trie {
true => Some(super::changes_trie_config()),
false => None,
},
authorities: authorities.clone(),
balances: authorities.into_iter().map(|a| (a, balance)).collect(),
balances: endowed_accounts.into_iter().map(|a| (a, balance)).collect(),
}
}
pub fn genesis_map(&self) -> HashMap<Vec<u8>, Vec<u8>> {
let wasm_runtime = include_bytes!("../wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm").to_vec();
let mut map: HashMap<Vec<u8>, Vec<u8>> = self.balances.iter()
.map(|&(account, balance)| (account.to_keyed_vec(b"balance:"), vec![].and(&balance)))
.map(|&(ref account, balance)| (account.to_keyed_vec(b"balance:"), vec![].and(&balance)))
.map(|(k, v)| (twox_128(&k[..])[..].to_vec(), v.to_vec()))
.chain(vec![
(well_known_keys::CODE.into(), wasm_runtime),
+14 -8
View File
@@ -29,7 +29,7 @@ use substrate_client::{
impl_runtime_apis,
};
use runtime_primitives::{
ApplyResult, Ed25519Signature, transaction_validity::TransactionValidity,
ApplyResult, transaction_validity::TransactionValidity,
create_runtime_str,
traits::{
BlindCheckable, BlakeTwo256, Block as BlockT, Extrinsic as ExtrinsicT,
@@ -38,7 +38,7 @@ use runtime_primitives::{
};
use runtime_version::RuntimeVersion;
pub use primitives::hash::H256;
use primitives::{Ed25519AuthorityId, OpaqueMetadata};
use primitives::{ed25519, sr25519, OpaqueMetadata};
#[cfg(any(feature = "std", test))]
use runtime_version::NativeVersion;
use inherents::{CheckInherentsResult, InherentData};
@@ -81,8 +81,8 @@ pub struct Transfer {
#[derive(Clone, PartialEq, Eq, Encode, Decode)]
#[cfg_attr(feature = "std", derive(Debug))]
pub enum Extrinsic {
AuthoritiesChange(Vec<Ed25519AuthorityId>),
Transfer(Transfer, Ed25519Signature),
AuthoritiesChange(Vec<AuthorityId>),
Transfer(Transfer, AccountSignature),
}
#[cfg(feature = "std")]
@@ -125,8 +125,14 @@ impl Extrinsic {
}
}
// The identity type used by authorities.
pub type AuthorityId = ed25519::Public;
// The signature type used by authorities.
pub type AuthoritySignature = ed25519::Signature;
/// An identifier for an account on this system.
pub type AccountId = H256;
pub type AccountId = sr25519::Public;
// The signature type used by accounts/transactions.
pub type AccountSignature = sr25519::Signature;
/// A simple hash type for all our hashing.
pub type Hash = H256;
/// The block number type used in this runtime.
@@ -134,7 +140,7 @@ pub type BlockNumber = u64;
/// Index of a transaction.
pub type Index = u64;
/// The item of a block digest.
pub type DigestItem = runtime_primitives::generic::DigestItem<H256, Ed25519AuthorityId>;
pub type DigestItem = runtime_primitives::generic::DigestItem<H256, AuthorityId, AuthoritySignature>;
/// The digest of a block.
pub type Digest = runtime_primitives::generic::Digest<DigestItem>;
/// A test block.
@@ -256,7 +262,7 @@ cfg_if! {
version()
}
fn authorities() -> Vec<Ed25519AuthorityId> {
fn authorities() -> Vec<AuthorityId> {
system::authorities()
}
@@ -347,7 +353,7 @@ cfg_if! {
version()
}
fn authorities() -> Vec<Ed25519AuthorityId> {
fn authorities() -> Vec<AuthorityId> {
system::authorities()
}
+90 -59
View File
@@ -26,8 +26,8 @@ use runtime_primitives::generic;
use runtime_primitives::{ApplyError, ApplyOutcome, ApplyResult, transaction_validity::TransactionValidity};
use parity_codec::{KeyedVec, Encode};
use super::{AccountId, BlockNumber, Extrinsic, Transfer, H256 as Hash, Block, Header, Digest};
use primitives::{Ed25519AuthorityId, Blake2Hasher};
use primitives::storage::well_known_keys;
use primitives::{Blake2Hasher, storage::well_known_keys};
use primitives::ed25519::Public as AuthorityId;
const NONCE_OF: &[u8] = b"nonce:";
const BALANCE_OF: &[u8] = b"balance:";
@@ -37,7 +37,7 @@ storage_items! {
// The current block number being processed. Set by `execute_block`.
Number: b"sys:num" => required BlockNumber;
ParentHash: b"sys:pha" => required Hash;
NewAuthorities: b"sys:new_auth" => Vec<Ed25519AuthorityId>;
NewAuthorities: b"sys:new_auth" => Vec<AuthorityId>;
}
pub fn balance_of_key(who: AccountId) -> Vec<u8> {
@@ -53,7 +53,7 @@ pub fn nonce_of(who: AccountId) -> u64 {
}
/// Get authorities ar given block.
pub fn authorities() -> Vec<Ed25519AuthorityId> {
pub fn authorities() -> Vec<AuthorityId> {
let len: u32 = storage::unhashed::get(well_known_keys::AUTHORITY_COUNT)
.expect("There are always authorities in test-runtime");
(0..len)
@@ -71,6 +71,36 @@ pub fn initialise_block(header: &Header) {
}
/// Actually execute all transitioning for `block`.
pub fn polish_block(block: &mut Block) {
let header = &mut block.header;
// check transaction trie root represents the transactions.
let txs = block.extrinsics.iter().map(Encode::encode).collect::<Vec<_>>();
let txs = txs.iter().map(Vec::as_slice).collect::<Vec<_>>();
let txs_root = enumerated_trie_root::<Blake2Hasher>(&txs).into();
info_expect_equal_hash(&txs_root, &header.extrinsics_root);
header.extrinsics_root = txs_root;
// execute transactions
block.extrinsics.iter().enumerate().for_each(|(i, e)| {
storage::unhashed::put(well_known_keys::EXTRINSIC_INDEX, &(i as u32));
execute_transaction_backend(e).unwrap_or_else(|_| panic!("Invalid transaction"));
storage::unhashed::kill(well_known_keys::EXTRINSIC_INDEX);
});
header.state_root = storage_root().into();
// check digest
let mut digest = Digest::default();
if let Some(storage_changes_root) = storage_changes_root(header.parent_hash.into(), header.number - 1) {
digest.push(generic::DigestItem::ChangesTrieRoot(storage_changes_root.into()));
}
if let Some(new_authorities) = <NewAuthorities>::take() {
digest.push(generic::DigestItem::AuthoritiesChange(new_authorities));
}
header.digest = digest;
}
pub fn execute_block(block: Block) {
let ref header = block.header;
@@ -83,9 +113,9 @@ pub fn execute_block(block: Block) {
// execute transactions
block.extrinsics.iter().enumerate().for_each(|(i, e)| {
storage::unhashed::put(well_known_keys::EXTRINSIC_INDEX, &(i as u32));
execute_transaction_backend(e).map_err(|_| ()).expect("Extrinsic error");
storage::unhashed::kill(well_known_keys::EXTRINSIC_INDEX);
storage::unhashed::put(well_known_keys::EXTRINSIC_INDEX, &(i as u32));
execute_transaction_backend(e).unwrap_or_else(|_| panic!("Invalid transaction"));
storage::unhashed::kill(well_known_keys::EXTRINSIC_INDEX);
});
// check storage root.
@@ -122,7 +152,7 @@ pub fn validate_transaction(utx: Extrinsic) -> TransactionValidity {
}
let hash = |from: &AccountId, nonce: u64| {
twox_128(&nonce.to_keyed_vec(from.as_bytes())).to_vec()
twox_128(&nonce.to_keyed_vec(&from.encode())).to_vec()
};
let requires = if tx.nonce != expected_nonce && tx.nonce > 0 {
let mut deps = Vec::new();
@@ -144,7 +174,6 @@ pub fn validate_transaction(utx: Extrinsic) -> TransactionValidity {
}
}
/// Execute a transaction outside of the block execution function.
/// This doesn't attempt to validate anything regarding the block.
pub fn execute_transaction(utx: Extrinsic) -> ApplyResult {
@@ -225,8 +254,8 @@ fn execute_transfer_backend(tx: &Transfer) -> ApplyResult {
Ok(ApplyOutcome::Success)
}
fn execute_new_authorities_backend(new_authorities: &[Ed25519AuthorityId]) -> ApplyResult {
let new_authorities: Vec<Ed25519AuthorityId> = new_authorities.iter().cloned().collect();
fn execute_new_authorities_backend(new_authorities: &[AuthorityId]) -> ApplyResult {
let new_authorities: Vec<AuthorityId> = new_authorities.iter().cloned().collect();
<NewAuthorities>::put(new_authorities);
Ok(ApplyOutcome::Success)
}
@@ -258,12 +287,11 @@ mod tests {
use runtime_io::{with_externalities, twox_128, TestExternalities};
use parity_codec::{Joiner, KeyedVec};
use keyring::Keyring;
use crate::{Header, Digest, Extrinsic, Transfer};
use substrate_test_client::{AuthorityKeyring, AccountKeyring};
use crate::{Header, Extrinsic, Transfer};
use primitives::{Blake2Hasher, map};
use primitives::storage::well_known_keys;
use substrate_executor::WasmExecutor;
use hex_literal::{hex, hex_impl};
const WASM_CODE: &'static [u8] =
include_bytes!("../wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm");
@@ -272,36 +300,34 @@ mod tests {
TestExternalities::new(map![
twox_128(b"latest").to_vec() => vec![69u8; 32],
twox_128(well_known_keys::AUTHORITY_COUNT).to_vec() => vec![].and(&3u32),
twox_128(&0u32.to_keyed_vec(well_known_keys::AUTHORITY_PREFIX)).to_vec() => Keyring::Alice.to_raw_public().to_vec(),
twox_128(&1u32.to_keyed_vec(well_known_keys::AUTHORITY_PREFIX)).to_vec() => Keyring::Bob.to_raw_public().to_vec(),
twox_128(&2u32.to_keyed_vec(well_known_keys::AUTHORITY_PREFIX)).to_vec() => Keyring::Charlie.to_raw_public().to_vec(),
twox_128(&Keyring::Alice.to_raw_public().to_keyed_vec(b"balance:")).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0]
twox_128(&0u32.to_keyed_vec(well_known_keys::AUTHORITY_PREFIX)).to_vec() => AuthorityKeyring::Alice.to_raw_public().to_vec(),
twox_128(&1u32.to_keyed_vec(well_known_keys::AUTHORITY_PREFIX)).to_vec() => AuthorityKeyring::Bob.to_raw_public().to_vec(),
twox_128(&2u32.to_keyed_vec(well_known_keys::AUTHORITY_PREFIX)).to_vec() => AuthorityKeyring::Charlie.to_raw_public().to_vec(),
twox_128(&AccountKeyring::Alice.to_raw_public().to_keyed_vec(b"balance:")).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0]
])
}
fn construct_signed_tx(tx: Transfer) -> Extrinsic {
let signature = Keyring::from_raw_public(tx.from.to_fixed_bytes()).unwrap().sign(&tx.encode()).into();
let signature = AccountKeyring::from_public(&tx.from).unwrap().sign(&tx.encode()).into();
Extrinsic::Transfer(tx, signature)
}
fn block_import_works<F>(block_executor: F) where F: Fn(Block, &mut TestExternalities<Blake2Hasher>) {
let mut t = new_test_ext();
let h = Header {
parent_hash: [69u8; 32].into(),
number: 1,
state_root: hex!("e51369d0b37e4aa1383f1e7a34c2eec75f18ee6b4b199a440f4f2456906e0eb7").into(),
extrinsics_root: hex!("03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314").into(),
digest: Digest { logs: vec![], },
state_root: Default::default(),
extrinsics_root: Default::default(),
digest: Default::default(),
};
let b = Block {
let mut b = Block {
header: h,
extrinsics: vec![],
};
block_executor(b, &mut t);
with_externalities(&mut new_test_ext(), || polish_block(&mut b));
block_executor(b, &mut new_test_ext());
}
#[test]
@@ -321,69 +347,74 @@ mod tests {
}
fn block_import_with_transaction_works<F>(block_executor: F) where F: Fn(Block, &mut TestExternalities<Blake2Hasher>) {
let mut t = new_test_ext();
with_externalities(&mut t, || {
assert_eq!(balance_of(Keyring::Alice.to_raw_public().into()), 111);
assert_eq!(balance_of(Keyring::Bob.to_raw_public().into()), 0);
});
let b = Block {
let mut b1 = Block {
header: Header {
parent_hash: [69u8; 32].into(),
number: 1,
state_root: hex!("f61a14ce70846cd6a1714bbe1b63b2ca1172df1c8c01adfd798bb08bd30dc486").into(),
extrinsics_root: hex!("198205cb7729fec8ccdc2e58571a4858586a4f305898078e0e8bee1dddea7e4b").into(),
digest: Digest { logs: vec![], },
state_root: Default::default(),
extrinsics_root: Default::default(),
digest: Default::default(),
},
extrinsics: vec![
construct_signed_tx(Transfer {
from: Keyring::Alice.to_raw_public().into(),
to: Keyring::Bob.to_raw_public().into(),
from: AccountKeyring::Alice.into(),
to: AccountKeyring::Bob.into(),
amount: 69,
nonce: 0,
})
],
};
with_externalities(&mut t, || {
execute_block(b.clone());
let mut dummy_ext = new_test_ext();
with_externalities(&mut dummy_ext, || polish_block(&mut b1));
assert_eq!(balance_of(Keyring::Alice.to_raw_public().into()), 42);
assert_eq!(balance_of(Keyring::Bob.to_raw_public().into()), 69);
});
let b = Block {
let mut b2 = Block {
header: Header {
parent_hash: b.header.hash(),
parent_hash: b1.header.hash(),
number: 2,
state_root: hex!("a47383d9a5d6c8c7531386abccdf512c76729a1a19c59b6c2e4f95dde419923a").into(),
extrinsics_root: hex!("041fa8971dda28745967179a9f39e3ca1a595c510682105df1cff74ae6f05e0d").into(),
digest: Digest { logs: vec![], },
state_root: Default::default(),
extrinsics_root: Default::default(),
digest: Default::default(),
},
extrinsics: vec![
construct_signed_tx(Transfer {
from: Keyring::Bob.to_raw_public().into(),
to: Keyring::Alice.to_raw_public().into(),
from: AccountKeyring::Bob.into(),
to: AccountKeyring::Alice.into(),
amount: 27,
nonce: 0,
}),
construct_signed_tx(Transfer {
from: Keyring::Alice.to_raw_public().into(),
to: Keyring::Charlie.to_raw_public().into(),
from: AccountKeyring::Alice.into(),
to: AccountKeyring::Charlie.into(),
amount: 69,
nonce: 1,
}),
],
};
block_executor(b, &mut t);
with_externalities(&mut dummy_ext, || polish_block(&mut b2));
drop(dummy_ext);
let mut t = new_test_ext();
with_externalities(&mut t, || {
assert_eq!(balance_of(AccountKeyring::Alice.into()), 111);
assert_eq!(balance_of(AccountKeyring::Bob.into()), 0);
});
assert_eq!(balance_of(Keyring::Alice.to_raw_public().into()), 0);
assert_eq!(balance_of(Keyring::Bob.to_raw_public().into()), 42);
assert_eq!(balance_of(Keyring::Charlie.to_raw_public().into()), 69);
block_executor(b1, &mut t);
with_externalities(&mut t, || {
assert_eq!(balance_of(AccountKeyring::Alice.into()), 42);
assert_eq!(balance_of(AccountKeyring::Bob.into()), 69);
});
block_executor(b2, &mut t);
with_externalities(&mut t, || {
assert_eq!(balance_of(AccountKeyring::Alice.into()), 0);
assert_eq!(balance_of(AccountKeyring::Bob.into()), 42);
assert_eq!(balance_of(AccountKeyring::Charlie.into()), 69);
});
}
+65 -7
View File
@@ -1,5 +1,13 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "aho-corasick"
version = "0.6.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "arrayref"
version = "0.3.5"
@@ -481,6 +489,11 @@ dependencies = [
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "hex"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "hex-literal"
version = "0.1.3"
@@ -651,6 +664,11 @@ name = "matches"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "memchr"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "memoffset"
version = "0.2.1"
@@ -1120,6 +1138,26 @@ name = "redox_syscall"
version = "0.1.51"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "regex"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"aho-corasick 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"regex-syntax 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
"thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex-syntax"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ring"
version = "0.14.6"
@@ -1159,7 +1197,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "schnorrkel"
version = "0.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
source = "git+https://github.com/w3f/schnorrkel#3179838da9dd4896c12bb910e7c42477a3250641"
dependencies = [
"clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"curve25519-dalek 1.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1168,6 +1206,7 @@ dependencies = [
"merlin 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"sha3 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
"subtle 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -1441,11 +1480,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "substrate-bip39"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
source = "git+https://github.com/paritytech/substrate-bip39#a28806512c977992af8d6740d45352f5a1c832a0"
dependencies = [
"hmac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"pbkdf2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"schnorrkel 0.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"schnorrkel 0.0.0 (git+https://github.com/w3f/schnorrkel)",
"sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -1561,19 +1600,21 @@ dependencies = [
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"hash-db 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"hash256-std-hasher 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"hex-literal 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"impl-serde 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-codec 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"primitive-types 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"ring 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"schnorrkel 0.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"schnorrkel 0.0.0 (git+https://github.com/w3f/schnorrkel)",
"serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)",
"sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"sr-std 0.1.0",
"substrate-bip39 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"substrate-bip39 0.2.0 (git+https://github.com/paritytech/substrate-bip39)",
"tiny-bip39 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"twox-hash 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1947,6 +1988,11 @@ name = "typenum"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "ucd-util"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "uint"
version = "0.6.1"
@@ -1994,6 +2040,11 @@ dependencies = [
"percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "utf8-ranges"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "vcpkg"
version = "0.2.6"
@@ -2066,6 +2117,7 @@ dependencies = [
]
[metadata]
"checksum aho-corasick 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "81ce3d38065e618af2d7b77e10c5ad9a069859b4be3c2250f674af3840d9c8a5"
"checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee"
"checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71"
"checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799"
@@ -2127,6 +2179,7 @@ dependencies = [
"checksum hash256-std-hasher 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f5c13dbac3cc50684760f54af18545c9e80fb75e93a3e586d71ebdc13138f6a4"
"checksum hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3bae29b6653b3412c2e71e9d486db9f9df5d701941d86683005efb9f2d28e3da"
"checksum heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1679e6ea370dee694f91f1dc469bf94cf8f52051d147aec3e1f9497c6fc22461"
"checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77"
"checksum hex-literal 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "27455ce8b4a6666c87220e4b59c9a83995476bdadc10197905e61dbe906e36fa"
"checksum hex-literal-impl 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1d340b6514f232f6db1bd16db65302a5278a04fef9ce867cb932e7e5fa21130a"
"checksum hmac 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7a13f4163aa0c5ca1be584aace0e2212b2e41be5478218d4f657f5f778b2ae2a"
@@ -2149,6 +2202,7 @@ dependencies = [
"checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c"
"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6"
"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
"checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39"
"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3"
"checksum memory-db 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94da53143d45f6bad3753f532e56ad57a6a26c0ca6881794583310c7cb4c885f"
"checksum memory_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "71d96e3f3c0b6325d8ccd83c33b28acb183edcb6c67938ba104ec546854b0882"
@@ -2201,12 +2255,14 @@ dependencies = [
"checksum rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b055d1e92aba6877574d8fe604a63c8b5df60f60e5982bf7ccbb1338ea527356"
"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
"checksum redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)" = "423e376fffca3dfa06c9e9790a9ccd282fafb3cc6e6397d01dbf64f9bacc6b85"
"checksum regex 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53ee8cfdddb2e0291adfb9f13d31d3bbe0a03c9a402c01b1e24188d86c35b24f"
"checksum regex-syntax 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8c2f35eedad5295fdf00a63d7d4b238135723f92b434ec06774dad15c7ab0861"
"checksum ring 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)" = "426bc186e3e95cac1e4a4be125a4aca7e84c2d616ffc02244eef36e2a60a093c"
"checksum rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "adacaae16d02b6ec37fdc7acfcddf365978de76d1983d3ee22afc260e1ca9619"
"checksum rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "403bb3a286107a04825a5f82e1270acc1e14028d3d554d7a1e08914549575ab8"
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
"checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7"
"checksum schnorrkel 0.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fe554f318830b48e5da8ab1ccb1ffd02b79228364dac7766b7cd1ec461ca5116"
"checksum schnorrkel 0.0.0 (git+https://github.com/w3f/schnorrkel)" = "<none>"
"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27"
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
@@ -2226,7 +2282,7 @@ dependencies = [
"checksum spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44363f6f51401c34e7be73db0db371c04705d35efbe9f7d6082e03a921a32c55"
"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8"
"checksum static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c19be23126415861cb3a23e501d34a708f7f9b2183c5252d690941c2e69199d5"
"checksum substrate-bip39 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ec6183ce9e04bec5f113ff19c8ef5355dad20a4196134b5402732bf5d3c1a351"
"checksum substrate-bip39 0.2.0 (git+https://github.com/paritytech/substrate-bip39)" = "<none>"
"checksum subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee"
"checksum subtle 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "702662512f3ddeb74a64ce2fbbf3707ee1b6bb663d28bb054e0779bbc720d926"
"checksum syn 0.15.27 (registry+https://github.com/rust-lang/crates.io-index)" = "525bd55255f03c816e5d7f615587bd13030c7103354fadb104993dcee6a788ec"
@@ -2254,12 +2310,14 @@ dependencies = [
"checksum trie-root 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e3c6fef2705af3258ec46a7e22286090394a44216201a1cf7d04b78db825e543"
"checksum twox-hash 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "555cd4909480122bbbf21e34faac4cb08a171f324775670447ed116726c474af"
"checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169"
"checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86"
"checksum uint 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e7780bb27fd8a22295e0d9d53ae3be253f715a0dccb1808527f478f1c2603708"
"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
"checksum unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "141339a08b982d942be2ca06ff8b076563cbe223d1befd5450716790d44e2426"
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
"checksum untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "55cd1f4b4e96b46aeb8d4855db4a7a9bd96eeeb5c6a1ab54593328761642ce2f"
"checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a"
"checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737"
"checksum vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "def296d3eb3b12371b2c7d0e83bfe1403e4db2d7a0bba324a12b21c4ee13143d"
"checksum wasmi 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "21ef487a11df1ed468cf613c78798c26282da5c30e9d49f824872d4c77b47d1d"
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
@@ -453,7 +453,7 @@ mod tests {
use super::*;
use futures::Stream;
use parity_codec::Encode;
use test_runtime::{Block, Extrinsic, Transfer, H256};
use test_runtime::{Block, Extrinsic, Transfer, H256, AccountId};
use assert_matches::assert_matches;
use crate::watcher;
@@ -493,7 +493,7 @@ mod tests {
/// Returns a block hash given the block id.
fn block_id_to_hash(&self, at: &BlockId<Self::Block>) -> Result<Option<BlockHash<Self>>, Self::Error> {
Ok(match at {
BlockId::Number(num) => Some(H256::from_low_u64_be(*num)),
BlockId::Number(num) => Some(H256::from_low_u64_be(*num)).into(),
BlockId::Hash(_) => None,
})
}
@@ -502,7 +502,7 @@ mod tests {
fn hash_and_length(&self, uxt: &ExtrinsicFor<Self>) -> (Self::Hash, usize) {
let len = uxt.encode().len();
(
(uxt.transfer().from.to_low_u64_be() << 5) + uxt.transfer().nonce,
(H256::from(uxt.transfer().from.clone()).to_low_u64_be() << 5) + uxt.transfer().nonce,
len
)
}
@@ -524,8 +524,8 @@ mod tests {
// when
let hash = pool.submit_one(&BlockId::Number(0), uxt(Transfer {
from: H256::from_low_u64_be(1),
to: H256::from_low_u64_be(2),
from: AccountId::from_h256(H256::from_low_u64_be(1)),
to: AccountId::from_h256(H256::from_low_u64_be(2)),
amount: 5,
nonce: 0,
})).unwrap();
@@ -539,8 +539,8 @@ mod tests {
// given
let pool = pool();
let uxt = uxt(Transfer {
from: H256::from_low_u64_be(1),
to: H256::from_low_u64_be(2),
from: AccountId::from_h256(H256::from_low_u64_be(1)),
to: AccountId::from_h256(H256::from_low_u64_be(2)),
amount: 5,
nonce: 0,
});
@@ -564,21 +564,21 @@ mod tests {
// when
let _hash = pool.submit_one(&BlockId::Number(0), uxt(Transfer {
from: H256::from_low_u64_be(1),
to: H256::from_low_u64_be(2),
from: AccountId::from_h256(H256::from_low_u64_be(1)),
to: AccountId::from_h256(H256::from_low_u64_be(2)),
amount: 5,
nonce: 0,
})).unwrap();
let _hash = pool.submit_one(&BlockId::Number(0), uxt(Transfer {
from: H256::from_low_u64_be(1),
to: H256::from_low_u64_be(2),
from: AccountId::from_h256(H256::from_low_u64_be(1)),
to: AccountId::from_h256(H256::from_low_u64_be(2)),
amount: 5,
nonce: 1,
})).unwrap();
// future doesn't count
let _hash = pool.submit_one(&BlockId::Number(0), uxt(Transfer {
from: H256::from_low_u64_be(1),
to: H256::from_low_u64_be(2),
from: AccountId::from_h256(H256::from_low_u64_be(1)),
to: AccountId::from_h256(H256::from_low_u64_be(2)),
amount: 5,
nonce: 3,
})).unwrap();
@@ -600,20 +600,20 @@ mod tests {
// given
let pool = pool();
let hash1 = pool.submit_one(&BlockId::Number(0), uxt(Transfer {
from: H256::from_low_u64_be(1),
to: H256::from_low_u64_be(2),
from: AccountId::from_h256(H256::from_low_u64_be(1)),
to: AccountId::from_h256(H256::from_low_u64_be(2)),
amount: 5,
nonce: 0,
})).unwrap();
let hash2 = pool.submit_one(&BlockId::Number(0), uxt(Transfer {
from: H256::from_low_u64_be(1),
to: H256::from_low_u64_be(2),
from: AccountId::from_h256(H256::from_low_u64_be(1)),
to: AccountId::from_h256(H256::from_low_u64_be(2)),
amount: 5,
nonce: 1,
})).unwrap();
let hash3 = pool.submit_one(&BlockId::Number(0), uxt(Transfer {
from: H256::from_low_u64_be(1),
to: H256::from_low_u64_be(2),
from: AccountId::from_h256(H256::from_low_u64_be(1)),
to: AccountId::from_h256(H256::from_low_u64_be(2)),
amount: 5,
nonce: 3,
})).unwrap();
@@ -636,8 +636,8 @@ mod tests {
// given
let pool = pool();
let hash1 = pool.submit_one(&BlockId::Number(0), uxt(Transfer {
from: H256::from_low_u64_be(1),
to: H256::from_low_u64_be(2),
from: AccountId::from_h256(H256::from_low_u64_be(1)),
to: AccountId::from_h256(H256::from_low_u64_be(2)),
amount: 5,
nonce: 0,
})).unwrap();
@@ -662,8 +662,8 @@ mod tests {
}, TestApi::default());
let hash1 = pool.submit_one(&BlockId::Number(0), uxt(Transfer {
from: H256::from_low_u64_be(1),
to: H256::from_low_u64_be(2),
from: AccountId::from_h256(H256::from_low_u64_be(1)),
to: AccountId::from_h256(H256::from_low_u64_be(2)),
amount: 5,
nonce: 1,
})).unwrap();
@@ -671,8 +671,8 @@ mod tests {
// when
let hash2 = pool.submit_one(&BlockId::Number(0), uxt(Transfer {
from: H256::from_low_u64_be(2),
to: H256::from_low_u64_be(2),
from: AccountId::from_h256(H256::from_low_u64_be(2)),
to: AccountId::from_h256(H256::from_low_u64_be(2)),
amount: 5,
nonce: 10,
})).unwrap();
@@ -697,8 +697,8 @@ mod tests {
// when
pool.submit_one(&BlockId::Number(0), uxt(Transfer {
from: H256::from_low_u64_be(1),
to: H256::from_low_u64_be(2),
from: AccountId::from_h256(H256::from_low_u64_be(1)),
to: AccountId::from_h256(H256::from_low_u64_be(2)),
amount: 5,
nonce: 1,
})).unwrap_err();
@@ -717,8 +717,8 @@ mod tests {
// given
let pool = pool();
let watcher = pool.submit_and_watch(&BlockId::Number(0), uxt(Transfer {
from: H256::from_low_u64_be(1),
to: H256::from_low_u64_be(2),
from: AccountId::from_h256(H256::from_low_u64_be(1)),
to: AccountId::from_h256(H256::from_low_u64_be(2)),
amount: 5,
nonce: 0,
})).unwrap();
@@ -733,7 +733,7 @@ mod tests {
// then
let mut stream = watcher.into_stream().wait();
assert_eq!(stream.next(), Some(Ok(watcher::Status::Ready)));
assert_eq!(stream.next(), Some(Ok(watcher::Status::Finalised(H256::from_low_u64_be(2)))));
assert_eq!(stream.next(), Some(Ok(watcher::Status::Finalised(H256::from_low_u64_be(2).into()))));
assert_eq!(stream.next(), None);
}
@@ -742,8 +742,8 @@ mod tests {
// given
let pool = pool();
let watcher = pool.submit_and_watch(&BlockId::Number(0), uxt(Transfer {
from: H256::from_low_u64_be(1),
to: H256::from_low_u64_be(2),
from: AccountId::from_h256(H256::from_low_u64_be(1)),
to: AccountId::from_h256(H256::from_low_u64_be(2)),
amount: 5,
nonce: 0,
})).unwrap();
@@ -758,7 +758,7 @@ mod tests {
// then
let mut stream = watcher.into_stream().wait();
assert_eq!(stream.next(), Some(Ok(watcher::Status::Ready)));
assert_eq!(stream.next(), Some(Ok(watcher::Status::Finalised(H256::from_low_u64_be(2)))));
assert_eq!(stream.next(), Some(Ok(watcher::Status::Finalised(H256::from_low_u64_be(2).into()))));
assert_eq!(stream.next(), None);
}
@@ -767,8 +767,8 @@ mod tests {
// given
let pool = pool();
let watcher = pool.submit_and_watch(&BlockId::Number(0), uxt(Transfer {
from: H256::from_low_u64_be(1),
to: H256::from_low_u64_be(2),
from: AccountId::from_h256(H256::from_low_u64_be(1)),
to: AccountId::from_h256(H256::from_low_u64_be(2)),
amount: 5,
nonce: 1,
})).unwrap();
@@ -777,8 +777,8 @@ mod tests {
// when
pool.submit_one(&BlockId::Number(0), uxt(Transfer {
from: H256::from_low_u64_be(1),
to: H256::from_low_u64_be(2),
from: AccountId::from_h256(H256::from_low_u64_be(1)),
to: AccountId::from_h256(H256::from_low_u64_be(2)),
amount: 5,
nonce: 0,
})).unwrap();
@@ -795,8 +795,8 @@ mod tests {
// given
let pool = pool();
let uxt = uxt(Transfer {
from: H256::from_low_u64_be(1),
to: H256::from_low_u64_be(2),
from: AccountId::from_h256(H256::from_low_u64_be(1)),
to: AccountId::from_h256(H256::from_low_u64_be(2)),
amount: 5,
nonce: 0,
});
@@ -819,8 +819,8 @@ mod tests {
// given
let pool = pool();
let uxt = uxt(Transfer {
from: H256::from_low_u64_be(1),
to: H256::from_low_u64_be(2),
from: AccountId::from_h256(H256::from_low_u64_be(1)),
to: AccountId::from_h256(H256::from_low_u64_be(2)),
amount: 5,
nonce: 0,
});
@@ -853,8 +853,8 @@ mod tests {
}, TestApi::default());
let xt = uxt(Transfer {
from: H256::from_low_u64_be(1),
to: H256::from_low_u64_be(2),
from: AccountId::from_h256(H256::from_low_u64_be(1)),
to: AccountId::from_h256(H256::from_low_u64_be(2)),
amount: 5,
nonce: 0,
});
@@ -863,8 +863,8 @@ mod tests {
// when
let xt = uxt(Transfer {
from: H256::from_low_u64_be(2),
to: H256::from_low_u64_be(1),
from: AccountId::from_h256(H256::from_low_u64_be(2)),
to: AccountId::from_h256(H256::from_low_u64_be(1)),
amount: 4,
nonce: 1,
});
+3 -4
View File
@@ -17,10 +17,9 @@
use super::*;
use keyring::Keyring::{self, *};
use parity_codec::Encode;
use txpool::{self, Pool};
use test_client::runtime::{AccountId, Block, Hash, Index, Extrinsic, Transfer};
use test_client::{runtime::{AccountId, Block, Hash, Index, Extrinsic, Transfer}, AccountKeyring::{self, *}};
use sr_primitives::{
generic::{self, BlockId},
traits::{Hash as HashT, BlakeTwo256},
@@ -86,9 +85,9 @@ fn number_of(at: &BlockId<Block>) -> u64 {
}
}
fn uxt(who: Keyring, nonce: Index) -> Extrinsic {
fn uxt(who: AccountKeyring, nonce: Index) -> Extrinsic {
let transfer = Transfer {
from: who.to_raw_public().into(),
from: who.into(),
to: AccountId::default(),
nonce,
amount: 1,