diff --git a/Cargo.lock b/Cargo.lock index 4b44d707371fd..d05223218f6e4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2390,7 +2390,9 @@ dependencies = [ "substrate-cli 2.0.0", "substrate-client 2.0.0", "substrate-consensus-aura 2.0.0", + "substrate-consensus-aura-primitives 2.0.0", "substrate-executor 2.0.0", + "substrate-finality-grandpa-primitives 2.0.0", "substrate-inherents 2.0.0", "substrate-network 2.0.0", "substrate-primitives 2.0.0", @@ -4298,6 +4300,7 @@ dependencies = [ "substrate-executor 2.0.0", "substrate-inherents 2.0.0", "substrate-keyring 2.0.0", + "substrate-keystore 2.0.0", "substrate-network 2.0.0", "substrate-primitives 2.0.0", "substrate-service 2.0.0", @@ -4347,6 +4350,7 @@ dependencies = [ "substrate-executor 2.0.0", "substrate-inherents 2.0.0", "substrate-keyring 2.0.0", + "substrate-keystore 2.0.0", "substrate-network 2.0.0", "substrate-primitives 2.0.0", "substrate-service 2.0.0", @@ -4576,6 +4580,7 @@ dependencies = [ "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", "substrate-client 2.0.0", + "substrate-consensus-babe-primitives 2.0.0", "substrate-consensus-common 2.0.0", "substrate-keyring 2.0.0", "substrate-peerset 2.0.0", diff --git a/core/cli/src/lib.rs b/core/cli/src/lib.rs index 7cd7db88979cf..dd942e110e62b 100644 --- a/core/cli/src/lib.rs +++ b/core/cli/src/lib.rs @@ -444,7 +444,6 @@ where config.disable_grandpa = cli.no_grandpa; config.grandpa_voter = cli.grandpa_voter; - let is_dev = cli.shared_params.dev; let client_id = config.client_id(); @@ -462,16 +461,10 @@ where cli.pool_config, )?; - if let Some(key) = cli.key { - config.keys.push(key); - } - - if cli.shared_params.dev && cli.keyring.account.is_none() { - config.keys.push("//Alice".into()); - } - - if let Some(account) = cli.keyring.account { - config.keys.push(format!("//{}", account)); + if cli.shared_params.dev { + config.dev_key_seed = cli.keyring.account + .map(|a| format!("//{}", a)) + .or_else(|| Some("//Alice".into())); } let rpc_interface: &str = if cli.rpc_external { "0.0.0.0" } else { "127.0.0.1" }; diff --git a/core/cli/src/params.rs b/core/cli/src/params.rs index e1018eb93a4e8..a186c47e306ad 100644 --- a/core/cli/src/params.rs +++ b/core/cli/src/params.rs @@ -310,10 +310,6 @@ pub struct RunCmd { #[structopt(long = "keystore-path", value_name = "PATH", parse(from_os_str))] pub keystore_path: Option, - /// Specify additional key seed - #[structopt(long = "key", value_name = "STRING")] - pub key: Option, - /// Enable validator mode #[structopt(long = "validator")] pub validator: bool, @@ -443,7 +439,7 @@ lazy_static::lazy_static! { let conflicts_with = keyring::Sr25519Keyring::iter() .filter(|b| a != *b) .map(|b| b.to_string().to_lowercase()) - .chain(["name", "key"].iter().map(ToString::to_string)) + .chain(["name"].iter().map(ToString::to_string)) .collect::>(); let name = a.to_string().to_lowercase(); @@ -485,6 +481,7 @@ impl AugmentClap for Keyring { .long(&a.name) .help(&a.help) .conflicts_with_all(&conflicts_with_strs) + .requires("dev") .takes_value(false) ) }) diff --git a/core/client/src/client.rs b/core/client/src/client.rs index 683b07dd70a17..e46d16a136d86 100644 --- a/core/client/src/client.rs +++ b/core/client/src/client.rs @@ -20,7 +20,7 @@ use std::{ marker::PhantomData, collections::{HashSet, BTreeMap, HashMap}, sync::Arc, panic::UnwindSafe, result, cell::RefCell, rc::Rc, }; -use crate::error::Error; +use log::{info, trace, warn}; use futures::channel::mpsc; use parking_lot::{Mutex, RwLock}; use primitives::NativeOrEncoded; @@ -47,40 +47,53 @@ use crate::runtime_api::{ }; use primitives::{ Blake2Hasher, H256, ChangesTrieConfiguration, convert_hash, - NeverNativeValue, ExecutionContext + NeverNativeValue, ExecutionContext, + storage::{StorageKey, StorageData, well_known_keys}, NativeOrEncoded +}; +use substrate_telemetry::{telemetry, SUBSTRATE_INFO}; +use runtime_primitives::{ + Justification, BuildStorage, + generic::{BlockId, SignedBlock, DigestItem}, + traits::{ + Block as BlockT, Header as HeaderT, Zero, NumberFor, CurrentHeight, + BlockNumberToHash, ApiRef, ProvideRuntimeApi, + SaturatedConversion, One, DigestFor, + }, }; -use primitives::storage::{StorageKey, StorageData}; -use primitives::storage::well_known_keys; -use parity_codec::{Encode, Decode}; use state_machine::{ DBValue, Backend as StateBackend, CodeExecutor, ChangesTrieAnchorBlockId, ExecutionStrategy, ExecutionManager, prove_read, prove_child_read, ChangesTrieRootsStorage, ChangesTrieStorage, key_changes, key_changes_proof, OverlayedChanges, NeverOffchainExt, }; -use hash_db::Hasher; - -use crate::backend::{ - self, BlockImportOperation, PrunableStateChangesTrieStorage, - StorageCollection, ChildStorageCollection -}; -use crate::blockchain::{ - self, Info as ChainInfo, Backend as ChainBackend, - HeaderBackend as ChainHeaderBackend, ProvideCache, Cache, -}; -use crate::call_executor::{CallExecutor, LocalCallExecutor}; use executor::{RuntimeVersion, RuntimeInfo}; -use crate::notifications::{StorageNotifications, StorageEventStream}; -use crate::light::{call_executor::prove_execution, fetcher::ChangesProof}; -use crate::cht; -use crate::error; -use crate::in_mem; -use crate::block_builder::{self, api::BlockBuilder as BlockBuilderAPI}; -use crate::genesis; -use substrate_telemetry::{telemetry, SUBSTRATE_INFO}; - -use log::{info, trace, warn}; +use consensus::{ + Error as ConsensusError, BlockImportParams, + ImportResult, BlockOrigin, ForkChoiceStrategy, + well_known_cache_keys::Id as CacheKeyId, + SelectChain, self, +}; +use crate::{ + runtime_api::{ + CallRuntimeAt, ConstructRuntimeApi, Core as CoreApi, ProofRecorder, + InitializeBlock, + }, + backend::{ + self, BlockImportOperation, PrunableStateChangesTrieStorage, + StorageCollection, ChildStorageCollection + }, + blockchain::{ + self, Info as ChainInfo, Backend as ChainBackend, + HeaderBackend as ChainHeaderBackend, ProvideCache, Cache, + }, + call_executor::{CallExecutor, LocalCallExecutor}, + notifications::{StorageNotifications, StorageEventStream}, + light::{call_executor::prove_execution, fetcher::ChangesProof}, + block_builder::{self, api::BlockBuilder as BlockBuilderAPI}, + error::Error, + cht, error, in_mem, genesis +}; /// Type that implements `futures::Stream` of block import events. pub type ImportNotifications = mpsc::UnboundedReceiver>; @@ -291,6 +304,20 @@ pub fn new_with_backend( Client::new(backend, call_executor, build_genesis_storage, Default::default()) } +/// Figure out the block type for a given type (for now, just a `Client`). +pub trait BlockOf { + /// The type of the block. + type Type: BlockT; +} + +impl BlockOf for Client where + B: backend::Backend, + E: CallExecutor, + Block: BlockT, +{ + type Type = Block; +} + impl Client where B: backend::Backend, E: CallExecutor, diff --git a/core/client/src/lib.rs b/core/client/src/lib.rs index a1351f20e4681..76882d1355fee 100644 --- a/core/client/src/lib.rs +++ b/core/client/src/lib.rs @@ -115,7 +115,7 @@ pub use crate::client::{ new_in_mem, BlockBody, BlockStatus, ImportNotifications, FinalityNotifications, BlockchainEvents, BlockImportNotification, Client, ClientInfo, ExecutionStrategies, FinalityNotification, - LongestChain, + LongestChain, BlockOf, utils, }; #[cfg(feature = "std")] diff --git a/core/consensus/aura/Cargo.toml b/core/consensus/aura/Cargo.toml index e7a5007e220b9..6c701925cb4d6 100644 --- a/core/consensus/aura/Cargo.toml +++ b/core/consensus/aura/Cargo.toml @@ -17,6 +17,7 @@ inherents = { package = "substrate-inherents", path = "../../inherents" } srml-aura = { path = "../../../srml/aura" } client = { package = "substrate-client", path = "../../client" } substrate-telemetry = { path = "../../telemetry" } +substrate-keystore = { path = "../../keystore" } consensus_common = { package = "substrate-consensus-common", path = "../common" } sr-primitives = { path = "../../sr-primitives" } futures-preview = { version = "0.3.0-alpha.17", features = ["compat"] } diff --git a/core/consensus/aura/primitives/src/lib.rs b/core/consensus/aura/primitives/src/lib.rs index 10c3c96e4fef3..974fb9187c632 100644 --- a/core/consensus/aura/primitives/src/lib.rs +++ b/core/consensus/aura/primitives/src/lib.rs @@ -23,6 +23,40 @@ use substrate_client::decl_runtime_apis; use rstd::vec::Vec; use sr_primitives::ConsensusEngineId; +mod app_sr25519 { + use substrate_primitives::{app_crypto, crypto::key_types::AURA, sr25519}; + app_crypto!(sr25519::Pair, sr25519::Public, sr25519::Signature, AURA); +} + +pub mod sr25519 { + /// An Aura authority keypair using S/R 25519 as its crypto. + #[cfg(feature = "std")] + pub type AuthorityPair = super::app_sr25519::Pair; + + /// An Aura authority signature using S/R 25519 as its crypto. + pub type AuthoritySignature = super::app_sr25519::Signature; + + /// An Aura authority identifier using S/R 25519 as its crypto. + pub type AuthorityId = super::app_sr25519::Public; +} + +mod app_ed25519 { + use substrate_primitives::{app_crypto, crypto::key_types::AURA, ed25519}; + app_crypto!(ed25519::Pair, ed25519::Public, ed25519::Signature, AURA); +} + +pub mod ed25519 { + /// An Aura authority keypair using Ed25519 as its crypto. + #[cfg(feature = "std")] + pub type AuthorityPair = super::app_ed25519::Pair; + + /// An Aura authority signature using Ed25519 as its crypto. + pub type AuthoritySignature = super::app_ed25519::Signature; + + /// An Aura authority identifier using Ed25519 as its crypto. + pub type AuthorityId = super::app_ed25519::Public; +} + /// The `ConsensusEngineId` of AuRa. pub const AURA_ENGINE_ID: ConsensusEngineId = [b'a', b'u', b'r', b'a']; diff --git a/core/consensus/aura/src/lib.rs b/core/consensus/aura/src/lib.rs index a08dcdf1d42fa..2de35a899794f 100644 --- a/core/consensus/aura/src/lib.rs +++ b/core/consensus/aura/src/lib.rs @@ -40,16 +40,18 @@ use consensus_common::import_queue::{ }; use client::{ block_builder::api::BlockBuilder as BlockBuilderApi, - blockchain::ProvideCache, + blockchain::{ProvideCache, HeaderBackend}, runtime_api::ApiExt, error::Result as CResult, backend::AuxStore, + BlockOf }; +use substrate_keystore::Store; use sr_primitives::{generic::{self, BlockId, OpaqueDigestItemId}, Justification}; use sr_primitives::traits::{Block as BlockT, Header, DigestItemFor, ProvideRuntimeApi, Zero, Member}; -use primitives::Pair; +use primitives::crypto::{Pair, AppPair, AppKey}; use inherents::{InherentDataProviders, InherentData}; use futures::{prelude::*, future}; @@ -141,7 +143,7 @@ pub fn start_aura( force_authoring: bool, ) -> Result, consensus_common::Error> where B: BlockT, - C: ProvideRuntimeApi + ProvideCache + AuxStore + Send + Sync, + C: ProvideRuntimeApi + BlockOf + ProvideCache + AuxStore + Send + Sync, C::Api: AuraApi>, SC: SelectChain, E::Proposer: Proposer, @@ -188,7 +190,7 @@ struct AuraWorker { impl SlotWorker for AuraWorker where B: BlockT, - C: ProvideRuntimeApi + ProvideCache + Sync, + C: ProvideRuntimeApi + BlockOf + ProvideCache + Sync, C::Api: AuraApi>, E: Environment, E::Proposer: Proposer, @@ -507,7 +509,7 @@ impl AuraVerifier #[forbid(deprecated)] impl Verifier for AuraVerifier where - C: ProvideRuntimeApi + Send + Sync + client::backend::AuxStore + ProvideCache, + C: ProvideRuntimeApi + Send + Sync + client::backend::AuxStore + ProvideCache + BlockOf, C::Api: BlockBuilderApi + AuraApi>, DigestItemFor: CompatibleDigestItem

, P: Pair + Send + Sync + 'static, @@ -610,7 +612,7 @@ impl Verifier for AuraVerifier where fn initialize_authorities_cache(client: &C) -> Result<(), ConsensusError> where A: Codec, B: BlockT, - C: ProvideRuntimeApi + ProvideCache, + C: ProvideRuntimeApi + BlockOf + ProvideCache, C::Api: AuraApi, { // no cache => no initialization @@ -644,7 +646,7 @@ fn initialize_authorities_cache(client: &C) -> Result<(), ConsensusErro fn authorities(client: &C, at: &BlockId) -> Result, ConsensusError> where A: Codec, B: BlockT, - C: ProvideRuntimeApi + ProvideCache, + C: ProvideRuntimeApi + BlockOf + ProvideCache, C::Api: AuraApi, { client @@ -657,6 +659,69 @@ fn authorities(client: &C, at: &BlockId) -> Result, Consensus .ok_or_else(|| consensus_common::Error::InvalidAuthoritiesSet.into()) } +/// Means of determining a list of authority keys, generally used to determine if we are an +/// authority by cross-referencing this list against the keys in the store and finding one that +/// appears in both. +/// +/// This is implemented directly on the `AppPair` key type. +pub trait AuthorityProvider: AppPair { + /// Provide a list of authority keys that is current as of a given block. + fn authorities_at(client: &C, at: &BlockId<::Type>) + -> Result::Public>, ConsensusError> + where + C: ProvideRuntimeApi + BlockOf + ProvideCache<::Type>, + C::Api: AuraApi<::Type, ::Public>; + + /// Provide a list of authority keys that is current. By default this will just use the state of + /// the best block, but you might want it to use some other block's state instead if it's + /// more sophisticated. Grandpa, for example, will probably want to use the state of the last + /// finalised block. + fn authorities(client: &C) -> Result::Public>, ConsensusError> where + C: ProvideRuntimeApi + BlockOf + ProvideCache<::Type> + + HeaderBackend<::Type>, + C::Api: AuraApi<::Type, ::Public> + { + Self::authorities_at::(client, &BlockId::Number(client.info().best_number)) + } + + /// Provide the authority key, if any, that is controlled by this node as of the given block. + fn authority(client: &C, keystore: Arc) -> Option where + C: ProvideRuntimeApi + BlockOf + ProvideCache<::Type> + + HeaderBackend<::Type>, + C::Api: AuraApi<::Type, ::Public> + { + let owned = keystore.contents::<::Public>().ok()?; + let authorities = Self::authorities(client).ok()?; + let maybe_pub = owned.into_iter() + .find(|i| authorities.contains(i)); + maybe_pub.and_then(|public| keystore.load(&public, "").ok()) + } +} + +impl AuthorityProvider for aura_primitives::ed25519::AuthorityPair { + /// Provide a list of authority keys that is current as of a given block. + fn authorities_at(client: &C, at: &BlockId<::Type>) + -> Result::Public>, ConsensusError> + where + C: ProvideRuntimeApi + BlockOf + ProvideCache<::Type>, + C::Api: AuraApi<::Type, ::Public>, + { + authorities::(client, at) + } +} + +impl AuthorityProvider for aura_primitives::sr25519::AuthorityPair { + /// Provide a list of authority keys that is current as of a given block. + fn authorities_at(client: &C, at: &BlockId<::Type>) + -> Result::Public>, ConsensusError> + where + C: ProvideRuntimeApi + BlockOf + ProvideCache<::Type>, + C::Api: AuraApi<::Type, ::Public>, + { + authorities::(client, at) + } +} + /// The Aura import queue type. pub type AuraImportQueue = BasicQueue; @@ -685,7 +750,7 @@ pub fn import_queue( inherent_data_providers: InherentDataProviders, ) -> Result, consensus_common::Error> where B: BlockT, - C: 'static + ProvideRuntimeApi + ProvideCache + Send + Sync + AuxStore, + C: 'static + ProvideRuntimeApi + BlockOf + ProvideCache + Send + Sync + AuxStore, C::Api: BlockBuilderApi + AuraApi>, DigestItemFor: CompatibleDigestItem

, P: Pair + Send + Sync + 'static, diff --git a/core/consensus/babe/Cargo.toml b/core/consensus/babe/Cargo.toml index 331c85dda8874..44125f8a55952 100644 --- a/core/consensus/babe/Cargo.toml +++ b/core/consensus/babe/Cargo.toml @@ -12,14 +12,15 @@ primitives = { package = "substrate-primitives", path = "../../primitives" } num-bigint = "0.2" num-rational = "0.2" num-traits = "0.2" -runtime_support = { package = "srml-support", path = "../../../srml/support" } -runtime_version = { package = "sr-version", path = "../../sr-version" } -runtime_io = { package = "sr-io", path = "../../sr-io" } +runtime-support = { package = "srml-support", path = "../../../srml/support" } +runtime-version = { package = "sr-version", path = "../../sr-version" } +runtime-io = { package = "sr-io", path = "../../sr-io" } inherents = { package = "substrate-inherents", path = "../../inherents" } substrate-telemetry = { path = "../../telemetry" } +substrate-keystore = { path = "../../keystore" } srml-babe = { path = "../../../srml/babe" } client = { package = "substrate-client", path = "../../client" } -consensus_common = { package = "substrate-consensus-common", path = "../common" } +consensus-common = { package = "substrate-consensus-common", path = "../common" } slots = { package = "substrate-consensus-slots", path = "../slots" } sr-primitives = { path = "../../sr-primitives" } fork-tree = { path = "../../utils/fork-tree" } diff --git a/core/consensus/babe/primitives/src/digest.rs b/core/consensus/babe/primitives/src/digest.rs index 6266b828fbb83..4c613667b9720 100644 --- a/core/consensus/babe/primitives/src/digest.rs +++ b/core/consensus/babe/primitives/src/digest.rs @@ -18,6 +18,7 @@ #[cfg(feature = "std")] use primitives::sr25519::Signature; +use super::AuthoritySignature; #[cfg(feature = "std")] use super::{BABE_ENGINE_ID, Epoch}; #[cfg(not(feature = "std"))] @@ -103,10 +104,10 @@ pub trait CompatibleDigestItem: Sized { fn as_babe_pre_digest(&self) -> Option; /// Construct a digest item which contains a BABE seal. - fn babe_seal(signature: Signature) -> Self; + fn babe_seal(signature: AuthoritySignature) -> Self; /// If this item is a BABE signature, return the signature. - fn as_babe_seal(&self) -> Option; + fn as_babe_seal(&self) -> Option; /// If this item is a BABE epoch, return it. fn as_babe_epoch(&self) -> Option; @@ -124,11 +125,11 @@ impl CompatibleDigestItem for DigestItem where self.try_to(OpaqueDigestItemId::PreRuntime(&BABE_ENGINE_ID)) } - fn babe_seal(signature: Signature) -> Self { + fn babe_seal(signature: AuthoritySignature) -> Self { DigestItem::Seal(BABE_ENGINE_ID, signature.encode()) } - fn as_babe_seal(&self) -> Option { + fn as_babe_seal(&self) -> Option { self.try_to(OpaqueDigestItemId::Seal(&BABE_ENGINE_ID)) } diff --git a/core/consensus/babe/primitives/src/lib.rs b/core/consensus/babe/primitives/src/lib.rs index 0e1cc217abc69..f880f1cffa8b1 100644 --- a/core/consensus/babe/primitives/src/lib.rs +++ b/core/consensus/babe/primitives/src/lib.rs @@ -31,14 +31,22 @@ use substrate_client::decl_runtime_apis; pub use digest::{BabePreDigest, CompatibleDigestItem}; pub use digest::{BABE_VRF_PREFIX, RawBabePreDigest}; +mod app { + use substrate_primitives::{app_crypto, crypto::key_types::BABE, sr25519}; + app_crypto!(sr25519::Pair, sr25519::Public, sr25519::Signature, BABE); +} + /// A Babe authority keypair. Necessarily equivalent to the schnorrkel public key used in /// the main Babe module. If that ever changes, then this must, too. #[cfg(feature = "std")] -pub type AuthorityPair = sr25519::Pair; +pub type AuthorityPair = app::Pair; + +/// A Babe authority signature. +pub type AuthoritySignature = app::Signature; /// A Babe authority identifier. Necessarily equivalent to the schnorrkel public key used in /// the main Babe module. If that ever changes, then this must, too. -pub type AuthorityId = sr25519::Public; +pub type AuthorityId = app::Public; /// The `ConsensusEngineId` of BABE. pub const BABE_ENGINE_ID: ConsensusEngineId = *b"BABE"; diff --git a/core/consensus/babe/src/lib.rs b/core/consensus/babe/src/lib.rs index 4a4261b8dd8a0..cf5da15cc171e 100644 --- a/core/consensus/babe/src/lib.rs +++ b/core/consensus/babe/src/lib.rs @@ -18,10 +18,12 @@ //! //! BABE (Blind Assignment for Blockchain Extension) consensus in Substrate. -#![forbid(unsafe_code, missing_docs, unused_must_use, unused_imports, unused_variables)] -#![cfg_attr(not(test), forbid(dead_code))] +//#![forbid(unsafe_code, missing_docs, unused_must_use, unused_imports, unused_variables)] +//#![cfg_attr(not(test), forbid(dead_code))] pub use babe_primitives::*; pub use consensus_common::SyncOracle; +use std::{collections::HashMap, sync::Arc, u64, fmt::{Debug, Display}, pin::Pin, time::{Instant, Duration}}; +use babe_primitives; use consensus_common::ImportResult; use consensus_common::import_queue::{ BoxJustificationImport, BoxFinalityProofImport, @@ -32,11 +34,11 @@ use sr_primitives::traits::{ Block as BlockT, Header, DigestItemFor, NumberFor, ProvideRuntimeApi, SimpleBitOps, Zero, }; -use std::{collections::HashMap, sync::Arc, u64, fmt::{Debug, Display}, pin::Pin, time::{Instant, Duration}}; +use substrate_keystore::Store; use runtime_support::serde::{Serialize, Deserialize}; use parity_codec::{Decode, Encode}; use parking_lot::{Mutex, MutexGuard}; -use primitives::{Blake2Hasher, H256, Pair, Public, sr25519}; +use primitives::{Blake2Hasher, H256, Pair, Public}; use merlin::Transcript; use inherents::{InherentDataProviders, InherentData}; use substrate_telemetry::{ @@ -65,8 +67,7 @@ use consensus_common::import_queue::{Verifier, BasicQueue}; use client::{ block_builder::api::BlockBuilder as BlockBuilderApi, blockchain::{self, HeaderBackend, ProvideCache}, - BlockchainEvents, - CallExecutor, Client, + BlockchainEvents, BlockOf, CallExecutor, Client, runtime_api::ApiExt, error::Result as ClientResult, backend::{AuxStore, Backend}, @@ -775,7 +776,8 @@ fn register_babe_inherent_data_provider( } fn get_keypair(q: &sr25519::Pair) -> &Keypair { - q.as_ref() + use primitives::crypto::IsWrappedBy; + primitives::sr25519::Pair::from_ref(q).as_ref() } #[allow(deprecated)] @@ -1195,6 +1197,117 @@ pub fn import_queue, I, RA, PRA>( Ok((queue, timestamp_core, block_import, pruning_task)) } +/// Provide a list of authority keys that is current as of a given block. +#[allow(deprecated)] +fn authorities_at(client: &C, at: &BlockId<::Type>) + -> Result, ConsensusError> +where + C: ProvideRuntimeApi + BlockOf + ProvideCache<::Type>, + C::Api: BabeApi<::Type> +{ + client + .cache() + .and_then(|cache| cache + .get_at(&well_known_cache_keys::AUTHORITIES, at) + .and_then(|v| Decode::decode(&mut &v[..])) + ) + .or_else(|| BabeApi::epoch(&*client.runtime_api(), at).ok() + .map(|epoch| epoch.authorities.into_iter().map(|x| x.0).collect()) + ) + .ok_or_else(|| consensus_common::Error::InvalidAuthoritiesSet.into()) +} + +/// Provide the authority key, if any, that is controlled by this node as of the given block. +fn authority(client: &C, keystore: Arc) -> Option where + C: ProvideRuntimeApi + BlockOf + ProvideCache<::Type> + + HeaderBackend<::Type>, + C::Api: BabeApi<::Type> +{ + let owned = keystore.contents::().ok()?; + let at = BlockId::Number(client.info().best_number); + /// The list of authority keys that is current. By default this will just use the state of + /// the best block, but you might want it to use some other block's state instead if it's + /// more sophisticated. Grandpa, for example, will probably want to use the state of the last + /// finalised block. + let authorities = authorities_at::(client, &at).ok()?; + let maybe_pub = owned.into_iter() + .find(|i| authorities.contains(i)); + maybe_pub.and_then(|public| keystore.load(&public, "").ok()) +} + +/// Type of source for block sealing. Different consensus algorithms have different sealing +/// methods; for PoW it'll be a miner or mining instance. For PoA/PoS it'll be a key type. +pub trait SealingSource { + /// Human-readable description of this general class. + /// + /// e.g. `"ProgPoW"`, `"S/R 25519 Key"`. + const SEALER_TYPE: &'static str; + /// Human-readable description of this specific instance. + /// + /// e.g. `"OpenCL GPU Radeon 8970 @ slot 1"`, `"5Gav1mbbo348grBREHTYgevvf4Gfe5GFE4"`. + fn format(&self) -> String; +} + +impl SealingSource for T { + const SEALER_TYPE: &'static str = "Key"; + fn format(&self) -> String { use primitives::crypto::Ss58Codec; self.to_ss58check() } +} + +/// A runtime service for a consensus worker. +/// +/// This is administered by the client service to help it spin up everything necessary. It can +/// provide API hooks for handling user-level/RPC events. It can return information regarding +/// the status of the service. +pub trait Service<'a>: 'a { + /// Instance of the source of sealing. Different consensus algorithms have different sealing + /// methods; for PoW it'll be a miner or mining instance. For PoA/PoS it'll be a key type. + type Sealer: SealingSource; + + /// The Client type. Different services can make different constraints on this. + type Client: ProvideRuntimeApi + BlockOf + ProvideCache<::Type> + + HeaderBackend<::Type>; + + /// Initialize the consensus service. + fn initialize(client: &'a Self::Client, keystore: Arc) -> Self; + + /// Return status of the authoring/sealing instance. For PoA/PoS consensus mechanisms, this + /// will just be a public key. For PoW mechanisms, this could be the miner instance. + fn sealer(&self) -> Option; +} + +/// The Babe consensus service struct. This can be passed in to the main service as (one of) the +/// consensus modules if your chain uses Babe block production. +pub struct BabeService<'a, Client> where + Client: ProvideRuntimeApi + BlockOf + ProvideCache<::Type> + + HeaderBackend<::Type>, + Client::Api: BabeApi<::Type>, +{ + /// The main client that lets us interact with the chain/state. + client: &'a Client, + /// The keystore. + keystore: Arc, +} + +impl<'a, Client> Service<'a> for BabeService<'a, Client> where + Client: ProvideRuntimeApi + BlockOf + ProvideCache<::Type> + + HeaderBackend<::Type>, + Client::Api: BabeApi<::Type> +{ + type Sealer = AuthorityId; + type Client = Client; + + fn initialize(client: &'a Self::Client, keystore: Arc) -> Self { + // TODO: Put in any default/test keys into the keystore. + // TODO: Actually initialise the babe worker. + Self { client, keystore } + } + + fn sealer(&self) -> Option { + authority(self.client, self.keystore.clone()) + .map(|p| p.public()) + } +} + /// BABE test helpers. Utility methods for manually authoring blocks. #[cfg(feature = "test-helpers")] pub mod test_helpers { @@ -1206,7 +1319,7 @@ pub mod test_helpers { client: &C, at: &BlockId, slot_number: u64, - key: &sr25519::Pair, + key: &AuthorityPair, c: (u64, u64), ) -> Option where B: BlockT, diff --git a/core/finality-grandpa/primitives/src/lib.rs b/core/finality-grandpa/primitives/src/lib.rs index b60acffc6c2f4..59109035ba94d 100644 --- a/core/finality-grandpa/primitives/src/lib.rs +++ b/core/finality-grandpa/primitives/src/lib.rs @@ -28,15 +28,20 @@ use sr_primitives::{ConsensusEngineId, traits::{DigestFor, NumberFor}}; use client::decl_runtime_apis; use rstd::vec::Vec; +mod app { + use substrate_primitives::{app_crypto, crypto::key_types::GRANDPA, ed25519}; + app_crypto!(ed25519::Pair, ed25519::Public, ed25519::Signature, GRANDPA); +} + /// The grandpa crypto scheme defined via the keypair type. #[cfg(feature = "std")] -pub type AuthorityPair = primitives::ed25519::Pair; +pub type AuthorityPair = app::Pair; /// Identity of a Grandpa authority. -pub type AuthorityId = primitives::ed25519::Public; +pub type AuthorityId = app::Public; /// Signature for a Grandpa authority. -pub type AuthoritySignature = primitives::ed25519::Signature; +pub type AuthoritySignature = app::Signature; /// The `ConsensusEngineId` of GRANDPA. pub const GRANDPA_ENGINE_ID: ConsensusEngineId = *b"FRNK"; diff --git a/core/finality-grandpa/src/communication/gossip.rs b/core/finality-grandpa/src/communication/gossip.rs index 3d14381e724b7..7106ac61a231d 100644 --- a/core/finality-grandpa/src/communication/gossip.rs +++ b/core/finality-grandpa/src/communication/gossip.rs @@ -86,7 +86,7 @@ use sr_primitives::traits::{NumberFor, Block as BlockT, Zero}; use network::consensus_gossip::{self as network_gossip, MessageIntent, ValidatorContext}; use network::{config::Roles, PeerId}; use parity_codec::{Encode, Decode}; -use crate::ed25519::Public as AuthorityId; +use fg_primitives::AuthorityId; use substrate_telemetry::{telemetry, CONSENSUS_DEBUG}; use log::{trace, debug, warn}; diff --git a/core/finality-grandpa/src/communication/mod.rs b/core/finality-grandpa/src/communication/mod.rs index e9be187eac09f..ad7d1b9666a54 100644 --- a/core/finality-grandpa/src/communication/mod.rs +++ b/core/finality-grandpa/src/communication/mod.rs @@ -50,7 +50,7 @@ use crate::environment::HasVoted; use gossip::{ GossipMessage, FullCatchUpMessage, FullCommitMessage, VoteOrPrecommitMessage, GossipValidator }; -use primitives::ed25519::{Public as AuthorityId, Signature as AuthoritySignature}; +use primitives::ed25519::{AuthorityPair, Public as AuthorityId, Signature as AuthoritySignature}; pub mod gossip; mod periodic; @@ -341,7 +341,7 @@ impl> NetworkBridge { round: Round, set_id: SetId, voters: Arc>, - local_key: Option>, + local_key: Option>, has_voted: HasVoted, ) -> ( impl Stream,Error=Error>, @@ -354,8 +354,7 @@ impl> NetworkBridge { ); let locals = local_key.and_then(|pair| { - let public = pair.public(); - let id = AuthorityId(public.0); + let id = pair.public(); if voters.contains_key(&id) { Some((pair, id)) } else { @@ -633,9 +632,9 @@ pub(crate) fn check_message_sig( round: u64, set_id: u64, ) -> Result<(), ()> { - let as_public = AuthorityId::from_raw(id.0); + let as_public = id.clone(); let encoded_raw = localized_payload(round, set_id, message); - if ed25519::Pair::verify(signature, &encoded_raw, as_public) { + if AuthorityPair::verify(signature, &encoded_raw, as_public) { Ok(()) } else { debug!(target: "afg", "Bad signature on message from {:?}", id); @@ -653,7 +652,7 @@ pub(crate) fn check_message_sig( struct OutgoingMessages> { round: u64, set_id: u64, - locals: Option<(Arc, AuthorityId)>, + locals: Option<(Arc, AuthorityId)>, sender: mpsc::UnboundedSender>, network: N, has_voted: HasVoted, diff --git a/core/finality-grandpa/src/environment.rs b/core/finality-grandpa/src/environment.rs index e82cc1f421d73..31eaadfbabbea 100644 --- a/core/finality-grandpa/src/environment.rs +++ b/core/finality-grandpa/src/environment.rs @@ -476,7 +476,7 @@ where { type Timer = Box + Send>; type Id = AuthorityId; - type Signature = ed25519::Signature; + type Signature = AuthoritySignature; // regular round message streams type In = Box>, + pub local_key: Option>, /// Some local identifier of the voter. pub name: Option, } @@ -396,7 +396,7 @@ where } fn global_communication, B, E, N, RA>( - local_key: Option<&Arc>, + local_key: Option<&Arc>, set_id: u64, voters: &Arc>, client: &Arc>, diff --git a/core/keystore/src/lib.rs b/core/keystore/src/lib.rs index 89cfca559c650..257b211450a7e 100644 --- a/core/keystore/src/lib.rs +++ b/core/keystore/src/lib.rs @@ -23,7 +23,7 @@ use std::path::PathBuf; use std::fs::{self, File}; use std::io::{self, Write}; -use primitives::crypto::{KeyTypeId, Pair, Public}; +use primitives::crypto::{KeyTypeId, AppKey, AppPublic, AppPair, Pair, Public, IsWrappedBy}; /// Keystore error. #[derive(Debug, derive_more::Display, derive_more::From)] @@ -69,8 +69,8 @@ impl Store { Ok(Store { path, additional: HashMap::new() }) } - fn get_pair(&self, public: &TPair::Public) -> Result> { - let key = (TPair::KEY_TYPE, public.to_raw_vec()); + fn get_pair(&self, public: &TPair::Public, key_type: KeyTypeId) -> Result> { + let key = (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)?; @@ -79,35 +79,55 @@ impl Store { Ok(None) } - fn insert_pair(&mut self, pair: &TPair) { - let key = (TPair::KEY_TYPE, pair.public().to_raw_vec()); + fn insert_pair(&mut self, pair: &TPair, key_type: KeyTypeId) { + let key = (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 { + pub fn generate_by_type(&self, password: &str, key_type: KeyTypeId) -> Result { let (pair, phrase, _) = TPair::generate_with_phrase(Some(password)); - let mut file = File::create(self.key_file_path::(&pair.public()))?; + let mut file = File::create(self.key_file_path::(&pair.public(), key_type))?; ::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 { + pub fn generate_from_seed_by_type(&mut self, seed: &str, key_type: KeyTypeId) -> Result { let pair = TPair::from_string(seed, None) .ok().ok_or(Error::InvalidSeed)?; - self.insert_pair(&pair); + self.insert_pair(&pair, key_type); Ok(pair) } + /// Generate a new key, placing it into the store. + pub fn generate< + Pair: AppPair + >(&self, password: &str) -> Result { + self.generate_by_type::(password, Pair::ID) + .map(Into::into) + } + + /// Create a new key from seed. Do not place it into the store. + pub fn generate_from_seed< + Pair: AppPair, + >(&mut self, seed: &str) -> Result { + self.generate_from_seed_by_type::(seed, Pair::ID) + .map(Into::into) + } + /// Load a key file with given public key. - pub fn load(&self, public: &TPair::Public, password: &str) -> Result { - if let Some(pair) = self.get_pair(public)? { + pub fn load_by_type(&self, + public: &TPair::Public, + password: &str, + key_type: KeyTypeId + ) -> Result { + if let Some(pair) = self.get_pair(public, key_type)? { return Ok(pair) } - let path = self.key_file_path::(public); + let path = self.key_file_path::(public, key_type); let file = File::open(path)?; let phrase: String = ::serde_json::from_reader(&file)?; @@ -119,18 +139,25 @@ impl Store { Ok(pair) } + /// Load a key file with given public key. + pub fn load< + Pair_: AppPair + >(&self, public: &::Public, password: &str) -> Result { + self.load_by_type::(IsWrappedBy::from_ref(public), password, Pair_::ID) + .map(Into::into) + } + /// Get public keys of all stored keys. - pub fn contents(&self) -> Result> { + pub fn contents_by_type(&self, key_type: KeyTypeId) -> Result> { let mut public_keys: Vec = self.additional.keys() .filter_map(|(ty, public)| { - if *ty != TPublic::KEY_TYPE { + if *ty != 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(); @@ -151,10 +178,22 @@ impl Store { Ok(public_keys) } - fn key_file_path(&self, public: &TPair::Public) -> PathBuf { + /// Get public keys of all stored keys. + /// + /// This will just use the type of the public key (a list of which to be returned) in order + /// to determine the key type. Unless you use a specialised application-type public key, then + /// this only give you keys registered under generic cryptography, and will not return keys + /// registered under the application type. + pub fn contents< + Public: AppPublic + >(&self) -> Result> { + self.contents_by_type::(Public::ID) + .map(|v| v.into_iter().map(Into::into).collect()) + } + + fn key_file_path(&self, public: &TPair::Public, key_type: KeyTypeId) -> PathBuf { let mut buf = self.path.clone(); - let bytes: [u8; 4] = TPair::KEY_TYPE.to_le_bytes(); - let key_type = hex::encode(bytes); + let key_type = hex::encode(key_type); let key = hex::encode(public.as_slice()); buf.push(key_type + key.as_str()); buf diff --git a/core/network/Cargo.toml b/core/network/Cargo.toml index 3d687486c03bc..26bb6055fa9fc 100644 --- a/core/network/Cargo.toml +++ b/core/network/Cargo.toml @@ -44,6 +44,7 @@ test-client = { package = "substrate-test-runtime-client", path = "../../core/te erased-serde = "0.3.9" void = "1.0" zeroize = "0.9.0" +babe-primitives = { package = "substrate-consensus-babe-primitives", path = "../consensus/babe/primitives" } [dev-dependencies] env_logger = { version = "0.6" } diff --git a/core/network/src/test/mod.rs b/core/network/src/test/mod.rs index c416d347d6b9c..110201057c783 100644 --- a/core/network/src/test/mod.rs +++ b/core/network/src/test/mod.rs @@ -57,7 +57,7 @@ use test_client::{self, AccountKeyring}; pub use test_client::runtime::{Block, Extrinsic, Hash, Transfer}; pub use test_client::TestClient; -type AuthorityId = primitives::sr25519::Public; +type AuthorityId = babe_primitives::AuthorityId; #[cfg(any(test, feature = "test-helpers"))] /// A Verifier that accepts all blocks and passes them on with the configured diff --git a/core/offchain/src/api.rs b/core/offchain/src/api.rs index 8af7b333f5f74..8466f97468a17 100644 --- a/core/offchain/src/api.rs +++ b/core/offchain/src/api.rs @@ -67,6 +67,7 @@ impl StoredKey { let phrase = sr25519::Pair::generate_with_phrase(password).1; Self { kind, phrase } } + CryptoKind::Dummy => Self { kind, phrase: String::new() }, } } @@ -80,6 +81,7 @@ impl StoredKey { sr25519::Pair::from_phrase(&self.phrase, password) .map(|x| LocalKey::Sr25519(x.0)) } + CryptoKind::Dummy => Err(())?, } .map_err(|e| { warn!("Error recovering Offchain Worker key. Password invalid? {:?}", e); diff --git a/core/primitives/src/crypto.rs b/core/primitives/src/crypto.rs index 327a8a3eb1254..a5e7c74c1b110 100644 --- a/core/primitives/src/crypto.rs +++ b/core/primitives/src/crypto.rs @@ -18,14 +18,12 @@ //! Cryptographic utilities. // end::description[] -#[cfg(feature = "std")] -use std::convert::{TryFrom, TryInto}; +use rstd::convert::{TryFrom, TryInto}; #[cfg(feature = "std")] use parking_lot::Mutex; #[cfg(feature = "std")] use rand::{RngCore, rngs::OsRng}; -#[cfg(feature = "std")] -use parity_codec::{Encode, Decode}; +use parity_codec::{Encode, Decode, Codec}; #[cfg(feature = "std")] use regex::Regex; #[cfg(feature = "std")] @@ -457,7 +455,8 @@ impl + AsRef<[u8]> + Default + Derive> Ss58Codec for T { } /// Trait suitable for typical cryptographic PKI key public type. -pub trait Public: AsRef<[u8]> + TypedKey + PartialEq + Eq + Clone + Send + Sync { +#[cfg(feature = "std")] +pub trait Public: AsRef<[u8]> + AsMut<[u8]> + Default + Derive + CryptoType + PartialEq + Eq + Clone + Send + Sync { /// 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 @@ -466,19 +465,108 @@ pub trait Public: AsRef<[u8]> + TypedKey + PartialEq + Eq + Clone + Send + Sync /// Return a `Vec` filled with raw data. #[cfg(feature = "std")] - fn to_raw_vec(&self) -> Vec; + fn to_raw_vec(&self) -> Vec { self.as_slice().to_owned() } /// Return a slice filled with raw data. - fn as_slice(&self) -> &[u8]; + fn as_slice(&self) -> &[u8] { self.as_ref() } +} + +/// Trait suitable for typical cryptographic PKI key public type. +#[cfg(not(feature = "std"))] +pub trait Public: AsRef<[u8]> + AsMut<[u8]> + Default + CryptoType + PartialEq + Eq + Clone + Send + Sync { + /// 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` filled with raw data. + #[cfg(feature = "std")] + fn to_raw_vec(&self) -> Vec { self.as_slice().to_owned() } + + /// Return a slice filled with raw data. + fn as_slice(&self) -> &[u8] { self.as_ref() } +} + +/// Dummy cryptography. Doesn't do anything. +#[derive(Clone, Hash, Default, Eq, PartialEq)] +pub struct Dummy; + +impl AsRef<[u8]> for Dummy { + fn as_ref(&self) -> &[u8] { &b""[..] } +} + +impl AsMut<[u8]> for Dummy { + fn as_mut(&mut self) -> &mut[u8] { + unsafe { + #[allow(mutable_transmutes)] + rstd::mem::transmute::<_, &'static mut [u8]>(&b""[..]) + } + } +} + +impl CryptoType for Dummy { + const KIND: Kind = Kind::Dummy; + type Pair = Dummy; +} + +#[cfg(feature = "std")] +impl Derive for Dummy {} + +/// Trait suitable for typical cryptographic PKI key public type. +impl Public for Dummy { + fn from_slice(_: &[u8]) -> Self { Self } + #[cfg(feature = "std")] + fn to_raw_vec(&self) -> Vec { vec![] } + fn as_slice(&self) -> &[u8] { b"" } +} + +#[cfg(feature = "std")] +impl Pair for Dummy { + type Public = Dummy; + type Seed = Dummy; + type Signature = Dummy; + type DeriveError = (); + fn generate_with_phrase(_: Option<&str>) -> (Self, String, Self::Seed) { Default::default() } + fn from_phrase(_: &str, _: Option<&str>) + -> Result<(Self, Self::Seed), SecretStringError> + { + Ok(Default::default()) + } + fn derive< + Iter: Iterator + >(&self, _: Iter) -> Result { Ok(Self) } + fn from_seed(_: &Self::Seed) -> Self { Self } + fn from_seed_slice(_: &[u8]) -> Result { Ok(Self) } + fn from_standard_components< + I: Iterator + >( + _: &str, + _: Option<&str>, + _: I + ) -> Result { Ok(Self) } + fn sign(&self, _: &[u8]) -> Self::Signature { Self } + fn verify, M: AsRef<[u8]>>( + _: &Self::Signature, + _: M, + _: P + ) -> bool { true } + fn verify_weak, M: AsRef<[u8]>>( + _: &[u8], + _: M, + _: P + ) -> bool { true } + fn public(&self) -> Self::Public { Self } + fn to_raw_vec(&self) -> Vec { vec![] } } /// 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: TypedKey + Sized + Clone + Send + Sync + 'static { +pub trait Pair: CryptoType + Sized + Clone + Send + Sync + 'static { /// The type which is used to encode a public key. - type Public: Public + Hash; + type Public: Public + Hash + Derive; /// The type used to (minimally) encode the data required to securely create /// a new key pair. @@ -603,28 +691,440 @@ pub trait Pair: TypedKey + Sized + Clone + Send + Sync + 'static { fn to_raw_vec(&self) -> Vec; } +/// A type of supported crypto. +#[derive(Clone, Copy, PartialEq, Eq, Encode, Decode)] +#[cfg_attr(feature = "std", derive(Debug))] +#[repr(u32)] +pub enum Kind { + /// SR25519 crypto (Schnorrkel) + Sr25519 = 0, + /// ED25519 crypto (Edwards) + Ed25519 = 1, + + /// Dummy kind, just for testing. + #[cfg(feature = "std")] + Dummy = !0, +} + +impl TryFrom for Kind { + type Error = (); + + fn try_from(kind: u32) -> Result { + Ok(match kind { + e if e == Kind::Sr25519 as usize as u32 => Kind::Sr25519, + e if e == Kind::Ed25519 as usize as u32 => Kind::Ed25519, + _ => Err(())?, + }) + } +} + +impl From for u32 { + fn from(kind: Kind) -> Self { + kind as u32 + } +} + +/// One type is wrapped by another. +pub trait IsWrappedBy: From + Into { + /// Get a reference to the inner from the outer. + fn from_ref(outer: &Outer) -> &Self; + /// Get a mutable reference to the inner from the outer. + fn from_mut(outer: &mut Outer) -> &mut Self; +} + +/// Opposite of `IsWrappedBy` - denotes a type which is a simple wrapper around another type. +pub trait Wraps: Sized { + /// The inner type it is wrapping. + type Inner: IsWrappedBy; +} + +impl IsWrappedBy for T where + Outer: AsRef + AsMut + From, + T: From, +{ + /// Get a reference to the inner from the outer. + fn from_ref(outer: &Outer) -> &Self { outer.as_ref() } + + /// Get a mutable reference to the inner from the outer. + fn from_mut(outer: &mut Outer) -> &mut Self { outer.as_mut() } +} + +impl UncheckedFrom for Outer where + Outer: Wraps, + Inner: IsWrappedBy + UncheckedFrom, +{ + fn unchecked_from(t: T) -> Self { + let inner: Inner = t.unchecked_into(); + inner.into() + } +} + +/// An application-specific key. +pub trait AppKey: 'static + Send + Sync + Sized + CryptoType + Clone { + /// The corresponding type as a generic crypto type. + type UntypedGeneric: IsWrappedBy; + + /// The corresponding public key type in this application scheme. + type Public: AppPublic; + + /// The corresponding key pair type in this application scheme. + type Pair: AppPair; + + /// The corresponding signature type in this application scheme. + type Signature: AppSignature; + + /// An identifier for this application-specific key type. + const ID: KeyTypeId; +} + +/// Type which implements Debug and Hash in std, not when no-std (std variant). +#[cfg(feature = "std")] +pub trait MaybeDebugHash: std::fmt::Debug + std::hash::Hash {} +#[cfg(feature = "std")] +impl MaybeDebugHash for T {} + +/// Type which implements Debug and Hash in std, not when no-std (no-std variant). +#[cfg(not(feature = "std"))] +pub trait MaybeDebugHash {} + +/// A application's public key. +pub trait AppPublic: AppKey + Public + Ord + PartialOrd + Eq + PartialEq + MaybeDebugHash + Codec { + /// The wrapped type which is just a plain instance of `Public`. + type Generic: + IsWrappedBy + Public + Ord + PartialOrd + Eq + PartialEq + MaybeDebugHash + Codec; +} + +/// A application's public key. +pub trait AppPair: AppKey + Pair::Public> { + /// The wrapped type which is just a plain instance of `Pair`. + type Generic: IsWrappedBy + Pair::Public as AppPublic>::Generic>; +} + +/// A application's public key. +pub trait AppSignature: AppKey + Eq + PartialEq + MaybeDebugHash { + /// The wrapped type which is just a plain instance of `Signature`. + type Generic: IsWrappedBy + Eq + PartialEq + MaybeDebugHash; +} + +/// Implement `AsRef` and `AsMut` for the provided type. +#[macro_export] +macro_rules! impl_as_ref_mut { + ($name:ty) => { + impl AsMut for $name { + fn as_mut(&mut self) -> &mut Self { + self + } + } + impl AsRef for $name { + fn as_ref(&self) -> &Self { + &self + } + } + } +} + +/// Implement bidirectional `From` and on-way `AsRef`/`AsMut` for two types, `$inner` and `$outer` +/// where . +/// +/// ```rust +/// impl_wrapper! { +/// pub struct Outer(Inner); +/// } +/// ``` +#[macro_export] +macro_rules! wrap { + ($( #[ $attr:meta ] )* struct $outer:ident($inner:ty);) => { + $( #[ $attr ] )* + struct $outer( $inner ); + $crate::wrap!($inner, $outer); + }; + ($( #[ $attr:meta ] )* pub struct $outer:ident($inner:ty);) => { + $( #[ $attr ] )* + pub struct $outer( $inner ); + $crate::wrap!($inner, $outer); + }; + ($inner:ty, $outer:ty) => { + impl $crate::crypto::Wraps for $outer { + type Inner = $inner; + } + impl From<$inner> for $outer { + fn from(inner: $inner) -> Self { + Self(inner) + } + } + impl From<$outer> for $inner { + fn from(outer: $outer) -> Self { + outer.0 + } + } + impl AsRef<$inner> for $outer { + fn as_ref(&self) -> &$inner { + &self.0 + } + } + impl AsMut<$inner> for $outer { + fn as_mut(&mut self) -> &mut $inner { + &mut self.0 + } + } + } +} + +/// Declares Public, Pair, Signature types which are functionally equivalent to `$pair`, but are new +/// Application-specific types whose identifier is `$key_type`. +/// +/// ```rust +/// // Declare a new set of crypto types using Ed25519 logic that identifies as `KeyTypeId` +/// // of value `b"fuba"`. +/// app_crypto!(ed25519, *b"fuba"); +/// ``` +#[macro_export] +macro_rules! app_crypto { + ($pair:ty, $public:ty, $sig:ty, $key_type:expr) => { + $crate::wrap!{ + /// A generic `AppPublic` wrapper type over Ed25519 crypto; this has no specific App. + #[derive(Clone, Default, Eq, PartialEq, Ord, PartialOrd, $crate::Encode, $crate::Decode)] + #[cfg_attr(feature = "std", derive(Debug, Hash))] + pub struct Public($public); + } + // TODO: needed for verify since it takes an AsRef, but should be removed once that is + // refactored. + $crate::impl_as_ref_mut!(Public); + + #[cfg(feature = "std")] + impl $crate::crypto::Derive for Public { + fn derive>(&self, + path: Iter + ) -> Option { + self.0.derive(path).map(Self) + } + } + #[cfg(feature = "std")] + impl ::std::fmt::Display for Public { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + use $crate::crypto::Ss58Codec; + write!(f, "{}", self.0.to_ss58check()) + } + } + #[cfg(feature = "std")] + impl $crate::serde::Serialize for Public { + fn serialize(&self, serializer: S) -> std::result::Result where + S: $crate::serde::Serializer + { + use $crate::crypto::Ss58Codec; + serializer.serialize_str(&self.to_ss58check()) + } + } + #[cfg(feature = "std")] + impl<'de> $crate::serde::Deserialize<'de> for Public { + fn deserialize(deserializer: D) -> std::result::Result where + D: $crate::serde::Deserializer<'de> + { + use $crate::crypto::Ss58Codec; + Public::from_ss58check(&String::deserialize(deserializer)?) + .map_err(|e| $crate::serde::de::Error::custom(format!("{:?}", e))) + } + } + impl AsRef<[u8]> for Public { + fn as_ref(&self) -> &[u8] { self.0.as_ref() } + } + impl AsMut<[u8]> for Public { + fn as_mut(&mut self) -> &mut [u8] { self.0.as_mut() } + } + impl $crate::crypto::CryptoType for Public { + const KIND: $crate::crypto::Kind = <$pair as $crate::crypto::CryptoType>::KIND; + type Pair = Pair; + } + impl $crate::crypto::Public for Public { + fn from_slice(x: &[u8]) -> Self { Self(<$public>::from_slice(x)) } + } + impl $crate::crypto::AppKey for Public { + type UntypedGeneric = $public; + type Public = Public; + type Pair = Pair; + type Signature = Signature; + const ID: $crate::crypto::KeyTypeId = $key_type; + } + impl $crate::crypto::AppPublic for Public { + type Generic = $public; + } + + $crate::wrap!{ + /// A generic `AppPublic` wrapper type over Ed25519 crypto; this has no specific App. + #[derive(Clone)] + pub struct Pair($pair); + } + + impl $crate::crypto::CryptoType for Pair { + const KIND: $crate::crypto::Kind = <$pair as $crate::crypto::CryptoType>::KIND; + type Pair = Pair; + } + #[cfg(feature = "std")] + impl $crate::crypto::Pair for Pair { + type Public = Public; + type Seed = <$pair as $crate::crypto::Pair>::Seed; + type Signature = Signature; + type DeriveError = <$pair as $crate::crypto::Pair>::DeriveError; + fn generate_with_phrase(password: Option<&str>) -> (Self, String, Self::Seed) { + let r = <$pair>::generate_with_phrase(password); + (Self(r.0), r.1, r.2) + } + fn from_phrase(phrase: &str, password: Option<&str>) + -> Result<(Self, Self::Seed), $crate::crypto::SecretStringError> + { + <$pair>::from_phrase(phrase, password).map(|r| (Self(r.0), r.1)) + } + fn derive< + Iter: Iterator + >(&self, path: Iter) -> Result { + self.0.derive(path).map(Self) + } + fn from_seed(seed: &Self::Seed) -> Self { Self(<$pair>::from_seed(seed)) } + fn from_seed_slice(seed: &[u8]) -> Result { + <$pair>::from_seed_slice(seed).map(Self) + } + fn from_standard_components< + I: Iterator + >( + seed: &str, + password: Option<&str>, + path: I + ) -> Result { + <$pair>::from_standard_components::(seed, password, path).map(Self) + } + fn sign(&self, msg: &[u8]) -> Self::Signature { + Signature(self.0.sign(msg)) + } + fn verify, M: AsRef<[u8]>>( + sig: &Self::Signature, + message: M, + pubkey: P + ) -> bool { + <$pair>::verify(&sig.0, message, &pubkey.as_ref().0) + } + fn verify_weak, M: AsRef<[u8]>>( + sig: &[u8], + message: M, + pubkey: P + ) -> bool { + <$pair>::verify_weak(sig, message, pubkey) + } + fn public(&self) -> Self::Public { Public(self.0.public()) } + fn to_raw_vec(&self) -> Vec { self.0.to_raw_vec() } + } + impl $crate::crypto::AppKey for Pair { + type UntypedGeneric = $pair; + type Public = Public; + type Pair = Pair; + type Signature = Signature; + const ID: $crate::crypto::KeyTypeId = $key_type; + } + impl $crate::crypto::AppPair for Pair { + type Generic = $pair; + } + + $crate::wrap!{ + /// A generic `AppPublic` wrapper type over Ed25519 crypto; this has no specific App. + #[derive(Clone, Default, Eq, PartialEq, $crate::Encode, $crate::Decode)] + #[cfg_attr(feature = "std", derive(Debug, Hash))] + pub struct Signature($sig); + } + + impl AsRef<[u8]> for Signature { + fn as_ref(&self) -> &[u8] { self.0.as_ref() } + } + impl $crate::crypto::CryptoType for Signature { + const KIND: $crate::crypto::Kind = <$pair as $crate::crypto::CryptoType>::KIND; + type Pair = Pair; + } + impl $crate::crypto::AppKey for Signature { + type UntypedGeneric = $sig; + type Public = Public; + type Pair = Pair; + type Signature = Signature; + const ID: $crate::crypto::KeyTypeId = $key_type; + } + impl $crate::crypto::AppSignature for Signature { + type Generic = $sig; + } + } +} + +// TODO: remove default cryptos + +/// Type which has a particular kind of crypto associated with it. +pub trait CryptoType { + /// The kind of crypto it has. + const KIND: Kind; + + /// The pair key type of this crypto. + type Pair: Pair; +} + /// An identifier for a type of cryptographic key. /// -/// 0-1024 are reserved. -pub type KeyTypeId = u32; +/// To avoid clashes with other modules when distributing your module publically, register your +/// `KeyTypeId` on the list here by making a PR. +/// +/// Values whose first character is `_` are reserved for private use and won't conflict with any +/// public modules. +pub type KeyTypeId = [u8; 4]; -/// Constant key types. +/// Known key types; this also functions as a global registry of key types for projects wishing to +/// avoid collisions with each other. +/// +/// It's not universal in the sense that *all* key types need to be mentioned here, it's just a +/// handy place to put common 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; + /// Key type for generic S/R 25519 key. + pub const SR25519: KeyTypeId = *b"sr25"; + /// Key type for generic Ed25519 key. + pub const ED25519: KeyTypeId = *b"ed25"; + /// Key type for Babe module, build-in. + pub const BABE: KeyTypeId = *b"babe"; + /// Key type for Grandpa module, build-in. + pub const GRANDPA: KeyTypeId = *b"gran"; + /// Key type for controlling an account in a Substrate runtime, built-in. + pub const ACCOUNT: KeyTypeId = *b"acco"; + /// Key type for Aura module, built-in. + pub const AURA: KeyTypeId = *b"aura"; + /// A key type ID useful for tests. + #[cfg(feature = "std")] + pub const DUMMY: KeyTypeId = *b"dumy"; } -/// A trait for something that has a key type ID. -pub trait TypedKey { - /// The type ID of this key. - const KEY_TYPE: KeyTypeId; +/*impl TryFrom for Kind { + type Error = (); + + fn try_from(kind: KeyTypeId) -> Result { + Ok(match kind { + e if e == key_types::SR25519 => Kind::Sr25519, + e if e == key_types::ED25519 => Kind::Ed25519, + e if e == key_types::BABE => Kind::Sr25519, + e if e == key_types::GRANDPA => Kind::Ed25519, + #[cfg(feature = "std")] + e if e == key_types::DUMMY => Kind::Dummy, + _ => Err(())?, + }) + } } +// This doesn't make much sense and should be reconsidered. +impl TryFrom for KeyTypeId { + type Error = (); + + fn try_from(kind: Kind) -> Result { + Ok(match kind { + Kind::Sr25519 => key_types::SR25519, + Kind::Ed25519 => key_types::ED25519, + #[cfg(feature = "std")] + Kind::Dummy => key_types::DUMMY, + }) + } +}*/ + #[cfg(test)] mod tests { use crate::DeriveJunction; @@ -640,13 +1140,31 @@ mod tests { Seed(Vec), } - #[derive(Clone, PartialEq, Eq, Hash)] + impl CryptoType for TestPair { + const KIND: Kind = Kind::Dummy; + type Pair = TestPair; + } + + #[derive(Clone, PartialEq, Eq, Hash, Default)] struct TestPublic; + impl Derive for TestPublic {} + impl CryptoType for TestPublic { + const KIND: Kind = Kind::Dummy; + type Pair = TestPair; + } + impl AsRef<[u8]> for TestPublic { fn as_ref(&self) -> &[u8] { &[] } } + + impl AsMut<[u8]> for TestPublic { + fn as_mut(&mut self) -> &mut[u8] { + &mut[] + } + } + impl Public for TestPublic { fn from_slice(_bytes: &[u8]) -> Self { Self @@ -658,9 +1176,7 @@ mod tests { vec![] } } - impl TypedKey for TestPublic { - const KEY_TYPE: u32 = 4242; - } + impl Pair for TestPair { type Public = TestPublic; type Seed = [u8; 0]; @@ -717,9 +1233,6 @@ mod tests { vec![] } } - impl TypedKey for TestPair { - const KEY_TYPE: u32 = 4242; - } #[test] fn interpret_std_seed_should_work() { diff --git a/core/primitives/src/ed25519.rs b/core/primitives/src/ed25519.rs index 5d1fe884a5180..4e34c53fd7230 100644 --- a/core/primitives/src/ed25519.rs +++ b/core/primitives/src/ed25519.rs @@ -32,7 +32,9 @@ 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::{key_types, KeyTypeId, Public as TraitPublic, TypedKey, UncheckedFrom}; +use crate::{impl_as_ref_mut, crypto::{ + Public as TraitPublic, UncheckedFrom, CryptoType, Kind +}}; /// 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 @@ -90,12 +92,6 @@ impl From for Public { } } -impl AsRef for Public { - fn as_ref(&self) -> &Public { - &self - } -} - impl From for H256 { fn from(x: Public) -> Self { x.0.into() @@ -296,6 +292,8 @@ impl Public { } } +impl_as_ref_mut!(Public); + impl TraitPublic for Public { /// A new instance from the given slice that should be 32 bytes long. /// @@ -306,31 +304,11 @@ impl TraitPublic for Public { r.copy_from_slice(data); Public(r) } - - /// Return a `Vec` filled with raw data. - #[cfg(feature = "std")] - fn to_raw_vec(&self) -> Vec { - let r: &[u8; 32] = self.as_ref(); - r.to_vec() - } - - /// Return a slice filled with raw data. - fn as_slice(&self) -> &[u8] { - let r: &[u8; 32] = self.as_ref(); - &r[..] - } } #[cfg(feature = "std")] impl Derive for Public {} -#[cfg(feature = "std")] -impl AsRef for Pair { - fn as_ref(&self) -> &Pair { - &self - } -} - /// Derive a single hard junction. #[cfg(feature = "std")] fn derive_hard_junction(secret_seed: &Seed, cc: &[u8; 32]) -> Seed { @@ -488,19 +466,31 @@ impl Pair { } } -impl TypedKey for Public { - const KEY_TYPE: KeyTypeId = key_types::ED25519; +impl CryptoType for Public { + const KIND: Kind = Kind::Ed25519; + type Pair = Pair; } -impl TypedKey for Signature { - const KEY_TYPE: KeyTypeId = key_types::ED25519; +impl CryptoType for Signature { + const KIND: Kind = Kind::Ed25519; + type Pair = Pair; } #[cfg(feature = "std")] -impl TypedKey for Pair { - const KEY_TYPE: KeyTypeId = key_types::ED25519; +impl CryptoType for Pair { + const KIND: Kind = Kind::Ed25519; + type Pair = Pair; +} + +mod app { + use crate::crypto::key_types::ED25519; + crate::app_crypto!(super::Pair, super::Public, super::Signature, ED25519); } +pub use app::Public as AppPublic; +pub use app::Pair as AppPair; +pub use app::Signature as AppSignature; + #[cfg(test)] mod test { use super::*; diff --git a/core/primitives/src/lib.rs b/core/primitives/src/lib.rs index 4fabb04ccb038..5d4210cb4f2d7 100644 --- a/core/primitives/src/lib.rs +++ b/core/primitives/src/lib.rs @@ -33,11 +33,13 @@ macro_rules! map { use rstd::prelude::*; use rstd::ops::Deref; -use parity_codec::{Encode, Decode}; #[cfg(feature = "std")] use std::borrow::Cow; #[cfg(feature = "std")] use serde::{Serialize, Deserialize}; +#[cfg(feature = "std")] +pub use serde;// << for macro +pub use parity_codec::{Encode, Decode};// << for macro #[cfg(feature = "std")] pub use impl_serde::serialize as bytes; diff --git a/core/primitives/src/offchain.rs b/core/primitives/src/offchain.rs index 5b6f8f5c22556..931597a6dde8f 100644 --- a/core/primitives/src/offchain.rs +++ b/core/primitives/src/offchain.rs @@ -16,11 +16,12 @@ //! Offchain workers types -use crate::crypto; use parity_codec::{Encode, Decode}; use rstd::prelude::{Vec, Box}; use rstd::convert::TryFrom; +pub use crate::crypto::Kind as CryptoKind; + /// A type of supported crypto. #[derive(Clone, Copy, PartialEq, Eq, Encode, Decode)] #[cfg_attr(feature = "std", derive(Debug))] @@ -58,35 +59,6 @@ impl From for u32 { } } -/// A type of supported crypto. -#[derive(Clone, Copy, PartialEq, Eq, Encode, Decode)] -#[cfg_attr(feature = "std", derive(Debug))] -#[repr(C)] -pub enum CryptoKind { - /// SR25519 crypto (Schnorrkel) - Sr25519 = crypto::key_types::SR25519 as isize, - /// ED25519 crypto (Edwards) - Ed25519 = crypto::key_types::ED25519 as isize, -} - -impl TryFrom for CryptoKind { - type Error = (); - - fn try_from(kind: u32) -> Result { - match kind { - e if e == CryptoKind::Sr25519 as isize as u32 => Ok(CryptoKind::Sr25519), - e if e == CryptoKind::Ed25519 as isize as u32 => Ok(CryptoKind::Ed25519), - _ => Err(()), - } - } -} - -impl From for u32 { - fn from(c: CryptoKind) -> Self { - c as isize as u32 - } -} - /// Key to use in the offchain worker crypto api. #[derive(Clone, Copy, PartialEq, Eq)] #[cfg_attr(feature = "std", derive(Debug))] diff --git a/core/primitives/src/sr25519.rs b/core/primitives/src/sr25519.rs index e01d989143c6b..37263ce982403 100644 --- a/core/primitives/src/sr25519.rs +++ b/core/primitives/src/sr25519.rs @@ -30,8 +30,10 @@ use substrate_bip39::mini_secret_from_entropy; #[cfg(feature = "std")] use bip39::{Mnemonic, Language, MnemonicType}; #[cfg(feature = "std")] -use crate::crypto::{Pair as TraitPair, DeriveJunction, Infallible, SecretStringError, Derive, Ss58Codec}; -use crate::crypto::{key_types, KeyTypeId, Public as TraitPublic, TypedKey, UncheckedFrom}; +use crate::crypto::{ + Pair as TraitPair, DeriveJunction, Infallible, SecretStringError, Derive, Ss58Codec +}; +use crate::{impl_as_ref_mut, crypto::{Public as TraitPublic, UncheckedFrom, CryptoType, Kind}}; use crate::hash::{H256, H512}; use parity_codec::{Encode, Decode}; @@ -63,11 +65,7 @@ impl Clone for Pair { } } -impl AsRef for Public { - fn as_ref(&self) -> &Public { - &self - } -} +impl_as_ref_mut!(Public); impl AsRef<[u8; 32]> for Public { fn as_ref(&self) -> &[u8; 32] { @@ -318,24 +316,6 @@ impl TraitPublic for Public { r.copy_from_slice(data); Public(r) } - - /// Return a `Vec` filled with raw data. - #[cfg(feature = "std")] - fn to_raw_vec(&self) -> Vec { - self.0.to_vec() - } - - /// Return a slice filled with raw data. - fn as_slice(&self) -> &[u8] { - &self.0 - } -} - -#[cfg(feature = "std")] -impl AsRef for Pair { - fn as_ref(&self) -> &Pair { - &self - } } #[cfg(feature = "std")] @@ -523,19 +503,31 @@ impl Pair { } } -impl TypedKey for Public { - const KEY_TYPE: KeyTypeId = key_types::SR25519; +impl CryptoType for Public { + const KIND: Kind = Kind::Sr25519; + type Pair = Pair; } -impl TypedKey for Signature { - const KEY_TYPE: KeyTypeId = key_types::SR25519; +impl CryptoType for Signature { + const KIND: Kind = Kind::Sr25519; + type Pair = Pair; } #[cfg(feature = "std")] -impl TypedKey for Pair { - const KEY_TYPE: KeyTypeId = key_types::SR25519; +impl CryptoType for Pair { + const KIND: Kind = Kind::Sr25519; + type Pair = Pair; +} + +mod app { + use crate::crypto::key_types::SR25519; + crate::app_crypto!(super::Pair, super::Public, super::Signature, SR25519); } +pub use app::Public as AppPublic; +pub use app::Pair as AppPair; +pub use app::Signature as AppSignature; + #[cfg(test)] mod test { use super::*; diff --git a/core/service/src/components.rs b/core/service/src/components.rs index dff6161f16523..b03fe95e39ae0 100644 --- a/core/service/src/components.rs +++ b/core/service/src/components.rs @@ -30,7 +30,7 @@ use sr_primitives::{ BuildStorage, traits::{Block as BlockT, Header as HeaderT, ProvideRuntimeApi}, generic::BlockId }; use crate::config::Configuration; -use primitives::{Blake2Hasher, H256, Pair}; +use primitives::{Blake2Hasher, H256, crypto::AppPair}; use rpc::{self, apis::system::SystemInfo}; use futures::{prelude::*, future::Executor, sync::mpsc}; @@ -294,9 +294,9 @@ pub trait ServiceFactory: 'static + Sized { /// Block type. type Block: BlockT; /// Consensus crypto type. - type ConsensusPair: Pair; + type ConsensusPair: AppPair; /// Finality crypto type. - type FinalityPair: Pair; + type FinalityPair: AppPair; /// The type that implements the runtime API. type RuntimeApi: Send + Sync; /// Network protocol extensions. diff --git a/core/service/src/config.rs b/core/service/src/config.rs index cd2364b37d17e..9c7a43466c159 100644 --- a/core/service/src/config.rs +++ b/core/service/src/config.rs @@ -56,8 +56,6 @@ pub struct Configuration { pub state_cache_child_ratio: Option, /// Pruning settings. pub pruning: PruningMode, - /// Additional key seeds. - pub keys: Vec, /// Chain configuration. pub chain_spec: ChainSpec, /// Custom configuration. @@ -92,6 +90,12 @@ pub struct Configuration { pub grandpa_voter: bool, /// Node keystore's password pub password: Protected, + /// Development key seed. + /// + /// When running in development mode, the seed will be used to generate authority keys by the keystore. + /// + /// Should only be set when `node` is running development mode. + pub dev_key_seed: Option, } impl Configuration { @@ -111,7 +115,6 @@ impl Configuration Configuration Service { None }; - // Keep the public key for telemetry - let public_key: String; - - // This is meant to be for testing only - // 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::(seed)?; - } - - public_key = match keystore.contents::()?.get(0) { - Some(public_key) => public_key.to_string(), - None => { - let key: ed25519::Pair = keystore.generate(&config.password.as_ref())?; - let public_key = key.public(); - info!("Generated a new keypair: {:?}", public_key); - public_key.to_string() - } - } - } else { - public_key = format!(""); + if let Some((keystore, seed)) = keystore.as_mut() + .and_then(|k| config.dev_key_seed.clone().map(|s| (k, s))) + { + //TODO: Generate the test keys for all required app keys. + keystore.generate_from_seed::(&seed)?; + keystore.generate_from_seed::(&seed)?; } let (client, on_demand) = Components::build_client(&config, executor)?; @@ -465,7 +449,6 @@ impl Service { "version" => version.clone(), "config" => "", "chain" => chain_name.clone(), - "pubkey" => &public_key, "authority" => is_authority, "network_id" => network_id.clone() ); @@ -914,7 +897,8 @@ pub struct AuthorityKeyProvider { impl offchain::AuthorityKeyProvider - for AuthorityKeyProvider +for + AuthorityKeyProvider where Block: sr_primitives::traits::Block, ConsensusPair: Pair, @@ -923,7 +907,7 @@ where type ConsensusPair = ConsensusPair; type FinalityPair = FinalityPair; - fn authority_key(&self, _at: &BlockId) -> Option { + fn authority_key(&self, _at: &BlockId) -> Option { if self.roles != Roles::AUTHORITY { return None } @@ -934,9 +918,11 @@ where }; let loaded_key = keystore - .contents() + .contents::<::Public>() .map(|keys| keys.get(0) - .map(|k| keystore.load(k, self.password.as_ref())) + .map(|k| + keystore.load::(k, self.password.as_ref()) + ) ); if let Ok(Some(Ok(key))) = loaded_key { @@ -946,7 +932,7 @@ where } } - fn fg_authority_key(&self, _at: &BlockId) -> Option { + fn fg_authority_key(&self, _at: &BlockId) -> Option { if self.roles != Roles::AUTHORITY { return None } @@ -957,9 +943,11 @@ where }; let loaded_key = keystore - .contents() + .contents::<::Public>() .map(|keys| keys.get(0) - .map(|k| keystore.load(k, self.password.as_ref())) + .map(|k| + keystore.load::(k, self.password.as_ref()) + ) ); if let Ok(Some(Ok(key))) = loaded_key { diff --git a/core/sr-primitives/src/generic/checked_extrinsic.rs b/core/sr-primitives/src/generic/checked_extrinsic.rs index 04ccd1162c6c6..eebc74951df77 100644 --- a/core/sr-primitives/src/generic/checked_extrinsic.rs +++ b/core/sr-primitives/src/generic/checked_extrinsic.rs @@ -22,7 +22,7 @@ use crate::traits::{ self, Member, MaybeDisplay, SignedExtension, DispatchError, Dispatchable, DispatchResult, ValidateUnsigned }; -use crate::weights::{GetDispatchInfo, DispatchInfo}; +use crate::weights::GetDispatchInfo; use crate::transaction_validity::TransactionValidity; /// Definition of something that the external world might want to say; its @@ -44,26 +44,22 @@ for CheckedExtrinsic where AccountId: Member + MaybeDisplay, - Call: Member + Dispatchable, - Extra: SignedExtension, + Call: Member + Dispatchable + GetDispatchInfo, + Extra: SignedExtension, Origin: From>, { type AccountId = AccountId; - type Call = Call; fn sender(&self) -> Option<&Self::AccountId> { self.signed.as_ref().map(|x| &x.0) } - fn validate>(&self, - info: DispatchInfo, - len: usize, - ) -> TransactionValidity { + fn validate>(&self, len: usize) -> TransactionValidity { if let Some((ref id, ref extra)) = self.signed { - Extra::validate(extra, id, info, len).into() + Extra::validate(extra, id, &self.function, len).into() } else { - match Extra::validate_unsigned(info, len) { + match Extra::validate_unsigned(&self.function, len) { Ok(extra) => match U::validate_unsigned(&self.function) { TransactionValidity::Valid(v) => TransactionValidity::Valid(v.combine_with(extra)), @@ -74,26 +70,14 @@ where } } - fn dispatch(self, - info: DispatchInfo, - len: usize, - ) -> Result { + fn dispatch(self, len: usize) -> Result { let maybe_who = if let Some((id, extra)) = self.signed { - Extra::pre_dispatch(extra, &id, info, len)?; + Extra::pre_dispatch(extra, &id, &self.function, len)?; Some(id) } else { - Extra::pre_dispatch_unsigned(info, len)?; + Extra::pre_dispatch_unsigned(&self.function, len)?; None }; Ok(self.function.dispatch(Origin::from(maybe_who))) } } - -impl GetDispatchInfo for CheckedExtrinsic -where - Call: GetDispatchInfo, -{ - fn get_dispatch_info(&self) -> DispatchInfo { - self.function.get_dispatch_info() - } -} diff --git a/core/sr-primitives/src/generic/unchecked_extrinsic.rs b/core/sr-primitives/src/generic/unchecked_extrinsic.rs index 092af6e6f3cdd..6fd152d05ce54 100644 --- a/core/sr-primitives/src/generic/unchecked_extrinsic.rs +++ b/core/sr-primitives/src/generic/unchecked_extrinsic.rs @@ -243,6 +243,7 @@ mod tests { struct TestExtra; impl SignedExtension for TestExtra { type AccountId = u64; + type Call = (); type AdditionalSigned = (); fn additional_signed(&self) -> rstd::result::Result<(), &'static str> { Ok(()) } } diff --git a/core/sr-primitives/src/lib.rs b/core/sr-primitives/src/lib.rs index 08cd4d1a053d1..2325678073fb4 100644 --- a/core/sr-primitives/src/lib.rs +++ b/core/sr-primitives/src/lib.rs @@ -52,7 +52,7 @@ pub mod transaction_validity; pub use generic::{DigestItem, Digest}; /// Re-export this since it's part of the API of this crate. -pub use primitives::crypto::{key_types, KeyTypeId}; +pub use primitives::crypto::{key_types, KeyTypeId, AppKey, Kind, CryptoType}; /// A message indicating an invalid signature in extrinsic. pub const BAD_SIGNATURE: &str = "bad signature in extrinsic"; diff --git a/core/sr-primitives/src/testing.rs b/core/sr-primitives/src/testing.rs index 0986c4f81af0e..0973ddcf34a47 100644 --- a/core/sr-primitives/src/testing.rs +++ b/core/sr-primitives/src/testing.rs @@ -20,19 +20,18 @@ use serde::{Serialize, Serializer, Deserialize, de::Error as DeError, Deserializ use std::{fmt::Debug, ops::Deref, fmt}; use crate::codec::{Codec, Encode, Decode}; use crate::traits::{ - self, Checkable, Applyable, BlakeTwo256, OpaqueKeys, TypedKey, DispatchError, DispatchResult, + self, Checkable, Applyable, BlakeTwo256, OpaqueKeys, DispatchError, DispatchResult, ValidateUnsigned, SignedExtension, Dispatchable, }; use crate::{generic, KeyTypeId}; use crate::weights::{GetDispatchInfo, DispatchInfo}; pub use primitives::H256; -use primitives::U256; +use primitives::{crypto::{Kind, CryptoType, Dummy, key_types}, U256}; use primitives::ed25519::{Public as AuthorityId}; use crate::transaction_validity::TransactionValidity; /// Authority Id -#[derive(Default, PartialEq, Eq, Clone, Encode, Decode, Debug)] -#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +#[derive(Default, PartialEq, Eq, Clone, Encode, Decode, Debug, Hash, Serialize, Deserialize)] pub struct UintAuthorityId(pub u64); impl Into for UintAuthorityId { fn into(self) -> AuthorityId { @@ -41,25 +40,15 @@ impl Into for UintAuthorityId { } } -/// The key-type of the `UintAuthorityId` -pub const UINT_DUMMY_KEY: KeyTypeId = 0xdeadbeef; - -impl TypedKey for UintAuthorityId { - const KEY_TYPE: KeyTypeId = UINT_DUMMY_KEY; -} - -impl AsRef<[u8]> for UintAuthorityId { - fn as_ref(&self) -> &[u8] { - let ptr = self.0 as *const _; - // It's safe to do this here since `UintAuthorityId` is `u64`. - unsafe { std::slice::from_raw_parts(ptr, 8) } - } +impl CryptoType for UintAuthorityId { + const KIND: Kind = Kind::Dummy; + type Pair = Dummy; } impl OpaqueKeys for UintAuthorityId { type KeyTypeIds = std::iter::Cloned>; - fn key_ids() -> Self::KeyTypeIds { [UINT_DUMMY_KEY].iter().cloned() } + fn key_ids() -> Self::KeyTypeIds { [key_types::DUMMY].iter().cloned() } // Unsafe, i know, but it's test code and it's just there because it's really convenient to // keep `UintAuthorityId` as a u64 under the hood. fn get_raw(&self, _: KeyTypeId) -> &[u8] { @@ -244,46 +233,32 @@ impl traits::Extrinsic for TestXt } impl Applyable for TestXt where - Call: 'static + Sized + Send + Sync + Clone + Eq + Codec + Debug + Dispatchable, - Extra: SignedExtension, + Call: 'static + Sized + Send + Sync + Clone + Eq + Codec + Debug + + Dispatchable + GetDispatchInfo, + Extra: SignedExtension, Origin: From> { type AccountId = u64; type Call = Call; - fn sender(&self) -> Option<&u64> { self.0.as_ref().map(|x| &x.0) } + fn sender(&self) -> Option<&Self::AccountId> { self.0.as_ref().map(|x| &x.0) } /// Checks to see if this is a valid *transaction*. It returns information on it if so. - fn validate>(&self, - _info: DispatchInfo, - _len: usize, - ) -> TransactionValidity { + fn validate>(&self, _len: usize) -> TransactionValidity { TransactionValidity::Valid(Default::default()) } /// Executes all necessary logic needed prior to dispatch and deconstructs into function call, /// index and sender. - fn dispatch(self, - info: DispatchInfo, - len: usize, - ) -> Result { + fn dispatch(self, len: usize) -> Result { let maybe_who = if let Some((who, extra)) = self.0 { - Extra::pre_dispatch(extra, &who, info, len)?; + Extra::pre_dispatch(extra, &who, &self.1, len)?; Some(who) } else { - Extra::pre_dispatch_unsigned(info, len)?; + Extra::pre_dispatch_unsigned(&self.1, len)?; None }; Ok(self.1.dispatch(maybe_who.into())) } } -impl GetDispatchInfo for TestXt { - fn get_dispatch_info(&self) -> DispatchInfo { - // for testing: weight == size. - DispatchInfo { - weight: self.encode().len() as _, - ..Default::default() - } - } -} diff --git a/core/sr-primitives/src/traits.rs b/core/sr-primitives/src/traits.rs index 2019bbf126b88..f623864376580 100644 --- a/core/sr-primitives/src/traits.rs +++ b/core/sr-primitives/src/traits.rs @@ -25,8 +25,7 @@ use primitives::{self, Hasher, Blake2Hasher}; use crate::codec::{Codec, Encode, Decode, HasCompact}; use crate::transaction_validity::{ValidTransaction, TransactionValidity}; use crate::generic::{Digest, DigestItem}; -use crate::weights::DispatchInfo; -pub use primitives::crypto::TypedKey; +use crate::weights::{GetDispatchInfo, DispatchInfo}; pub use integer_sqrt::IntegerSquareRoot; pub use num_traits::{ Zero, One, Bounded, CheckedAdd, CheckedSub, CheckedMul, CheckedDiv, @@ -771,7 +770,7 @@ pub enum DispatchError { Payment, /// General error to do with the exhaustion of block resources. - Resource, + Exhausted, /// General error to do with the permissions of the sender. NoPermission, @@ -787,16 +786,13 @@ pub enum DispatchError { /// General error to do with the transaction's proofs (e.g. signature). BadProof, - -/* /// General error to do with actually executing the dispatched logic. - User(&'static str),*/ } impl From for i8 { fn from(e: DispatchError) -> i8 { match e { DispatchError::Payment => -64, - DispatchError::Resource => -65, + DispatchError::Exhausted => -65, DispatchError::NoPermission => -66, DispatchError::BadState => -67, DispatchError::Stale => -68, @@ -831,6 +827,9 @@ pub trait SignedExtension: /// The type which encodes the sender identity. type AccountId; + /// The type which encodes the call to be dispatched. + type Call: GetDispatchInfo; + /// Any additional data that will go into the signed payload. This may be created dynamically /// from the transaction using the `additional_signed` function. type AdditionalSigned: Encode; @@ -839,35 +838,41 @@ pub trait SignedExtension: /// also perform any pre-signature-verification checks and return an error if needed. fn additional_signed(&self) -> Result; - /// Validate a signed transaction for the transaction queue. + /// Validate a signed transaction for the transaction queue. fn validate( &self, _who: &Self::AccountId, - _info: DispatchInfo, + _call: &Self::Call, _len: usize, - ) -> Result { Ok(Default::default()) } + ) -> Result { + Ok(Default::default()) + } /// Do any pre-flight stuff for a signed transaction. fn pre_dispatch( self, who: &Self::AccountId, - info: DispatchInfo, + call: &Self::Call, len: usize, - ) -> Result<(), DispatchError> { self.validate(who, info, len).map(|_| ()) } + ) -> Result<(), DispatchError> { + self.validate(who, call, len).map(|_| ()) + } /// Validate an unsigned transaction for the transaction queue. Normally the default /// implementation is fine since `ValidateUnsigned` is a better way of recognising and /// validating unsigned transactions. fn validate_unsigned( - _info: DispatchInfo, + _call: &Self::Call, _len: usize, ) -> Result { Ok(Default::default()) } /// Do any pre-flight stuff for a unsigned transaction. fn pre_dispatch_unsigned( - info: DispatchInfo, + call: &Self::Call, len: usize, - ) -> Result<(), DispatchError> { Self::validate_unsigned(info, len).map(|_| ()) } + ) -> Result<(), DispatchError> { + Self::validate_unsigned(call, len).map(|_| ()) + } } macro_rules! tuple_impl_indexed { @@ -877,9 +882,11 @@ macro_rules! tuple_impl_indexed { ([$($direct:ident)+] ; [$($index:tt,)+]) => { impl< AccountId, - $($direct: SignedExtension),+ + Call: GetDispatchInfo, + $($direct: SignedExtension),+ > SignedExtension for ($($direct),+,) { type AccountId = AccountId; + type Call = Call; type AdditionalSigned = ($($direct::AdditionalSigned,)+); fn additional_signed(&self) -> Result { Ok(( $(self.$index.additional_signed()?,)+ )) @@ -887,33 +894,33 @@ macro_rules! tuple_impl_indexed { fn validate( &self, who: &Self::AccountId, - info: DispatchInfo, + call: &Self::Call, len: usize, ) -> Result { - let aggregator = vec![$(<$direct as SignedExtension>::validate(&self.$index, who, info, len)?),+]; + let aggregator = vec![$(<$direct as SignedExtension>::validate(&self.$index, who, call, len)?),+]; Ok(aggregator.into_iter().fold(ValidTransaction::default(), |acc, a| acc.combine_with(a))) } fn pre_dispatch( self, who: &Self::AccountId, - info: DispatchInfo, + call: &Self::Call, len: usize, ) -> Result<(), DispatchError> { - $(self.$index.pre_dispatch(who, info, len)?;)+ + $(self.$index.pre_dispatch(who, call, len)?;)+ Ok(()) } fn validate_unsigned( - info: DispatchInfo, + call: &Self::Call, len: usize, ) -> Result { - let aggregator = vec![$($direct::validate_unsigned(info, len)?),+]; + let aggregator = vec![$($direct::validate_unsigned(call, len)?),+]; Ok(aggregator.into_iter().fold(ValidTransaction::default(), |acc, a| acc.combine_with(a))) } fn pre_dispatch_unsigned( - info: DispatchInfo, + call: &Self::Call, len: usize, ) -> Result<(), DispatchError> { - $($direct::pre_dispatch_unsigned(info, len)?;)+ + $($direct::pre_dispatch_unsigned(call, len)?;)+ Ok(()) } } @@ -936,11 +943,12 @@ macro_rules! tuple_impl_indexed { #[allow(non_snake_case)] tuple_impl_indexed!(A, B, C, D, E, F, G, H, I, J, ; 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,); -/// Only for base bone testing when you don't care about signed extensions at all.\ +/// Only for bare bone testing when you don't care about signed extensions at all. #[cfg(feature = "std")] impl SignedExtension for () { type AccountId = u64; type AdditionalSigned = (); + type Call = (); fn additional_signed(&self) -> rstd::result::Result<(), &'static str> { Ok(()) } } @@ -961,17 +969,11 @@ pub trait Applyable: Sized + Send + Sync { fn sender(&self) -> Option<&Self::AccountId>; /// Checks to see if this is a valid *transaction*. It returns information on it if so. - fn validate>(&self, - info: DispatchInfo, - len: usize, - ) -> TransactionValidity; + fn validate>(&self, len: usize) -> TransactionValidity; /// Executes all necessary logic needed prior to dispatch and deconstructs into function call, /// index and sender. - fn dispatch(self, - info: DispatchInfo, - len: usize, - ) -> Result; + fn dispatch(self, len: usize) -> Result; } /// Auxiliary wrapper that holds an api instance and binds it to the given lifetime. diff --git a/core/sr-primitives/src/weights.rs b/core/sr-primitives/src/weights.rs index 45ac59e0d5489..f9e2307254ccb 100644 --- a/core/sr-primitives/src/weights.rs +++ b/core/sr-primitives/src/weights.rs @@ -93,6 +93,12 @@ pub trait GetDispatchInfo { fn get_dispatch_info(&self) -> DispatchInfo; } +/// To enable using `()` as a call type if needed for testing. +#[cfg(feature = "std")] +impl GetDispatchInfo for () { + fn get_dispatch_info(&self) -> DispatchInfo { Default::default() } +} + /// Means of weighing some particular kind of data (`T`). pub trait WeighData { /// Weigh the data `T` given by `target`. diff --git a/core/test-runtime/client/src/lib.rs b/core/test-runtime/client/src/lib.rs index 36a2fd3e86d40..9c7fddb95d6c7 100644 --- a/core/test-runtime/client/src/lib.rs +++ b/core/test-runtime/client/src/lib.rs @@ -26,6 +26,7 @@ pub use block_builder_ext::BlockBuilderExt; pub use generic_test_client::*; pub use runtime; +use primitives::sr25519; use runtime::genesismap::{GenesisConfig, additional_storage_with_genesis}; use sr_primitives::traits::{Block as BlockT, Header as HeaderT, Hash as HashT}; @@ -183,9 +184,9 @@ fn genesis_config(support_changes_trie: bool, heap_pages_override: Option) GenesisConfig::new( support_changes_trie, vec![ - Sr25519Keyring::Alice.into(), - Sr25519Keyring::Bob.into(), - Sr25519Keyring::Charlie.into(), + sr25519::Public::from(Sr25519Keyring::Alice).into(), + sr25519::Public::from(Sr25519Keyring::Bob).into(), + sr25519::Public::from(Sr25519Keyring::Charlie).into(), ], vec![ AccountKeyring::Alice.into(), AccountKeyring::Bob.into(), diff --git a/core/test-runtime/src/lib.rs b/core/test-runtime/src/lib.rs index c529fa201fbef..98ee41b38a3bb 100644 --- a/core/test-runtime/src/lib.rs +++ b/core/test-runtime/src/lib.rs @@ -40,6 +40,7 @@ use sr_primitives::{ BlindCheckable, BlakeTwo256, Block as BlockT, Extrinsic as ExtrinsicT, GetNodeBlockType, GetRuntimeBlockType, Verify, IdentityLookup }, + weights::{DispatchInfo, GetDispatchInfo, DispatchClass}, }; use runtime_version::RuntimeVersion; pub use primitives::hash::H256; @@ -111,6 +112,15 @@ pub enum Extrinsic { StorageChange(Vec, Option>), } +impl GetDispatchInfo for Extrinsic { + fn get_dispatch_info(&self) -> DispatchInfo { + match *self { + Extrinsic::AuthoritiesChange(..) => DispatchInfo { weight: 10, class: DispatchClass::Operational }, + _ => Default::default(), + } + } +} + #[cfg(feature = "std")] impl serde::Serialize for Extrinsic { fn serialize(&self, seq: S) -> Result where S: ::serde::Serializer { @@ -138,7 +148,7 @@ impl BlindCheckable for Extrinsic { } impl ExtrinsicT for Extrinsic { - type Call = (); + type Call = Extrinsic; fn is_signed(&self) -> Option { if let Extrinsic::IncludeData(_) = *self { @@ -148,8 +158,8 @@ impl ExtrinsicT for Extrinsic { } } - fn new_unsigned(_call: Self::Call) -> Option { - None + fn new_unsigned(call: Self::Call) -> Option { + Some(call) } } @@ -338,6 +348,7 @@ parameter_types! { impl srml_system::Trait for Runtime { type Origin = Origin; + type Call = Extrinsic; type Index = u64; type BlockNumber = u64; type Hash = H256; diff --git a/node-template/Cargo.toml b/node-template/Cargo.toml index 4c85ef38174ca..1ac994188b6f7 100644 --- a/node-template/Cargo.toml +++ b/node-template/Cargo.toml @@ -28,6 +28,8 @@ inherents = { package = "substrate-inherents", path = "../core/inherents" } 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" } +aura-primitives = { package = "substrate-consensus-aura-primitives", path = "../core/consensus/aura/primitives" } +grandpa-primitives = { package = "substrate-finality-grandpa-primitives", path = "../core/finality-grandpa/primitives" } substrate-client = { path = "../core/client" } basic-authorship = { package = "substrate-basic-authorship", path = "../core/basic-authorship" } node-template-runtime = { path = "runtime" } diff --git a/node-template/runtime/src/lib.rs b/node-template/runtime/src/lib.rs index 7b2201c8efe99..50b4d18b417a1 100644 --- a/node-template/runtime/src/lib.rs +++ b/node-template/runtime/src/lib.rs @@ -9,7 +9,7 @@ include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); use rstd::prelude::*; -use primitives::{ed25519, sr25519, OpaqueMetadata}; +use primitives::{sr25519, OpaqueMetadata}; use sr_primitives::{ApplyResult, transaction_validity::TransactionValidity, generic, create_runtime_str}; use sr_primitives::traits::{NumberFor, BlakeTwo256, Block as BlockT, StaticLookup, Verify, ConvertInto}; use sr_primitives::weights::Weight; @@ -30,10 +30,10 @@ pub use sr_primitives::{Permill, Perbill}; pub use support::{StorageValue, construct_runtime, parameter_types}; /// Alias to the signature scheme used for Aura authority signatures. -pub type AuraSignature = ed25519::Signature; +pub type AuraSignature = consensus_aura::sr25519::AuthoritySignature; /// The Ed25519 pub key of an session that belongs to an Aura authority of the chain. -pub type AuraId = ed25519::Public; +pub type AuraId = consensus_aura::sr25519::AuthorityId; /// Alias to pubkey that identifies an account on the chain. pub type AccountId = ::Signer; @@ -104,6 +104,8 @@ parameter_types! { impl system::Trait for Runtime { /// The identifier used to distinguish between accounts. type AccountId = AccountId; + /// The aggregated dispatch type that is available for extrinsics. + type Call = Call; /// The lookup mechanism to get account ID from whatever is passed in dispatchers. type Lookup = Indices; /// The index type for storing how many extrinsics an account has signed. diff --git a/node-template/runtime/src/template.rs b/node-template/runtime/src/template.rs index d0c51443904d9..baf157a4fe8ae 100644 --- a/node-template/runtime/src/template.rs +++ b/node-template/runtime/src/template.rs @@ -93,6 +93,7 @@ mod tests { } impl system::Trait for Test { type Origin = Origin; + type Call = (); type Index = u64; type BlockNumber = u64; type Hash = H256; diff --git a/node-template/src/chain_spec.rs b/node-template/src/chain_spec.rs index 3970522b37ab5..65caab70dbe5f 100644 --- a/node-template/src/chain_spec.rs +++ b/node-template/src/chain_spec.rs @@ -1,8 +1,9 @@ -use primitives::{ed25519, sr25519, Pair}; +use primitives::{sr25519, Pair}; use node_template_runtime::{ AccountId, GenesisConfig, AuraConfig, BalancesConfig, SudoConfig, IndicesConfig, SystemConfig, WASM_BINARY, AuraId }; +use aura_primitives::sr25519::AuthorityPair as AuraPair; use substrate_service; // Note this is the URL for the telemetry server @@ -23,7 +24,7 @@ pub enum Alternative { } fn authority_key(s: &str) -> AuraId { - ed25519::Pair::from_string(&format!("//{}", s), None) + AuraPair::from_string(&format!("//{}", s), None) .expect("static values are valid; qed") .public() } diff --git a/node-template/src/service.rs b/node-template/src/service.rs index e5d83a189397d..fdc1e9b84e93a 100644 --- a/node-template/src/service.rs +++ b/node-template/src/service.rs @@ -15,7 +15,7 @@ use basic_authorship::ProposerFactory; use consensus::{import_queue, start_aura, AuraImportQueue, SlotDuration}; use futures::prelude::*; use substrate_client::{self as client, LongestChain}; -use primitives::{ed25519::Pair, Pair as PairT}; +use primitives::{Pair as PairT}; use inherents::InherentDataProviders; use network::{config::DummyFinalityProofRequestBuilder, construct_simple_protocol}; use substrate_executor::native_executor_instance; @@ -43,8 +43,8 @@ construct_simple_protocol! { construct_service_factory! { struct Factory { Block = Block, - ConsensusPair = Pair, - FinalityPair = Pair, + ConsensusPair = aura_primitives::sr25519::AuthorityPair, + FinalityPair = grandpa_primitives::AuthorityPair, RuntimeApi = RuntimeApi, NetworkProtocol = NodeProtocol { |config| Ok(NodeProtocol::new()) }, RuntimeDispatch = Executor, @@ -100,7 +100,7 @@ construct_service_factory! { Self::Block, > { |config: &mut FactoryFullConfiguration , client: Arc>, _select_chain: Self::SelectChain| { - import_queue::<_, _, Pair>( + import_queue::<_, _, aura_primitives::sr25519::AuthorityPair>( SlotDuration::get_or_compute(&*client)?, Box::new(client.clone()), None, @@ -115,7 +115,7 @@ construct_service_factory! { > { |config: &mut FactoryFullConfiguration, client: Arc>| { let fprb = Box::new(DummyFinalityProofRequestBuilder::default()) as Box<_>; - import_queue::<_, _, Pair>( + import_queue::<_, _, aura_primitives::sr25519::AuthorityPair>( SlotDuration::get_or_compute(&*client)?, Box::new(client.clone()), None, diff --git a/node/cli/src/chain_spec.rs b/node/cli/src/chain_spec.rs index d2fd0cfbc5100..c9ad36fc96812 100644 --- a/node/cli/src/chain_spec.rs +++ b/node/cli/src/chain_spec.rs @@ -16,8 +16,7 @@ //! Substrate chain configurations. -use babe_primitives::AuthorityId as BabeId; -use primitives::{ed25519, sr25519, Pair, crypto::UncheckedInto}; +use primitives::{sr25519, Pair, crypto::UncheckedInto}; use node_primitives::{AccountId, Balance}; use node_runtime::{ BabeConfig, BalancesConfig, ContractsConfig, CouncilConfig, DemocracyConfig, @@ -30,7 +29,8 @@ pub use node_runtime::GenesisConfig; use substrate_service; use hex_literal::hex; use substrate_telemetry::TelemetryEndpoints; -use grandpa::AuthorityId as GrandpaId; +use grandpa_primitives::{AuthorityId as GrandpaId, AuthorityPair as GrandpaPair}; +use babe_primitives::{AuthorityId as BabeId, AuthorityPair as BabePair}; const STAGING_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/"; @@ -42,11 +42,8 @@ pub fn flaming_fir_config() -> Result { ChainSpec::from_json_bytes(&include_bytes!("../res/flaming-fir.json")[..]) } -fn session_keys(ed_key: ed25519::Public, sr_key: sr25519::Public) -> SessionKeys { - SessionKeys { - ed25519: ed_key, - sr25519: sr_key, - } +fn session_keys(grandpa: GrandpaId, babe: BabeId) -> SessionKeys { + SessionKeys { grandpa, babe } } fn staging_testnet_config_genesis() -> GenesisConfig { @@ -56,7 +53,9 @@ fn staging_testnet_config_genesis() -> GenesisConfig { // and // for i in 1 2 3 4 ; do for j in session; do subkey --ed25519 inspect "$secret"//fir//$j//$i; done; done - let initial_authorities: Vec<(AccountId, AccountId, BabeId, GrandpaId)> = vec![( + // TODO: actually use sr25519 for babe keys (right now they seems to just be copies of the + // ed25519 grandpa key). + let initial_authorities: Vec<(AccountId, AccountId, GrandpaId, BabeId)> = vec![( // 5Fbsd6WXDGiLTxunqeK5BATNiocfCqu9bS1yArVjCgeBLkVy hex!["9c7a2ee14e565db0c69f78c7b4cd839fbf52b607d867e9e9c5a79042898a0d12"].unchecked_into(), // 5EnCiV7wSHeNhjW3FSUwiJNkcc2SBkPLn5Nj93FmbLtBjQUq @@ -122,7 +121,7 @@ fn staging_testnet_config_genesis() -> GenesisConfig { }), session: Some(SessionConfig { keys: initial_authorities.iter().map(|x| { - (x.0.clone(), session_keys(x.3.clone(), x.2.clone())) + (x.0.clone(), session_keys(x.2.clone(), x.3.clone())) }).collect::>(), }), staking: Some(StakingConfig { @@ -159,14 +158,14 @@ fn staging_testnet_config_genesis() -> GenesisConfig { key: endowed_accounts[0].clone(), }), babe: Some(BabeConfig { - authorities: initial_authorities.iter().map(|x| (x.2.clone(), 1)).collect(), + authorities: initial_authorities.iter().map(|x| (x.3.clone(), 1)).collect(), }), im_online: Some(ImOnlineConfig { gossip_at: 0, last_new_era_start: 0, }), grandpa: Some(GrandpaConfig { - authorities: initial_authorities.iter().map(|x| (x.3.clone(), 1)).collect(), + authorities: initial_authorities.iter().map(|x| (x.2.clone(), 1)).collect(), }), } } @@ -195,31 +194,31 @@ pub fn get_account_id_from_seed(seed: &str) -> AccountId { /// Helper function to generate BabeId from seed pub fn get_babe_id_from_seed(seed: &str) -> BabeId { - sr25519::Pair::from_string(&format!("//{}", seed), None) + BabePair::from_string(&format!("//{}", seed), None) .expect("static values are valid; qed") .public() } /// Helper function to generate GrandpaId from seed pub fn get_grandpa_id_from_seed(seed: &str) -> GrandpaId { - ed25519::Pair::from_string(&format!("//{}", seed), None) + GrandpaPair::from_string(&format!("//{}", seed), None) .expect("static values are valid; qed") .public() } /// Helper function to generate stash, controller and session key from seed -pub fn get_authority_keys_from_seed(seed: &str) -> (AccountId, AccountId, BabeId, GrandpaId) { +pub fn get_authority_keys_from_seed(seed: &str) -> (AccountId, AccountId, GrandpaId, BabeId) { ( get_account_id_from_seed(&format!("{}//stash", seed)), get_account_id_from_seed(seed), + get_grandpa_id_from_seed(seed), get_babe_id_from_seed(seed), - get_grandpa_id_from_seed(seed) ) } /// Helper function to create GenesisConfig for testing pub fn testnet_genesis( - initial_authorities: Vec<(AccountId, AccountId, BabeId, GrandpaId)>, + initial_authorities: Vec<(AccountId, AccountId, GrandpaId, BabeId)>, root_key: AccountId, endowed_accounts: Option>, enable_println: bool, @@ -260,7 +259,7 @@ pub fn testnet_genesis( }), session: Some(SessionConfig { keys: initial_authorities.iter().map(|x| { - (x.0.clone(), session_keys(x.3.clone(), x.2.clone())) + (x.0.clone(), session_keys(x.2.clone(), x.3.clone())) }).collect::>(), }), staking: Some(StakingConfig { @@ -302,14 +301,14 @@ pub fn testnet_genesis( key: root_key, }), babe: Some(BabeConfig { - authorities: initial_authorities.iter().map(|x| (x.2.clone(), 1)).collect(), + authorities: initial_authorities.iter().map(|x| (x.3.clone(), 1)).collect(), }), im_online: Some(ImOnlineConfig{ gossip_at: 0, last_new_era_start: 0, }), grandpa: Some(GrandpaConfig { - authorities: initial_authorities.iter().map(|x| (x.3.clone(), 1)).collect(), + authorities: initial_authorities.iter().map(|x| (x.2.clone(), 1)).collect(), }), } } diff --git a/node/cli/src/service.rs b/node/cli/src/service.rs index 6c45f45d008cb..0f19b75395ca1 100644 --- a/node/cli/src/service.rs +++ b/node/cli/src/service.rs @@ -119,7 +119,12 @@ construct_service_factory! { } } - if let Some(babe_key) = service.authority_key() { + // TODO: key used should be automated and both of these should be plugins. + + let maybe_babe_key: Option = None;//service.authority_key(); + let maybe_grandpa_key = None;//service.fg_authority_key(); + + if let Some(babe_key) = maybe_babe_key { info!("Using BABE key {}", babe_key.public()); let proposer = substrate_basic_authorship::ProposerFactory { @@ -149,14 +154,14 @@ construct_service_factory! { service.spawn_task(Box::new(select)); } - let grandpa_key = if service.config.disable_grandpa { + let maybe_grandpa_key = if service.config.disable_grandpa { None } else { - service.fg_authority_key() + maybe_grandpa_key }; let config = grandpa::Config { - local_key: grandpa_key.map(Arc::new), + local_key: maybe_grandpa_key.map(Arc::new), // FIXME #1578 make this available through chainspec gossip_duration: Duration::from_millis(333), justification_period: 4096, diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index 583496508e0d1..47dcca6991c2f 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -111,6 +111,7 @@ parameter_types! { impl system::Trait for Runtime { type Origin = Origin; + type Call = Call; type Index = Index; type BlockNumber = BlockNumber; type Hash = Hash; @@ -186,14 +187,14 @@ impl authorship::Trait for Runtime { type EventHandler = Staking; } -type SessionHandlers = (Grandpa, Babe, ImOnline); +type SessionHandlers = (Grandpa, Babe); impl_opaque_keys! { pub struct SessionKeys { - #[id(key_types::ED25519)] - pub ed25519: GrandpaId, - #[id(key_types::SR25519)] - pub sr25519: BabeId, + #[id(key_types::GRANDPA)] + pub grandpa: GrandpaId, + #[id(key_types::BABE)] + pub babe: BabeId, } } diff --git a/srml/assets/src/lib.rs b/srml/assets/src/lib.rs index 363e1c351cdea..bacf722d5d836 100644 --- a/srml/assets/src/lib.rs +++ b/srml/assets/src/lib.rs @@ -264,6 +264,7 @@ mod tests { impl system::Trait for Test { type Origin = Origin; type Index = u64; + type Call = (); type BlockNumber = u64; type Hash = H256; type Hashing = BlakeTwo256; diff --git a/srml/aura/src/lib.rs b/srml/aura/src/lib.rs index 1402cb1d9e472..4637a3226fca9 100644 --- a/srml/aura/src/lib.rs +++ b/srml/aura/src/lib.rs @@ -53,6 +53,7 @@ pub use timestamp; use rstd::{result, prelude::*}; use parity_codec::Encode; use srml_support::{decl_storage, decl_module, Parameter, storage::StorageValue, traits::Get}; +use primitives::crypto::AppPublic; use sr_primitives::{ traits::{SaturatedConversion, Saturating, Zero, One, Member, IsMember, TypedKey}, generic::DigestItem, @@ -156,7 +157,7 @@ pub trait Trait: timestamp::Trait { type HandleReport: HandleReport; /// The identifier type for an authority. - type AuthorityId: Member + Parameter + TypedKey + Default; + type AuthorityId: Member + Parameter + AppPublic + Default; } decl_storage! { diff --git a/srml/aura/src/mock.rs b/srml/aura/src/mock.rs index f00e090b686f1..2002366cbbedd 100644 --- a/srml/aura/src/mock.rs +++ b/srml/aura/src/mock.rs @@ -47,6 +47,7 @@ impl system::Trait for Test { type Origin = Origin; type Index = u64; type BlockNumber = u64; + type Call = (); type Hash = H256; type Hashing = ::sr_primitives::traits::BlakeTwo256; type AccountId = u64; diff --git a/srml/authorship/src/lib.rs b/srml/authorship/src/lib.rs index 2325dac5f3c87..162ef99a4567f 100644 --- a/srml/authorship/src/lib.rs +++ b/srml/authorship/src/lib.rs @@ -349,6 +349,7 @@ mod tests { type Origin = Origin; type Index = u64; type BlockNumber = u64; + type Call = (); type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u64; diff --git a/srml/balances/src/lib.rs b/srml/balances/src/lib.rs index bff5e90c32d5a..67b8799625b2f 100644 --- a/srml/balances/src/lib.rs +++ b/srml/balances/src/lib.rs @@ -164,7 +164,7 @@ use sr_primitives::traits::{ Saturating, Bounded, SignedExtension, SaturatedConversion, DispatchError, Convert, }; use sr_primitives::transaction_validity::{TransactionPriority, ValidTransaction}; -use sr_primitives::weights::{DispatchInfo, SimpleDispatchInfo, Weight}; +use sr_primitives::weights::{DispatchInfo, GetDispatchInfo, SimpleDispatchInfo, Weight}; use system::{IsDeadAccount, OnNewAccount, ensure_signed, ensure_root}; mod mock; @@ -763,6 +763,7 @@ impl, I: Instance> PartialEq for ElevatedTrait { impl, I: Instance> Eq for ElevatedTrait {} impl, I: Instance> system::Trait for ElevatedTrait { type Origin = T::Origin; + type Call = T::Call; type Index = T::Index; type BlockNumber = T::BlockNumber; type Hash = T::Hash; @@ -1213,15 +1214,17 @@ impl, I: Instance> rstd::fmt::Debug for TakeFees { impl, I: Instance + Clone + Eq> SignedExtension for TakeFees { type AccountId = T::AccountId; + type Call = T::Call; type AdditionalSigned = (); fn additional_signed(&self) -> rstd::result::Result<(), &'static str> { Ok(()) } fn validate( &self, who: &Self::AccountId, - info: DispatchInfo, + call: &Self::Call, len: usize, ) -> rstd::result::Result { + let info = call.get_dispatch_info(); // pay any fees. let fee = Self::compute_fee(len, info, self.0); let imbalance = >::withdraw( diff --git a/srml/balances/src/mock.rs b/srml/balances/src/mock.rs index 2c84bb9afb3fe..c45108f553655 100644 --- a/srml/balances/src/mock.rs +++ b/srml/balances/src/mock.rs @@ -18,7 +18,12 @@ #![cfg(test)] -use sr_primitives::{Perbill, traits::{Convert, IdentityLookup}, testing::Header, weights::{DispatchInfo, Weight}}; +use sr_primitives::{ + Perbill, + testing::Header, + traits::{Convert, IdentityLookup}, + weights::{DispatchInfo, Weight, GetDispatchInfo}, +}; use primitives::{H256, Blake2Hasher}; use runtime_io; use srml_support::{impl_outer_origin, parameter_types}; @@ -86,7 +91,8 @@ impl system::Trait for Runtime { type Index = u64; type BlockNumber = u64; type Hash = H256; - type Hashing = ::sr_primitives::traits::BlakeTwo256; + type Hashing = sr_primitives::traits::BlakeTwo256; + type Call = (); type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; @@ -208,7 +214,18 @@ impl ExtBuilder { pub type System = system::Module; pub type Balances = Module; -/// create a transaction info struct from weight. Handy to avoid building the whole struct. -pub fn info_from_weight(w: Weight) -> DispatchInfo { - DispatchInfo { weight: w, ..Default::default() } +pub enum TestCall { + Five, + Two, + Max, +} + +impl GetDispatchInfo for TestCall { + fn get_dispatch_info(&self) -> DispatchInfo { + match *self { + TestCall::Five => DispatchInfo { weight: 5, ..Default::default() }, + TestCall::Two => DispatchInfo { weight: 2, ..Default::default() }, + TestCall::Max => DispatchInfo { weight: Weight::max_value(), ..Default::default() }, + } + } } diff --git a/srml/balances/src/tests.rs b/srml/balances/src/tests.rs index 5a977747fe068..12db45fa7289d 100644 --- a/srml/balances/src/tests.rs +++ b/srml/balances/src/tests.rs @@ -19,7 +19,7 @@ #![cfg(test)] use super::*; -use mock::{Balances, ExtBuilder, Runtime, System, info_from_weight}; +use mock::{Balances, ExtBuilder, Runtime, System, TestCall}; use runtime_io::with_externalities; use srml_support::{ assert_noop, assert_ok, assert_err, @@ -127,7 +127,7 @@ fn lock_reasons_should_work() { assert!( as SignedExtension>::pre_dispatch( TakeFees::from(1), &1, - info_from_weight(1), + &TestCall::Five, 0, ).is_ok()); @@ -140,7 +140,7 @@ fn lock_reasons_should_work() { assert!( as SignedExtension>::pre_dispatch( TakeFees::from(1), &1, - info_from_weight(1), + &TestCall::Five, 0, ).is_ok()); @@ -150,7 +150,7 @@ fn lock_reasons_should_work() { assert!( as SignedExtension>::pre_dispatch( TakeFees::from(1), &1, - info_from_weight(1), + &TestCall::Five, 0, ).is_err()); } @@ -757,10 +757,10 @@ fn signed_extension_take_fees_work() { .build(), || { let len = 10; - assert!(TakeFees::::from(0).pre_dispatch(&1, info_from_weight(5), len).is_ok()); + assert!(TakeFees::::from(0).pre_dispatch(&1, &TestCall::Five, len).is_ok()); assert_eq!(Balances::free_balance(&1), 100 - 20 - 25); - assert!(TakeFees::::from(5 /* tipped */).pre_dispatch(&1, info_from_weight(3), len).is_ok()); - assert_eq!(Balances::free_balance(&1), 100 - 20 - 25 - 20 - 5 - 15); + assert!(TakeFees::::from(5 /* tipped */).pre_dispatch(&1, &TestCall::Two, len).is_ok()); + assert_eq!(Balances::free_balance(&1), 100 - 20 - 25 - 20 - 5 - 10); } ); } @@ -777,7 +777,7 @@ fn signed_extension_take_fees_is_bounded() { use sr_primitives::weights::Weight; // maximum weight possible - assert!(TakeFees::::from(0).pre_dispatch(&1, info_from_weight(Weight::max_value()), 10).is_ok()); + assert!(TakeFees::::from(0).pre_dispatch(&1, &TestCall::Max, 10).is_ok()); // fee will be proportional to what is the actual maximum weight in the runtime. assert_eq!( Balances::free_balance(&1), diff --git a/srml/collective/src/lib.rs b/srml/collective/src/lib.rs index 20c11bdf9b7f6..713bf77147c24 100644 --- a/srml/collective/src/lib.rs +++ b/srml/collective/src/lib.rs @@ -413,6 +413,7 @@ mod tests { type Origin = Origin; type Index = u64; type BlockNumber = u64; + type Call = (); type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u64; diff --git a/srml/contracts/src/exec.rs b/srml/contracts/src/exec.rs index 084558e76f804..cbb37609e2240 100644 --- a/srml/contracts/src/exec.rs +++ b/srml/contracts/src/exec.rs @@ -260,7 +260,7 @@ pub struct ExecutionContext<'a, T: Trait + 'a, V, L> { pub overlay: OverlayAccountDb<'a, T>, pub depth: usize, pub events: Vec>, - pub calls: Vec<(T::AccountId, T::Call)>, + pub calls: Vec<(T::AccountId, ::Call)>, pub config: &'a Config, pub vm: &'a V, pub loader: &'a L, diff --git a/srml/contracts/src/lib.rs b/srml/contracts/src/lib.rs index c4e588e12e42a..06d370eb791cc 100644 --- a/srml/contracts/src/lib.rs +++ b/srml/contracts/src/lib.rs @@ -333,7 +333,7 @@ pub trait Trait: timestamp::Trait { /// /// It is recommended (though not required) for this function to return a fee that would be taken /// by the Executive module for regular dispatch. - type ComputeDispatchFee: ComputeDispatchFee>; + type ComputeDispatchFee: ComputeDispatchFee<::Call, BalanceOf>; /// trie id generator type TrieIdGenerator: TrieIdGenerator; @@ -427,8 +427,8 @@ where /// The default dispatch fee computor computes the fee in the same way that /// the implementation of `MakePayment` for the Balances module does. pub struct DefaultDispatchFeeComputor(PhantomData); -impl ComputeDispatchFee> for DefaultDispatchFeeComputor { - fn compute_dispatch_fee(call: &T::Call) -> BalanceOf { +impl ComputeDispatchFee<::Call, BalanceOf> for DefaultDispatchFeeComputor { + fn compute_dispatch_fee(call: &::Call) -> BalanceOf { let encoded_len = call.using_encoded(|encoded| encoded.len() as u32); let base_fee = T::TransactionBaseFee::get(); let byte_fee = T::TransactionByteFee::get(); diff --git a/srml/contracts/src/tests.rs b/srml/contracts/src/tests.rs index f4699a8c1a9f7..72c4f55e153f1 100644 --- a/srml/contracts/src/tests.rs +++ b/srml/contracts/src/tests.rs @@ -107,6 +107,7 @@ impl system::Trait for Test { type Index = u64; type BlockNumber = u64; type Hash = H256; + type Call = (); type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; diff --git a/srml/council/src/lib.rs b/srml/council/src/lib.rs index 6d2db9373d482..712b2ca835a80 100644 --- a/srml/council/src/lib.rs +++ b/srml/council/src/lib.rs @@ -107,6 +107,7 @@ mod tests { type Origin = Origin; type Index = u64; type BlockNumber = u64; + type Call = (); type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u64; diff --git a/srml/democracy/src/lib.rs b/srml/democracy/src/lib.rs index ae53a53bb8c4d..8c2e0557d1fe1 100644 --- a/srml/democracy/src/lib.rs +++ b/srml/democracy/src/lib.rs @@ -1025,6 +1025,7 @@ mod tests { type Origin = Origin; type Index = u64; type BlockNumber = u64; + type Call = (); type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u64; diff --git a/srml/elections/src/lib.rs b/srml/elections/src/lib.rs index 0e761c94c8fd7..e6aefb5da2c31 100644 --- a/srml/elections/src/lib.rs +++ b/srml/elections/src/lib.rs @@ -1132,6 +1132,7 @@ mod tests { type Origin = Origin; type Index = u64; type BlockNumber = u64; + type Call = (); type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u64; diff --git a/srml/example/src/lib.rs b/srml/example/src/lib.rs index 5925c438a8a05..2d4fa43fb561e 100644 --- a/srml/example/src/lib.rs +++ b/srml/example/src/lib.rs @@ -533,6 +533,7 @@ mod tests { type Index = u64; type BlockNumber = u64; type Hash = H256; + type Call = (); type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; diff --git a/srml/executive/src/lib.rs b/srml/executive/src/lib.rs index b1368e8a282d0..d6f739ec1f845 100644 --- a/srml/executive/src/lib.rs +++ b/srml/executive/src/lib.rs @@ -108,7 +108,7 @@ mod internal { fn from(d: DispatchError) -> Self { match d { DispatchError::Payment => ApplyError::CantPay, - DispatchError::Resource => ApplyError::FullBlock, + DispatchError::Exhausted => ApplyError::FullBlock, DispatchError::NoPermission => ApplyError::CantPay, DispatchError::BadState => ApplyError::CantPay, DispatchError::Stale => ApplyError::Stale, @@ -142,7 +142,7 @@ impl< > ExecuteBlock for Executive where Block::Extrinsic: Checkable + Codec, - CheckedOf: Applyable + GetDispatchInfo, + CheckedOf: Applyable, CallOf: Dispatchable, OriginOf: From>, UnsignedValidator: ValidateUnsigned>, @@ -161,7 +161,7 @@ impl< > Executive where Block::Extrinsic: Checkable + Codec, - CheckedOf: Applyable + GetDispatchInfo, + CheckedOf: Applyable, CallOf: Dispatchable, OriginOf: From>, UnsignedValidator: ValidateUnsigned>, @@ -285,8 +285,7 @@ where // AUDIT: Under no circumstances may this function panic from here onwards. // Decode parameters and dispatch - let dispatch_info = xt.get_dispatch_info(); - let r = Applyable::dispatch(xt, dispatch_info, encoded_len) + let r = Applyable::dispatch(xt, encoded_len) .map_err(internal::ApplyError::from)?; >::note_applied_extrinsic(&r, encoded_len as u32); @@ -340,8 +339,7 @@ where Err(_) => return TransactionValidity::Invalid(UNKNOWN_ERROR), }; - let dispatch_info = xt.get_dispatch_info(); - xt.validate::(dispatch_info, encoded_len) + xt.validate::(encoded_len) } /// Start an offchain worker and generate extrinsics. @@ -359,7 +357,7 @@ mod tests { use primitives::{H256, Blake2Hasher}; use sr_primitives::generic::Era; use sr_primitives::Perbill; - use sr_primitives::weights::Weight; + use sr_primitives::weights::{Weight, GetDispatchInfo}; use sr_primitives::traits::{Header as HeaderT, BlakeTwo256, IdentityLookup, ConvertInto}; use sr_primitives::testing::{Digest, Header, Block}; use srml_support::{impl_outer_event, impl_outer_origin, parameter_types}; @@ -368,8 +366,7 @@ mod tests { use hex_literal::hex; impl_outer_origin! { - pub enum Origin for Runtime { - } + pub enum Origin for Runtime { } } impl_outer_event!{ @@ -383,13 +380,14 @@ mod tests { pub struct Runtime; parameter_types! { pub const BlockHashCount: u64 = 250; - pub const MaximumBlockWeight: u32 = 1024; - pub const MaximumBlockLength: u32 = 2 * 1024; + pub const MaximumBlockWeight: u32 = 1_000_000_000; + pub const MaximumBlockLength: u32 = 128 * 1024; pub const AvailableBlockRatio: Perbill = Perbill::one(); } impl system::Trait for Runtime { type Origin = Origin; type Index = u64; + type Call = Call; type BlockNumber = u64; type Hash = primitives::H256; type Hashing = BlakeTwo256; @@ -461,14 +459,9 @@ mod tests { #[test] fn balance_transfer_dispatch_works() { - let mut t = system::GenesisConfig::default().build_storage::().unwrap(); - balances::GenesisConfig:: { - balances: vec![(1, 211)], - vesting: vec![], - }.assimilate_storage(&mut t.0, &mut t.1).unwrap(); + let mut t = new_test_ext(1_000_000); let xt = sr_primitives::testing::TestXt(sign_extra(1, 0, 0), Call::transfer(2, 69)); - let weight = xt.get_dispatch_info().weight as u64; - let mut t = runtime_io::TestExternalities::::new_with_children(t); + let weight = Call::::transfer(2, 69).get_dispatch_info().weight as u64; with_externalities(&mut t, || { Executive::initialize_block(&Header::new( 1, @@ -479,7 +472,7 @@ mod tests { )); let r = Executive::apply_extrinsic(xt); assert_eq!(r, Ok(ApplyOutcome::Success)); - assert_eq!(>::total_balance(&1), 142 - 10 - weight); + assert_eq!(>::total_balance(&1), 111_000_000 - 69 - 10 - weight); assert_eq!(>::total_balance(&2), 69); }); } @@ -563,13 +556,16 @@ mod tests { #[test] fn block_weight_limit_enforced() { - let mut t = new_test_ext(10000); - // given: TestXt uses the encoded len as fixed Len: + let mut t = new_test_ext(1_000_000_000); let xt = sr_primitives::testing::TestXt(sign_extra(1, 0, 0), Call::transfer::(33, 0)); + let weight = Call::transfer::(33, 0).get_dispatch_info().weight as u32; let encoded = xt.encode(); let encoded_len = encoded.len() as Weight; - let limit = AvailableBlockRatio::get() * MaximumBlockWeight::get(); - let num_to_exhaust_block = limit / encoded_len; + let len_limit = AvailableBlockRatio::get() * MaximumBlockLength::get(); + let weight_limit = AvailableBlockRatio::get() * MaximumBlockWeight::get(); + let num_to_exhaust_block = rstd::cmp::min(len_limit / encoded_len, weight_limit / weight); + + let mut total_len = 0u32; with_externalities(&mut t, || { Executive::initialize_block(&Header::new( 1, @@ -579,13 +575,17 @@ mod tests { Digest::default(), )); assert_eq!(>::all_extrinsics_weight(), 0); + assert_eq!(>::all_extrinsics_len(), 0); for nonce in 0..=num_to_exhaust_block { let xt = sr_primitives::testing::TestXt(sign_extra(1, nonce.into(), 0), Call::transfer::(33, 0)); + let added_len = xt.clone().encode().len() as u32; let res = Executive::apply_extrinsic(xt); if nonce != num_to_exhaust_block { + total_len += added_len; assert_eq!(res.unwrap(), ApplyOutcome::Success); - assert_eq!(>::all_extrinsics_weight(), encoded_len * (nonce + 1)); + assert_eq!(>::all_extrinsics_weight(), weight * (nonce + 1)); + assert_eq!(>::all_extrinsics_len(), total_len); assert_eq!(>::extrinsic_index(), Some(nonce as u32 + 1)); } else { assert_eq!(res, Err(ApplyError::FullBlock)); @@ -599,9 +599,10 @@ mod tests { let xt = sr_primitives::testing::TestXt(sign_extra(1, 0, 0), Call::transfer(33, 0)); let x1 = sr_primitives::testing::TestXt(sign_extra(1, 1, 0), Call::transfer(33, 0)); let x2 = sr_primitives::testing::TestXt(sign_extra(1, 2, 0), Call::transfer(33, 0)); + let weight = Call::::transfer(33, 0).get_dispatch_info().weight; let len = xt.clone().encode().len() as u32; - let mut t = new_test_ext(1); - with_externalities(&mut t, || { + + with_externalities(&mut new_test_ext(1_000_000), || { assert_eq!(>::all_extrinsics_weight(), 0); assert_eq!(>::all_extrinsics_weight(), 0); @@ -609,8 +610,7 @@ mod tests { assert_eq!(Executive::apply_extrinsic(x1.clone()).unwrap(), ApplyOutcome::Success); assert_eq!(Executive::apply_extrinsic(x2.clone()).unwrap(), ApplyOutcome::Success); - // default weight for `TestXt` == encoded length. - assert_eq!(>::all_extrinsics_weight(), (3 * len).into()); + assert_eq!(>::all_extrinsics_weight(), (3 * weight).into()); assert_eq!(>::all_extrinsics_len(), 3 * len); let _ = >::finalize(); @@ -636,17 +636,17 @@ mod tests { fn can_pay_for_tx_fee_on_full_lock() { let id: LockIdentifier = *b"0 "; let execute_with_lock = |lock: WithdrawReasons| { - let mut t = new_test_ext(1); + let mut t = new_test_ext(1_000_000); with_externalities(&mut t, || { as LockableCurrency>::set_lock( id, &1, - 110, + 111 * 1_000_000 - 10, // lock most of the balance. 10, lock, ); let xt = sr_primitives::testing::TestXt(sign_extra(1, 0, 0), Call::transfer(2, 10)); - let weight = xt.get_dispatch_info().weight as u64; + let weight = Call::::transfer(2, 10).get_dispatch_info().weight as u64; Executive::initialize_block(&Header::new( 1, H256::default(), @@ -658,10 +658,10 @@ mod tests { if lock == WithdrawReasons::except(WithdrawReason::TransactionPayment) { assert_eq!(Executive::apply_extrinsic(xt).unwrap(), ApplyOutcome::Fail); // but tx fee has been deducted. the transaction failed on transfer, not on fee. - assert_eq!(>::total_balance(&1), 111 - 10 - weight); + assert_eq!(>::total_balance(&1), 111_000_000 - 10 - weight); } else { assert_eq!(Executive::apply_extrinsic(xt), Err(ApplyError::CantPay)); - assert_eq!(>::total_balance(&1), 111); + assert_eq!(>::total_balance(&1), 111_000_000); } }); }; diff --git a/srml/finality-tracker/src/lib.rs b/srml/finality-tracker/src/lib.rs index f0e2ae0f5420d..a76104e79990b 100644 --- a/srml/finality-tracker/src/lib.rs +++ b/srml/finality-tracker/src/lib.rs @@ -308,6 +308,7 @@ mod tests { type Origin = Origin; type Index = u64; type BlockNumber = u64; + type Call = (); type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u64; diff --git a/srml/generic-asset/src/lib.rs b/srml/generic-asset/src/lib.rs index 60d1f0a3ffeb9..2e5f1b8056114 100644 --- a/srml/generic-asset/src/lib.rs +++ b/srml/generic-asset/src/lib.rs @@ -1048,6 +1048,7 @@ impl PartialEq for ElevatedTrait { impl Eq for ElevatedTrait {} impl system::Trait for ElevatedTrait { type Origin = T::Origin; + type Call = T::Call; type Index = T::Index; type BlockNumber = T::BlockNumber; type Hash = T::Hash; diff --git a/srml/generic-asset/src/mock.rs b/srml/generic-asset/src/mock.rs index 80e04a6b7e429..4f8e5d886fd12 100644 --- a/srml/generic-asset/src/mock.rs +++ b/srml/generic-asset/src/mock.rs @@ -45,6 +45,7 @@ impl system::Trait for Test { type Origin = Origin; type Index = u64; type BlockNumber = u64; + type Call = (); type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u64; diff --git a/srml/grandpa/src/mock.rs b/srml/grandpa/src/mock.rs index 637ae7c25f179..e6df8697bf79a 100644 --- a/srml/grandpa/src/mock.rs +++ b/srml/grandpa/src/mock.rs @@ -51,6 +51,7 @@ impl system::Trait for Test { type Origin = Origin; type Index = u64; type BlockNumber = u64; + type Call = (); type Hash = H256; type Hashing = ::sr_primitives::traits::BlakeTwo256; type AccountId = u64; diff --git a/srml/im-online/src/lib.rs b/srml/im-online/src/lib.rs index 8254cb60780fd..50c846745bd6a 100644 --- a/srml/im-online/src/lib.rs +++ b/srml/im-online/src/lib.rs @@ -68,8 +68,8 @@ // Ensure we're `no_std` when compiling for Wasm. #![cfg_attr(not(feature = "std"), no_std)] -use primitives::{ - crypto::TypedKey, offchain::CryptoKey, +use substrate_primitives::{ + crypto::{AppKey, CryptoType}, offchain::CryptoKey, offchain::OpaqueNetworkState, offchain::StorageKind, sr25519, ed25519, @@ -148,10 +148,10 @@ pub trait Trait: system::Trait + session::Trait { /// A extrinsic right from the external world. This is unchecked and so /// can contain a signature. - type UncheckedExtrinsic: ExtrinsicT + Encode + Decode; + type UncheckedExtrinsic: ExtrinsicT::Call> + Encode + Decode; /// The identifier type for an authority. - type AuthorityId: Member + Parameter + Default + TypedKey + Decode + Encode + AsRef<[u8]>; + type AuthorityId: Member + Parameter + Default + AppKey + Decode + Encode + AsRef<[u8]>; /// Number of sessions per era. type SessionsPerEra: Get; @@ -428,10 +428,10 @@ impl srml_support::unsigned::ValidateUnsigned for Module { let encoded_heartbeat = heartbeat.encode(); - let signature_valid = match ::KEY_TYPE { - ed25519::Public::KEY_TYPE => + let signature_valid = match ::KIND { + ed25519::Public::KIND => sr_io::ed25519_verify(&signature, &encoded_heartbeat, &heartbeat.authority_id), - sr25519::Public::KEY_TYPE => + sr25519::Public::KIND => sr_io::sr25519_verify(&signature, &encoded_heartbeat, &heartbeat.authority_id), _ => return TransactionValidity::Invalid(ApplyError::BadSignature as i8), }; diff --git a/srml/indices/src/mock.rs b/srml/indices/src/mock.rs index ef4b2eb649a01..d3ddfb0e09f7f 100644 --- a/srml/indices/src/mock.rs +++ b/srml/indices/src/mock.rs @@ -75,6 +75,7 @@ impl system::Trait for Runtime { type Origin = Origin; type Index = u64; type BlockNumber = u64; + type Call = (); type Hash = H256; type Hashing = ::sr_primitives::traits::BlakeTwo256; type AccountId = u64; diff --git a/srml/session/src/historical.rs b/srml/session/src/historical.rs index 402a73adf364f..0b838a857fa79 100644 --- a/srml/session/src/historical.rs +++ b/srml/session/src/historical.rs @@ -100,9 +100,9 @@ impl Module { /// Specialization of the crate-level `OnSessionEnding` which returns the old /// set of full identification when changing the validator set. pub trait OnSessionEnding: crate::OnSessionEnding { - /// Returns the set of new validators, if any, along with the old validators - /// and their full identifications. - fn on_session_ending(ending: SessionIndex, applied_at: SessionIndex) + /// If there was a validator set change, its returns the set of new validators along with the + /// old validators and their full identifications. + fn on_session_ending(ending: SessionIndex, will_apply_at: SessionIndex) -> Option<(Vec, Vec<(ValidatorId, FullIdentification)>)>; } diff --git a/srml/session/src/lib.rs b/srml/session/src/lib.rs index a189a91da2848..ad0c2ff511ec5 100644 --- a/srml/session/src/lib.rs +++ b/srml/session/src/lib.rs @@ -121,7 +121,7 @@ use rstd::{prelude::*, marker::PhantomData, ops::{Sub, Rem}}; use parity_codec::Decode; -use sr_primitives::KeyTypeId; +use sr_primitives::{KeyTypeId, AppKey}; use sr_primitives::weights::SimpleDispatchInfo; use sr_primitives::traits::{Convert, Zero, Member, OpaqueKeys, TypedKey}; use srml_support::{ @@ -172,10 +172,13 @@ pub trait OnSessionEnding { /// Handle the fact that the session is ending, and optionally provide the new validator set. /// /// `ending_index` is the index of the currently ending session. - /// The returned validator set, if any, will not be applied until `next_index`. - /// `next_index` is guaranteed to be at least `ending_index + 1`, since session indices don't - /// repeat. - fn on_session_ending(ending_index: SessionIndex, next_index: SessionIndex) -> Option>; + /// The returned validator set, if any, will not be applied until `will_apply_at`. + /// `will_apply_at` is guaranteed to be at least `ending_index + 1`, since session indices don't + /// repeat, but it could be some time after in case we are staging authority set changes. + fn on_session_ending( + ending_index: SessionIndex, + will_apply_at: SessionIndex + ) -> Option>; } impl OnSessionEnding for () { @@ -198,7 +201,7 @@ pub trait SessionHandler { /// One session-key type handler. pub trait OneSessionHandler { /// The key type expected. - type Key: Decode + Default + TypedKey; + type Key: Decode + Default + AppKey; fn on_new_session<'a, I: 'a>(changed: bool, validators: I, queued_validators: I) where I: Iterator, ValidatorId: 'a; @@ -222,10 +225,10 @@ macro_rules! impl_session_handlers { ) { $( let our_keys: Box> = Box::new(validators.iter() - .map(|k| (&k.0, k.1.get::<$t::Key>(<$t::Key as TypedKey>::KEY_TYPE) + .map(|k| (&k.0, k.1.get::<$t::Key>(<$t::Key as AppKey>::ID) .unwrap_or_default()))); let queued_keys: Box> = Box::new(queued_validators.iter() - .map(|k| (&k.0, k.1.get::<$t::Key>(<$t::Key as TypedKey>::KEY_TYPE) + .map(|k| (&k.0, k.1.get::<$t::Key>(<$t::Key as AppKey>::ID) .unwrap_or_default()))); $t::on_new_session(changed, our_keys, queued_keys); )* @@ -604,24 +607,6 @@ mod tests { }) } - #[test] - fn keys_cleared_on_kill() { - let mut ext = new_test_ext(); - with_externalities(&mut ext, || { - assert_eq!(Session::validators(), vec![1, 2, 3]); - assert_eq!(Session::load_keys(&1), Some(UintAuthorityId(1))); - - let id = ::KEY_TYPE; - assert_eq!(Session::key_owner(id, UintAuthorityId(1).get_raw(id)), Some(1)); - - Session::on_free_balance_zero(&1); - assert_eq!(Session::load_keys(&1), None); - assert_eq!(Session::key_owner(id, UintAuthorityId(1).get_raw(id)), None); - - assert!(Changed::get()); - }) - } - #[test] fn authorities_should_track_validators() { with_externalities(&mut new_test_ext(), || { diff --git a/srml/session/src/mock.rs b/srml/session/src/mock.rs index 734f5bbde4bd6..0194ee131e3be 100644 --- a/srml/session/src/mock.rs +++ b/srml/session/src/mock.rs @@ -123,6 +123,7 @@ impl system::Trait for Test { type Origin = Origin; type Index = u64; type BlockNumber = u64; + type Call = (); type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u64; diff --git a/srml/staking/src/mock.rs b/srml/staking/src/mock.rs index 344ef70e3b6f4..787c4f13b733b 100644 --- a/srml/staking/src/mock.rs +++ b/srml/staking/src/mock.rs @@ -110,6 +110,7 @@ impl system::Trait for Test { type Origin = Origin; type Index = u64; type BlockNumber = BlockNumber; + type Call = (); type Hash = H256; type Hashing = ::sr_primitives::traits::BlakeTwo256; type AccountId = AccountId; diff --git a/srml/support/src/storage/hashed/generator.rs b/srml/support/src/storage/hashed/generator.rs index 4d367fb2a870a..6b4f5829a3f74 100644 --- a/srml/support/src/storage/hashed/generator.rs +++ b/srml/support/src/storage/hashed/generator.rs @@ -238,6 +238,23 @@ pub trait StorageMap { /// Take the value under a key. fn take>(key: &K, storage: &mut S) -> Self::Query; + /// Swap the values of two keys. + fn swap>(key1: &K, key2: &K, storage: &mut S) { + let k1 = Self::key_for(key1); + let k2 = Self::key_for(key2); + let v1 = storage.get_raw(&k1[..]); + if let Some(val) = storage.get_raw(&k2[..]) { + storage.put_raw(&k1[..], &val[..]); + } else { + storage.kill(&k1[..]) + } + if let Some(val) = v1 { + storage.put_raw(&k2[..], &val[..]); + } else { + storage.kill(&k2[..]) + } + } + /// Store a value to be associated with the given key from the map. fn insert>(key: &K, val: &V, storage: &mut S) { storage.put(&Self::key_for(key)[..], val); diff --git a/srml/support/src/storage/mod.rs b/srml/support/src/storage/mod.rs index 46b6603d91dc0..385fad42eb260 100644 --- a/srml/support/src/storage/mod.rs +++ b/srml/support/src/storage/mod.rs @@ -191,6 +191,9 @@ pub trait StorageMap { /// Load the value associated with the given key from the map. fn get>(key: KeyArg) -> Self::Query; + /// Swap the values of two keys. + fn swap, KeyArg2: Borrow>(key1: KeyArg1, key2: KeyArg2); + /// Store a value to be associated with the given key from the map. fn insert, ValArg: Borrow>(key: KeyArg, val: ValArg); @@ -227,6 +230,10 @@ impl StorageMap for U where U: hashed::generator::S U::get(key.borrow(), &RuntimeStorage) } + fn swap, KeyArg2: Borrow>(key1: KeyArg1, key2: KeyArg2) { + U::swap(key1.borrow(), key2.borrow(), &mut RuntimeStorage) + } + fn insert, ValArg: Borrow>(key: KeyArg, val: ValArg) { U::insert(key.borrow(), val.borrow(), &mut RuntimeStorage) } diff --git a/srml/system/benches/bench.rs b/srml/system/benches/bench.rs index 8e13e92d3f8d8..8b67ba50bd655 100644 --- a/srml/system/benches/bench.rs +++ b/srml/system/benches/bench.rs @@ -63,6 +63,7 @@ impl system::Trait for Runtime { type Origin = Origin; type Index = u64; type BlockNumber = u64; + type Call = (); type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u64; diff --git a/srml/system/src/lib.rs b/srml/system/src/lib.rs index 1d73567c77f49..9a7aab500f331 100644 --- a/srml/system/src/lib.rs +++ b/srml/system/src/lib.rs @@ -79,7 +79,7 @@ use rstd::map; use rstd::marker::PhantomData; use sr_primitives::generic::{self, Era}; use sr_primitives::Perbill; -use sr_primitives::weights::{Weight, DispatchInfo, DispatchClass, WeightMultiplier, SimpleDispatchInfo}; +use sr_primitives::weights::{Weight, DispatchInfo, DispatchClass, WeightMultiplier, SimpleDispatchInfo, GetDispatchInfo}; use sr_primitives::transaction_validity::{ValidTransaction, TransactionPriority, TransactionLongevity}; use sr_primitives::traits::{self, CheckEqual, SimpleArithmetic, Zero, SignedExtension, Convert, SimpleBitOps, Hash, Member, MaybeDisplay, EnsureOrigin, CurrentHeight, BlockNumberToHash, @@ -151,6 +151,9 @@ pub trait Trait: 'static + Eq + Clone { /// The aggregated `Origin` type used by dispatchable calls. type Origin: Into, Self::Origin>> + From>; + /// The aggregated `Call` type. + type Call: GetDispatchInfo; + /// Account index (aka nonce) type. This stores the number of previous transactions associated with a sender /// account. type Index: @@ -836,7 +839,7 @@ impl CheckWeight { let added_weight = info.weight.min(limit); let next_weight = current_weight.saturating_add(added_weight); if next_weight > limit { - return Err(DispatchError::Resource) + return Err(DispatchError::Exhausted) } Ok(next_weight) } @@ -851,7 +854,7 @@ impl CheckWeight { let added_len = len as u32; let next_len = current_len.saturating_add(added_len); if next_len > limit { - return Err(DispatchError::Resource) + return Err(DispatchError::Exhausted) } Ok(next_len) } @@ -873,6 +876,7 @@ impl CheckWeight { impl SignedExtension for CheckWeight { type AccountId = T::AccountId; + type Call = T::Call; type AdditionalSigned = (); fn additional_signed(&self) -> rstd::result::Result<(), &'static str> { Ok(()) } @@ -880,9 +884,10 @@ impl SignedExtension for CheckWeight { fn pre_dispatch( self, _who: &Self::AccountId, - info: DispatchInfo, + call: &Self::Call, len: usize, ) -> Result<(), DispatchError> { + let info = call.get_dispatch_info(); let next_len = Self::check_block_length(info, len)?; AllExtrinsicsLen::put(next_len); let next_weight = Self::check_weight(info)?; @@ -893,12 +898,13 @@ impl SignedExtension for CheckWeight { fn validate( &self, _who: &Self::AccountId, - info: DispatchInfo, + call: &Self::Call, len: usize, ) -> Result { // There is no point in writing to storage here since changes are discarded. This basically // discards any transaction which is bigger than the length or weight limit **alone**,which // is a guarantee that it will fail in the pre-dispatch phase. + let info = call.get_dispatch_info(); let _ = Self::check_block_length(info, len)?; let _ = Self::check_weight(info)?; Ok(ValidTransaction { priority: Self::get_priority(info), ..Default::default() }) @@ -933,6 +939,7 @@ impl rstd::fmt::Debug for CheckNonce { impl SignedExtension for CheckNonce { type AccountId = T::AccountId; + type Call = T::Call; type AdditionalSigned = (); fn additional_signed(&self) -> rstd::result::Result<(), &'static str> { Ok(()) } @@ -940,7 +947,7 @@ impl SignedExtension for CheckNonce { fn pre_dispatch( self, who: &Self::AccountId, - _info: DispatchInfo, + _call: &Self::Call, _len: usize, ) -> Result<(), DispatchError> { let expected = >::get(who); @@ -956,9 +963,10 @@ impl SignedExtension for CheckNonce { fn validate( &self, who: &Self::AccountId, - info: DispatchInfo, + call: &Self::Call, _len: usize, ) -> Result { + let info = call.get_dispatch_info(); // check index let expected = >::get(who); if self.0 < expected { @@ -1003,6 +1011,7 @@ impl rstd::fmt::Debug for CheckEra { impl SignedExtension for CheckEra { type AccountId = T::AccountId; + type Call = T::Call; type AdditionalSigned = T::Hash; fn additional_signed(&self) -> Result { let current_u64 = >::block_number().saturated_into::(); @@ -1066,6 +1075,7 @@ mod tests { impl Trait for Test { type Origin = Origin; + type Call = TestCall; type Index = u64; type BlockNumber = u64; type Hash = H256; @@ -1092,6 +1102,32 @@ mod tests { type System = Module; + #[derive(Copy, Clone)] + pub enum TestCall { + Default, + Max, + Free, + Small, + Medium, + Big, + Op, + } + + impl GetDispatchInfo for TestCall { + fn get_dispatch_info(&self) -> DispatchInfo { + let limit = MaximumBlockWeight::get(); + match *self { + TestCall::Default => Default::default(), + TestCall::Free => DispatchInfo { weight: 0, ..Default::default() }, + TestCall::Max => DispatchInfo { weight: Weight::max_value(), ..Default::default() }, + TestCall::Small => DispatchInfo { weight: 100, ..Default::default() }, + TestCall::Medium => DispatchInfo { weight: limit - 1, ..Default::default() }, + TestCall::Big => DispatchInfo { weight: limit + 1, ..Default::default() }, + TestCall::Op => DispatchInfo { weight: 100, class: DispatchClass::Operational }, + } + } + } + fn new_test_ext() -> runtime_io::TestExternalities { GenesisConfig::default().build_storage::().unwrap().0.into() } @@ -1242,38 +1278,30 @@ mod tests { fn signed_ext_check_nonce_works() { with_externalities(&mut new_test_ext(), || { >::insert(1, 1); - let info = DispatchInfo::default(); let len = 0_usize; // stale - assert!(CheckNonce::(0).validate(&1, info, len).is_err()); - assert!(CheckNonce::(0).pre_dispatch(&1, info, len).is_err()); + assert!(CheckNonce::(0).validate(&1, &TestCall::Default, len).is_err()); + assert!(CheckNonce::(0).pre_dispatch(&1, &TestCall::Default, len).is_err()); // correct - assert!(CheckNonce::(1).validate(&1, info, len).is_ok()); - assert!(CheckNonce::(1).pre_dispatch(&1, info, len).is_ok()); + assert!(CheckNonce::(1).validate(&1, &TestCall::Default, len).is_ok()); + assert!(CheckNonce::(1).pre_dispatch(&1, &TestCall::Default, len).is_ok()); // future - assert!(CheckNonce::(5).validate(&1, info, len).is_ok()); - assert!(CheckNonce::(5).pre_dispatch(&1, info, len).is_err()); + assert!(CheckNonce::(5).validate(&1, &TestCall::Default, len).is_ok()); + assert!(CheckNonce::(5).pre_dispatch(&1, &TestCall::Default, len).is_err()); }) } #[test] fn signed_ext_check_weight_works_normal_tx() { with_externalities(&mut new_test_ext(), || { - let normal_limit = normal_weight_limit(); - let small = DispatchInfo { weight: 100, ..Default::default() }; - let medium = DispatchInfo { - weight: normal_limit - 1, - ..Default::default() - }; - let big = DispatchInfo { - weight: normal_limit + 1, - ..Default::default() - }; + let small = TestCall::Small; + let medium = TestCall::Medium; + let big = TestCall::Big; let len = 0_usize; let reset_check_weight = |i, f, s| { AllExtrinsicsWeight::put(s); - let r = CheckWeight::(PhantomData).pre_dispatch(&1, i, len); + let r = CheckWeight::(PhantomData).pre_dispatch(&1, &i, len); if f { assert!(r.is_err()) } else { assert!(r.is_ok()) } }; @@ -1286,11 +1314,11 @@ mod tests { #[test] fn signed_ext_check_weight_fee_works() { with_externalities(&mut new_test_ext(), || { - let free = DispatchInfo { weight: 0, ..Default::default() }; + let free = TestCall::Free; let len = 0_usize; assert_eq!(System::all_extrinsics_weight(), 0); - let r = CheckWeight::(PhantomData).pre_dispatch(&1, free, len); + let r = CheckWeight::(PhantomData).pre_dispatch(&1, &free, len); assert!(r.is_ok()); assert_eq!(System::all_extrinsics_weight(), 0); }) @@ -1299,12 +1327,12 @@ mod tests { #[test] fn signed_ext_check_weight_max_works() { with_externalities(&mut new_test_ext(), || { - let max = DispatchInfo { weight: Weight::max_value(), ..Default::default() }; + let max = TestCall::Max; let len = 0_usize; let normal_limit = normal_weight_limit(); assert_eq!(System::all_extrinsics_weight(), 0); - let r = CheckWeight::(PhantomData).pre_dispatch(&1, max, len); + let r = CheckWeight::(PhantomData).pre_dispatch(&1, &max, len); assert!(r.is_ok()); assert_eq!(System::all_extrinsics_weight(), normal_limit); }) @@ -1313,39 +1341,39 @@ mod tests { #[test] fn signed_ext_check_weight_works_operational_tx() { with_externalities(&mut new_test_ext(), || { - let normal = DispatchInfo { weight: 100, ..Default::default() }; - let op = DispatchInfo { weight: 100, class: DispatchClass::Operational }; + let normal = TestCall::Medium; + let op = TestCall::Op; let len = 0_usize; let normal_limit = normal_weight_limit(); // given almost full block AllExtrinsicsWeight::put(normal_limit); // will not fit. - assert!(CheckWeight::(PhantomData).pre_dispatch(&1, normal, len).is_err()); + assert!(CheckWeight::(PhantomData).pre_dispatch(&1, &normal, len).is_err()); // will fit. - assert!(CheckWeight::(PhantomData).pre_dispatch(&1, op, len).is_ok()); + assert!(CheckWeight::(PhantomData).pre_dispatch(&1, &op, len).is_ok()); // likewise for length limit. let len = 100_usize; AllExtrinsicsLen::put(normal_length_limit()); - assert!(CheckWeight::(PhantomData).pre_dispatch(&1, normal, len).is_err()); - assert!(CheckWeight::(PhantomData).pre_dispatch(&1, op, len).is_ok()); + assert!(CheckWeight::(PhantomData).pre_dispatch(&1, &normal, len).is_err()); + assert!(CheckWeight::(PhantomData).pre_dispatch(&1, &op, len).is_ok()); }) } #[test] fn signed_ext_check_weight_priority_works() { with_externalities(&mut new_test_ext(), || { - let normal = DispatchInfo { weight: 100, class: DispatchClass::Normal }; - let op = DispatchInfo { weight: 100, class: DispatchClass::Operational }; + let normal = TestCall::Small; + let op = TestCall::Op; let len = 0_usize; assert_eq!( - CheckWeight::(PhantomData).validate(&1, normal, len).unwrap().priority, + CheckWeight::(PhantomData).validate(&1, &normal, len).unwrap().priority, 100, ); assert_eq!( - CheckWeight::(PhantomData).validate(&1, op, len).unwrap().priority, + CheckWeight::(PhantomData).validate(&1, &op, len).unwrap().priority, Bounded::max_value(), ); }) @@ -1354,11 +1382,12 @@ mod tests { #[test] fn signed_ext_check_weight_block_size_works() { with_externalities(&mut new_test_ext(), || { - let normal = DispatchInfo::default(); + let normal = TestCall::Default; let normal_limit = normal_weight_limit() as usize; + let reset_check_weight = |tx, s, f| { AllExtrinsicsLen::put(0); - let r = CheckWeight::(PhantomData).pre_dispatch(&1, tx, s); + let r = CheckWeight::(PhantomData).pre_dispatch(&1, &tx, s); if f { assert!(r.is_err()) } else { assert!(r.is_ok()) } }; @@ -1367,7 +1396,7 @@ mod tests { reset_check_weight(normal, normal_limit + 1, true); // Operational ones don't have this limit. - let op = DispatchInfo { weight: 0, class: DispatchClass::Operational }; + let op = TestCall::Op; reset_check_weight(op, normal_limit, false); reset_check_weight(op, normal_limit + 100, false); reset_check_weight(op, 1024, false); diff --git a/srml/timestamp/src/lib.rs b/srml/timestamp/src/lib.rs index cc439da8ee548..f5bf49e65f339 100644 --- a/srml/timestamp/src/lib.rs +++ b/srml/timestamp/src/lib.rs @@ -358,6 +358,7 @@ mod tests { type Origin = Origin; type Index = u64; type BlockNumber = u64; + type Call = (); type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u64; diff --git a/srml/treasury/src/lib.rs b/srml/treasury/src/lib.rs index 702fe3048e94d..66effdd790614 100644 --- a/srml/treasury/src/lib.rs +++ b/srml/treasury/src/lib.rs @@ -382,6 +382,7 @@ mod tests { type Origin = Origin; type Index = u64; type BlockNumber = u64; + type Call = (); type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u64;