Generic keystore (#3008)

* Add KeyTypeId.

* Implement clone for sr25519::Pair.

* Extend Pair with to_raw_vec.

* Implement TypedKey for Signature and Pair.

* Add trait Public.

* Make keystore generic.

* Fixup clone.

* Fix tests.

* Update service.

* Fix imports.

* Fix build.

* Fix babe build.

* Fix subkey build.

* Make authority setup generic.

* Update node-template.

* Fix build.

* Remove unsafe code.

* Fix tests.
This commit is contained in:
David Craven
2019-07-04 13:14:55 +02:00
committed by GitHub
parent 336053f7ae
commit 51e345c901
15 changed files with 279 additions and 122 deletions
+1
View File
@@ -2222,6 +2222,7 @@ dependencies = [
"substrate-consensus-aura-primitives 2.0.0",
"substrate-consensus-common 2.0.0",
"substrate-finality-grandpa 2.0.0",
"substrate-finality-grandpa-primitives 2.0.0",
"substrate-inherents 2.0.0",
"substrate-keyring 2.0.0",
"substrate-keystore 2.0.0",
+1 -1
View File
@@ -45,7 +45,7 @@ use std::{sync::Arc, u64, fmt::{Debug, Display}, time::{Instant, Duration}};
use runtime_support::serde::{Serialize, Deserialize};
use parity_codec::{Decode, Encode};
use parking_lot::Mutex;
use primitives::{crypto::Pair, sr25519};
use primitives::{Pair, Public, sr25519};
use merlin::Transcript;
use inherents::{InherentDataProviders, InherentData};
use substrate_telemetry::{
+1 -1
View File
@@ -18,7 +18,7 @@
use std::{collections::HashMap, ops::Deref};
use lazy_static::lazy_static;
use substrate_primitives::{ed25519::{Pair, Public, Signature}, Pair as PairT, H256};
use substrate_primitives::{ed25519::{Pair, Public, Signature}, Pair as PairT, Public as PublicT, H256};
pub use substrate_primitives::ed25519;
/// Set of test accounts.
+2 -2
View File
@@ -19,7 +19,7 @@
use std::collections::HashMap;
use std::ops::Deref;
use lazy_static::lazy_static;
use substrate_primitives::{sr25519::{Pair, Public, Signature}, Pair as PairT, H256};
use substrate_primitives::{sr25519::{Pair, Public, Signature}, Pair as PairT, Public as PublicT, H256};
pub use substrate_primitives::sr25519;
/// Set of test accounts.
@@ -68,7 +68,7 @@ impl Keyring {
}
pub fn to_raw_public_vec(self) -> Vec<u8> {
Public::from(self).into_raw_vec()
Public::from(self).to_raw_vec()
}
pub fn sign(self, msg: &[u8]) -> Signature {
+58 -30
View File
@@ -23,7 +23,7 @@ use std::path::PathBuf;
use std::fs::{self, File};
use std::io::{self, Write};
use substrate_primitives::{ed25519::{Pair, Public}, Pair as PairT};
use substrate_primitives::crypto::{KeyTypeId, Pair, Public, TypedKey};
/// Keystore error.
#[derive(Debug, derive_more::Display, derive_more::From)]
@@ -59,7 +59,7 @@ impl std::error::Error for Error {
/// Key store.
pub struct Store {
path: PathBuf,
additional: HashMap<Public, Pair>,
additional: HashMap<(KeyTypeId, Vec<u8>), Vec<u8>>,
}
impl Store {
@@ -69,33 +69,49 @@ impl Store {
Ok(Store { path, additional: HashMap::new() })
}
fn get_pair<TPair: Pair + TypedKey>(&self, public: &TPair::Public) -> Result<Option<TPair>> {
let key = (TPair::KEY_TYPE, public.to_raw_vec());
if let Some(bytes) = self.additional.get(&key) {
let pair = TPair::from_seed_slice(bytes)
.map_err(|_| Error::InvalidSeed)?;
return Ok(Some(pair));
}
Ok(None)
}
fn insert_pair<TPair: Pair + TypedKey>(&mut self, pair: &TPair) {
let key = (TPair::KEY_TYPE, pair.public().to_raw_vec());
self.additional.insert(key, pair.to_raw_vec());
}
/// Generate a new key, placing it into the store.
pub fn generate(&self, password: &str) -> Result<Pair> {
let (pair, phrase, _) = Pair::generate_with_phrase(Some(password));
let mut file = File::create(self.key_file_path(&pair.public()))?;
pub fn generate<TPair: Pair + TypedKey>(&self, password: &str) -> Result<TPair> {
let (pair, phrase, _) = TPair::generate_with_phrase(Some(password));
let mut file = File::create(self.key_file_path::<TPair>(&pair.public()))?;
::serde_json::to_writer(&file, &phrase)?;
file.flush()?;
Ok(pair)
}
/// Create a new key from seed. Do not place it into the store.
pub fn generate_from_seed(&mut self, seed: &str) -> Result<Pair> {
let pair = Pair::from_string(seed, None)
pub fn generate_from_seed<TPair: Pair + TypedKey>(&mut self, seed: &str) -> Result<TPair> {
let pair = TPair::from_string(seed, None)
.ok().ok_or(Error::InvalidSeed)?;
self.additional.insert(pair.public(), pair.clone());
self.insert_pair(&pair);
Ok(pair)
}
/// Load a key file with given public key.
pub fn load(&self, public: &Public, password: &str) -> Result<Pair> {
if let Some(pair) = self.additional.get(public) {
return Ok(pair.clone());
pub fn load<TPair: Pair + TypedKey>(&self, public: &TPair::Public, password: &str) -> Result<TPair> {
if let Some(pair) = self.get_pair(public)? {
return Ok(pair)
}
let path = self.key_file_path(public);
let path = self.key_file_path::<TPair>(public);
let file = File::open(path)?;
let phrase: String = ::serde_json::from_reader(&file)?;
let (pair, _) = Pair::from_phrase(&phrase, Some(password))
let (pair, _) = TPair::from_phrase(&phrase, Some(password))
.ok().ok_or(Error::InvalidPhrase)?;
if &pair.public() != public {
return Err(Error::InvalidPassword);
@@ -104,22 +120,28 @@ impl Store {
}
/// Get public keys of all stored keys.
pub fn contents(&self) -> Result<Vec<Public>> {
let mut public_keys: Vec<Public> = self.additional.keys().cloned().collect();
pub fn contents<TPublic: Public + TypedKey>(&self) -> Result<Vec<TPublic>> {
let mut public_keys: Vec<TPublic> = self.additional.keys()
.filter_map(|(ty, public)| {
if *ty != TPublic::KEY_TYPE {
return None
}
Some(TPublic::from_slice(public))
})
.collect();
let key_type: [u8; 4] = TPublic::KEY_TYPE.to_le_bytes();
for entry in fs::read_dir(&self.path)? {
let entry = entry?;
let path = entry.path();
// skip directories and non-unicode file names (hex is unicode)
if let Some(name) = path.file_name().and_then(|n| n.to_str()) {
if name.len() != 64 { continue }
match hex::decode(name) {
Ok(ref hex) if hex.len() == 32 => {
let mut buf = [0; 32];
buf.copy_from_slice(&hex[..]);
public_keys.push(Public(buf));
Ok(ref hex) => {
if hex[0..4] != key_type { continue }
let public = TPublic::from_slice(&hex[4..]);
public_keys.push(public);
}
_ => continue,
}
@@ -129,9 +151,12 @@ impl Store {
Ok(public_keys)
}
fn key_file_path(&self, public: &Public) -> PathBuf {
fn key_file_path<TPair: Pair + TypedKey>(&self, public: &TPair::Public) -> PathBuf {
let mut buf = self.path.clone();
buf.push(hex::encode(public.as_slice()));
let bytes: [u8; 4] = TPair::KEY_TYPE.to_le_bytes();
let key_type = hex::encode(bytes);
let key = hex::encode(public.as_slice());
buf.push(key_type + key.as_str());
buf
}
}
@@ -140,6 +165,7 @@ impl Store {
mod tests {
use super::*;
use tempdir::TempDir;
use substrate_primitives::ed25519;
use substrate_primitives::crypto::Ss58Codec;
#[test]
@@ -147,16 +173,16 @@ mod tests {
let temp_dir = TempDir::new("keystore").unwrap();
let store = Store::open(temp_dir.path().to_owned()).unwrap();
assert!(store.contents().unwrap().is_empty());
assert!(store.contents::<ed25519::Public>().unwrap().is_empty());
let key = store.generate("thepassword").unwrap();
let key2 = store.load(&key.public(), "thepassword").unwrap();
let key: ed25519::Pair = store.generate("thepassword").unwrap();
let key2: ed25519::Pair = store.load(&key.public(), "thepassword").unwrap();
assert!(store.load(&key.public(), "notthepassword").is_err());
assert!(store.load::<ed25519::Pair>(&key.public(), "notthepassword").is_err());
assert_eq!(key.public(), key2.public());
assert_eq!(store.contents().unwrap()[0], key.public());
assert_eq!(store.contents::<ed25519::Public>().unwrap()[0], key.public());
}
#[test]
@@ -164,7 +190,9 @@ 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("0x3d97c819d68f9bafa7d6e79cb991eebcd77d966c5334c0b94d9e1fa7ad0869dc").unwrap();
let pair: ed25519::Pair = store
.generate_from_seed("0x3d97c819d68f9bafa7d6e79cb991eebcd77d966c5334c0b94d9e1fa7ad0869dc")
.unwrap();
assert_eq!("5DKUrgFqCPV8iAXx9sjy1nyBygQCeiUYRFWurZGhnrn3HJCA", pair.public().to_ss58check());
}
}
+64 -4
View File
@@ -26,6 +26,8 @@ use parity_codec::{Encode, Decode};
use regex::Regex;
#[cfg(feature = "std")]
use base58::{FromBase58, ToBase58};
#[cfg(feature = "std")]
use std::hash::Hash;
/// The root phrase for our publicly known keys.
pub const DEV_PHRASE: &str = "bottom drive obey lake curtain smoke basket hold race lonely fit walk";
@@ -286,13 +288,30 @@ impl<T: AsMut<[u8]> + AsRef<[u8]> + Default + Derive> Ss58Codec for T {
}
}
/// Trait suitable for typical cryptographic PKI key public type.
pub trait Public: PartialEq + Eq {
/// A new instance from the given slice that should be 32 bytes long.
///
/// NOTE: No checking goes on to ensure this is a real public key. Only use it if
/// you are certain that the array actually is a pubkey. GIGO!
fn from_slice(data: &[u8]) -> Self;
/// Return a `Vec<u8>` filled with raw data.
#[cfg(feature = "std")]
fn to_raw_vec(&self) -> Vec<u8>;
/// Return a slice filled with raw data.
fn as_slice(&self) -> &[u8];
}
/// 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 + 'static {
pub trait Pair: Sized + 'static
{
/// TThe type which is used to encode a public key.
type Public;
type Public: Public + Hash;
/// The type used to (minimally) encode the data required to securely create
/// a new key pair.
@@ -412,6 +431,31 @@ pub trait Pair: Sized + 'static {
path,
)
}
/// Return a vec filled with raw data.
fn to_raw_vec(&self) -> Vec<u8>;
}
/// An identifier for a type of cryptographic key.
///
/// 0-1024 are reserved.
pub type KeyTypeId = u32;
/// Constant key types.
pub mod key_types {
use super::KeyTypeId;
/// ED25519 public key.
pub const ED25519: KeyTypeId = 10;
/// SR25519 public key.
pub const SR25519: KeyTypeId = 20;
}
/// A trait for something that has a key type ID.
pub trait TypedKey {
/// The type ID of this key.
const KEY_TYPE: KeyTypeId;
}
#[cfg(test)]
@@ -429,8 +473,21 @@ mod tests {
Seed(Vec<u8>),
}
#[derive(PartialEq, Eq, Hash)]
struct TestPublic;
impl Public for TestPublic {
fn from_slice(bytes: &[u8]) -> Self {
Self
}
fn as_slice(&self) -> &[u8] {
&[]
}
fn to_raw_vec(&self) -> Vec<u8> {
vec![]
}
}
impl Pair for TestPair {
type Public = ();
type Public = TestPublic;
type Seed = [u8; 0];
type Signature = ();
type DeriveError = ();
@@ -464,7 +521,7 @@ mod tests {
_message: M,
_pubkey: P
) -> bool { true }
fn public(&self) -> Self::Public { () }
fn public(&self) -> Self::Public { TestPublic }
fn from_standard_components<I: Iterator<Item=DeriveJunction>>(
phrase: &str,
password: Option<&str>,
@@ -481,6 +538,9 @@ mod tests {
{
Ok(TestPair::Seed(seed.to_owned()))
}
fn to_raw_vec(&self) -> Vec<u8> {
vec![]
}
}
#[test]
+38 -18
View File
@@ -32,7 +32,7 @@ use bip39::{Mnemonic, Language, MnemonicType};
use crate::crypto::{Pair as TraitPair, DeriveJunction, SecretStringError, Derive, Ss58Codec};
#[cfg(feature = "std")]
use serde::{de, Serializer, Serialize, Deserializer, Deserialize};
use crate::crypto::UncheckedFrom;
use crate::crypto::{key_types, KeyTypeId, Public as TraitPublic, TypedKey, UncheckedFrom};
/// 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
@@ -282,16 +282,6 @@ impl Public {
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
@@ -300,23 +290,35 @@ impl Public {
Public(x.into())
}
/// Return a slice filled with raw data.
pub fn as_array_ref(&self) -> &[u8; 32] {
self.as_ref()
}
}
impl TraitPublic for Public {
/// A new instance from the given slice that should be 32 bytes long.
///
/// NOTE: No checking goes on to ensure this is a real public key. Only use it if
/// you are certain that the array actually is a pubkey. GIGO!
fn from_slice(data: &[u8]) -> Self {
let mut r = [0u8; 32];
r.copy_from_slice(data);
Public(r)
}
/// Return a `Vec<u8>` filled with raw data.
#[cfg(feature = "std")]
pub fn to_raw_vec(self) -> Vec<u8> {
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] {
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")]
@@ -460,6 +462,11 @@ impl TraitPair for Pair {
_ => false,
}
}
/// Return a vec filled with raw data.
fn to_raw_vec(&self) -> Vec<u8> {
self.seed().to_vec()
}
}
#[cfg(feature = "std")]
@@ -481,6 +488,19 @@ impl Pair {
}
}
impl TypedKey for Public {
const KEY_TYPE: KeyTypeId = key_types::ED25519;
}
impl TypedKey for Signature {
const KEY_TYPE: KeyTypeId = key_types::ED25519;
}
#[cfg(feature = "std")]
impl TypedKey for Pair {
const KEY_TYPE: KeyTypeId = key_types::ED25519;
}
#[cfg(test)]
mod test {
use super::*;
+1 -1
View File
@@ -69,7 +69,7 @@ pub use self::hash::{H160, H256, H512, convert_hash};
pub use self::uint::U256;
pub use changes_trie::ChangesTrieConfiguration;
#[cfg(feature = "std")]
pub use crypto::{DeriveJunction, Pair};
pub use crypto::{DeriveJunction, Pair, Public};
pub use hash_db::Hasher;
// Switch back to Blake after PoC-3 is out
+67 -27
View File
@@ -31,13 +31,14 @@ use substrate_bip39::mini_secret_from_entropy;
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 crate::crypto::{key_types, KeyTypeId, Public as TraitPublic, TypedKey, UncheckedFrom};
use crate::hash::{H256, H512};
use parity_codec::{Encode, Decode};
#[cfg(feature = "std")]
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
#[cfg(feature = "std")]
use schnorrkel::keys::MINI_SECRET_KEY_LENGTH;
use schnorrkel::keys::{MINI_SECRET_KEY_LENGTH, SECRET_KEY_LENGTH};
// signing context
#[cfg(feature = "std")]
@@ -51,6 +52,17 @@ pub struct Public(pub [u8; 32]);
#[cfg(feature = "std")]
pub struct Pair(Keypair);
#[cfg(feature = "std")]
impl Clone for Pair {
fn clone(&self) -> Self {
Pair(schnorrkel::Keypair {
public: self.0.public.clone(),
secret: schnorrkel::SecretKey::from_bytes(&self.0.secret.to_bytes()[..])
.expect("key is always the correct size; qed")
})
}
}
impl AsRef<Public> for Public {
fn as_ref(&self) -> &Public {
&self
@@ -282,16 +294,6 @@ impl Public {
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
@@ -300,21 +302,33 @@ impl Public {
Public(x.into())
}
/// Return a slice filled with raw data.
pub fn as_array_ref(&self) -> &[u8; 32] {
self.as_ref()
}
}
impl TraitPublic for Public {
/// A new instance from the given slice that should be 32 bytes long.
///
/// NOTE: No checking goes on to ensure this is a real public key. Only use it if
/// you are certain that the array actually is a pubkey. GIGO!
fn from_slice(data: &[u8]) -> Self {
let mut r = [0u8; 32];
r.copy_from_slice(data);
Public(r)
}
/// Return a `Vec<u8>` filled with raw data.
#[cfg(feature = "std")]
pub fn into_raw_vec(self) -> Vec<u8> {
fn to_raw_vec(&self) -> Vec<u8> {
self.0.to_vec()
}
/// Return a slice filled with raw data.
pub fn as_slice(&self) -> &[u8] {
fn as_slice(&self) -> &[u8] {
&self.0
}
/// Return a slice filled with raw data.
pub fn as_array_ref(&self) -> &[u8; 32] {
self.as_ref()
}
}
#[cfg(feature = "std")]
@@ -397,14 +411,22 @@ impl TraitPair for Pair {
///
/// 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()
))
match seed.len() {
MINI_SECRET_KEY_LENGTH => {
Ok(Pair(
MiniSecretKey::from_bytes(seed)
.map_err(|_| SecretStringError::InvalidSeed)?
.expand_to_keypair()
))
}
SECRET_KEY_LENGTH => {
Ok(Pair(
SecretKey::from_bytes(seed)
.map_err(|_| SecretStringError::InvalidSeed)?
.to_keypair()
))
}
_ => Err(SecretStringError::InvalidSeedLength)
}
}
@@ -478,6 +500,11 @@ impl TraitPair for Pair {
Err(_) => false,
}
}
/// Return a vec filled with raw data.
fn to_raw_vec(&self) -> Vec<u8> {
self.0.secret.to_bytes().to_vec()
}
}
#[cfg(feature = "std")]
@@ -495,6 +522,19 @@ impl Pair {
}
}
impl TypedKey for Public {
const KEY_TYPE: KeyTypeId = key_types::SR25519;
}
impl TypedKey for Signature {
const KEY_TYPE: KeyTypeId = key_types::SR25519;
}
#[cfg(feature = "std")]
impl TypedKey for Pair {
const KEY_TYPE: KeyTypeId = key_types::SR25519;
}
#[cfg(test)]
mod test {
use super::*;
+13 -11
View File
@@ -38,7 +38,7 @@ use futures::prelude::*;
use keystore::Store as Keystore;
use log::{info, warn, debug, error};
use parity_codec::{Encode, Decode};
use primitives::Pair;
use primitives::{Pair, Public, crypto::TypedKey, ed25519};
use runtime_primitives::generic::BlockId;
use runtime_primitives::traits::{Header, NumberFor, SaturatedConversion};
use substrate_executor::NativeExecutor;
@@ -182,13 +182,13 @@ impl<Components: components::Components> Service<Components> {
// FIXME #1063 remove this
if let Some(keystore) = keystore.as_mut() {
for seed in &config.keys {
keystore.generate_from_seed(seed)?;
keystore.generate_from_seed::<ed25519::Pair>(seed)?;
}
public_key = match keystore.contents()?.get(0) {
public_key = match keystore.contents::<ed25519::Public>()?.get(0) {
Some(public_key) => public_key.to_string(),
None => {
let key = keystore.generate(&config.password)?;
let key: ed25519::Pair = keystore.generate(&config.password)?;
let public_key = key.public();
info!("Generated a new keypair: {:?}", public_key);
public_key.to_string()
@@ -542,11 +542,15 @@ impl<Components: components::Components> Service<Components> {
}
/// give the authority key, if we are an authority and have a key
pub fn authority_key(&self) -> Option<primitives::ed25519::Pair> {
pub fn authority_key<TPair>(&self) -> Option<TPair>
where
TPair: Pair + TypedKey,
<TPair as Pair>::Public: Public + TypedKey,
{
if self.config.roles != Roles::AUTHORITY { return None }
if let Some(keystore) = &self.keystore {
if let Ok(Some(Ok(key))) = keystore.contents().map(|keys| keys.get(0)
.map(|k| keystore.load(k, &self.config.password)))
if let Ok(Some(Ok(key))) = keystore.contents::<TPair::Public>().map(|keys| keys.get(0)
.map(|k| keystore.load::<TPair>(k, &self.config.password)))
{
Some(key)
} else {
@@ -856,7 +860,6 @@ fn build_system_rpc_handler<Components: components::Components>(
/// # use transaction_pool::{self, txpool::{Pool as TransactionPool}};
/// # use network::construct_simple_protocol;
/// # use client::{self, LongestChain};
/// # use primitives::{Pair as PairT, ed25519};
/// # use consensus_common::import_queue::{BasicQueue, Verifier};
/// # use consensus_common::{BlockOrigin, ImportBlock, well_known_cache_keys::Id as CacheKeyId};
/// # use node_runtime::{GenesisConfig, RuntimeApi};
@@ -903,7 +906,7 @@ fn build_system_rpc_handler<Components: components::Components>(
/// { |config| <FullComponents<Factory>>::new(config) },
/// // Setup as Consensus Authority (if the role and key are given)
/// AuthoritySetup = {
/// |service: Self::FullService, key: Option<Arc<ed25519::Pair>>| {
/// |service: Self::FullService| {
/// Ok(service)
/// }},
/// LightService = LightComponents<Self>
@@ -1029,8 +1032,7 @@ macro_rules! construct_service_factory {
) -> Result<Self::FullService, $crate::Error>
{
( $( $full_service_init )* ) (config).and_then(|service| {
let key = (&service).authority_key().map(Arc::new);
($( $authority_setup )*)(service, key)
($( $authority_setup )*)(service)
})
}
}
+3 -3
View File
@@ -65,8 +65,8 @@ construct_service_factory! {
FullComponents::<Factory>::new(config)
},
AuthoritySetup = {
|service: Self::FullService, key: Option<Arc<Pair>>| {
if let Some(key) = key {
|service: Self::FullService| {
if let Some(key) = service.authority_key::<Pair>() {
info!("Using authority key {}", key.public());
let proposer = Arc::new(ProposerFactory {
client: service.client(),
@@ -77,7 +77,7 @@ construct_service_factory! {
.ok_or_else(|| ServiceError::SelectChainRequired)?;
let aura = start_aura(
SlotDuration::get_or_compute(&*client)?,
key.clone(),
Arc::new(key),
client.clone(),
select_chain,
client,
+4 -3
View File
@@ -24,10 +24,11 @@ substrate-basic-authorship = { path = "../../core/basic-authorship" }
substrate-service = { path = "../../core/service" }
transaction_pool = { package = "substrate-transaction-pool", path = "../../core/transaction-pool" }
network = { package = "substrate-network", path = "../../core/network" }
consensus = { package = "substrate-consensus-aura", path = "../../core/consensus/aura" }
grandpa = { package = "substrate-finality-grandpa", path = "../../core/finality-grandpa" }
sr-primitives = { path = "../../core/sr-primitives" }
aura = { package = "substrate-consensus-aura", path = "../../core/consensus/aura" }
aura_primitives = { package = "substrate-consensus-aura-primitives", path = "../../core/consensus/aura/primitives" }
grandpa = { package = "substrate-finality-grandpa", path = "../../core/finality-grandpa" }
grandpa_primitives = { package = "substrate-finality-grandpa-primitives", path = "../../core/finality-grandpa/primitives" }
sr-primitives = { path = "../../core/sr-primitives" }
node-executor = { path = "../executor" }
substrate-keystore = { path = "../../core/keystore" }
substrate-telemetry = { package = "substrate-telemetry", path = "../../core/telemetry" }
+17 -16
View File
@@ -21,13 +21,13 @@
use std::sync::Arc;
use std::time::Duration;
use aura::{import_queue, start_aura, AuraImportQueue, SlotDuration};
use client::{self, LongestChain};
use consensus::{import_queue, start_aura, AuraImportQueue, SlotDuration};
use grandpa::{self, FinalityProofProvider as GrandpaFinalityProofProvider};
use node_executor;
use primitives::{Pair as PairT, ed25519};
use primitives::Pair;
use futures::prelude::*;
use node_primitives::Block;
use node_primitives::{AuraPair, Block};
use node_runtime::{GenesisConfig, RuntimeApi};
use substrate_service::{
FactoryFullConfiguration, LightComponents, FullComponents, FullBackend,
@@ -79,12 +79,13 @@ construct_service_factory! {
{ |config: FactoryFullConfiguration<Self>|
FullComponents::<Factory>::new(config) },
AuthoritySetup = {
|mut service: Self::FullService, local_key: Option<Arc<ed25519::Pair>>| {
|mut service: Self::FullService| {
let (block_import, link_half) = service.config.custom.grandpa_import_setup.take()
.expect("Link Half and Block Import are present for Full Services or setup failed before. qed");
if let Some(ref key) = local_key {
info!("Using authority key {}", key.public());
if let Some(aura_key) = service.authority_key::<AuraPair>() {
info!("Using aura key {}", aura_key.public());
let proposer = Arc::new(substrate_basic_authorship::ProposerFactory {
client: service.client(),
transaction_pool: service.transaction_pool(),
@@ -93,9 +94,10 @@ construct_service_factory! {
let client = service.client();
let select_chain = service.select_chain()
.ok_or(ServiceError::SelectChainRequired)?;
let aura = start_aura(
SlotDuration::get_or_compute(&*client)?,
key.clone(),
Arc::new(aura_key),
client,
select_chain,
block_import.clone(),
@@ -104,19 +106,18 @@ construct_service_factory! {
service.config.custom.inherent_data_providers.clone(),
service.config.force_authoring,
)?;
service.spawn_task(Box::new(aura.select(service.on_exit()).then(|_| Ok(()))));
info!("Running Grandpa session as Authority {}", key.public());
let select = aura.select(service.on_exit()).then(|_| Ok(()));
service.spawn_task(Box::new(select));
}
let local_key = if service.config.disable_grandpa {
let grandpa_key = if service.config.disable_grandpa {
None
} else {
local_key
service.authority_key::<grandpa_primitives::AuthorityPair>()
};
let config = grandpa::Config {
local_key,
local_key: grandpa_key.map(Arc::new),
// FIXME #1578 make this available through chainspec
gossip_duration: Duration::from_millis(333),
justification_period: 4096,
@@ -165,7 +166,7 @@ construct_service_factory! {
config.custom.grandpa_import_setup = Some((block_import.clone(), link_half));
import_queue::<_, _, ed25519::Pair>(
import_queue::<_, _, AuraPair>(
slot_duration,
block_import,
Some(justification_import),
@@ -189,7 +190,7 @@ construct_service_factory! {
let finality_proof_import = block_import.clone();
let finality_proof_request_builder = finality_proof_import.create_finality_proof_request_builder();
import_queue::<_, _, ed25519::Pair>(
import_queue::<_, _, AuraPair>(
SlotDuration::get_or_compute(&*client)?,
block_import,
None,
@@ -215,7 +216,7 @@ construct_service_factory! {
#[cfg(test)]
mod tests {
use std::sync::Arc;
use consensus::CompatibleDigestItem;
use aura::CompatibleDigestItem;
use consensus_common::{Environment, Proposer, ImportBlock, BlockOrigin, ForkChoiceStrategy};
use node_primitives::DigestItem;
use node_runtime::{BalancesCall, Call, CENTS, UncheckedExtrinsic};
+7 -3
View File
@@ -44,12 +44,16 @@ pub type Balance = u128;
/// Type used for expressing timestamp.
pub type Moment = u64;
/// Alias to the signature scheme used for Aura authority signatures.
pub type AuraSignature = primitives::ed25519::Signature;
/// The aura crypto scheme defined via the keypair type.
#[cfg(feature = "std")]
pub type AuraPair = primitives::ed25519::Pair;
/// The Ed25519 pub key of an session that belongs to an Aura authority of the chain.
/// Identity of an Aura authority.
pub type AuraId = primitives::ed25519::Public;
/// Signature for an Aura authority.
pub type AuraSignature = primitives::ed25519::Signature;
/// Index of a transaction in the chain.
pub type Index = u64;
+2 -2
View File
@@ -22,7 +22,7 @@ use std::{str::FromStr, io::{stdin, Read}};
use hex_literal::hex;
use clap::load_yaml;
use bip39::{Mnemonic, Language, MnemonicType};
use substrate_primitives::{ed25519, sr25519, hexdisplay::HexDisplay, Pair, crypto::Ss58Codec, blake2_256};
use substrate_primitives::{ed25519, sr25519, hexdisplay::HexDisplay, Pair, Public, crypto::Ss58Codec, blake2_256};
use parity_codec::{Encode, Decode, Compact};
use sr_primitives::generic::Era;
use node_primitives::{Balance, Index, Hash};
@@ -32,7 +32,7 @@ mod vanity;
trait Crypto {
type Pair: Pair<Public=Self::Public>;
type Public: Ss58Codec + AsRef<[u8]>;
type Public: Public + Ss58Codec + AsRef<[u8]> + std::hash::Hash;
fn pair_from_suri(suri: &str, password: Option<&str>) -> Self::Pair {
Self::Pair::from_string(suri, password).expect("Invalid phrase")
}