From f04d7de11ac6c10b572edadd3b2e3d2ba30ff594 Mon Sep 17 00:00:00 2001 From: Yash Garg Date: Thu, 3 Oct 2019 06:43:59 +0530 Subject: [PATCH 001/167] Update README.adoc (#3744) * Update README.adoc * Update README.adoc Co-Authored-By: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Update README.adoc Co-Authored-By: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Update README.adoc Co-Authored-By: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Update README.adoc Co-Authored-By: joe petrowski <25483142+joepetrowski@users.noreply.github.com> --- README.adoc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.adoc b/README.adoc index 39b0912b7d..810d07c612 100644 --- a/README.adoc +++ b/README.adoc @@ -20,13 +20,13 @@ See also https://www.parity.io/what-is-substrate/. Substrate is still an early stage project, and while it has already been used as the basis of major projects like Polkadot, using it is still a significant undertaking. In particular, you should have a good knowledge of blockchain concepts and basic cryptography. Terminology like header, block, client, hash, transaction and signature should be familiar. At present you will need a working knowledge of Rust to be able to do anything interesting (though eventually, we aim for this not to be the case). -Substrate is designed to be used in one of three ways: +Substrate is designed for use in one of three ways: -1. Trivial: By running the Substrate binary `substrate` and configuring it with a genesis block that includes the current demonstration runtime. In this case, you just build Substrate, configure a JSON file and launch your own blockchain. This affords you the least amount of customisability, primarily allowing you to change the genesis parameters of the various included runtime modules such as balances, staking, block-period, fees and governance. +**1. Trivial**: By running the Substrate binary `substrate` and configuring it with a genesis block that includes the current demonstration runtime. In this case, you just build Substrate, configure a JSON file, and launch your own blockchain. This affords you the least amount of customizability, primarily allowing you to change the genesis parameters of the various included runtime modules such as balances, staking, block-period, fees, and governance. -2. Modular: By hacking together modules from the Substrate Runtime Module Library into a new runtime and possibly altering or reconfiguring the Substrate client's block authoring logic. This affords you a very large amount of freedom over your own blockchain's logic, letting you change datatypes, add or remove modules and, crucially, add your own modules. Much can be changed without touching the block-authoring logic (since it is generic). If this is the case, then the existing Substrate binary can be used for block authoring and syncing. If the block authoring logic needs to be tweaked, then a new altered block-authoring binary must be built as a separate project and used by validators. This is how the Polkadot relay chain is built and should suffice for almost all circumstances in the near to mid-term. +**2. Modular**: By hacking together modules from the Substrate Runtime Module Library (SRML) into a new runtime and possibly altering or reconfiguring the Substrate client's block authoring logic. This affords you a very large amount of freedom over your blockchain's logic, letting you change datatypes, add or remove modules, and crucially, add your own modules. Much can be changed without touching the block authoring logic (since it is generic). If this is the case, then the existing Substrate binary can be used for block authoring and syncing. If the block authoring logic needs to be tweaked, then a new, altered block authoring binary must be built as a separate project and used by validators. This is how the Polkadot relay chain is built and should suffice for almost all circumstances in the near to mid-term. -3. Generic: The entire Substrate Runtime Module Library can be ignored and the entire runtime designed and implemented from scratch. If desired, this can be done in a language other than Rust, providing it can target WebAssembly. If the runtime can be made to be compatible with the existing client's block authoring logic, then you can simply construct a new genesis block from your Wasm blob and launch your chain with the existing Rust-based Substrate client. If not, then you'll need to alter the client's block authoring logic accordingly. This is probably a useless option for most projects right now, but provides complete flexibility allowing for a long-term far-reaching upgrade path for the Substrate paradigm. +**3. Generic**: The entire SRML can be ignored and the entire runtime designed and implemented from scratch. If desired, this can be done in a language other than Rust, provided it can target WebAssembly. If the runtime can be made compatible with the existing client's block authoring logic, then you can simply construct a new genesis block from your Wasm blob and launch your chain with the existing Rust-based Substrate client. If not, then you'll need to alter the client's block authoring logic accordingly. This is probably a useless option for most projects right now, but provides complete flexibility allowing for a long-term, far-reaching upgrade path for the Substrate paradigm. === The Basics of Substrate -- GitLab From 8492a268cacb13b0e51d7fa8551a1c662882390a Mon Sep 17 00:00:00 2001 From: Xiliang Chen Date: Thu, 3 Oct 2019 14:16:07 +1300 Subject: [PATCH 002/167] Minor fixes (#3751) * fix warning * use compact for balance type * bump version --- node/runtime/src/lib.rs | 2 +- srml/elections-phragmen/src/lib.rs | 2 +- srml/elections/src/lib.rs | 4 ++-- srml/scored-pool/src/lib.rs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index 82ffe5390f..190385d6bc 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -85,7 +85,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // implementation changes and behavior does not, then leave spec_version as // is and increment impl_version. spec_version: 170, - impl_version: 170, + impl_version: 171, apis: RUNTIME_API_VERSIONS, }; diff --git a/srml/elections-phragmen/src/lib.rs b/srml/elections-phragmen/src/lib.rs index b7cf1a4013..58c0f11340 100644 --- a/srml/elections-phragmen/src/lib.rs +++ b/srml/elections-phragmen/src/lib.rs @@ -181,7 +181,7 @@ decl_module! { /// Writes: O(V) given `V` votes. V is bounded by 16. /// # #[weight = SimpleDispatchInfo::FixedNormal(100_000)] - fn vote(origin, votes: Vec, value: BalanceOf) { + fn vote(origin, votes: Vec, #[compact] value: BalanceOf) { let who = ensure_signed(origin)?; let candidates_count = >::decode_len().unwrap_or(0) as usize; diff --git a/srml/elections/src/lib.rs b/srml/elections/src/lib.rs index 2a683879f8..8c90090349 100644 --- a/srml/elections/src/lib.rs +++ b/srml/elections/src/lib.rs @@ -344,7 +344,7 @@ decl_module! { votes: Vec, #[compact] index: VoteIndex, hint: SetIndex, - value: BalanceOf + #[compact] value: BalanceOf ) -> Result { let who = ensure_signed(origin)?; Self::do_set_approvals(who, votes, index, hint, value) @@ -361,7 +361,7 @@ decl_module! { votes: Vec, #[compact] index: VoteIndex, hint: SetIndex, - value: BalanceOf + #[compact] value: BalanceOf ) -> Result { let who = Self::proxy(ensure_signed(origin)?).ok_or("not a proxy")?; Self::do_set_approvals(who, votes, index, hint, value) diff --git a/srml/scored-pool/src/lib.rs b/srml/scored-pool/src/lib.rs index 4739e165d1..609f17b457 100644 --- a/srml/scored-pool/src/lib.rs +++ b/srml/scored-pool/src/lib.rs @@ -91,7 +91,7 @@ mod tests; use codec::FullCodec; use rstd::prelude::*; use support::{ - StorageValue, decl_module, decl_storage, decl_event, ensure, + decl_module, decl_storage, decl_event, ensure, traits::{ChangeMembers, InitializeMembers, Currency, Get, ReservableCurrency}, }; use system::{self, ensure_root, ensure_signed}; -- GitLab From ddd7368b73e7d47cff8b51776ad4c0bc4fb007c9 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Thu, 3 Oct 2019 11:02:20 +0800 Subject: [PATCH 003/167] Cumulative fixes to make working with consensus-pow easier (#3617) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * consensus-pow: add difficulty data to auxiliary * Timestamp api * Implement FinalityProofProvider for () * Add DifficultyApi * Remove assumption that Difficulty is u128 * Use a separate trait for add instead of hard-code it as Saturating * Some convenience functions to work with PowVerifier * Try to fix mining unstability * Fix generic resolution * Unused best_header variable * Fix hash calculation * Remove artificial sleep * Tweak proposer waiting time * Revert sleep removal The reason why it was there is because when mine_loop returns, it means an error happened. In that case, we'd better sleep for a moment before trying again, because immediately trying would most likely just fail. * Pass sync oracle to mining So that it does not mine when major syncing * Expose build time as a parameter Instead of hardcode it as previously 100ms. * Update lock file * Fix compile * Support skipping check_inherents for ancient blocks For PoW, older blocks are secured by the work, and can mostly be considered to be finalized. Thus we can save both code complexity and validation time by skipping checking inherents for them. * Move difficulty fetch function out of loop To make things faster * Remove seed from mining Each engine can use its own Rng source. * Better comments * Add TotalDifficulty definition for U256 and u128 * Update core/consensus/pow/src/lib.rs Co-Authored-By: André Silva * Rename TotalDifficulty::add -> increment * Use SelectChain to fetch the best header/hash * Update lock file --- Cargo.lock | 1 + core/consensus/pow/primitives/Cargo.toml | 2 + core/consensus/pow/primitives/src/lib.rs | 45 +++++-- core/consensus/pow/src/lib.rs | 164 +++++++++++++++++------ core/network/src/chain.rs | 6 + 5 files changed, 168 insertions(+), 50 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9d80227547..7043341751 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4861,6 +4861,7 @@ dependencies = [ name = "substrate-consensus-pow-primitives" version = "2.0.0" dependencies = [ + "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", "sr-std 2.0.0", "substrate-client 2.0.0", diff --git a/core/consensus/pow/primitives/Cargo.toml b/core/consensus/pow/primitives/Cargo.toml index a7e0d284b0..021e4c80a7 100644 --- a/core/consensus/pow/primitives/Cargo.toml +++ b/core/consensus/pow/primitives/Cargo.toml @@ -10,6 +10,7 @@ substrate-client = { path = "../../../client", default-features = false } rstd = { package = "sr-std", path = "../../../sr-std", default-features = false } sr-primitives = { path = "../../../sr-primitives", default-features = false } primitives = { package = "substrate-primitives", path = "../../../primitives", default-features = false } +codec = { package = "parity-scale-codec", version = "1.0.0", default-features = false, features = ["derive"] } [features] default = ["std"] @@ -18,4 +19,5 @@ std = [ "substrate-client/std", "sr-primitives/std", "primitives/std", + "codec/std", ] diff --git a/core/consensus/pow/primitives/src/lib.rs b/core/consensus/pow/primitives/src/lib.rs index 807a7b2df2..2079b1cbe7 100644 --- a/core/consensus/pow/primitives/src/lib.rs +++ b/core/consensus/pow/primitives/src/lib.rs @@ -20,17 +20,46 @@ use rstd::vec::Vec; use sr_primitives::ConsensusEngineId; +use codec::Decode; +use substrate_client::decl_runtime_apis; /// The `ConsensusEngineId` of PoW. pub const POW_ENGINE_ID: ConsensusEngineId = [b'p', b'o', b'w', b'_']; -/// Type of difficulty. -/// -/// For runtime designed for Substrate, it's always possible to fit its total -/// difficulty range under `u128::max_value()` because it can be freely scaled -/// up or scaled down. Very few PoW chains use difficulty values -/// larger than `u128::max_value()`. -pub type Difficulty = u128; - /// Type of seal. pub type Seal = Vec; + +/// Define methods that total difficulty should implement. +pub trait TotalDifficulty { + fn increment(&mut self, other: Self); +} + +impl TotalDifficulty for primitives::U256 { + fn increment(&mut self, other: Self) { + let ret = self.saturating_add(other); + *self = ret; + } +} + +impl TotalDifficulty for u128 { + fn increment(&mut self, other: Self) { + let ret = self.saturating_add(other); + *self = ret; + } +} + +decl_runtime_apis! { + /// API necessary for timestamp-based difficulty adjustment algorithms. + pub trait TimestampApi { + /// Return the timestamp in the current block. + fn timestamp() -> Moment; + } + + /// API for those chains that put their difficulty adjustment algorithm directly + /// onto runtime. Note that while putting difficulty adjustment algorithm to + /// runtime is safe, putting the PoW algorithm on runtime is not. + pub trait DifficultyApi { + /// Return the target difficulty of the next block. + fn difficulty() -> Difficulty; + } +} diff --git a/core/consensus/pow/src/lib.rs b/core/consensus/pow/src/lib.rs index 8bc0d3593a..7f282e2052 100644 --- a/core/consensus/pow/src/lib.rs +++ b/core/consensus/pow/src/lib.rs @@ -41,12 +41,12 @@ use sr_primitives::Justification; use sr_primitives::generic::{BlockId, Digest, DigestItem}; use sr_primitives::traits::{Block as BlockT, Header as HeaderT, ProvideRuntimeApi}; use srml_timestamp::{TimestampInherentData, InherentError as TIError}; -use pow_primitives::{Difficulty, Seal, POW_ENGINE_ID}; +use pow_primitives::{Seal, TotalDifficulty, POW_ENGINE_ID}; use primitives::H256; use inherents::{InherentDataProviders, InherentData}; use consensus_common::{ - BlockImportParams, BlockOrigin, ForkChoiceStrategy, - Environment, Proposer, + BlockImportParams, BlockOrigin, ForkChoiceStrategy, SyncOracle, Environment, Proposer, + SelectChain, }; use consensus_common::import_queue::{BoxBlockImport, BasicQueue, Verifier}; use codec::{Encode, Decode}; @@ -63,59 +63,78 @@ fn aux_key(hash: &H256) -> Vec { /// Auxiliary storage data for PoW. #[derive(Encode, Decode, Clone, Debug, Default)] -pub struct PowAux { - /// Total difficulty. +pub struct PowAux { + /// Difficulty of the current block. + pub difficulty: Difficulty, + /// Total difficulty up to current block. pub total_difficulty: Difficulty, } -impl PowAux { +impl PowAux where + Difficulty: Decode + Default, +{ /// Read the auxiliary from client. pub fn read(client: &C, hash: &H256) -> Result { let key = aux_key(hash); match client.get_aux(&key).map_err(|e| format!("{:?}", e))? { - Some(bytes) => PowAux::decode(&mut &bytes[..]).map_err(|e| format!("{:?}", e)), - None => Ok(PowAux::default()), + Some(bytes) => Self::decode(&mut &bytes[..]) + .map_err(|e| format!("{:?}", e)), + None => Ok(Self::default()), } } } /// Algorithm used for proof of work. pub trait PowAlgorithm { + /// Difficulty for the algorithm. + type Difficulty: TotalDifficulty + Default + Encode + Decode + Ord + Clone + Copy; + /// Get the next block's difficulty. - fn difficulty(&self, parent: &BlockId) -> Result; + fn difficulty(&self, parent: &BlockId) -> Result; /// Verify proof of work against the given difficulty. fn verify( &self, parent: &BlockId, pre_hash: &H256, seal: &Seal, - difficulty: Difficulty, + difficulty: Self::Difficulty, ) -> Result; /// Mine a seal that satisfy the given difficulty. fn mine( &self, parent: &BlockId, pre_hash: &H256, - seed: &H256, - difficulty: Difficulty, + difficulty: Self::Difficulty, round: u32, ) -> Result, String>; } /// A verifier for PoW blocks. -pub struct PowVerifier { +pub struct PowVerifier, C, S, Algorithm> { client: Arc, algorithm: Algorithm, inherent_data_providers: inherents::InherentDataProviders, + select_chain: Option, + check_inherents_after: <::Header as HeaderT>::Number, } -impl PowVerifier { - fn check_header>( +impl, C, S, Algorithm> PowVerifier { + pub fn new( + client: Arc, + algorithm: Algorithm, + check_inherents_after: <::Header as HeaderT>::Number, + select_chain: Option, + inherent_data_providers: inherents::InherentDataProviders, + ) -> Self { + Self { client, algorithm, inherent_data_providers, select_chain, check_inherents_after } + } + + fn check_header( &self, mut header: B::Header, parent_block_id: BlockId, - ) -> Result<(B::Header, Difficulty, DigestItem), String> where + ) -> Result<(B::Header, Algorithm::Difficulty, DigestItem), String> where Algorithm: PowAlgorithm, { let hash = header.hash(); @@ -146,7 +165,7 @@ impl PowVerifier { Ok((header, difficulty, seal)) } - fn check_inherents>( + fn check_inherents( &self, block: B, block_id: BlockId, @@ -157,6 +176,10 @@ impl PowVerifier { { const MAX_TIMESTAMP_DRIFT_SECS: u64 = 60; + if *block.header().number() < self.check_inherents_after { + return Ok(()) + } + let inherent_res = self.client.runtime_api().check_inherents( &block_id, block, @@ -183,9 +206,10 @@ impl PowVerifier { } } -impl, C, Algorithm> Verifier for PowVerifier where +impl, C, S, Algorithm> Verifier for PowVerifier where C: ProvideRuntimeApi + Send + Sync + HeaderBackend + AuxStore + ProvideCache + BlockOf, C::Api: BlockBuilderApi, + S: SelectChain, Algorithm: PowAlgorithm + Send + Sync, { fn verify( @@ -199,17 +223,23 @@ impl, C, Algorithm> Verifier for PowVerifier select_chain.best_chain() + .map_err(|e| format!("Fetch best chain failed via select chain: {:?}", e))? + .hash(), + None => self.client.info().best_hash, + }; let hash = header.hash(); let parent_hash = *header.parent_hash(); let best_aux = PowAux::read(self.client.as_ref(), &best_hash)?; let mut aux = PowAux::read(self.client.as_ref(), &parent_hash)?; - let (checked_header, difficulty, seal) = self.check_header::( + let (checked_header, difficulty, seal) = self.check_header( header, BlockId::Hash(parent_hash), )?; - aux.total_difficulty = aux.total_difficulty.saturating_add(difficulty); + aux.difficulty = difficulty; + aux.total_difficulty.increment(difficulty); if let Some(inner_body) = body.take() { let block = B::new(checked_header.clone(), inner_body); @@ -241,7 +271,7 @@ impl, C, Algorithm> Verifier for PowVerifier Result<(), consensus_common::Error> { if !inherent_data_providers.has_provider(&srml_timestamp::INHERENT_IDENTIFIER) { @@ -258,10 +288,12 @@ fn register_pow_inherent_data_provider( pub type PowImportQueue = BasicQueue; /// Import queue for PoW engine. -pub fn import_queue( +pub fn import_queue( block_import: BoxBlockImport, client: Arc, algorithm: Algorithm, + check_inherents_after: <::Header as HeaderT>::Number, + select_chain: Option, inherent_data_providers: InherentDataProviders, ) -> Result, consensus_common::Error> where B: BlockT, @@ -269,14 +301,17 @@ pub fn import_queue( C: Send + Sync + AuxStore + 'static, C::Api: BlockBuilderApi, Algorithm: PowAlgorithm + Send + Sync + 'static, + S: SelectChain + 'static, { register_pow_inherent_data_provider(&inherent_data_providers)?; - let verifier = PowVerifier { - client: client.clone(), + let verifier = PowVerifier::new( + client.clone(), algorithm, + check_inherents_after, + select_chain, inherent_data_providers, - }; + ); Ok(BasicQueue::new( verifier, @@ -296,19 +331,24 @@ pub fn import_queue( /// information, or just be a graffiti. `round` is for number of rounds the /// CPU miner runs each time. This parameter should be tweaked so that each /// mining round is within sub-second time. -pub fn start_mine, C, Algorithm, E>( +pub fn start_mine, C, Algorithm, E, SO, S>( mut block_import: BoxBlockImport, client: Arc, algorithm: Algorithm, mut env: E, preruntime: Option>, round: u32, + mut sync_oracle: SO, + build_time: std::time::Duration, + select_chain: Option, inherent_data_providers: inherents::InherentDataProviders, ) where C: HeaderBackend + AuxStore + 'static, Algorithm: PowAlgorithm + Send + Sync + 'static, E: Environment + Send + Sync + 'static, E::Error: std::fmt::Debug, + SO: SyncOracle + Send + Sync + 'static, + S: SelectChain + 'static, { if let Err(_) = register_pow_inherent_data_provider(&inherent_data_providers) { warn!("Registering inherent data provider for timestamp failed"); @@ -323,6 +363,9 @@ pub fn start_mine, C, Algorithm, E>( &mut env, preruntime.as_ref(), round, + &mut sync_oracle, + build_time.clone(), + select_chain.as_ref(), &inherent_data_providers ) { Ok(()) => (), @@ -331,31 +374,52 @@ pub fn start_mine, C, Algorithm, E>( e ), } - std::thread::sleep(std::time::Duration::new(1, 0)); } }); } -fn mine_loop, C, Algorithm, E>( +fn mine_loop, C, Algorithm, E, SO, S>( block_import: &mut BoxBlockImport, client: &C, algorithm: &Algorithm, env: &mut E, preruntime: Option<&Vec>, round: u32, + sync_oracle: &mut SO, + build_time: std::time::Duration, + select_chain: Option<&S>, inherent_data_providers: &inherents::InherentDataProviders, ) -> Result<(), String> where C: HeaderBackend + AuxStore, Algorithm: PowAlgorithm, E: Environment, E::Error: std::fmt::Debug, + SO: SyncOracle, + S: SelectChain, { 'outer: loop { - let best_hash = client.info().best_hash; - let best_header = client.header(BlockId::Hash(best_hash)) - .map_err(|e| format!("Fetching best header failed: {:?}", e))? - .ok_or("Best header does not exist")?; + if sync_oracle.is_major_syncing() { + debug!(target: "pow", "Skipping proposal due to sync."); + std::thread::sleep(std::time::Duration::new(1, 0)); + continue 'outer + } + + let (best_hash, best_header) = match select_chain { + Some(select_chain) => { + let header = select_chain.best_chain() + .map_err(|e| format!("Fetching best header failed using select chain: {:?}", e))?; + let hash = header.hash(); + (hash, header) + }, + None => { + let hash = client.info().best_hash; + let header = client.header(BlockId::Hash(hash)) + .map_err(|e| format!("Fetching best header failed: {:?}", e))? + .ok_or("Best header does not exist")?; + (hash, header) + }, + }; let mut aux = PowAux::read(client, &best_hash)?; let mut proposer = env.init(&best_header).map_err(|e| format!("{:?}", e))?; @@ -368,21 +432,19 @@ fn mine_loop, C, Algorithm, E>( let block = futures::executor::block_on(proposer.propose( inherent_data, inherent_digest, - std::time::Duration::new(0, 0) + build_time.clone(), )).map_err(|e| format!("Block proposing error: {:?}", e))?; let (header, body) = block.deconstruct(); - let seed = H256::random(); let (difficulty, seal) = { - loop { - let difficulty = algorithm.difficulty( - &BlockId::Hash(best_hash), - )?; + let difficulty = algorithm.difficulty( + &BlockId::Hash(best_hash), + )?; + loop { let seal = algorithm.mine( &BlockId::Hash(best_hash), &header.hash(), - &seed, difficulty, round, )?; @@ -397,10 +459,28 @@ fn mine_loop, C, Algorithm, E>( } }; - aux.total_difficulty = aux.total_difficulty.saturating_add(difficulty); - let hash = header.hash(); + aux.difficulty = difficulty; + aux.total_difficulty.increment(difficulty); + let hash = { + let mut header = header.clone(); + header.digest_mut().push(DigestItem::Seal(POW_ENGINE_ID, seal.clone())); + header.hash() + }; let key = aux_key(&hash); + let best_hash = match select_chain { + Some(select_chain) => select_chain.best_chain() + .map_err(|e| format!("Fetch best hash failed via select chain: {:?}", e))? + .hash(), + None => client.info().best_hash, + }; + let best_aux = PowAux::::read(client, &best_hash)?; + + // if the best block has changed in the meantime drop our proposal + if best_aux.total_difficulty > aux.total_difficulty { + continue 'outer + } + let import_block = BlockImportParams { origin: BlockOrigin::Own, header, diff --git a/core/network/src/chain.rs b/core/network/src/chain.rs index 1a1f649cae..f68942fd96 100644 --- a/core/network/src/chain.rs +++ b/core/network/src/chain.rs @@ -83,6 +83,12 @@ pub trait FinalityProofProvider: Send + Sync { fn prove_finality(&self, for_block: Block::Hash, request: &[u8]) -> Result>, Error>; } +impl FinalityProofProvider for () { + fn prove_finality(&self, _for_block: Block::Hash, _request: &[u8]) -> Result>, Error> { + Ok(None) + } +} + impl Client for SubstrateClient where B: client::backend::Backend + Send + Sync + 'static, E: CallExecutor + Send + Sync + 'static, -- GitLab From 73104d3ae1ec061c4efd981a83cdd09104ba159f Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Thu, 3 Oct 2019 12:37:37 +0200 Subject: [PATCH 004/167] Split off TypeId so as not to pull in sr-io (#3740) * Add type-id * Builds with std now. * Fix for cargo * Remove unneeded stuff * Move TypeId. --- core/primitives/src/lib.rs | 5 +++++ core/sr-primitives/src/lib.rs | 4 ++-- core/sr-primitives/src/traits.rs | 8 +------- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/core/primitives/src/lib.rs b/core/primitives/src/lib.rs index 8086c9832a..310f0133ef 100644 --- a/core/primitives/src/lib.rs +++ b/core/primitives/src/lib.rs @@ -219,3 +219,8 @@ impl codec::Decode for NeverNativeValue { } } +/// Provide a simple 4 byte identifier for a type. +pub trait TypeId { + /// Simple 4 byte identifier. + const TYPE_ID: [u8; 4]; +} diff --git a/core/sr-primitives/src/lib.rs b/core/sr-primitives/src/lib.rs index 1e26a3d423..bdcbfb0b46 100644 --- a/core/sr-primitives/src/lib.rs +++ b/core/sr-primitives/src/lib.rs @@ -56,7 +56,7 @@ pub mod weights; 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, CryptoType}; +pub use primitives::{TypeId, crypto::{key_types, KeyTypeId, CryptoType}}; pub use app_crypto::RuntimeAppPublic; /// Re-export arithmetic stuff. @@ -82,7 +82,7 @@ use traits::{Verify, Lazy}; #[derive(Clone, Copy, Eq, PartialEq, Encode, Decode)] pub struct ModuleId(pub [u8; 8]); -impl traits::TypeId for ModuleId { +impl TypeId for ModuleId { const TYPE_ID: [u8; 4] = *b"modl"; } diff --git a/core/sr-primitives/src/traits.rs b/core/sr-primitives/src/traits.rs index de200bdf55..10c2e80658 100644 --- a/core/sr-primitives/src/traits.rs +++ b/core/sr-primitives/src/traits.rs @@ -23,7 +23,7 @@ use runtime_io; use std::fmt::{Debug, Display}; #[cfg(feature = "std")] use serde::{Serialize, Deserialize, de::DeserializeOwned}; -use primitives::{self, Hasher, Blake2Hasher}; +use primitives::{self, Hasher, Blake2Hasher, TypeId}; use crate::codec::{Codec, Encode, Decode, HasCompact}; use crate::transaction_validity::{ ValidTransaction, TransactionValidity, TransactionValidityError, UnknownTransaction, @@ -1123,12 +1123,6 @@ pub trait AccountIdConversion: Sized { fn try_from_sub_account(x: &AccountId) -> Option<(Self, S)>; } -/// Provide a simple 4 byte identifier for a type. -pub trait TypeId { - /// Simple 4 byte identifier. - const TYPE_ID: [u8; 4]; -} - /// Format is TYPE_ID ++ encode(parachain ID) ++ 00.... where 00... is indefinite trailing zeroes to /// fill AccountId. impl AccountIdConversion for Id { -- GitLab From f17d023bbe179f15678ac9989f471c9b18917e17 Mon Sep 17 00:00:00 2001 From: Joshy Orndorff Date: Thu, 3 Oct 2019 23:12:06 -0800 Subject: [PATCH 005/167] Grammar (#3754) --- core/consensus/pow/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/consensus/pow/src/lib.rs b/core/consensus/pow/src/lib.rs index 7f282e2052..766c1c63e0 100644 --- a/core/consensus/pow/src/lib.rs +++ b/core/consensus/pow/src/lib.rs @@ -100,7 +100,7 @@ pub trait PowAlgorithm { seal: &Seal, difficulty: Self::Difficulty, ) -> Result; - /// Mine a seal that satisfy the given difficulty. + /// Mine a seal that satisfies the given difficulty. fn mine( &self, parent: &BlockId, -- GitLab From 3dedd246c62255ba6f9b777ecba318dfc2078d85 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Fri, 4 Oct 2019 14:56:41 +0200 Subject: [PATCH 006/167] Decouple BABE from session (#3760) --- core/test-runtime/src/lib.rs | 4 + node-template/runtime/src/lib.rs | 1 + node/runtime/src/lib.rs | 3 +- srml/babe/src/lib.rs | 171 +++++++++++++++++++++---------- srml/babe/src/mock.rs | 1 + 5 files changed, 125 insertions(+), 55 deletions(-) diff --git a/core/test-runtime/src/lib.rs b/core/test-runtime/src/lib.rs index ff9826acae..e75cb69149 100644 --- a/core/test-runtime/src/lib.rs +++ b/core/test-runtime/src/lib.rs @@ -405,6 +405,10 @@ parameter_types! { impl srml_babe::Trait for Runtime { type EpochDuration = EpochDuration; type ExpectedBlockTime = ExpectedBlockTime; + // there is no actual runtime in this test-runtime, so testing crates + // are manually adding the digests. normally in this situation you'd use + // srml_babe::SameAuthoritiesForever. + type EpochChangeTrigger = srml_babe::ExternalTrigger; } /// Adds one to the given input and returns the final result. diff --git a/node-template/runtime/src/lib.rs b/node-template/runtime/src/lib.rs index 6b2b335d68..216cb0edc2 100644 --- a/node-template/runtime/src/lib.rs +++ b/node-template/runtime/src/lib.rs @@ -189,6 +189,7 @@ parameter_types! { impl babe::Trait for Runtime { type EpochDuration = EpochDuration; type ExpectedBlockTime = ExpectedBlockTime; + type EpochChangeTrigger = babe::SameAuthoritiesForever; } impl grandpa::Trait for Runtime { diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index 190385d6bc..490c2f300f 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -84,7 +84,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // and set impl_version to equal spec_version. If only runtime // implementation changes and behavior does not, then leave spec_version as // is and increment impl_version. - spec_version: 170, + spec_version: 171, impl_version: 171, apis: RUNTIME_API_VERSIONS, }; @@ -142,6 +142,7 @@ parameter_types! { impl babe::Trait for Runtime { type EpochDuration = EpochDuration; type ExpectedBlockTime = ExpectedBlockTime; + type EpochChangeTrigger = babe::ExternalTrigger; } impl indices::Trait for Runtime { diff --git a/srml/babe/src/lib.rs b/srml/babe/src/lib.rs index 330ec89ba5..e69877d783 100644 --- a/srml/babe/src/lib.rs +++ b/srml/babe/src/lib.rs @@ -122,8 +122,52 @@ impl ProvideInherentData for InherentDataProvider { } pub trait Trait: timestamp::Trait { + /// The amount of time, in slots, that each epoch should last. type EpochDuration: Get; + + /// The expected average block time at which BABE should be creating + /// blocks. Since BABE is probabilistic it is not trivial to figure out + /// what the expected average block time should be based on the slot + /// duration and the security parameter `c` (where `1 - c` represents + /// the probability of a slot being empty). type ExpectedBlockTime: Get; + + /// BABE requires some logic to be triggered on every block to query for whether an epoch + /// has ended and to perform the transition to the next epoch. + /// + /// Typically, the `ExternalTrigger` type should be used. An internal trigger should only be used + /// when no other module is responsible for changing authority set. + type EpochChangeTrigger: EpochChangeTrigger; +} + +/// Trigger an epoch change, if any should take place. +pub trait EpochChangeTrigger { + /// Trigger an epoch change, if any should take place. This should be called + /// during every block, after initialization is done. + fn trigger(now: T::BlockNumber); +} + +/// A type signifying to BABE that an external trigger +/// for epoch changes (e.g. srml-session) is used. +pub struct ExternalTrigger; + +impl EpochChangeTrigger for ExternalTrigger { + fn trigger(_: T::BlockNumber) { } // nothing - trigger is external. +} + +/// A type signifying to BABE that it should perform epoch changes +/// with an internal trigger, recycling the same authorities forever. +pub struct SameAuthoritiesForever; + +impl EpochChangeTrigger for SameAuthoritiesForever { + fn trigger(now: T::BlockNumber) { + if >::should_epoch_change(now) { + let authorities = >::authorities(); + let next_authorities = authorities.clone(); + + >::enact_epoch_change(authorities, next_authorities); + } + } } /// The length of the BABE randomness @@ -203,8 +247,8 @@ decl_module! { const ExpectedBlockTime: T::Moment = T::ExpectedBlockTime::get(); /// Initialization - fn on_initialize() { - Self::do_initialize(); + fn on_initialize(now: T::BlockNumber) { + Self::do_initialize(now); } /// Block finalization @@ -263,21 +307,10 @@ impl session::ShouldEndSession for Module { // it might be (and it is in current implementation) that session module is calling // should_end_session() from it's own on_initialize() handler // => because session on_initialize() is called earlier than ours, let's ensure - // that we have synced with digest before checking if session should be ended - Self::do_initialize(); + // that we have synced with digest before checking if session should be ended. + Self::do_initialize(now); - // The session has technically ended during the passage of time - // between this block and the last, but we have to "end" the session now, - // since there is no earlier possible block we could have done it. - // - // The exception is for block 1: the genesis has slot 0, so we treat - // epoch 0 as having started at the slot of block 1. We want to use - // the same randomness and validator set as signalled in the genesis, - // so we don't rotate the session. - now != sr_primitives::traits::One::one() && { - let diff = CurrentSlot::get().saturating_sub(Self::current_epoch_start()); - diff >= T::EpochDuration::get() - } + Self::should_epoch_change(now) } } @@ -336,6 +369,69 @@ impl Module { ::MinimumPeriod::get().saturating_mul(2.into()) } + /// Determine whether an epoch change should take place at this block. + /// Assumes that initialization has already taken place. + pub fn should_epoch_change(now: T::BlockNumber) -> bool { + // The epoch has technically ended during the passage of time + // between this block and the last, but we have to "end" the epoch now, + // since there is no earlier possible block we could have done it. + // + // The exception is for block 1: the genesis has slot 0, so we treat + // epoch 0 as having started at the slot of block 1. We want to use + // the same randomness and validator set as signalled in the genesis, + // so we don't rotate the epoch. + now != sr_primitives::traits::One::one() && { + let diff = CurrentSlot::get().saturating_sub(Self::current_epoch_start()); + diff >= T::EpochDuration::get() + } + } + + /// DANGEROUS: Enact an epoch change. Should be done on every block where `should_epoch_change` has returned `true`, + /// and the caller is the only caller of this function. + /// + /// Typically, this is not handled directly by the user, but by higher-level validator-set manager logic like + /// `srml-session`. + pub fn enact_epoch_change( + authorities: Vec<(AuthorityId, BabeAuthorityWeight)>, + next_authorities: Vec<(AuthorityId, BabeAuthorityWeight)>, + ) { + // PRECONDITION: caller has done initialization and is guaranteed + // by the session module to be called before this. + #[cfg(debug_assertions)] + { + assert!(Self::initialized().is_some()) + } + + // Update epoch index + let epoch_index = EpochIndex::get() + .checked_add(1) + .expect("epoch indices will never reach 2^64 before the death of the universe; qed"); + + EpochIndex::put(epoch_index); + Authorities::put(authorities); + + // Update epoch randomness. + let next_epoch_index = epoch_index + .checked_add(1) + .expect("epoch indices will never reach 2^64 before the death of the universe; qed"); + + // Returns randomness for the current epoch and computes the *next* + // epoch randomness. + let randomness = Self::randomness_change_epoch(next_epoch_index); + Randomness::put(randomness); + + // After we update the current epoch, we signal the *next* epoch change + // so that nodes can track changes. + let next_randomness = NextRandomness::get(); + + let next = NextEpochDescriptor { + authorities: next_authorities, + randomness: next_randomness, + }; + + Self::deposit_consensus(ConsensusLog::NextEpochData(next)) + } + // finds the start slot of the current epoch. only guaranteed to // give correct results after `do_initialize` of the first block // in the chain (as its result is based off of `GenesisSlot`). @@ -363,7 +459,7 @@ impl Module { } } - fn do_initialize() { + fn do_initialize(now: T::BlockNumber) { // since do_initialize can be called twice (if session module is present) // => let's ensure that we only modify the storage once per block let initialized = Self::initialized().is_some(); @@ -414,6 +510,9 @@ impl Module { }); Initialized::put(maybe_vrf); + + // enact epoch change, if necessary. + T::EpochChangeTrigger::trigger::(now) } /// Call this function exactly once when an epoch changes, to update the @@ -460,51 +559,15 @@ impl session::OneSessionHandler for Module { fn on_new_session<'a, I: 'a>(_changed: bool, validators: I, queued_validators: I) where I: Iterator { - // PRECONDITION: `should_end_session` has done initialization and is guaranteed - // by the session module to be called before this. - #[cfg(debug_assertions)] - { - assert!(Self::initialized().is_some()) - } - - // Update epoch index - let epoch_index = EpochIndex::get() - .checked_add(1) - .expect("epoch indices will never reach 2^64 before the death of the universe; qed"); - - EpochIndex::put(epoch_index); - - // Update authorities. let authorities = validators.map(|(_account, k)| { (k, 1) }).collect::>(); - Authorities::put(authorities); - - // Update epoch randomness. - let next_epoch_index = epoch_index - .checked_add(1) - .expect("epoch indices will never reach 2^64 before the death of the universe; qed"); - - // Returns randomness for the current epoch and computes the *next* - // epoch randomness. - let randomness = Self::randomness_change_epoch(next_epoch_index); - Randomness::put(randomness); - - // After we update the current epoch, we signal the *next* epoch change - // so that nodes can track changes. let next_authorities = queued_validators.map(|(_account, k)| { (k, 1) }).collect::>(); - let next_randomness = NextRandomness::get(); - - let next = NextEpochDescriptor { - authorities: next_authorities, - randomness: next_randomness, - }; - - Self::deposit_consensus(ConsensusLog::NextEpochData(next)) + Self::enact_epoch_change(authorities, next_authorities) } fn on_disabled(i: usize) { diff --git a/srml/babe/src/mock.rs b/srml/babe/src/mock.rs index 741f08fc08..acc08c7a3b 100644 --- a/srml/babe/src/mock.rs +++ b/srml/babe/src/mock.rs @@ -98,6 +98,7 @@ impl timestamp::Trait for Test { impl Trait for Test { type EpochDuration = EpochDuration; type ExpectedBlockTime = ExpectedBlockTime; + type EpochChangeTrigger = crate::ExternalTrigger; } pub fn new_test_ext(authorities: Vec) -> runtime_io::TestExternalities { -- GitLab From c0d293236a574f1297c59de1f8d53f06c8eb605e Mon Sep 17 00:00:00 2001 From: kaichao Date: Sat, 5 Oct 2019 01:00:18 +0800 Subject: [PATCH 007/167] Enable opt-in google analytics for RustDocs. (#3762) --- .gitlab-ci.yml | 2 +- rustdoc-header.html | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 rustdoc-header.html diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 60a75d5db4..a6ef113044 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -288,7 +288,7 @@ build-rust-doc-release: <<: *build-only script: - rm -f ./crate-docs/index.html # use it as an indicator if the job succeeds - - BUILD_DUMMY_WASM_BINARY=1 time cargo +nightly doc --release --all --verbose + - BUILD_DUMMY_WASM_BINARY=1 time RUSTDOCFLAGS="--html-in-header $(pwd)/rustdoc-header.html" cargo +nightly doc --release --all --verbose - cp -R ./target/doc ./crate-docs - echo "" > ./crate-docs/index.html - sccache -s diff --git a/rustdoc-header.html b/rustdoc-header.html new file mode 100644 index 0000000000..a679d5e299 --- /dev/null +++ b/rustdoc-header.html @@ -0,0 +1,10 @@ + + + + -- GitLab From 1774f6131e1ee1ffea7cd5e8127cc4ec3d237e8a Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Fri, 4 Oct 2019 19:13:54 +0200 Subject: [PATCH 008/167] Utility module for doing stuff like batch calls (#3759) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Implement and test batch * Add files. * Remove comments. * Update srml/utility/src/lib.rs Co-Authored-By: Bastian Köcher * Fixes --- Cargo.lock | 16 ++++ Cargo.toml | 1 + node/runtime/Cargo.toml | 2 + node/runtime/src/lib.rs | 6 ++ srml/assets/src/lib.rs | 9 ++- srml/utility/Cargo.toml | 30 +++++++ srml/utility/src/lib.rs | 173 ++++++++++++++++++++++++++++++++++++++++ 7 files changed, 233 insertions(+), 4 deletions(-) create mode 100644 srml/utility/Cargo.toml create mode 100644 srml/utility/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 7043341751..ca1270929f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2486,6 +2486,7 @@ dependencies = [ "srml-system 2.0.0", "srml-timestamp 2.0.0", "srml-treasury 2.0.0", + "srml-utility 2.0.0", "substrate-authority-discovery-primitives 2.0.0", "substrate-client 2.0.0", "substrate-consensus-babe-primitives 2.0.0", @@ -4421,6 +4422,21 @@ dependencies = [ "substrate-primitives 2.0.0", ] +[[package]] +name = "srml-utility" +version = "2.0.0" +dependencies = [ + "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-io 2.0.0", + "sr-primitives 2.0.0", + "sr-std 2.0.0", + "srml-balances 2.0.0", + "srml-support 2.0.0", + "srml-system 2.0.0", + "substrate-primitives 2.0.0", +] + [[package]] name = "stable_deref_trait" version = "1.1.1" diff --git a/Cargo.toml b/Cargo.toml index a345b880da..71ba1c17f1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -103,6 +103,7 @@ members = [ "srml/system", "srml/timestamp", "srml/treasury", + "srml/utility", "node/cli", "node/executor", "node/primitives", diff --git a/node/runtime/Cargo.toml b/node/runtime/Cargo.toml index 9b794130e7..f256575086 100644 --- a/node/runtime/Cargo.toml +++ b/node/runtime/Cargo.toml @@ -48,6 +48,7 @@ support = { package = "srml-support", path = "../../srml/support", default-featu system = { package = "srml-system", path = "../../srml/system", default-features = false } timestamp = { package = "srml-timestamp", path = "../../srml/timestamp", default-features = false } treasury = { package = "srml-treasury", path = "../../srml/treasury", default-features = false } +utility = { package = "srml-utility", path = "../../srml/utility", default-features = false } [build-dependencies] wasm-builder-runner = { package = "substrate-wasm-builder-runner", version = "1.0.2", path = "../../core/utils/wasm-builder-runner" } @@ -92,5 +93,6 @@ std = [ "system/std", "timestamp/std", "treasury/std", + "utility/std", "version/std", ] diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index 490c2f300f..b06ba19ee5 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -134,6 +134,11 @@ impl system::Trait for Runtime { type Version = Version; } +impl utility::Trait for Runtime { + type Event = Event; + type Call = Call; +} + parameter_types! { pub const EpochDuration: u64 = EPOCH_DURATION_IN_SLOTS; pub const ExpectedBlockTime: Moment = MILLISECS_PER_BLOCK; @@ -492,6 +497,7 @@ construct_runtime!( UncheckedExtrinsic = UncheckedExtrinsic { System: system::{Module, Call, Storage, Config, Event}, + Utility: utility::{Module, Call, Event}, Babe: babe::{Module, Call, Storage, Config, Inherent(Timestamp)}, Timestamp: timestamp::{Module, Call, Storage, Inherent}, Authorship: authorship::{Module, Call, Storage, Inherent}, diff --git a/srml/assets/src/lib.rs b/srml/assets/src/lib.rs index b143085232..2a4245176a 100644 --- a/srml/assets/src/lib.rs +++ b/srml/assets/src/lib.rs @@ -196,10 +196,11 @@ decl_module! { } decl_event!( - pub enum Event - where ::AccountId, - ::Balance, - ::AssetId { + pub enum Event where + ::AccountId, + ::Balance, + ::AssetId, + { /// Some assets were issued. Issued(AssetId, AccountId, Balance), /// Some assets were transferred. diff --git a/srml/utility/Cargo.toml b/srml/utility/Cargo.toml new file mode 100644 index 0000000000..d46ed62a55 --- /dev/null +++ b/srml/utility/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "srml-utility" +version = "2.0.0" +authors = ["Parity Technologies "] +edition = "2018" + +[dependencies] +serde = { version = "1.0", optional = true } +codec = { package = "parity-scale-codec", version = "1.0.0", default-features = false } +support = { package = "srml-support", path = "../support", default-features = false } +system = { package = "srml-system", path = "../system", default-features = false } +sr-primitives = { path = "../../core/sr-primitives", default-features = false } +rstd = { package = "sr-std", path = "../../core/sr-std", default-features = false } +runtime-io = { package = "sr-io", path = "../../core/sr-io", default-features = false } + +[dev-dependencies] +primitives = { package = "substrate-primitives", path = "../../core/primitives" } +balances = { package = "srml-balances", path = "../balances" } + +[features] +default = ["std"] +std = [ + "serde", + "codec/std", + "sr-primitives/std", + "support/std", + "system/std", + "runtime-io/std", + "rstd/std" +] diff --git a/srml/utility/src/lib.rs b/srml/utility/src/lib.rs new file mode 100644 index 0000000000..9fe34ee2d0 --- /dev/null +++ b/srml/utility/src/lib.rs @@ -0,0 +1,173 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +//! # Utility Module +//! A module full of useful helpers for practical chain management. + +// Ensure we're `no_std` when compiling for Wasm. +#![cfg_attr(not(feature = "std"), no_std)] + +use rstd::prelude::*; +use support::{decl_module, decl_event, Parameter}; +use system::ensure_root; +use sr_primitives::{ + traits::{Dispatchable, DispatchResult}, weights::SimpleDispatchInfo +}; + +/// Configuration trait. +pub trait Trait: system::Trait { + /// The overarching event type. + type Event: From> + Into<::Event>; + + /// The overarching call type. + type Call: Parameter + Dispatchable; +} + +pub type DispatchResultOf = DispatchResult<<::Call as Dispatchable>::Error>; + +decl_event!( + /// Events type. + pub enum Event where + DispatchResult = DispatchResultOf, + { + BatchExecuted(Vec), + } +); + +decl_module! { + pub struct Module for enum Call where origin: T::Origin { + /// Deposit one of this module's events by using the default implementation. + fn deposit_event() = default; + + /// Send a batch of dispatch calls (only root). + #[weight = SimpleDispatchInfo::FreeOperational] + fn batch(origin, calls: Vec<::Call>) { + ensure_root(origin)?; + let results = calls.into_iter() + .map(|call| call.dispatch(system::RawOrigin::Root.into())) + .collect::>(); + Self::deposit_event(RawEvent::BatchExecuted(results)); + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + use support::{assert_ok, assert_noop, impl_outer_origin, parameter_types, impl_outer_dispatch}; + use runtime_io::with_externalities; + use primitives::{H256, Blake2Hasher}; + use sr_primitives::{ + Perbill, traits::{BlakeTwo256, IdentityLookup}, testing::Header + }; + + impl_outer_origin! { + pub enum Origin for Test {} + } + + impl_outer_dispatch! { + pub enum Call for Test where origin: Origin { + balances::Balances, + utility::Utility, + } + } + + // For testing the module, we construct most of a mock runtime. This means + // first constructing a configuration type (`Test`) which `impl`s each of the + // configuration traits of modules we want to use. + #[derive(Clone, Eq, PartialEq)] + pub struct Test; + parameter_types! { + pub const BlockHashCount: u64 = 250; + pub const MaximumBlockWeight: u32 = 1024; + pub const MaximumBlockLength: u32 = 2 * 1024; + pub const AvailableBlockRatio: Perbill = Perbill::one(); + } + impl system::Trait for Test { + type Origin = Origin; + type Index = u64; + type BlockNumber = u64; + type Hash = H256; + type Call = Call; + type Hashing = BlakeTwo256; + type AccountId = u64; + type Lookup = IdentityLookup; + type Header = Header; + type WeightMultiplierUpdate = (); + type Event = (); + type BlockHashCount = BlockHashCount; + type MaximumBlockWeight = MaximumBlockWeight; + type MaximumBlockLength = MaximumBlockLength; + type AvailableBlockRatio = AvailableBlockRatio; + type Version = (); + } + parameter_types! { + pub const ExistentialDeposit: u64 = 0; + pub const TransferFee: u64 = 0; + pub const CreationFee: u64 = 0; + pub const TransactionBaseFee: u64 = 0; + pub const TransactionByteFee: u64 = 0; + } + impl balances::Trait for Test { + type Balance = u64; + type OnFreeBalanceZero = (); + type OnNewAccount = (); + type Event = (); + type TransactionPayment = (); + type TransferPayment = (); + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type TransferFee = TransferFee; + type CreationFee = CreationFee; + type TransactionBaseFee = TransactionBaseFee; + type TransactionByteFee = TransactionByteFee; + type WeightToFee = (); + } + impl Trait for Test { + type Event = (); + type Call = Call; + } + type Balances = balances::Module; + type Utility = Module; + + fn new_test_ext() -> runtime_io::TestExternalities { + let mut t = system::GenesisConfig::default().build_storage::().unwrap(); + balances::GenesisConfig:: { + balances: vec![(1, 10), (2, 0)], + vesting: vec![], + }.assimilate_storage(&mut t).unwrap(); + t.into() + } + + #[test] + fn batch_works() { + with_externalities(&mut new_test_ext(), || { + assert_eq!(Balances::free_balance(1), 10); + assert_eq!(Balances::free_balance(2), 0); + assert_noop!(Utility::batch(Origin::signed(1), vec![ + Call::Balances(balances::Call::force_transfer(1, 2, 5)), + Call::Balances(balances::Call::force_transfer(1, 2, 5)) + ]), "RequireRootOrigin"); + assert_ok!(Utility::batch(Origin::ROOT, vec![ + Call::Balances(balances::Call::force_transfer(1, 2, 5)), + Call::Balances(balances::Call::force_transfer(1, 2, 5)) + ])); + assert_eq!(Balances::free_balance(1), 0); + assert_eq!(Balances::free_balance(2), 10); + }); + } +} -- GitLab From b4cd2485d5070cdb6c4f9c2bdbc31be0f9fff65c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= Date: Fri, 4 Oct 2019 18:51:08 +0100 Subject: [PATCH 009/167] babe: ancient epoch tree pruning (#3746) * babe: prune epoch tree when importing a new epoch change * fork-tree: fix tree pruning * babe: actually prune epoch change fork tree * Fix typos * babe: add test for epoch tree pruning * fork-tree: fix pruning of stale forks --- core/consensus/babe/src/epoch_changes.rs | 38 ++++-- core/consensus/babe/src/lib.rs | 78 ++++++----- core/consensus/babe/src/tests.rs | 161 +++++++++++++++++++++++ core/utils/fork-tree/src/lib.rs | 88 +++++++------ 4 files changed, 280 insertions(+), 85 deletions(-) diff --git a/core/consensus/babe/src/epoch_changes.rs b/core/consensus/babe/src/epoch_changes.rs index 311271ae15..09a14d2864 100644 --- a/core/consensus/babe/src/epoch_changes.rs +++ b/core/consensus/babe/src/epoch_changes.rs @@ -190,23 +190,35 @@ impl EpochChanges where EpochChanges { inner: ForkTree::new() } } - /// Prune out finalized epochs, except for the ancestor of the finalized block. + /// Prune out finalized epochs, except for the ancestor of the finalized + /// block. The given slot should be the slot number at which the finalized + /// block was authored. pub fn prune_finalized>( &mut self, descendent_of_builder: D, - _hash: &Hash, - _number: Number, + hash: &Hash, + number: Number, + slot: SlotNumber, ) -> Result<(), fork_tree::Error> { - let _is_descendent_of = descendent_of_builder + let is_descendent_of = descendent_of_builder .build_is_descendent_of(None); - // TODO: - // https://github.com/paritytech/substrate/issues/3651 - // + let predicate = |epoch: &PersistedEpoch| match *epoch { + PersistedEpoch::Genesis(_, ref epoch_1) => + slot >= epoch_1.end_slot(), + PersistedEpoch::Regular(ref epoch_n) => + slot >= epoch_n.end_slot(), + }; + // prune any epochs which could not be _live_ as of the children of the - // finalized block. - // i.e. re-root the fork tree to the oldest ancestor of (hash, number) - // where epoch.end_slot() >= slot(hash) + // finalized block, i.e. re-root the fork tree to the oldest ancestor of + // (hash, number) where epoch.end_slot() >= finalized_slot + self.inner.prune( + hash, + &number, + &is_descendent_of, + &predicate, + )?; Ok(()) } @@ -300,6 +312,12 @@ impl EpochChanges where Err(e) => Err(e), } } + + /// Return the inner fork tree, useful for testing purposes. + #[cfg(test)] + pub fn tree(&self) -> &ForkTree { + &self.inner + } } /// Type alias to produce the epoch-changes tree from a block type. diff --git a/core/consensus/babe/src/lib.rs b/core/consensus/babe/src/lib.rs index d2a16bedb8..b4f376b50d 100644 --- a/core/consensus/babe/src/lib.rs +++ b/core/consensus/babe/src/lib.rs @@ -254,24 +254,6 @@ pub fn start_babe(BabeParams { &inherent_data_providers, )?; - let epoch_changes = babe_link.epoch_changes.clone(); - let pruning_task = client.finality_notification_stream() - .for_each(move |notification| { - // TODO: supply is-descendent-of and maybe write to disk _now_ - // as opposed to waiting for the next epoch? - let res = epoch_changes.lock().prune_finalized( - descendent_query(&*client), - ¬ification.hash, - *notification.header.number(), - ); - - if let Err(e) = res { - babe_err!("Could not prune expired epoch changes: {:?}", e); - } - - future::ready(()) - }); - babe_info!("Starting BABE Authorship worker"); let slot_worker = slots::start_slot_worker( config.0, @@ -280,9 +262,9 @@ pub fn start_babe(BabeParams { sync_oracle, inherent_data_providers, babe_link.time_source, - ).map(|_| ()); + ); - Ok(future::select(slot_worker, pruning_task).map(|_| Ok::<(), ()>(())).compat()) + Ok(slot_worker.map(|_| Ok::<(), ()>(())).compat()) } struct BabeWorker { @@ -889,6 +871,8 @@ impl BlockImport for BabeBlockImport BlockImport for BabeBlockImport(&finalized_header) + .expect("finalized header must be valid; \ + valid blocks have a pre-digest; qed") + .slot_number() + }; + epoch_changes.prune_finalized( + descendent_query(&*self.client), + &info.finalized_hash, + info.finalized_number, + finalized_slot, + ).map_err(|e| ConsensusError::ClientImport(format!("{:?}", e)))?; + + epoch_changes.import( + descendent_query(&*self.client), + hash, + number, + *block.header.parent_hash(), + next_epoch, + ).map_err(|e| ConsensusError::ClientImport(format!("{:?}", e)))?; + + Ok(()) + }; - if let Err(e) = res { - let err = ConsensusError::ClientImport(format!("{:?}", e)); + if let Err(e) = prune_and_import() { babe_err!("Failed to launch next epoch: {:?}", e); *epoch_changes = old_epoch_changes.expect("set `Some` above and not taken; qed"); - return Err(err); + return Err(e); } crate::aux_schema::write_epoch_changes::( @@ -935,10 +946,7 @@ impl BlockImport for BabeBlockImport b, Err(e) => return future::ready(Err(e)), @@ -597,3 +598,163 @@ fn importing_block_one_sets_genesis_epoch() { ).unwrap().unwrap().into_inner(); assert_eq!(epoch_for_second_block, genesis_epoch); } + +#[test] +fn importing_epoch_change_block_prunes_tree() { + use client::backend::Finalizer; + + let mut net = BabeTestNet::new(1); + + let peer = net.peer(0); + let data = peer.data.as_ref().expect("babe link set up during initialization"); + + let client = peer.client().as_full().expect("Only full clients are used in tests").clone(); + let mut block_import = data.block_import.lock().take().expect("import set up during init"); + let epoch_changes = data.link.epoch_changes.clone(); + + // This is just boilerplate code for proposing and importing a valid BABE + // block that's built on top of the given parent. The proposer takes care + // of producing epoch change digests according to the epoch duration (which + // is set to 6 slots in the test runtime). + let mut propose_and_import_block = |parent_header| { + let mut environ = DummyFactory { + client: client.clone(), + config: data.link.config.clone(), + epoch_changes: data.link.epoch_changes.clone(), + mutator: Arc::new(|_, _| ()), + }; + + let mut proposer = environ.init(&parent_header).unwrap(); + let parent_pre_digest = find_pre_digest::(&parent_header).unwrap(); + + let pre_digest = sr_primitives::generic::Digest { + logs: vec![ + Item::babe_pre_digest( + BabePreDigest::Secondary { + authority_index: 0, + slot_number: parent_pre_digest.slot_number() + 1, + }, + ), + ], + }; + + let mut block = futures::executor::block_on(proposer.propose_with(pre_digest)).unwrap(); + + let seal = { + // sign the pre-sealed hash of the block and then + // add it to a digest item. + let pair = AuthorityPair::from_seed(&[1; 32]); + let pre_hash = block.header.hash(); + let signature = pair.sign(pre_hash.as_ref()); + Item::babe_seal(signature) + }; + + let post_hash = { + block.header.digest_mut().push(seal.clone()); + let h = block.header.hash(); + block.header.digest_mut().pop(); + h + }; + + let next_epoch_digest = + find_next_epoch_digest::(&block.header).unwrap(); + + let import_result = block_import.import_block( + BlockImportParams { + origin: BlockOrigin::Own, + header: block.header, + justification: None, + post_digests: vec![seal], + body: Some(block.extrinsics), + finalized: false, + auxiliary: Vec::new(), + fork_choice: ForkChoiceStrategy::LongestChain, + }, + Default::default(), + ).unwrap(); + + match import_result { + ImportResult::Imported(_) => {}, + _ => panic!("expected block to be imported"), + } + + (post_hash, next_epoch_digest) + }; + + let mut propose_and_import_blocks = |parent_id, n| { + let mut hashes = Vec::new(); + let mut parent_header = client.header(&parent_id).unwrap().unwrap(); + + for _ in 0..n { + let (block_hash, _) = propose_and_import_block(parent_header); + hashes.push(block_hash); + parent_header = client.header(&BlockId::Hash(block_hash)).unwrap().unwrap(); + } + + hashes + }; + + // This is the block tree that we're going to use in this test. Each node + // represents an epoch change block, the epoch duration is 6 slots. + // + // *---- F (#7) + // / *------ G (#19) - H (#25) + // / / + // A (#1) - B (#7) - C (#13) - D (#19) - E (#25) + // \ + // *------ I (#25) + + // Create and import the canon chain and keep track of fork blocks (A, C, D) + // from the diagram above. + let canon_hashes = propose_and_import_blocks(BlockId::Number(0), 30); + + // Create the forks + let fork_1 = propose_and_import_blocks(BlockId::Hash(canon_hashes[0]), 10); + let fork_2 = propose_and_import_blocks(BlockId::Hash(canon_hashes[12]), 15); + let fork_3 = propose_and_import_blocks(BlockId::Hash(canon_hashes[18]), 10); + + // We should be tracking a total of 9 epochs in the fork tree + assert_eq!( + epoch_changes.lock().tree().iter().count(), + 9, + ); + + // And only one root + assert_eq!( + epoch_changes.lock().tree().roots().count(), + 1, + ); + + // We finalize block #13 from the canon chain, so on the next epoch + // change the tree should be pruned, to not contain F (#7). + client.finalize_block(BlockId::Hash(canon_hashes[12]), None, false).unwrap(); + propose_and_import_blocks(BlockId::Hash(client.info().chain.best_hash), 7); + + // at this point no hashes from the first fork must exist on the tree + assert!( + !epoch_changes.lock().tree().iter().map(|(h, _, _)| h).any(|h| fork_1.contains(h)), + ); + + // but the epoch changes from the other forks must still exist + assert!( + epoch_changes.lock().tree().iter().map(|(h, _, _)| h).any(|h| fork_2.contains(h)) + ); + + assert!( + epoch_changes.lock().tree().iter().map(|(h, _, _)| h).any(|h| fork_3.contains(h)), + ); + + // finalizing block #25 from the canon chain should prune out the second fork + client.finalize_block(BlockId::Hash(canon_hashes[24]), None, false).unwrap(); + propose_and_import_blocks(BlockId::Hash(client.info().chain.best_hash), 8); + + // at this point no hashes from the second fork must exist on the tree + assert!( + !epoch_changes.lock().tree().iter().map(|(h, _, _)| h).any(|h| fork_2.contains(h)), + ); + + // while epoch changes from the last fork should still exist + assert!( + epoch_changes.lock().tree().iter().map(|(h, _, _)| h).any(|h| fork_3.contains(h)), + ); +} diff --git a/core/utils/fork-tree/src/lib.rs b/core/utils/fork-tree/src/lib.rs index 4299918755..b0258a9ca2 100644 --- a/core/utils/fork-tree/src/lib.rs +++ b/core/utils/fork-tree/src/lib.rs @@ -86,55 +86,45 @@ impl ForkTree where N: Ord + Clone, V: Clone, { - /// Prune all nodes that are not descendents of `hash` according to - /// `is_descendent_of`. The given function `is_descendent_of` should return - /// `true` if the second hash (target) is a descendent of the first hash - /// (base). After pruning the tree it should have one or zero roots. The - /// number and order of calls to `is_descendent_of` is unspecified and - /// subject to change. - pub fn prune( + /// Prune the tree, removing all non-canonical nodes. We find the node in the + /// tree that is the deepest ancestor of the given hash and that passes the + /// given predicate. If such a node exists, we re-root the tree to this + /// node. Otherwise the tree remains unchanged. The given function + /// `is_descendent_of` should return `true` if the second hash (target) is a + /// descendent of the first hash (base). + pub fn prune( &mut self, hash: &H, - number: N, - is_descendent_of: &F + number: &N, + is_descendent_of: &F, + predicate: &P, ) -> Result<(), Error> where E: std::error::Error, - F: Fn(&H, &H) -> Result + F: Fn(&H, &H) -> Result, + P: Fn(&V) -> bool, { - let mut new_root = None; - for node in self.node_iter() { - // if the node has a lower number than the one being finalized then - // we only keep if it has no children and the finalized block is a - // descendent of this node - if node.number < number { - if !node.children.is_empty() || !is_descendent_of(&node.hash, hash)? { - continue; - } - } - - // if the node has the same number as the finalized block then it - // must have the same hash - if node.number == number && node.hash != *hash { - continue; - } + let new_root = self.find_node_where( + hash, + number, + is_descendent_of, + predicate, + )?; - // if the node has a higher number then we keep it if it is a - // descendent of the finalized block - if node.number > number && !is_descendent_of(hash, &node.hash)? { - continue; - } + if let Some(root) = new_root { + let mut root = root.clone(); - new_root = Some(node); - break; - } + // we found the deepest ancestor of the finalized block, so we prune + // out any children that don't include the finalized block. + root.children.retain(|node| { + node.number == *number && node.hash == *hash || + node.number < *number && is_descendent_of(&node.hash, hash).unwrap_or(false) + }); - if let Some(root) = new_root { - self.roots = vec![root.clone()]; + self.roots = vec![root]; } Ok(()) } - } impl ForkTree where @@ -1203,18 +1193,36 @@ mod test { tree.prune( &"C", - 3, + &3, &is_descendent_of, + &|_| true, + ).unwrap(); + + assert_eq!( + tree.roots.iter().map(|node| node.hash).collect::>(), + vec!["B"], + ); + + assert_eq!( + tree.iter().map(|(hash, _, _)| *hash).collect::>(), + vec!["B", "C", "D", "E"], + ); + + tree.prune( + &"E", + &5, + &is_descendent_of, + &|_| true, ).unwrap(); assert_eq!( tree.roots.iter().map(|node| node.hash).collect::>(), - vec!["C"], + vec!["D"], ); assert_eq!( tree.iter().map(|(hash, _, _)| *hash).collect::>(), - vec!["C", "D", "E"], + vec!["D", "E"], ); } -- GitLab From fdac986a38db63bbaa413a0e211b98f55a185158 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= Date: Fri, 4 Oct 2019 19:55:03 +0100 Subject: [PATCH 010/167] babe: small compilation fix (#3764) * babe: fix type on find_pre_digest call * fork-tree: optimize prune * babe: fix test compilation --- core/consensus/babe/src/lib.rs | 2 +- core/consensus/babe/src/tests.rs | 2 +- core/utils/fork-tree/src/lib.rs | 5 +++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/core/consensus/babe/src/lib.rs b/core/consensus/babe/src/lib.rs index b4f376b50d..683425e815 100644 --- a/core/consensus/babe/src/lib.rs +++ b/core/consensus/babe/src/lib.rs @@ -896,7 +896,7 @@ impl BlockImport for BabeBlockImport(&finalized_header) + find_pre_digest::(&finalized_header) .expect("finalized header must be valid; \ valid blocks have a pre-digest; qed") .slot_number() diff --git a/core/consensus/babe/src/tests.rs b/core/consensus/babe/src/tests.rs index f06cc6f46c..46c038b187 100644 --- a/core/consensus/babe/src/tests.rs +++ b/core/consensus/babe/src/tests.rs @@ -625,7 +625,7 @@ fn importing_epoch_change_block_prunes_tree() { }; let mut proposer = environ.init(&parent_header).unwrap(); - let parent_pre_digest = find_pre_digest::(&parent_header).unwrap(); + let parent_pre_digest = find_pre_digest(&parent_header).unwrap(); let pre_digest = sr_primitives::generic::Digest { logs: vec![ diff --git a/core/utils/fork-tree/src/lib.rs b/core/utils/fork-tree/src/lib.rs index b0258a9ca2..f192ee5478 100644 --- a/core/utils/fork-tree/src/lib.rs +++ b/core/utils/fork-tree/src/lib.rs @@ -115,10 +115,11 @@ impl ForkTree where // we found the deepest ancestor of the finalized block, so we prune // out any children that don't include the finalized block. - root.children.retain(|node| { + let children = std::mem::replace(&mut root.children, Vec::new()); + root.children = children.into_iter().filter(|node| { node.number == *number && node.hash == *hash || node.number < *number && is_descendent_of(&node.hash, hash).unwrap_or(false) - }); + }).take(1).collect(); self.roots = vec![root]; } -- GitLab From 062748f2b932a00947d1b9b2ae85f6dcbbce03e1 Mon Sep 17 00:00:00 2001 From: kaichao Date: Sat, 5 Oct 2019 03:30:50 +0800 Subject: [PATCH 011/167] Fix RustDoc generation. (#3763) * Attemp to fix it. * Move env to the begining. --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a6ef113044..769ee60d1e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -288,7 +288,7 @@ build-rust-doc-release: <<: *build-only script: - rm -f ./crate-docs/index.html # use it as an indicator if the job succeeds - - BUILD_DUMMY_WASM_BINARY=1 time RUSTDOCFLAGS="--html-in-header $(pwd)/rustdoc-header.html" cargo +nightly doc --release --all --verbose + - BUILD_DUMMY_WASM_BINARY=1 RUSTDOCFLAGS="--html-in-header $(pwd)/rustdoc-header.html" time cargo +nightly doc --release --all --verbose - cp -R ./target/doc ./crate-docs - echo "" > ./crate-docs/index.html - sccache -s -- GitLab From 4d40591c69260ff78adc5525d2fddfcc60c28c14 Mon Sep 17 00:00:00 2001 From: Marcio Diaz Date: Sat, 5 Oct 2019 10:43:19 +0200 Subject: [PATCH 012/167] Use header metadata in babe verify. (#3756) * Use header_metadata in verify. * Log hash in header_metadata error. * Fix naming, error. --- core/client/db/src/lib.rs | 4 ++-- core/client/db/src/light.rs | 2 +- core/client/src/in_mem.rs | 2 +- core/consensus/babe/src/lib.rs | 7 +++---- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/core/client/db/src/lib.rs b/core/client/db/src/lib.rs index 126622364a..7cc6ef54a0 100644 --- a/core/client/db/src/lib.rs +++ b/core/client/db/src/lib.rs @@ -42,7 +42,7 @@ use client::backend::NewBlockState; use client::blockchain::{well_known_cache_keys, HeaderBackend}; use client::{ForkBlocks, ExecutionStrategies}; use client::backend::{StorageCollection, ChildStorageCollection}; -use client::error::Result as ClientResult; +use client::error::{Result as ClientResult, Error as ClientError}; use codec::{Decode, Encode}; use hash_db::{Hasher, Prefix}; use kvdb::{KeyValueDB, DBTransaction}; @@ -417,7 +417,7 @@ impl HeaderMetadata for BlockchainDb { header_metadata.clone(), ); header_metadata - }).ok_or(client::error::Error::UnknownBlock("header not found in db".to_owned())) + }).ok_or(ClientError::UnknownBlock(format!("header not found in db: {}", hash))) }) } diff --git a/core/client/db/src/light.rs b/core/client/db/src/light.rs index 111b8e0deb..19fc7fde35 100644 --- a/core/client/db/src/light.rs +++ b/core/client/db/src/light.rs @@ -207,7 +207,7 @@ impl HeaderMetadata for LightStorage { header_metadata.clone(), ); header_metadata - }).ok_or(ClientError::UnknownBlock("header not found in db".to_owned())) + }).ok_or(ClientError::UnknownBlock(format!("header not found in db: {}", hash))) }) } diff --git a/core/client/src/in_mem.rs b/core/client/src/in_mem.rs index 99dc1b6263..5c35400d77 100644 --- a/core/client/src/in_mem.rs +++ b/core/client/src/in_mem.rs @@ -324,7 +324,7 @@ impl HeaderMetadata for Blockchain { fn header_metadata(&self, hash: Block::Hash) -> Result, Self::Error> { self.header(BlockId::hash(hash))?.map(|header| CachedHeaderMetadata::from(&header)) - .ok_or(error::Error::UnknownBlock("header not found".to_owned())) + .ok_or(error::Error::UnknownBlock(format!("header not found: {}", hash))) } fn insert_header_metadata(&self, _hash: Block::Hash, _metadata: CachedHeaderMetadata) { diff --git a/core/consensus/babe/src/lib.rs b/core/consensus/babe/src/lib.rs index 683425e815..000c14269f 100644 --- a/core/consensus/babe/src/lib.rs +++ b/core/consensus/babe/src/lib.rs @@ -593,9 +593,8 @@ impl Verifier for BabeVerifier(&header)?; let epoch = { @@ -603,7 +602,7 @@ impl Verifier for BabeVerifier Date: Sat, 5 Oct 2019 09:44:07 +0100 Subject: [PATCH 013/167] babe: prune the epoch tree on startup (#3768) --- core/consensus/babe/src/lib.rs | 69 ++++++++++++++++++++++++---------- 1 file changed, 49 insertions(+), 20 deletions(-) diff --git a/core/consensus/babe/src/lib.rs b/core/consensus/babe/src/lib.rs index 000c14269f..4f69c176ce 100644 --- a/core/consensus/babe/src/lib.rs +++ b/core/consensus/babe/src/lib.rs @@ -112,7 +112,7 @@ mod tests; pub use babe_primitives::{ AuthorityId, AuthorityPair, AuthoritySignature, Epoch, NextEpochDescriptor, }; -pub use epoch_changes::{EpochChanges, SharedEpochChanges}; +pub use epoch_changes::{EpochChanges, EpochChangesFor, SharedEpochChanges}; macro_rules! babe_err { ($($i: expr),+) => { @@ -889,24 +889,10 @@ impl BlockImport for BabeBlockImport(&finalized_header) - .expect("finalized header must be valid; \ - valid blocks have a pre-digest; qed") - .slot_number() - }; - - epoch_changes.prune_finalized( - descendent_query(&*self.client), - &info.finalized_hash, - info.finalized_number, - finalized_slot, - ).map_err(|e| ConsensusError::ClientImport(format!("{:?}", e)))?; + prune_finalized( + &self.client, + &mut epoch_changes, + )?; epoch_changes.import( descendent_query(&*self.client), @@ -989,6 +975,40 @@ impl BlockImport for BabeBlockImport( + client: &Client, + epoch_changes: &mut EpochChangesFor, +) -> Result<(), ConsensusError> where + Block: BlockT, + E: CallExecutor + Send + Sync, + B: Backend, + RA: Send + Sync, +{ + let info = client.info().chain; + + let finalized_slot = { + let finalized_header = client.header(&BlockId::Hash(info.finalized_hash)) + .map_err(|e| ConsensusError::ClientImport(format!("{:?}", e)))? + .expect("best finalized hash was given by client; \ + finalized headers must exist in db; qed"); + + find_pre_digest::(&finalized_header) + .expect("finalized header must be valid; \ + valid blocks have a pre-digest; qed") + .slot_number() + }; + + epoch_changes.prune_finalized( + descendent_query(&*client), + &info.finalized_hash, + info.finalized_number, + finalized_slot, + ).map_err(|e| ConsensusError::ClientImport(format!("{:?}", e)))?; + + Ok(()) +} + /// Produce a BABE block-import object to be used later on in the construction of /// an import-queue. /// @@ -1001,7 +1021,8 @@ pub fn block_import, I, RA, PRA>( api: Arc, ) -> ClientResult<(BabeBlockImport, BabeLink)> where B: Backend, - E: CallExecutor, + E: CallExecutor + Send + Sync, + RA: Send + Sync, { let epoch_changes = aux_schema::load_epoch_changes(&*client)?; let link = BabeLink { @@ -1010,6 +1031,14 @@ pub fn block_import, I, RA, PRA>( config: config.clone(), }; + // NOTE: this isn't entirely necessary, but since we didn't use to prune the + // epoch tree it is useful as a migration, so that nodes prune long trees on + // startup rather than waiting until importing the next epoch change block. + prune_finalized( + &client, + &mut epoch_changes.lock(), + )?; + let import = BabeBlockImport::new( client, api, -- GitLab From 179bdd3170d992d2dca33054c41181119032ba98 Mon Sep 17 00:00:00 2001 From: Micheal Waltz Date: Sat, 5 Oct 2019 11:04:22 +0000 Subject: [PATCH 014/167] Fix docker builds #3731 (#3767) --- Dockerfile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 0271db8d14..1ebc7b04aa 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,13 +5,15 @@ FROM phusion/baseimage:0.10.2 as builder LABEL maintainer="chevdor@gmail.com" LABEL description="This is the build stage for Substrate. Here we create the binary." +ENV DEBIAN_FRONTEND=noninteractive + ARG PROFILE=release WORKDIR /substrate COPY . /substrate RUN apt-get update && \ - apt-get dist-upgrade -y && \ + apt-get dist-upgrade -y -o Dpkg::Options::="--force-confold" && \ apt-get install -y cmake pkg-config libssl-dev git clang RUN curl https://sh.rustup.rs -sSf | sh -s -- -y && \ -- GitLab From aba25769f23dc1bbfeb18b4326cb67234076bd7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Sat, 5 Oct 2019 13:06:38 +0200 Subject: [PATCH 015/167] srml-utility: Store errors as `DispatchError` to make the decodable (#3766) --- node/runtime/src/lib.rs | 6 +++--- srml/utility/src/lib.rs | 17 ++++++----------- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index b06ba19ee5..7495190464 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -84,8 +84,8 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // and set impl_version to equal spec_version. If only runtime // implementation changes and behavior does not, then leave spec_version as // is and increment impl_version. - spec_version: 171, - impl_version: 171, + spec_version: 172, + impl_version: 172, apis: RUNTIME_API_VERSIONS, }; @@ -497,7 +497,7 @@ construct_runtime!( UncheckedExtrinsic = UncheckedExtrinsic { System: system::{Module, Call, Storage, Config, Event}, - Utility: utility::{Module, Call, Event}, + Utility: utility::{Module, Call, Event}, Babe: babe::{Module, Call, Storage, Config, Inherent(Timestamp)}, Timestamp: timestamp::{Module, Call, Storage, Inherent}, Authorship: authorship::{Module, Call, Storage, Inherent}, diff --git a/srml/utility/src/lib.rs b/srml/utility/src/lib.rs index 9fe34ee2d0..c0b1954da9 100644 --- a/srml/utility/src/lib.rs +++ b/srml/utility/src/lib.rs @@ -23,27 +23,21 @@ use rstd::prelude::*; use support::{decl_module, decl_event, Parameter}; use system::ensure_root; -use sr_primitives::{ - traits::{Dispatchable, DispatchResult}, weights::SimpleDispatchInfo -}; +use sr_primitives::{traits::Dispatchable, weights::SimpleDispatchInfo, DispatchError}; /// Configuration trait. pub trait Trait: system::Trait { /// The overarching event type. - type Event: From> + Into<::Event>; + type Event: From + Into<::Event>; /// The overarching call type. type Call: Parameter + Dispatchable; } -pub type DispatchResultOf = DispatchResult<<::Call as Dispatchable>::Error>; - decl_event!( /// Events type. - pub enum Event where - DispatchResult = DispatchResultOf, - { - BatchExecuted(Vec), + pub enum Event { + BatchExecuted(Vec>), } ); @@ -58,8 +52,9 @@ decl_module! { ensure_root(origin)?; let results = calls.into_iter() .map(|call| call.dispatch(system::RawOrigin::Root.into())) + .map(|res| res.map_err(Into::into)) .collect::>(); - Self::deposit_event(RawEvent::BatchExecuted(results)); + Self::deposit_event(Event::BatchExecuted(results)); } } } -- GitLab From f860828600c278769c0ea36909b14ef47d4c2107 Mon Sep 17 00:00:00 2001 From: Hernando Castano Date: Sun, 6 Oct 2019 22:44:32 +0900 Subject: [PATCH 016/167] Make the purge-chain prompt a little nicer (#3772) --- core/cli/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/cli/src/lib.rs b/core/cli/src/lib.rs index 7d5593f2cd..2e7619116c 100644 --- a/core/cli/src/lib.rs +++ b/core/cli/src/lib.rs @@ -423,7 +423,7 @@ impl<'a> ParseAndPreparePurge<'a> { let db_path = config.database_path; if !self.params.yes { - print!("Are you sure to remove {:?}? (y/n)", &db_path); + print!("Are you sure to remove {:?}? [y/N]: ", &db_path); stdout().flush().expect("failed to flush stdout"); let mut input = String::new(); -- GitLab From b942db7efe14a3465bc0917befdf771de8cd0fab Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Mon, 7 Oct 2019 09:00:15 +0300 Subject: [PATCH 017/167] Fix state RPC subscriptions on light node (#3626) * fetch all keys at once in light RPC subscriptions * restore lost fil --- Cargo.lock | 1 + core/rpc/Cargo.toml | 1 + core/rpc/api/src/subscriptions.rs | 7 +- core/rpc/src/state/mod.rs | 119 +----- core/rpc/src/state/state_full.rs | 142 ++++++- core/rpc/src/state/state_light.rs | 651 ++++++++++++++++++++++++++---- 6 files changed, 714 insertions(+), 207 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ca1270929f..170ed9e2f1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5224,6 +5224,7 @@ dependencies = [ "jsonrpc-pubsub 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 2.0.0", diff --git a/core/rpc/Cargo.toml b/core/rpc/Cargo.toml index 5178fc56d8..e6f0db1c9c 100644 --- a/core/rpc/Cargo.toml +++ b/core/rpc/Cargo.toml @@ -23,6 +23,7 @@ substrate-executor = { path = "../executor" } substrate-keystore = { path = "../keystore" } transaction_pool = { package = "substrate-transaction-pool", path = "../transaction-pool" } hash-db = { version = "0.15.2", default-features = false } +parking_lot = { version = "0.9.0" } [dev-dependencies] assert_matches = "1.3.0" diff --git a/core/rpc/api/src/subscriptions.rs b/core/rpc/api/src/subscriptions.rs index bff184cade..a1e486138f 100644 --- a/core/rpc/api/src/subscriptions.rs +++ b/core/rpc/api/src/subscriptions.rs @@ -74,13 +74,14 @@ impl Subscriptions { /// Second parameter is a function that converts Subscriber sink into a future. /// This future will be driven to completion by the underlying event loop /// or will be cancelled in case #cancel is invoked. - pub fn add(&self, subscriber: Subscriber, into_future: G) where + pub fn add(&self, subscriber: Subscriber, into_future: G) -> SubscriptionId where G: FnOnce(Sink) -> R, R: future::IntoFuture, F: future::Future + Send + 'static, { let id = self.next_id.next_id(); - if let Ok(sink) = subscriber.assign_id(id.into()) { + let subscription_id: SubscriptionId = id.into(); + if let Ok(sink) = subscriber.assign_id(subscription_id.clone()) { let (tx, rx) = oneshot::channel(); let future = into_future(sink) .into_future() @@ -92,6 +93,8 @@ impl Subscriptions { error!("Failed to spawn RPC subscription task"); } } + + subscription_id } /// Cancel subscription. diff --git a/core/rpc/src/state/mod.rs b/core/rpc/src/state/mod.rs index 390f95ab41..b922601b0a 100644 --- a/core/rpc/src/state/mod.rs +++ b/core/rpc/src/state/mod.rs @@ -23,27 +23,24 @@ mod state_light; mod tests; use std::sync::Arc; -use futures03::{future, StreamExt as _, TryStreamExt as _}; use jsonrpc_pubsub::{typed::Subscriber, SubscriptionId}; -use log::warn; use rpc::{ Result as RpcResult, - futures::{stream, Future, Sink, Stream}, + futures::Future, }; use api::Subscriptions; use client::{ - BlockchainEvents, Client, CallExecutor, + Client, CallExecutor, runtime_api::Metadata, light::{blockchain::RemoteBlockchain, fetcher::Fetcher}, }; use primitives::{ Blake2Hasher, Bytes, H256, - storage::{well_known_keys, StorageKey, StorageData, StorageChangeSet}, + storage::{StorageKey, StorageData, StorageChangeSet}, }; use runtime_version::RuntimeVersion; use sr_primitives::{ - generic::BlockId, traits::{Block as BlockT, ProvideRuntimeApi}, }; @@ -59,12 +56,6 @@ pub trait StateBackend: Send + Sync + 'static E: client::CallExecutor + Send + Sync + 'static, RA: Send + Sync + 'static, { - /// Get client reference. - fn client(&self) -> &Arc>; - - /// Get subscriptions reference. - fn subscriptions(&self) -> &Subscriptions; - /// Call runtime method at given block. fn call( &self, @@ -161,123 +152,29 @@ pub trait StateBackend: Send + Sync + 'static &self, _meta: crate::metadata::Metadata, subscriber: Subscriber, - ) { - let stream = match self.client().storage_changes_notification_stream( - Some(&[StorageKey(well_known_keys::CODE.to_vec())]), - None, - ) { - Ok(stream) => stream, - Err(err) => { - let _ = subscriber.reject(Error::from(client_err(err)).into()); - return; - } - }; - - self.subscriptions().add(subscriber, |sink| { - let version = self.runtime_version(None.into()) - .map_err(Into::into) - .wait(); - - let client = self.client().clone(); - let mut previous_version = version.clone(); - - let stream = stream - .filter_map(move |_| { - let info = client.info(); - let version = client - .runtime_version_at(&BlockId::hash(info.chain.best_hash)) - .map_err(client_err) - .map_err(Into::into); - if previous_version != version { - previous_version = version.clone(); - future::ready(Some(Ok::<_, ()>(version))) - } else { - future::ready(None) - } - }) - .compat(); - - sink - .sink_map_err(|e| warn!("Error sending notifications: {:?}", e)) - .send_all( - stream::iter_result(vec![Ok(version)]) - .chain(stream) - ) - // we ignore the resulting Stream (if the first stream is over we are unsubscribed) - .map(|_| ()) - }); - } + ); /// Unsubscribe from runtime version subscription fn unsubscribe_runtime_version( &self, _meta: Option, id: SubscriptionId, - ) -> RpcResult { - Ok(self.subscriptions().cancel(id)) - } + ) -> RpcResult; /// New storage subscription fn subscribe_storage( &self, _meta: crate::metadata::Metadata, subscriber: Subscriber>, - keys: Option> - ) { - let keys = Into::>>::into(keys); - let stream = match self.client().storage_changes_notification_stream( - keys.as_ref().map(|x| &**x), - None - ) { - Ok(stream) => stream, - Err(err) => { - let _ = subscriber.reject(client_err(err).into()); - return; - }, - }; - - // initial values - let initial = stream::iter_result(keys - .map(|keys| { - let block = self.client().info().chain.best_hash; - let changes = keys - .into_iter() - .map(|key| self.storage(Some(block.clone()).into(), key.clone()) - .map(|val| (key.clone(), val)) - .wait() - .unwrap_or_else(|_| (key, None)) - ) - .collect(); - vec![Ok(Ok(StorageChangeSet { block, changes }))] - }).unwrap_or_default()); - - self.subscriptions().add(subscriber, |sink| { - let stream = stream - .map(|(block, changes)| Ok::<_, ()>(Ok(StorageChangeSet { - block, - changes: changes.iter() - .filter_map(|(o_sk, k, v)| if o_sk.is_none() { - Some((k.clone(),v.cloned())) - } else { None }).collect(), - }))) - .compat(); - - sink - .sink_map_err(|e| warn!("Error sending notifications: {:?}", e)) - .send_all(initial.chain(stream)) - // we ignore the resulting Stream (if the first stream is over we are unsubscribed) - .map(|_| ()) - }) - } + keys: Option>, + ); /// Unsubscribe from storage subscription fn unsubscribe_storage( &self, _meta: Option, id: SubscriptionId, - ) -> RpcResult { - Ok(self.subscriptions().cancel(id)) - } + ) -> RpcResult; } /// Create new state API that works on full node. diff --git a/core/rpc/src/state/state_full.rs b/core/rpc/src/state/state_full.rs index 8b3dcd3d69..6f0472163f 100644 --- a/core/rpc/src/state/state_full.rs +++ b/core/rpc/src/state/state_full.rs @@ -19,16 +19,22 @@ use std::collections::{BTreeMap, HashMap}; use std::sync::Arc; use std::ops::Range; -use rpc::futures::future::result; +use futures03::{future, StreamExt as _, TryStreamExt as _}; +use log::warn; +use jsonrpc_pubsub::{typed::Subscriber, SubscriptionId}; +use rpc::{ + Result as RpcResult, + futures::{stream, Future, Sink, Stream, future::result}, +}; use api::Subscriptions; use client::{ - Client, CallExecutor, runtime_api::Metadata, + Client, CallExecutor, BlockchainEvents, runtime_api::Metadata, backend::Backend, error::Result as ClientResult, }; use primitives::{ H256, Blake2Hasher, Bytes, offchain::NeverOffchainExt, - storage::{StorageKey, StorageData, StorageChangeSet}, + storage::{well_known_keys, StorageKey, StorageData, StorageChangeSet}, }; use runtime_version::RuntimeVersion; use state_machine::ExecutionStrategy; @@ -53,6 +59,7 @@ struct QueryStorageRange { pub filtered_range: Option>, } +/// State API backend for full nodes. pub struct FullState { client: Arc>, subscriptions: Subscriptions, @@ -64,7 +71,7 @@ impl FullState B: Backend + Send + Sync + 'static, E: CallExecutor + Send + Sync + 'static + Clone, { - /// + /// Create new state API backend for full nodes. pub fn new(client: Arc>, subscriptions: Subscriptions) -> Self { Self { client, subscriptions } } @@ -225,14 +232,6 @@ impl StateBackend for FullState: ProvideRuntimeApi, as ProvideRuntimeApi>::Api: Metadata, { - fn client(&self) -> &Arc> { - &self.client - } - - fn subscriptions(&self) -> &Subscriptions { - &self.subscriptions - } - fn call( &self, block: Option, @@ -352,6 +351,125 @@ impl StateBackend for FullState, + ) { + let stream = match self.client.storage_changes_notification_stream( + Some(&[StorageKey(well_known_keys::CODE.to_vec())]), + None, + ) { + Ok(stream) => stream, + Err(err) => { + let _ = subscriber.reject(Error::from(client_err(err)).into()); + return; + } + }; + + self.subscriptions.add(subscriber, |sink| { + let version = self.runtime_version(None.into()) + .map_err(Into::into) + .wait(); + + let client = self.client.clone(); + let mut previous_version = version.clone(); + + let stream = stream + .filter_map(move |_| { + let info = client.info(); + let version = client + .runtime_version_at(&BlockId::hash(info.chain.best_hash)) + .map_err(client_err) + .map_err(Into::into); + if previous_version != version { + previous_version = version.clone(); + future::ready(Some(Ok::<_, ()>(version))) + } else { + future::ready(None) + } + }) + .compat(); + + sink + .sink_map_err(|e| warn!("Error sending notifications: {:?}", e)) + .send_all( + stream::iter_result(vec![Ok(version)]) + .chain(stream) + ) + // we ignore the resulting Stream (if the first stream is over we are unsubscribed) + .map(|_| ()) + }); + } + + fn unsubscribe_runtime_version( + &self, + _meta: Option, + id: SubscriptionId, + ) -> RpcResult { + Ok(self.subscriptions.cancel(id)) + } + + fn subscribe_storage( + &self, + _meta: crate::metadata::Metadata, + subscriber: Subscriber>, + keys: Option>, + ) { + let keys = Into::>>::into(keys); + let stream = match self.client.storage_changes_notification_stream( + keys.as_ref().map(|x| &**x), + None + ) { + Ok(stream) => stream, + Err(err) => { + let _ = subscriber.reject(client_err(err).into()); + return; + }, + }; + + // initial values + let initial = stream::iter_result(keys + .map(|keys| { + let block = self.client.info().chain.best_hash; + let changes = keys + .into_iter() + .map(|key| self.storage(Some(block.clone()).into(), key.clone()) + .map(|val| (key.clone(), val)) + .wait() + .unwrap_or_else(|_| (key, None)) + ) + .collect(); + vec![Ok(Ok(StorageChangeSet { block, changes }))] + }).unwrap_or_default()); + + self.subscriptions.add(subscriber, |sink| { + let stream = stream + .map(|(block, changes)| Ok::<_, ()>(Ok(StorageChangeSet { + block, + changes: changes.iter() + .filter_map(|(o_sk, k, v)| if o_sk.is_none() { + Some((k.clone(),v.cloned())) + } else { None }).collect(), + }))) + .compat(); + + sink + .sink_map_err(|e| warn!("Error sending notifications: {:?}", e)) + .send_all(initial.chain(stream)) + // we ignore the resulting Stream (if the first stream is over we are unsubscribed) + .map(|_| ()) + }); + } + + fn unsubscribe_storage( + &self, + _meta: Option, + id: SubscriptionId, + ) -> RpcResult { + Ok(self.subscriptions.cancel(id)) + } } /// Splits passed range into two subranges where: diff --git a/core/rpc/src/state/state_light.rs b/core/rpc/src/state/state_light.rs index 456992db66..3d0c7979e3 100644 --- a/core/rpc/src/state/state_light.rs +++ b/core/rpc/src/state/state_light.rs @@ -16,19 +16,31 @@ //! State API backend for light nodes. -use std::sync::Arc; +use std::{ + sync::Arc, + collections::{HashSet, HashMap, hash_map::Entry}, +}; use codec::Decode; -use futures03::{future::{ready, Either}, FutureExt, TryFutureExt}; +use futures03::{ + future::{ready, Either}, + channel::oneshot::{channel, Sender}, + FutureExt, TryFutureExt, + StreamExt as _, TryStreamExt as _, +}; use hash_db::Hasher; use jsonrpc_pubsub::{typed::Subscriber, SubscriptionId}; +use log::warn; +use parking_lot::Mutex; use rpc::{ Result as RpcResult, + futures::Sink, futures::future::{result, Future}, + futures::stream::Stream, }; use api::Subscriptions; use client::{ - Client, CallExecutor, backend::Backend, + BlockchainEvents, Client, CallExecutor, backend::Backend, error::Error as ClientError, light::{ blockchain::{future_header, RemoteBlockchain}, @@ -42,18 +54,89 @@ use primitives::{ use runtime_version::RuntimeVersion; use sr_primitives::{ generic::BlockId, - traits::{Block as BlockT, Header as HeaderT}, + traits::Block as BlockT, }; use super::{StateBackend, error::{FutureResult, Error}, client_err}; +/// Storage data map of storage keys => (optional) storage value. +type StorageMap = HashMap>; + +/// State API backend for light nodes. pub struct LightState, B, E, RA> { client: Arc>, subscriptions: Subscriptions, + version_subscriptions: SimpleSubscriptions, + storage_subscriptions: Arc>>, remote_blockchain: Arc>, fetcher: Arc, } +/// Shared requests container. +trait SharedRequests: Clone + Send + Sync { + /// Tries to listen for already issued request, or issues request. + /// + /// Returns true if requests has been issued. + fn listen_request( + &self, + block: Hash, + sender: Sender>, + ) -> bool; + + /// Returns (and forgets) all listeners for given request. + fn on_response_received(&self, block: Hash) -> Vec>>; +} + +/// Storage subscriptions data. +struct StorageSubscriptions { + /// Active storage requests. + active_requests: HashMap>>>, + /// Map of subscription => keys that this subscription watch for. + keys_by_subscription: HashMap>, + /// Map of key => set of subscriptions that watch this key. + subscriptions_by_key: HashMap>, +} + +impl SharedRequests for Arc>> { + fn listen_request( + &self, + block: Block::Hash, + sender: Sender>, + ) -> bool { + let mut subscriptions = self.lock(); + let active_requests_at = subscriptions.active_requests.entry(block).or_default(); + active_requests_at.push(sender); + active_requests_at.len() == 1 + } + + fn on_response_received(&self, block: Block::Hash) -> Vec>> { + self.lock().active_requests.remove(&block).unwrap_or_default() + } +} + +/// Simple, maybe shared, subscription data that shares per block requests. +type SimpleSubscriptions = Arc>>>>>; + +impl SharedRequests for SimpleSubscriptions where + Hash: Send + Eq + std::hash::Hash, + V: Send, +{ + fn listen_request( + &self, + block: Hash, + sender: Sender>, + ) -> bool { + let mut subscriptions = self.lock(); + let active_requests_at = subscriptions.entry(block).or_default(); + active_requests_at.push(sender); + active_requests_at.len() == 1 + } + + fn on_response_received(&self, block: Hash) -> Vec>> { + self.lock().remove(&block).unwrap_or_default() + } +} + impl + 'static, B, E, RA> LightState where Block: BlockT, @@ -61,39 +144,31 @@ impl + 'static, B, E, RA> LightState + Send + Sync + 'static + Clone, RA: Send + Sync + 'static, { - /// + /// Create new state API backend for light nodes. pub fn new( client: Arc>, subscriptions: Subscriptions, remote_blockchain: Arc>, fetcher: Arc, ) -> Self { - Self { client, subscriptions, remote_blockchain, fetcher, } + Self { + client, + subscriptions, + version_subscriptions: Arc::new(Mutex::new(HashMap::new())), + storage_subscriptions: Arc::new(Mutex::new(StorageSubscriptions { + active_requests: HashMap::new(), + keys_by_subscription: HashMap::new(), + subscriptions_by_key: HashMap::new(), + })), + remote_blockchain, + fetcher, + } } /// Returns given block hash or best block hash if None is passed. fn block_or_best(&self, hash: Option) -> Block::Hash { hash.unwrap_or_else(|| self.client.info().chain.best_hash) } - - /// Resolve header by hash. - fn resolve_header( - &self, - block: Option, - ) -> impl std::future::Future> { - let block = self.block_or_best(block); - let maybe_header = future_header( - &*self.remote_blockchain, - &*self.fetcher, - BlockId::Hash(block), - ); - - maybe_header.then(move |result| - ready(result.and_then(|maybe_header| - maybe_header.ok_or(ClientError::UnknownBlock(format!("{}", block))) - ).map_err(client_err)), - ) - } } impl StateBackend for LightState @@ -104,34 +179,19 @@ impl StateBackend for LightState + 'static { - fn client(&self) -> &Arc> { - &self.client - } - - fn subscriptions(&self) -> &Subscriptions { - &self.subscriptions - } - fn call( &self, block: Option, method: String, call_data: Bytes, ) -> FutureResult { - let fetcher = self.fetcher.clone(); - let call_result = self.resolve_header(block) - .then(move |result| match result { - Ok(header) => Either::Left(fetcher.remote_call(RemoteCallRequest { - block: header.hash(), - header, - method, - call_data: call_data.0, - retry_count: Default::default(), - }).then(|result| ready(result.map(Bytes).map_err(client_err)))), - Err(error) => Either::Right(ready(Err(error))), - }); - - Box::new(call_result.boxed().compat()) + Box::new(call( + &*self.remote_blockchain, + self.fetcher.clone(), + self.block_or_best(block), + method, + call_data, + ).boxed().compat()) } fn storage_keys( @@ -147,26 +207,15 @@ impl StateBackend for LightState, key: StorageKey, ) -> FutureResult> { - let fetcher = self.fetcher.clone(); - let storage = self.resolve_header(block) - .then(move |result| match result { - Ok(header) => Either::Left(fetcher.remote_read(RemoteReadRequest { - block: header.hash(), - header, - keys: vec![key.0.clone()], - retry_count: Default::default(), - }).then(move |result| ready(result - .map(|mut data| data - .remove(&key.0) - .expect("successful result has entry for all keys; qed") - .map(StorageData) - ) - .map_err(client_err) - ))), - Err(error) => Either::Right(ready(Err(error))), - }); - - Box::new(storage.boxed().compat()) + Box::new(storage( + &*self.remote_blockchain, + self.fetcher.clone(), + self.block_or_best(block), + vec![key.0.clone()], + ).boxed().compat().map(move |mut values| values + .remove(&key) + .expect("successful request has entries for all requested keys; qed") + )) } fn storage_hash( @@ -197,11 +246,12 @@ impl StateBackend for LightState FutureResult> { + let block = self.block_or_best(block); let fetcher = self.fetcher.clone(); - let child_storage = self.resolve_header(block) + let child_storage = resolve_header(&*self.remote_blockchain, &*self.fetcher, block) .then(move |result| match result { Ok(header) => Either::Left(fetcher.remote_read_child(RemoteReadChildRequest { - block: header.hash(), + block, header, storage_key: child_storage_key.0, keys: vec![key.0.clone()], @@ -247,12 +297,11 @@ impl StateBackend for LightState) -> FutureResult { - let version = self.call(block, "Core_version".into(), Bytes(Vec::new())) - .and_then(|version| Decode::decode(&mut &version.0[..]) - .map_err(|_| client_err(ClientError::VersionInvalid)) - ); - - Box::new(version) + Box::new(runtime_version( + &*self.remote_blockchain, + self.fetcher.clone(), + self.block_or_best(block), + ).boxed().compat()) } fn query_storage( @@ -267,31 +316,469 @@ impl StateBackend for LightState>, - _keys: Option> + subscriber: Subscriber>, + keys: Option> ) { + let keys = match keys { + Some(keys) => keys, + None => { + warn!("Cannot subscribe to all keys on light client. Subscription rejected."); + return; + } + }; + + let keys = keys.iter().cloned().collect::>(); + let keys_to_check = keys.iter().map(|k| k.0.clone()).collect::>(); + let subscription_id = self.subscriptions.add(subscriber, move |sink| { + let fetcher = self.fetcher.clone(); + let remote_blockchain = self.remote_blockchain.clone(); + let storage_subscriptions = self.storage_subscriptions.clone(); + let initial_block = self.block_or_best(None); + let initial_keys = keys_to_check.iter().cloned().collect::>(); + + let changes_stream = subscription_stream::( + storage_subscriptions.clone(), + self.client + .import_notification_stream() + .map(|notification| Ok::<_, ()>(notification.hash)) + .compat(), + display_error(storage( + &*remote_blockchain, + fetcher.clone(), + initial_block, + initial_keys, + ).map(move |r| r.map(|r| (initial_block, r)))), + move |block| { + // there'll be single request per block for all active subscriptions + // with all subscribed keys + let keys = storage_subscriptions + .lock() + .subscriptions_by_key + .keys() + .map(|k| k.0.clone()) + .collect(); + + storage( + &*remote_blockchain, + fetcher.clone(), + block, + keys, + ) + }, + move |block, old_value, new_value| { + // let's only select keys which are valid for this subscription + let new_value = new_value + .iter() + .filter(|(k, _)| keys_to_check.contains(&k.0)) + .map(|(k, v)| (k.clone(), v.clone())) + .collect::>(); + let value_differs = old_value + .as_ref() + .map(|old_value| **old_value != new_value) + .unwrap_or(true); + match value_differs { + true => Some(StorageChangeSet { + block, + changes: new_value + .iter() + .map(|(k, v)| (k.clone(), v.clone())) + .collect(), + }), + false => None, + } + } + ); + + sink + .sink_map_err(|e| warn!("Error sending notifications: {:?}", e)) + .send_all(changes_stream.map(|changes| Ok(changes))) + // we ignore the resulting Stream (if the first stream is over we are unsubscribed) + .map(|_| ()) + }); + + // remember keys associated with this subscription + let mut storage_subscriptions = self.storage_subscriptions.lock(); + storage_subscriptions.keys_by_subscription.insert(subscription_id.clone(), keys.clone()); + for key in keys { + storage_subscriptions + .subscriptions_by_key + .entry(key) + .or_default() + .insert(subscription_id.clone()); + } } fn unsubscribe_storage( &self, _meta: Option, - _id: SubscriptionId, + id: SubscriptionId, ) -> RpcResult { - Ok(false) + if !self.subscriptions.cancel(id.clone()) { + return Ok(false); + } + + // forget subscription keys + let mut storage_subscriptions = self.storage_subscriptions.lock(); + let keys = storage_subscriptions.keys_by_subscription.remove(&id); + for key in keys.into_iter().flat_map(|keys| keys.into_iter()) { + match storage_subscriptions.subscriptions_by_key.entry(key) { + Entry::Vacant(_) => unreachable!("every key from keys_by_subscription has\ + corresponding entry in subscriptions_by_key; qed"), + Entry::Occupied(mut entry) => { + entry.get_mut().remove(&id); + if entry.get().is_empty() { + entry.remove(); + } + } + } + } + + Ok(true) } fn subscribe_runtime_version( &self, _meta: crate::metadata::Metadata, - _subscriber: Subscriber, + subscriber: Subscriber, ) { + self.subscriptions.add(subscriber, move |sink| { + let fetcher = self.fetcher.clone(); + let remote_blockchain = self.remote_blockchain.clone(); + let version_subscriptions = self.version_subscriptions.clone(); + let initial_block = self.block_or_best(None); + + let versions_stream = subscription_stream::( + version_subscriptions, + self.client + .import_notification_stream() + .map(|notification| Ok::<_, ()>(notification.hash)) + .compat(), + display_error(runtime_version( + &*remote_blockchain, + fetcher.clone(), + initial_block, + ).map(move |r| r.map(|r| (initial_block, r)))), + move |block| runtime_version( + &*remote_blockchain, + fetcher.clone(), + block, + ), + |_, old_version, new_version| { + let version_differs = old_version + .as_ref() + .map(|old_version| *old_version != new_version) + .unwrap_or(true); + match version_differs { + true => Some(new_version.clone()), + false => None, + } + } + ); + + sink + .sink_map_err(|e| warn!("Error sending notifications: {:?}", e)) + .send_all(versions_stream.map(|version| Ok(version))) + // we ignore the resulting Stream (if the first stream is over we are unsubscribed) + .map(|_| ()) + }); } fn unsubscribe_runtime_version( &self, _meta: Option, - _id: SubscriptionId, + id: SubscriptionId, ) -> RpcResult { - Ok(false) + Ok(self.subscriptions.cancel(id)) + } +} + +/// Resolve header by hash. +fn resolve_header>( + remote_blockchain: &dyn RemoteBlockchain, + fetcher: &F, + block: Block::Hash, +) -> impl std::future::Future> { + let maybe_header = future_header( + remote_blockchain, + fetcher, + BlockId::Hash(block), + ); + + maybe_header.then(move |result| + ready(result.and_then(|maybe_header| + maybe_header.ok_or(ClientError::UnknownBlock(format!("{}", block))) + ).map_err(client_err)), + ) +} + +/// Call runtime method at given block +fn call>( + remote_blockchain: &dyn RemoteBlockchain, + fetcher: Arc, + block: Block::Hash, + method: String, + call_data: Bytes, +) -> impl std::future::Future> { + resolve_header(remote_blockchain, &*fetcher, block) + .then(move |result| match result { + Ok(header) => Either::Left(fetcher.remote_call(RemoteCallRequest { + block, + header, + method, + call_data: call_data.0, + retry_count: Default::default(), + }).then(|result| ready(result.map(Bytes).map_err(client_err)))), + Err(error) => Either::Right(ready(Err(error))), + }) +} + +/// Get runtime version at given block. +fn runtime_version>( + remote_blockchain: &dyn RemoteBlockchain, + fetcher: Arc, + block: Block::Hash, +) -> impl std::future::Future> { + call( + remote_blockchain, + fetcher, + block, + "Core_version".into(), + Bytes(Vec::new()), + ) + .then(|version| ready(version.and_then(|version| + Decode::decode(&mut &version.0[..]).map_err(|_| client_err(ClientError::VersionInvalid)) + ))) +} + +/// Get storage value at given key at given block. +fn storage>( + remote_blockchain: &dyn RemoteBlockchain, + fetcher: Arc, + block: Block::Hash, + keys: Vec>, +) -> impl std::future::Future>, Error>> { + resolve_header(remote_blockchain, &*fetcher, block) + .then(move |result| match result { + Ok(header) => Either::Left(fetcher.remote_read(RemoteReadRequest { + block, + header, + keys, + retry_count: Default::default(), + }).then(|result| ready(result + .map(|result| result + .into_iter() + .map(|(key, value)| (StorageKey(key), value.map(StorageData))) + .collect() + ).map_err(client_err) + ))), + Err(error) => Either::Right(ready(Err(error))), + }) +} + +/// Returns subscription stream that issues request on every imported block and +/// if value has changed from previous block, emits (stream) item. +fn subscription_stream< + Block, + Requests, + FutureBlocksStream, + V, N, + InitialRequestFuture, + IssueRequest, IssueRequestFuture, + CompareValues, +>( + shared_requests: Requests, + future_blocks_stream: FutureBlocksStream, + initial_request: InitialRequestFuture, + issue_request: IssueRequest, + compare_values: CompareValues, +) -> impl Stream where + Block: BlockT, + Requests: 'static + SharedRequests, + FutureBlocksStream: Stream, + V: Send + 'static + Clone, + InitialRequestFuture: std::future::Future> + Send + 'static, + IssueRequest: 'static + Fn(Block::Hash) -> IssueRequestFuture, + IssueRequestFuture: std::future::Future> + Send + 'static, + CompareValues: Fn(Block::Hash, Option<&V>, &V) -> Option, +{ + // we need to send initial value first, then we'll only be sending if value has changed + let previous_value = Arc::new(Mutex::new(None)); + + // prepare 'stream' of initial values + let initial_value_stream = ignore_error(initial_request) + .boxed() + .compat() + .into_stream(); + + // prepare stream of future values + // + // we do not want to stop stream if single request fails + // (the warning should have been already issued by the request issuer) + let future_values_stream = future_blocks_stream + .and_then(move |block| ignore_error(maybe_share_remote_request::( + shared_requests.clone(), + block, + &issue_request, + ).map(move |r| r.map(|v| (block, v)))).boxed().compat()); + + // now let's return changed values for selected blocks + initial_value_stream + .chain(future_values_stream) + .filter_map(move |block_and_new_value| block_and_new_value.and_then(|(block, new_value)| { + let mut previous_value = previous_value.lock(); + compare_values(block, previous_value.as_ref(), &new_value) + .map(|notification_value| { + *previous_value = Some(new_value); + notification_value + }) + })) + .map_err(|_| ()) +} + +/// Request some data from remote node, probably reusing response from already +/// (in-progress) existing request. +fn maybe_share_remote_request( + shared_requests: Requests, + block: Block::Hash, + issue_request: &IssueRequest, +) -> impl std::future::Future> where + V: Clone, + Requests: SharedRequests, + IssueRequest: Fn(Block::Hash) -> IssueRequestFuture, + IssueRequestFuture: std::future::Future>, +{ + let (sender, receiver) = channel(); + let need_issue_request = shared_requests.listen_request(block, sender); + + // if that isn't the first request - just listen for existing request' response + if !need_issue_request { + return Either::Right(receiver.then(|r| ready(r.unwrap_or(Err(()))))); + } + + // that is the first request - issue remote request + notify all listeners on + // completion + Either::Left( + display_error(issue_request(block)) + .then(move |remote_result| { + let listeners = shared_requests.on_response_received(block); + // skip first element, because this future is the first element + for receiver in listeners.into_iter().skip(1) { + if let Err(_) = receiver.send(remote_result.clone()) { + // we don't care if receiver has been dropped already + } + } + + ready(remote_result) + }) + ) +} + +/// Convert successful future result into Ok(result) and error into Err(()), +/// displaying warning. +fn display_error(future: F) -> impl std::future::Future> where + F: std::future::Future> +{ + future.then(|result| ready(match result { + Ok(result) => Ok(result), + Err(err) => { + warn!("Remote request for subscription data has failed with: {:?}", err); + Err(()) + }, + })) +} + +/// Convert successful future result into Ok(Some(result)) and error into Ok(None), +/// displaying warning. +fn ignore_error(future: F) -> impl std::future::Future, ()>> where + F: std::future::Future> +{ + future.then(|result| ready(match result { + Ok(result) => Ok(Some(result)), + Err(()) => Ok(None), + })) +} + +#[cfg(test)] +mod tests { + use rpc::futures::stream::futures_ordered; + use test_client::runtime::Block; + use super::*; + + #[test] + fn subscription_stream_works() { + let stream = subscription_stream::( + SimpleSubscriptions::default(), + futures_ordered(vec![result(Ok(H256::from([2; 32]))), result(Ok(H256::from([3; 32])))]), + ready(Ok((H256::from([1; 32]), 100))), + |block| match block[0] { + 2 => ready(Ok(100)), + 3 => ready(Ok(200)), + _ => unreachable!("should not issue additional requests"), + }, + |_, old_value, new_value| match old_value == Some(new_value) { + true => None, + false => Some(new_value.clone()), + } + ); + + assert_eq!( + stream.collect().wait(), + Ok(vec![100, 200]) + ); + } + + #[test] + fn subscription_stream_ignores_failed_requests() { + let stream = subscription_stream::( + SimpleSubscriptions::default(), + futures_ordered(vec![result(Ok(H256::from([2; 32]))), result(Ok(H256::from([3; 32])))]), + ready(Ok((H256::from([1; 32]), 100))), + |block| match block[0] { + 2 => ready(Err(client_err(ClientError::NotAvailableOnLightClient))), + 3 => ready(Ok(200)), + _ => unreachable!("should not issue additional requests"), + }, + |_, old_value, new_value| match old_value == Some(new_value) { + true => None, + false => Some(new_value.clone()), + } + ); + + assert_eq!( + stream.collect().wait(), + Ok(vec![100, 200]) + ); + } + + #[test] + fn maybe_share_remote_request_shares_request() { + type UnreachableFuture = futures03::future::Ready>; + + let shared_requests = SimpleSubscriptions::default(); + + // let's 'issue' requests for B1 + shared_requests.lock().insert( + H256::from([1; 32]), + vec![channel().0], + ); + + // make sure that no additional requests are issued when we're asking for B1 + let _ = maybe_share_remote_request::( + shared_requests.clone(), + H256::from([1; 32]), + &|_| unreachable!("no duplicate requests issued"), + ); + + // make sure that additional requests is issued when we're asking for B2 + let request_issued = Arc::new(Mutex::new(false)); + let _ = maybe_share_remote_request::( + shared_requests.clone(), + H256::from([2; 32]), + &|_| { + *request_issued.lock() = true; + ready(Ok(Default::default())) + }, + ); + assert!(*request_issued.lock()); } } -- GitLab From 6b8e5431fe39916119f7dafc44a956f8fada824a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20=C5=A0kvorc?= Date: Mon, 7 Oct 2019 09:34:10 +0200 Subject: [PATCH 018/167] Alternative sysvar setup for Windows (#3761) * Alternative sysvar setup for Windows The command line setup did not work for me. This adds instructions and images on how to do it through the UI. * Modified instructions to use Powershell, removed images from PR. --- README.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.adoc b/README.adoc index 810d07c612..f5d7f95713 100644 --- a/README.adoc +++ b/README.adoc @@ -246,7 +246,7 @@ If you are trying to set up Substrate on Windows, you should do the following: .\bootstrap-vcpkg.bat .\vcpkg.exe install openssl:x64-windows-static -7. After, you need to add OpenSSL to your System Variables: +7. After, you need to add OpenSSL to your System Variables. Note that in order for the following commands to work, you need to use Windows Powershell: $env:OPENSSL_DIR = 'C:\Tools\vcpkg\installed\x64-windows-static' $env:OPENSSL_STATIC = 'Yes' -- GitLab From 1c7e65fa3618f81880940fbfb779285b646a1617 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= Date: Mon, 7 Oct 2019 14:28:28 +0100 Subject: [PATCH 019/167] client: fix comparison of CachedHeaderMetadata in tree_route (#3776) * client: fix comparison of CachedHeaderMetadata in tree_route * client: add regression test for tree_route --- core/client/db/src/lib.rs | 34 ++++++++++++++++++++++++++ core/client/header-metadata/src/lib.rs | 4 +-- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/core/client/db/src/lib.rs b/core/client/db/src/lib.rs index 7cc6ef54a0..7061e9d29a 100644 --- a/core/client/db/src/lib.rs +++ b/core/client/db/src/lib.rs @@ -2222,6 +2222,40 @@ mod tests { } } + #[test] + fn test_tree_route_regression() { + // NOTE: this is a test for a regression introduced in #3665, the result + // of tree_route would be erroneously computed, since it was taking into + // account the `ancestor` in `CachedHeaderMetadata` for the comparison. + // in this test we simulate the same behavior with the side-effect + // triggering the issue being eviction of a previously fetched record + // from the cache, therefore this test is dependent on the LRU cache + // size for header metadata, which is currently set to 5000 elements. + let backend = Backend::::new_test(10000, 10000); + let blockchain = backend.blockchain(); + + let genesis = insert_header(&backend, 0, Default::default(), Vec::new(), Default::default()); + + let block100 = (1..=100).fold(genesis, |parent, n| { + insert_header(&backend, n, parent, Vec::new(), Default::default()) + }); + + let block7000 = (101..=7000).fold(block100, |parent, n| { + insert_header(&backend, n, parent, Vec::new(), Default::default()) + }); + + // This will cause the ancestor of `block100` to be set to `genesis` as a side-effect. + lowest_common_ancestor(blockchain, genesis, block100).unwrap(); + + // While traversing the tree we will have to do 6900 calls to + // `header_metadata`, which will make sure we will exhaust our cache + // which only takes 5000 elements. In particular, the `CachedHeaderMetadata` struct for + // block #100 will be evicted and will get a new value (with ancestor set to its parent). + let tree_route = tree_route(blockchain, block100, block7000).unwrap(); + + assert!(tree_route.retracted().is_empty()); + } + #[test] fn test_leaves_with_complex_block_tree() { let backend: Arc> = Arc::new(Backend::new_test(20, 20)); diff --git a/core/client/header-metadata/src/lib.rs b/core/client/header-metadata/src/lib.rs index cce45f264e..a8c3886020 100644 --- a/core/client/header-metadata/src/lib.rs +++ b/core/client/header-metadata/src/lib.rs @@ -122,7 +122,7 @@ pub fn tree_route>( // numbers are equal now. walk backwards until the block is the same - while to != from { + while to.hash != from.hash { to_branch.push(HashAndNumber { number: to.number, hash: to.hash, @@ -257,7 +257,7 @@ impl HeaderMetadata for HeaderMetadataCache { } /// Cached header metadata. Used to efficiently traverse the tree. -#[derive(Debug, Clone, Eq, PartialEq)] +#[derive(Debug, Clone)] pub struct CachedHeaderMetadata { /// Hash of the header. pub hash: Block::Hash, -- GitLab From c5e0897d45727ba545ac2152c3a3caf6a675be7a Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Tue, 8 Oct 2019 09:23:27 +0200 Subject: [PATCH 020/167] Example of how to inspect arguments in weight calculation (#3753) * document how to make a custom weight calculator * Simpler explanation and implementation. * remove unneeded where --- srml/example/src/lib.rs | 62 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 59 insertions(+), 3 deletions(-) diff --git a/srml/example/src/lib.rs b/srml/example/src/lib.rs index fe16fb7d6e..ef8eead7ba 100644 --- a/srml/example/src/lib.rs +++ b/srml/example/src/lib.rs @@ -258,13 +258,51 @@ use support::{dispatch::Result, decl_module, decl_storage, decl_event}; use system::{ensure_signed, ensure_root}; use codec::{Encode, Decode}; use sr_primitives::{ - traits::{SignedExtension, Bounded}, weights::{SimpleDispatchInfo, DispatchInfo}, + traits::{SignedExtension, Bounded, SaturatedConversion}, + weights::{SimpleDispatchInfo, DispatchInfo, DispatchClass, ClassifyDispatch, WeighData, Weight}, transaction_validity::{ ValidTransaction, TransactionValidityError, InvalidTransaction, TransactionValidity, }, }; -/// Our module's configuration trait. All our types and consts go in here. If the +// A custom weight calculator tailored for the dispatch call `set_dummy()`. This actually examines +// the arguments and makes a decision based upon them. +// +// The `WeightData` trait has access to the arguments of the dispatch that it wants to assign a +// weight to. Nonetheless, the trait itself can not make any assumptions about what that type +// generic type of the arguments, `T`, is. Based on our needs, we could replace `T` with a more +// concrete type while implementing the trait. The `decl_module!` expects whatever implements +// `WeighData` to replace `T` with a tuple of the dispatch arguments. This is exactly how we will +// craft the implementation below. +// +// The rules of `WeightForSetDummy` is as follows: +// - The final weight of each dispatch is calculated as the argument of the call multiplied by the +// parameter given to the `WeightForSetDummy`'s constructor. +// - assigns a dispatch class `operational` if the argument of the call is more than 1000. +struct WeightForSetDummy(BalanceOf); + +impl WeighData<(&BalanceOf,)> for WeightForSetDummy +{ + fn weigh_data(&self, target: (&BalanceOf,)) -> Weight { + let multiplier = self.0; + (*target.0 * multiplier).saturated_into::() + } +} + +impl ClassifyDispatch<(&BalanceOf,)> for WeightForSetDummy { + fn classify_dispatch(&self, target: (&BalanceOf,)) -> DispatchClass { + if *target.0 > >::from(1000u32) { + DispatchClass::Operational + } else { + DispatchClass::Normal + } + } +} + +/// A type alias for the balance type from this module's point of view. +type BalanceOf = ::Balance; + +/// Our module's configuration trait. All our types and constants go in here. If the /// module is dependent on specific other modules, then their configuration traits /// should be added to our implied traits list. /// @@ -454,6 +492,7 @@ decl_module! { // without worrying about gameability or attack scenarios. // If you not specify `Result` explicitly as return value, it will be added automatically // for you and `Ok(())` will be returned. + #[weight = WeightForSetDummy::(>::from(100u32))] fn set_dummy(origin, #[compact] new_value: T::Balance) { ensure_root(origin)?; // Put the new value into storage. @@ -600,7 +639,10 @@ mod tests { // The testing primitives are very useful for avoiding having to work with signatures // or public keys. `u64` is used as the `AccountId` and no `Signature`s are required. use sr_primitives::{ - Perbill, traits::{BlakeTwo256, OnInitialize, OnFinalize, IdentityLookup}, testing::Header + Perbill, + traits::{BlakeTwo256, OnInitialize, OnFinalize, IdentityLookup}, + weights::GetDispatchInfo, + testing::Header }; impl_outer_origin! { @@ -726,4 +768,18 @@ mod tests { ); }) } + + #[test] + fn weights_work() { + // must have a default weight. + let default_call = >::accumulate_dummy(10); + let info = default_call.get_dispatch_info(); + // aka. `let info = as GetDispatchInfo>::get_dispatch_info(&default_call);` + assert_eq!(info.weight, 10_000); + + // must have a custom weight of `100 * arg = 2000` + let custom_call = >::set_dummy(20); + let info = custom_call.get_dispatch_info(); + assert_eq!(info.weight, 2000); + } } -- GitLab From ac11c330a95827211e1999781b5f691e72387c9e Mon Sep 17 00:00:00 2001 From: Xiliang Chen Date: Tue, 8 Oct 2019 22:30:16 +1300 Subject: [PATCH 021/167] expose module errors into metadata (#3752) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * expose module errors into metadata * it checks * Tests for error metadata * Apply suggestions from code review Co-Authored-By: Bastian Köcher * remove inherent errors from metadata * bump version * Apply suggestions from code review Co-Authored-By: Bastian Köcher * Update srml/support/src/error.rs Co-Authored-By: Bastian Köcher --- srml/metadata/src/lib.rs | 34 ++++++++++++++++++++++----- srml/support/src/dispatch.rs | 10 +++++++- srml/support/src/error.rs | 20 ++++++++++++++-- srml/support/src/metadata.rs | 39 ++++++++++++++++++++++++++++--- srml/support/test/tests/system.rs | 3 +++ 5 files changed, 94 insertions(+), 12 deletions(-) diff --git a/srml/metadata/src/lib.rs b/srml/metadata/src/lib.rs index bf7c379000..244d117564 100644 --- a/srml/metadata/src/lib.rs +++ b/srml/metadata/src/lib.rs @@ -179,7 +179,7 @@ pub struct OuterEventMetadata { >, } -/// All the metadata about a event. +/// All the metadata about an event. #[derive(Clone, PartialEq, Eq, Encode)] #[cfg_attr(feature = "std", derive(Decode, Debug, Serialize))] pub struct EventMetadata { @@ -209,6 +209,25 @@ pub struct ModuleConstantMetadata { pub documentation: DecodeDifferentArray<&'static str, StringBuf>, } +/// All the metadata about a module error. +#[derive(Clone, PartialEq, Eq, Encode)] +#[cfg_attr(feature = "std", derive(Decode, Debug, Serialize))] +pub struct ErrorMetadata { + pub name: DecodeDifferentStr, + pub documentation: DecodeDifferentArray<&'static str, StringBuf>, +} + +/// All the metadata about errors in a module. +pub trait ModuleErrorMetadata { + fn metadata() -> &'static [ErrorMetadata]; +} + +impl ModuleErrorMetadata for &'static str { + fn metadata() -> &'static [ErrorMetadata] { + &[] + } +} + /// A technical trait to store lazy initiated vec value as static dyn pointer. pub trait DefaultByte: Send + Sync { fn default_byte(&self) -> Vec; @@ -326,8 +345,10 @@ pub enum RuntimeMetadata { V5(RuntimeMetadataDeprecated), /// Version 6 for runtime metadata. No longer used. V6(RuntimeMetadataDeprecated), - /// Version 7 for runtime metadata. - V7(RuntimeMetadataV7), + /// Version 7 for runtime metadata. No longer used. + V7(RuntimeMetadataDeprecated), + /// Version 8 for runtime metadata. + V8(RuntimeMetadataV8), } /// Enum that should fail. @@ -351,12 +372,12 @@ impl Decode for RuntimeMetadataDeprecated { /// The metadata of a runtime. #[derive(Eq, Encode, PartialEq)] #[cfg_attr(feature = "std", derive(Decode, Debug, Serialize))] -pub struct RuntimeMetadataV7 { +pub struct RuntimeMetadataV8 { pub modules: DecodeDifferentArray, } /// The latest version of the metadata. -pub type RuntimeMetadataLastVersion = RuntimeMetadataV7; +pub type RuntimeMetadataLastVersion = RuntimeMetadataV8; /// All metadata about an runtime module. #[derive(Clone, PartialEq, Eq, Encode)] @@ -367,6 +388,7 @@ pub struct ModuleMetadata { pub calls: ODFnA, pub event: ODFnA, pub constants: DFnA, + pub errors: DFnA, } type ODFnA = Option>; @@ -380,6 +402,6 @@ impl Into for RuntimeMetadataPrefixed { impl Into for RuntimeMetadataLastVersion { fn into(self) -> RuntimeMetadataPrefixed { - RuntimeMetadataPrefixed(META_RESERVED, RuntimeMetadata::V7(self)) + RuntimeMetadataPrefixed(META_RESERVED, RuntimeMetadata::V8(self)) } } diff --git a/srml/support/src/dispatch.rs b/srml/support/src/dispatch.rs index 67cd3e44bf..fd24c257ae 100644 --- a/srml/support/src/dispatch.rs +++ b/srml/support/src/dispatch.rs @@ -23,7 +23,7 @@ pub use std::fmt; pub use crate::codec::{Codec, EncodeLike, Decode, Encode, Input, Output, HasCompact, EncodeAsRef}; pub use srml_metadata::{ FunctionMetadata, DecodeDifferent, DecodeDifferentArray, FunctionArgumentMetadata, - ModuleConstantMetadata, DefaultByte, DefaultByteGetter, + ModuleConstantMetadata, DefaultByte, DefaultByteGetter, ModuleErrorMetadata, ErrorMetadata }; pub use sr_primitives::{ weights::{ @@ -1298,6 +1298,14 @@ macro_rules! decl_module { { $( $other_where_bounds )* } $( $constants )* } + + impl<$trait_instance: $trait_name $(, $instance: $instantiable)?> $crate::dispatch::ModuleErrorMetadata + for $mod_type<$trait_instance $(, $instance)?> where $( $other_where_bounds )* + { + fn metadata() -> &'static [$crate::dispatch::ErrorMetadata] { + <$error_type as $crate::dispatch::ModuleErrorMetadata>::metadata() + } + } } } diff --git a/srml/support/src/error.rs b/srml/support/src/error.rs index 2f9d9379bf..848bd126d2 100644 --- a/srml/support/src/error.rs +++ b/srml/support/src/error.rs @@ -18,6 +18,7 @@ #[doc(hidden)] pub use sr_primitives::traits::LookupError; +pub use srml_metadata::{ModuleErrorMetadata, ErrorMetadata, DecodeDifferent}; /// Declare an error type for a runtime module. /// @@ -49,7 +50,7 @@ macro_rules! decl_error { $(#[$attr:meta])* pub enum $error:ident { $( - $( #[$variant_attr:meta] )* + $( #[doc = $doc_attr:tt] )* $name:ident ),* $(,)? @@ -62,7 +63,7 @@ macro_rules! decl_error { Other(&'static str), CannotLookup, $( - $(#[$variant_attr])* + $( #[doc = $doc_attr] )* $name ),* } @@ -115,6 +116,21 @@ macro_rules! decl_error { $crate::dispatch::DispatchError::new(None, self.as_u8(), Some(self.as_str())) } } + + impl $crate::error::ModuleErrorMetadata for $error { + fn metadata() -> &'static [$crate::error::ErrorMetadata] { + &[ + $( + $crate::error::ErrorMetadata { + name: $crate::error::DecodeDifferent::Encode(stringify!($name)), + documentation: $crate::error::DecodeDifferent::Encode(&[ + $( $doc_attr ),* + ]), + } + ),* + ] + } + } }; (@GENERATE_AS_U8 $self:ident diff --git a/srml/support/src/metadata.rs b/srml/support/src/metadata.rs index 7ae5f7d193..a223a14f9e 100644 --- a/srml/support/src/metadata.rs +++ b/srml/support/src/metadata.rs @@ -17,7 +17,7 @@ pub use srml_metadata::{ DecodeDifferent, FnEncode, RuntimeMetadata, ModuleMetadata, RuntimeMetadataLastVersion, DefaultByteGetter, RuntimeMetadataPrefixed, StorageEntryMetadata, StorageMetadata, - StorageEntryType, StorageEntryModifier, DefaultByte, StorageHasher + StorageEntryType, StorageEntryModifier, DefaultByte, StorageHasher, ModuleErrorMetadata }; /// Implements the metadata support for the given runtime and all its modules. @@ -96,6 +96,11 @@ macro_rules! __runtime_modules_to_metadata { $crate::metadata::FnEncode( $mod::$module::<$runtime $(, $mod::$instance )?>::module_constants_metadata ) + ), + errors: $crate::metadata::DecodeDifferent::Encode( + $crate::metadata::FnEncode( + <$mod::$module::<$runtime $(, $mod::$instance )?> as $crate::metadata::ModuleErrorMetadata>::metadata + ) ) }; $( $rest )* @@ -227,6 +232,7 @@ mod tests { use srml_metadata::{ EventMetadata, StorageEntryModifier, StorageEntryType, FunctionMetadata, StorageEntryMetadata, ModuleMetadata, RuntimeMetadataPrefixed, DefaultByte, ModuleConstantMetadata, DefaultByteGetter, + ErrorMetadata, }; use codec::{Encode, Decode}; use crate::traits::Get; @@ -278,7 +284,7 @@ mod tests { } mod event_module { - use crate::dispatch::Result; + use crate::dispatch::DispatchResult; pub trait Trait { type Origin; @@ -296,7 +302,19 @@ mod tests { decl_module! { pub struct Module for enum Call where origin: T::Origin { - fn aux_0(_origin) -> Result { unreachable!() } + type Error = Error; + + fn aux_0(_origin) -> DispatchResult { unreachable!() } + } + } + + crate::decl_error! { + pub enum Error { + /// Some user input error + UserInputError, + /// Something bad happened + /// this could be due to many reasons + BadThingHappened, } } } @@ -447,6 +465,7 @@ mod tests { } ]) ), + errors: DecodeDifferent::Encode(FnEncode(|| &[])), }, ModuleMetadata { name: DecodeDifferent::Encode("Module"), @@ -469,6 +488,19 @@ mod tests { ]) )), constants: DecodeDifferent::Encode(FnEncode(|| &[])), + errors: DecodeDifferent::Encode(FnEncode(|| &[ + ErrorMetadata { + name: DecodeDifferent::Encode("UserInputError"), + documentation: DecodeDifferent::Encode(&[" Some user input error"]), + }, + ErrorMetadata { + name: DecodeDifferent::Encode("BadThingHappened"), + documentation: DecodeDifferent::Encode(&[ + " Something bad happened", + " this could be due to many reasons", + ]), + }, + ])), }, ModuleMetadata { name: DecodeDifferent::Encode("Module2"), @@ -505,6 +537,7 @@ mod tests { ]) )), constants: DecodeDifferent::Encode(FnEncode(|| &[])), + errors: DecodeDifferent::Encode(FnEncode(|| &[])), }, ]) }; diff --git a/srml/support/test/tests/system.rs b/srml/support/test/tests/system.rs index 1040b26cc6..f1a427060a 100644 --- a/srml/support/test/tests/system.rs +++ b/srml/support/test/tests/system.rs @@ -29,7 +29,10 @@ support::decl_event!( support::decl_error! { pub enum Error { + /// Test error documentation TestError, + /// Error documentation + /// with multiple lines AnotherError } } -- GitLab From 607d7e833edd4db346e4aa14983a9af3f92d2756 Mon Sep 17 00:00:00 2001 From: Jim Posen Date: Tue, 8 Oct 2019 12:57:12 +0200 Subject: [PATCH 022/167] Refactor NativeExecutor to support multiple Wasm execution methods (#3677) * executor: Move definitions of externals out of wasm_executor module. * executor: Create WasmRuntime trait. This will be used to decouple the runtime cache from wasmi execution. * executor: Remove WasmExecutor and move methods to wasmi_execution. These will now be crate-internal functions and there is no need for the struct. * executor: Set default default_heap_pages in NativeExecutor. * cli: CLI configuration for Wasm execution method. * executor: Remove wasmi-specific code from wasm_runtime. * Respond to review comments. --- core/cli/src/lib.rs | 3 + core/cli/src/params.rs | 43 +- core/client/src/genesis.rs | 2 +- core/client/src/lib.rs | 4 +- core/client/src/light/call_executor.rs | 12 +- core/client/src/light/fetcher.rs | 40 +- core/executor/src/error.rs | 15 + .../{wasm_executor.rs => host_interface.rs} | 803 +--------------- core/executor/src/lib.rs | 8 +- core/executor/src/native_executor.rs | 111 +-- core/executor/src/sandbox.rs | 37 +- core/executor/src/wasm_runtime.rs | 173 ++++ core/executor/src/wasm_runtimes_cache.rs | 353 ------- core/executor/src/wasmi_execution.rs | 902 ++++++++++++++++++ core/service/src/builder.rs | 10 +- core/service/src/config.rs | 4 + core/service/test/src/lib.rs | 1 + core/sr-api-macros/tests/runtime_calls.rs | 2 +- core/test-client/src/lib.rs | 12 +- core/test-runtime/client/src/lib.rs | 4 +- core/test-runtime/src/system.rs | 51 +- node/executor/src/lib.rs | 6 +- 22 files changed, 1359 insertions(+), 1237 deletions(-) rename core/executor/src/{wasm_executor.rs => host_interface.rs} (61%) create mode 100644 core/executor/src/wasm_runtime.rs delete mode 100644 core/executor/src/wasm_runtimes_cache.rs create mode 100644 core/executor/src/wasmi_execution.rs diff --git a/core/cli/src/lib.rs b/core/cli/src/lib.rs index 2e7619116c..d4bb4f6f0d 100644 --- a/core/cli/src/lib.rs +++ b/core/cli/src/lib.rs @@ -380,6 +380,7 @@ impl<'a> ParseAndPrepareImport<'a> { Exit: IntoExit { let mut config = create_config_with_db_path(spec_factory, &self.params.shared_params, self.version)?; + config.wasm_method = self.params.wasm_method.into(); config.execution_strategies = ExecutionStrategies { importing: self.params.execution.into(), other: self.params.execution.into(), @@ -692,6 +693,8 @@ where service::Roles::FULL }; + config.wasm_method = cli.wasm_method.into(); + let exec = cli.execution_strategies; let exec_all_or = |strat: params::ExecutionStrategy| exec.execution.unwrap_or(strat).into(); config.execution_strategies = ExecutionStrategies { diff --git a/core/cli/src/params.rs b/core/cli/src/params.rs index 6656e1653f..b453c7dabd 100644 --- a/core/cli/src/params.rs +++ b/core/cli/src/params.rs @@ -18,7 +18,6 @@ use crate::traits::{AugmentClap, GetLogFilter}; use std::path::PathBuf; use structopt::{StructOpt, clap::{arg_enum, App, AppSettings, _clap_count_exprs, SubCommand, Arg}}; -use client; pub use crate::execution_strategy::ExecutionStrategy; @@ -44,6 +43,24 @@ impl Into for ExecutionStrategy { } } +arg_enum! { + /// How to execute Wasm runtime code + #[allow(missing_docs)] + #[derive(Debug, Clone)] + pub enum WasmExecutionMethod { + // Uses an interpreter. + Interpreted, + } +} + +impl Into for WasmExecutionMethod { + fn into(self) -> service::config::WasmExecutionMethod { + match self { + WasmExecutionMethod::Interpreted => service::config::WasmExecutionMethod::Interpreted, + } + } +} + arg_enum! { /// Whether off-chain workers are enabled. #[allow(missing_docs)] @@ -404,6 +421,18 @@ pub struct RunCmd { )] pub offchain_worker: OffchainWorkerEnabled, + /// Method for executing Wasm runtime code. + #[structopt( + long = "wasm-execution", + value_name = "METHOD", + raw( + possible_values = "&WasmExecutionMethod::variants()", + case_insensitive = "true", + default_value = r#""Interpreted""# + ) + )] + pub wasm_method: WasmExecutionMethod, + #[allow(missing_docs)] #[structopt(flatten)] pub execution_strategies: ExecutionStrategies, @@ -651,6 +680,18 @@ pub struct ImportBlocksCmd { #[structopt(flatten)] pub shared_params: SharedParams, + /// Method for executing Wasm runtime code. + #[structopt( + long = "wasm-execution", + value_name = "METHOD", + raw( + possible_values = "&WasmExecutionMethod::variants()", + case_insensitive = "true", + default_value = r#""Interpreted""# + ) + )] + pub wasm_method: WasmExecutionMethod, + /// The means of execution used when calling into the runtime while importing blocks. #[structopt( long = "execution", diff --git a/core/client/src/genesis.rs b/core/client/src/genesis.rs index 0c0d49f8ea..51e0536613 100644 --- a/core/client/src/genesis.rs +++ b/core/client/src/genesis.rs @@ -63,7 +63,7 @@ mod tests { ); fn executor() -> executor::NativeExecutor { - executor::NativeExecutor::new(None) + executor::NativeExecutor::new(executor::WasmExecutionMethod::Interpreted, None) } fn construct_block( diff --git a/core/client/src/lib.rs b/core/client/src/lib.rs index 70c9b75926..5a2cb746f3 100644 --- a/core/client/src/lib.rs +++ b/core/client/src/lib.rs @@ -49,7 +49,7 @@ //! use substrate_client::{Client, in_mem::Backend, LocalCallExecutor}; //! use primitives::Blake2Hasher; //! use sr_primitives::{StorageOverlay, ChildrenStorageOverlay}; -//! use executor::NativeExecutor; +//! use executor::{NativeExecutor, WasmExecutionMethod}; //! //! // In this example, we're using the `Block` and `RuntimeApi` types from the //! // `substrate-test-runtime-client` crate. These types are automatically generated when @@ -62,7 +62,7 @@ //! backend.clone(), //! LocalCallExecutor::new( //! backend.clone(), -//! NativeExecutor::::new(None), +//! NativeExecutor::::new(WasmExecutionMethod::Interpreted, None), //! None, //! ), //! // This parameter provides the storage for the chain genesis. diff --git a/core/client/src/light/call_executor.rs b/core/client/src/light/call_executor.rs index ec182cca11..d969c39a5a 100644 --- a/core/client/src/light/call_executor.rs +++ b/core/client/src/light/call_executor.rs @@ -304,7 +304,7 @@ mod tests { use consensus::BlockOrigin; use primitives::offchain::NeverOffchainExt; use test_client::{self, runtime::{Header, Digest, Block}, ClientExt, TestClient}; - use executor::NativeExecutor; + use executor::{NativeExecutor, WasmExecutionMethod}; use crate::backend::{Backend, NewBlockState}; use crate::in_mem::Backend as InMemBackend; use super::*; @@ -399,6 +399,10 @@ mod tests { } } + fn local_executor() -> NativeExecutor { + NativeExecutor::new(WasmExecutionMethod::Interpreted, None) + } + #[test] fn execution_proof_is_generated_and_checked() { fn execute(remote_client: &TestClient, at: u64, method: &'static str) -> (Vec, Vec) { @@ -413,8 +417,7 @@ mod tests { ).unwrap(); // check remote execution proof locally - let local_executor = NativeExecutor::::new(None); - let local_result = check_execution_proof(&local_executor, &RemoteCallRequest { + let local_result = check_execution_proof(&local_executor(), &RemoteCallRequest { block: test_client::runtime::Hash::default(), header: remote_header, method: method.into(), @@ -437,9 +440,8 @@ mod tests { ).unwrap(); // check remote execution proof locally - let local_executor = NativeExecutor::::new(None); let execution_result = check_execution_proof_with_make_header( - &local_executor, + &local_executor(), &RemoteCallRequest { block: test_client::runtime::Hash::default(), header: remote_header, diff --git a/core/client/src/light/fetcher.rs b/core/client/src/light/fetcher.rs index 3c4387209a..51e1ed3b81 100644 --- a/core/client/src/light/fetcher.rs +++ b/core/client/src/light/fetcher.rs @@ -503,7 +503,7 @@ pub mod tests { use parking_lot::Mutex; use codec::Decode; use crate::client::tests::prepare_client_with_key_changes; - use executor::{self, NativeExecutor}; + use executor::{NativeExecutor, WasmExecutionMethod}; use crate::error::Error as ClientError; use test_client::{ self, ClientExt, blockchain::HeaderBackend, AccountKeyring, @@ -563,12 +563,16 @@ pub mod tests { } type TestChecker = LightDataChecker< - executor::NativeExecutor, + NativeExecutor, Blake2Hasher, Block, DummyStorage, >; + fn local_executor() -> NativeExecutor { + NativeExecutor::new(WasmExecutionMethod::Interpreted, None) + } + fn prepare_for_read_proof_check() -> (TestChecker, Header, Vec>, u32) { // prepare remote client let remote_client = test_client::new(); @@ -596,8 +600,10 @@ pub mod tests { None, crate::backend::NewBlockState::Final, ).unwrap(); - let local_executor = NativeExecutor::::new(None); - let local_checker = LightDataChecker::new(Arc::new(DummyBlockchain::new(DummyStorage::new())), local_executor); + let local_checker = LightDataChecker::new( + Arc::new(DummyBlockchain::new(DummyStorage::new())), + local_executor() + ); (local_checker, remote_block_header, remote_read_proof, heap_pages) } @@ -636,8 +642,10 @@ pub mod tests { None, crate::backend::NewBlockState::Final, ).unwrap(); - let local_executor = NativeExecutor::::new(None); - let local_checker = LightDataChecker::new(Arc::new(DummyBlockchain::new(DummyStorage::new())), local_executor); + let local_checker = LightDataChecker::new( + Arc::new(DummyBlockchain::new(DummyStorage::new())), + local_executor(), + ); (local_checker, remote_block_header, remote_read_proof, child_value) } @@ -662,8 +670,10 @@ pub mod tests { if insert_cht { local_storage.insert_cht_root(1, local_cht_root); } - let local_executor = NativeExecutor::::new(None); - let local_checker = LightDataChecker::new(Arc::new(DummyBlockchain::new(DummyStorage::new())), local_executor); + let local_checker = LightDataChecker::new( + Arc::new(DummyBlockchain::new(DummyStorage::new())), + local_executor(), + ); (local_checker, local_cht_root, remote_block_header, remote_header_proof) } @@ -744,7 +754,7 @@ pub mod tests { let (remote_client, local_roots, test_cases) = prepare_client_with_key_changes(); let local_checker = TestChecker::new( Arc::new(DummyBlockchain::new(DummyStorage::new())), - NativeExecutor::::new(None) + local_executor(), ); let local_checker = &local_checker as &dyn FetchChecker; let max = remote_client.info().chain.best_number; @@ -813,7 +823,7 @@ pub mod tests { local_storage.changes_tries_cht_roots.insert(0, local_cht_root); let local_checker = TestChecker::new( Arc::new(DummyBlockchain::new(local_storage)), - NativeExecutor::::new(None) + local_executor(), ); // check proof on local client @@ -842,7 +852,7 @@ pub mod tests { let (remote_client, local_roots, test_cases) = prepare_client_with_key_changes(); let local_checker = TestChecker::new( Arc::new(DummyBlockchain::new(DummyStorage::new())), - NativeExecutor::::new(None) + local_executor(), ); let local_checker = &local_checker as &dyn FetchChecker; let max = remote_client.info().chain.best_number; @@ -924,7 +934,7 @@ pub mod tests { // fails when changes trie CHT is missing from the local db let local_checker = TestChecker::new( Arc::new(DummyBlockchain::new(DummyStorage::new())), - NativeExecutor::::new(None) + local_executor(), ); assert!(local_checker.check_changes_tries_proof(4, &remote_proof.roots, remote_proof.roots_proof.clone()).is_err()); @@ -934,7 +944,7 @@ pub mod tests { local_storage.changes_tries_cht_roots.insert(0, local_cht_root); let local_checker = TestChecker::new( Arc::new(DummyBlockchain::new(local_storage)), - NativeExecutor::::new(None) + local_executor(), ); assert!(local_checker.check_changes_tries_proof(4, &remote_proof.roots, vec![]).is_err()); } @@ -948,7 +958,7 @@ pub mod tests { let local_checker = TestChecker::new( Arc::new(DummyBlockchain::new(DummyStorage::new())), - NativeExecutor::::new(None) + local_executor(), ); let body_request = RemoteBodyRequest { @@ -971,7 +981,7 @@ pub mod tests { let local_checker = TestChecker::new( Arc::new(DummyBlockchain::new(DummyStorage::new())), - NativeExecutor::::new(None) + local_executor(), ); let body_request = RemoteBodyRequest { diff --git a/core/executor/src/error.rs b/core/executor/src/error.rs index c5148241ee..6b3c45ee49 100644 --- a/core/executor/src/error.rs +++ b/core/executor/src/error.rs @@ -98,3 +98,18 @@ impl From for Error { Error::Other(err) } } + +/// Type for errors occurring during Wasm runtime construction. +#[derive(Debug, derive_more::Display)] +pub enum WasmError { + /// Code could not be read from the state. + CodeNotFound, + /// Failure to reinitialize runtime instance from snapshot. + ApplySnapshotFailed, + /// Wasm code failed validation. + InvalidModule, + /// Wasm code could not be deserialized. + CantDeserializeWasm, + /// Instantiation error. + Instantiation(Error), +} diff --git a/core/executor/src/wasm_executor.rs b/core/executor/src/host_interface.rs similarity index 61% rename from core/executor/src/wasm_executor.rs rename to core/executor/src/host_interface.rs index 6ded0adad6..7c99415f6c 100644 --- a/core/executor/src/wasm_executor.rs +++ b/core/executor/src/host_interface.rs @@ -14,33 +14,20 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -//! Wasm interface module. +//! Definition and implementation of the Substrate Wasm host interface. //! -//! This module defines and implements the wasm part of Substrate Host Interface and provides -//! an interface for calling into the wasm runtime. +//! These are the host functions callable from within the Substrate runtime. -use std::{convert::TryFrom, str, panic}; -use tiny_keccak; -use secp256k1; +use crate::error::{Error, Result}; -use wasmi::{ - Module, ModuleInstance, MemoryInstance, MemoryRef, TableRef, ImportsBuilder, ModuleRef, - memory_units::Pages, RuntimeValue::{I32, I64, self}, -}; -use super::{sandbox, allocator, error::{Error, Result}}; -use codec::{Encode, Decode}; +use codec::Encode; +use std::{convert::TryFrom, str, panic}; use primitives::{ - blake2_128, blake2_256, twox_64, twox_128, twox_256, ed25519, sr25519, Pair, crypto::KeyTypeId, - offchain, sandbox as sandbox_primitives, Blake2Hasher, - traits::Externalities, -}; -use trie::TrieConfiguration; -use trie::trie_types::Layout; -use log::trace; -use wasm_interface::{ - FunctionContext, HostFunctions, Pointer, WordSize, Sandbox, MemoryId, PointerType, - Result as WResult, + blake2_128, blake2_256, twox_64, twox_128, twox_256, ed25519, sr25519, Blake2Hasher, Pair, + crypto::KeyTypeId, offchain, }; +use trie::{TrieConfiguration, trie_types::Layout}; +use wasm_interface::{FunctionContext, Pointer, PointerType, Result as WResult, WordSize}; #[cfg(feature="wasm-extern-trace")] macro_rules! debug_trace { @@ -52,317 +39,7 @@ macro_rules! debug_trace { ( $( $x:tt )* ) => () } -struct FunctionExecutor { - sandbox_store: sandbox::Store, - heap: allocator::FreeingBumpHeapAllocator, - memory: MemoryRef, - table: Option, -} - -impl FunctionExecutor { - fn new(m: MemoryRef, heap_base: u32, t: Option) -> Result { - Ok(FunctionExecutor { - sandbox_store: sandbox::Store::new(), - heap: allocator::FreeingBumpHeapAllocator::new(heap_base), - memory: m, - table: t, - }) - } -} - -impl sandbox::SandboxCapabilities for FunctionExecutor { - type SupervisorFuncRef = wasmi::FuncRef; - - fn store(&self) -> &sandbox::Store { - &self.sandbox_store - } - fn store_mut(&mut self) -> &mut sandbox::Store { - &mut self.sandbox_store - } - fn allocate(&mut self, len: WordSize) -> Result> { - let heap = &mut self.heap; - self.memory.with_direct_access_mut(|mem| { - heap.allocate(mem, len) - }) - } - fn deallocate(&mut self, ptr: Pointer) -> Result<()> { - let heap = &mut self.heap; - self.memory.with_direct_access_mut(|mem| { - heap.deallocate(mem, ptr) - }) - } - fn write_memory(&mut self, ptr: Pointer, data: &[u8]) -> Result<()> { - self.memory.set(ptr.into(), data).map_err(Into::into) - } - fn read_memory(&self, ptr: Pointer, len: WordSize) -> Result> { - self.memory.get(ptr.into(), len as usize).map_err(Into::into) - } - - fn invoke( - &mut self, - dispatch_thunk: &Self::SupervisorFuncRef, - invoke_args_ptr: Pointer, - invoke_args_len: WordSize, - state: u32, - func_idx: sandbox::SupervisorFuncIndex, - ) -> Result - { - let result = wasmi::FuncInstance::invoke( - dispatch_thunk, - &[ - RuntimeValue::I32(u32::from(invoke_args_ptr) as i32), - RuntimeValue::I32(invoke_args_len as i32), - RuntimeValue::I32(state as i32), - RuntimeValue::I32(usize::from(func_idx) as i32), - ], - self, - ); - match result { - Ok(Some(RuntimeValue::I64(val))) => Ok(val), - Ok(_) => return Err("Supervisor function returned unexpected result!".into()), - Err(err) => Err(Error::Trap(err)), - } - } -} - -impl FunctionContext for FunctionExecutor { - fn read_memory_into(&self, address: Pointer, dest: &mut [u8]) -> WResult<()> { - self.memory.get_into(address.into(), dest).map_err(|e| format!("{:?}", e)) - } - - fn write_memory(&mut self, address: Pointer, data: &[u8]) -> WResult<()> { - self.memory.set(address.into(), data).map_err(|e| format!("{:?}", e)) - } - - fn allocate_memory(&mut self, size: WordSize) -> WResult> { - let heap = &mut self.heap; - self.memory.with_direct_access_mut(|mem| { - heap.allocate(mem, size).map_err(|e| format!("{:?}", e)) - }) - } - - fn deallocate_memory(&mut self, ptr: Pointer) -> WResult<()> { - let heap = &mut self.heap; - self.memory.with_direct_access_mut(|mem| { - heap.deallocate(mem, ptr).map_err(|e| format!("{:?}", e)) - }) - } - - fn sandbox(&mut self) -> &mut dyn Sandbox { - self - } -} - -impl Sandbox for FunctionExecutor { - fn memory_get( - &self, - memory_id: MemoryId, - offset: WordSize, - buf_ptr: Pointer, - buf_len: WordSize, - ) -> WResult { - let sandboxed_memory = self.sandbox_store.memory(memory_id).map_err(|e| format!("{:?}", e))?; - - match MemoryInstance::transfer( - &sandboxed_memory, - offset as usize, - &self.memory, - buf_ptr.into(), - buf_len as usize, - ) { - Ok(()) => Ok(sandbox_primitives::ERR_OK), - Err(_) => Ok(sandbox_primitives::ERR_OUT_OF_BOUNDS), - } - } - - fn memory_set( - &mut self, - memory_id: MemoryId, - offset: WordSize, - val_ptr: Pointer, - val_len: WordSize, - ) -> WResult { - let sandboxed_memory = self.sandbox_store.memory(memory_id).map_err(|e| format!("{:?}", e))?; - - match MemoryInstance::transfer( - &self.memory, - val_ptr.into(), - &sandboxed_memory, - offset as usize, - val_len as usize, - ) { - Ok(()) => Ok(sandbox_primitives::ERR_OK), - Err(_) => Ok(sandbox_primitives::ERR_OUT_OF_BOUNDS), - } - } - - fn memory_teardown(&mut self, memory_id: MemoryId) -> WResult<()> { - self.sandbox_store.memory_teardown(memory_id).map_err(|e| format!("{:?}", e)) - } - - fn memory_new( - &mut self, - initial: u32, - maximum: u32, - ) -> WResult { - self.sandbox_store.new_memory(initial, maximum).map_err(|e| format!("{:?}", e)) - } - - fn invoke( - &mut self, - instance_id: u32, - export_name: &str, - args: &[u8], - return_val: Pointer, - return_val_len: WordSize, - state: u32, - ) -> WResult { - trace!(target: "sr-sandbox", "invoke, instance_idx={}", instance_id); - - // Deserialize arguments and convert them into wasmi types. - let args = Vec::::decode(&mut &args[..]) - .map_err(|_| "Can't decode serialized arguments for the invocation")? - .into_iter() - .map(Into::into) - .collect::>(); - - let instance = self.sandbox_store.instance(instance_id).map_err(|e| format!("{:?}", e))?; - let result = instance.invoke(export_name, &args, self, state); - - match result { - Ok(None) => Ok(sandbox_primitives::ERR_OK), - Ok(Some(val)) => { - // Serialize return value and write it back into the memory. - sandbox_primitives::ReturnValue::Value(val.into()).using_encoded(|val| { - if val.len() > return_val_len as usize { - Err("Return value buffer is too small")?; - } - self.write_memory(return_val, val).map_err(|_| "Return value buffer is OOB")?; - Ok(sandbox_primitives::ERR_OK) - }) - } - Err(_) => Ok(sandbox_primitives::ERR_EXECUTION), - } - } - - fn instance_teardown(&mut self, instance_id: u32) -> WResult<()> { - self.sandbox_store.instance_teardown(instance_id).map_err(|e| format!("{:?}", e)) - } - - fn instance_new( - &mut self, - dispatch_thunk_id: u32, - wasm: &[u8], - raw_env_def: &[u8], - state: u32, - ) -> WResult { - // Extract a dispatch thunk from instance's table by the specified index. - let dispatch_thunk = { - let table = self.table.as_ref() - .ok_or_else(|| "Runtime doesn't have a table; sandbox is unavailable")?; - table.get(dispatch_thunk_id) - .map_err(|_| "dispatch_thunk_idx is out of the table bounds")? - .ok_or_else(|| "dispatch_thunk_idx points on an empty table entry")? - .clone() - }; - - let instance_idx_or_err_code = - match sandbox::instantiate(self, dispatch_thunk, wasm, raw_env_def, state) { - Ok(instance_idx) => instance_idx, - Err(sandbox::InstantiationError::StartTrapped) => - sandbox_primitives::ERR_EXECUTION, - Err(_) => sandbox_primitives::ERR_MODULE, - }; - - Ok(instance_idx_or_err_code as u32) - } -} - -trait WritePrimitive { - fn write_primitive(&mut self, ptr: Pointer, t: T) -> WResult<()>; -} - -impl WritePrimitive for &mut dyn FunctionContext { - fn write_primitive(&mut self, ptr: Pointer, t: u32) -> WResult<()> { - let r = t.to_le_bytes(); - self.write_memory(ptr.cast(), &r) - } -} - -trait ReadPrimitive { - fn read_primitive(&self, offset: Pointer) -> WResult; -} - -impl ReadPrimitive for &mut dyn FunctionContext { - fn read_primitive(&self, ptr: Pointer) -> WResult { - let mut r = [0u8; 4]; - self.read_memory_into(ptr.cast(), &mut r)?; - Ok(u32::from_le_bytes(r)) - } -} - -fn deadline_to_timestamp(deadline: u64) -> Option { - if deadline == 0 { - None - } else { - Some(offchain::Timestamp::from_unix_millis(deadline)) - } -} - -impl FunctionExecutor { - fn resolver() -> &'static dyn wasmi::ModuleImportResolver { - struct Resolver; - impl wasmi::ModuleImportResolver for Resolver { - fn resolve_func(&self, name: &str, signature: &wasmi::Signature) - -> std::result::Result - { - let signature = wasm_interface::Signature::from(signature); - - if let Some((index, func)) = SubstrateExternals::functions().iter() - .enumerate() - .find(|f| name == f.1.name()) - { - if signature == func.signature() { - Ok(wasmi::FuncInstance::alloc_host(signature.into(), index)) - } else { - Err(wasmi::Error::Instantiation( - format!( - "Invalid signature for function `{}` expected `{:?}`, got `{:?}`", - func.name(), - signature, - func.signature(), - ) - )) - } - } else { - Err(wasmi::Error::Instantiation( - format!("Export {} not found", name), - )) - } - } - } - &Resolver - } -} - -impl wasmi::Externals for FunctionExecutor { - fn invoke_index(&mut self, index: usize, args: wasmi::RuntimeArgs) - -> std::result::Result, wasmi::Trap> - { - let mut args = args.as_ref().iter().copied().map(Into::into); - let function = SubstrateExternals::functions().get(index).ok_or_else(|| - Error::from( - format!("Could not find host function with index: {}", index), - ) - )?; - - function.execute(self, &mut args) - .map_err(Error::FunctionExecution) - .map_err(wasmi::Trap::from) - .map(|v| v.map(Into::into)) - } -} -struct SubstrateExternals; +pub struct SubstrateExternals; impl_wasm_host_interface! { impl SubstrateExternals where context { @@ -1400,6 +1077,29 @@ impl_wasm_host_interface! { } } +trait WritePrimitive { + fn write_primitive(&mut self, ptr: Pointer, t: T) -> WResult<()>; +} + +impl WritePrimitive for &mut dyn FunctionContext { + fn write_primitive(&mut self, ptr: Pointer, t: u32) -> WResult<()> { + let r = t.to_le_bytes(); + self.write_memory(ptr.cast(), &r) + } +} + +trait ReadPrimitive { + fn read_primitive(&self, offset: Pointer) -> WResult; +} + +impl ReadPrimitive for &mut dyn FunctionContext { + fn read_primitive(&self, ptr: Pointer) -> WResult { + let mut r = [0u8; 4]; + self.read_memory_into(ptr.cast(), &mut r)?; + Ok(u32::from_le_bytes(r)) + } +} + /// Execute closure that access external storage. /// /// All panics that happen within closure are captured and transformed into @@ -1419,438 +1119,11 @@ fn with_external_storage(f: F) -> std::result::Result .map_err(|err| format!("{}", err)) } -/// Wasm rust executor for contracts. -/// -/// Executes the provided code in a sandboxed wasm runtime. -#[derive(Debug, Clone)] -pub struct WasmExecutor; - -impl WasmExecutor { - /// Create a new instance. - pub fn new() -> Self { - WasmExecutor - } - - /// Call a given method in the given code. - /// - /// Signature of this method needs to be `(I32, I32) -> I64`. - /// - /// This should be used for tests only. - pub fn call>( - &self, - ext: &mut E, - heap_pages: usize, - code: &[u8], - method: &str, - data: &[u8], - ) -> Result> { - let module = wasmi::Module::from_buffer(code)?; - let module = Self::instantiate_module(heap_pages, &module)?; - - self.call_in_wasm_module(ext, &module, method, data) - } - - /// Call a given method with a custom signature in the given code. - /// - /// This should be used for tests only. - pub fn call_with_custom_signature< - E: Externalities, - F: FnOnce(&mut dyn FnMut(&[u8]) -> Result) -> Result>, - FR: FnOnce(Option, &MemoryRef) -> Result>, - R, - >( - &self, - ext: &mut E, - heap_pages: usize, - code: &[u8], - method: &str, - create_parameters: F, - filter_result: FR, - ) -> Result { - let module = wasmi::Module::from_buffer(code)?; - let module = Self::instantiate_module(heap_pages, &module)?; - - self.call_in_wasm_module_with_custom_signature( - ext, - &module, - method, - create_parameters, - filter_result, - ) - } - - fn get_mem_instance(module: &ModuleRef) -> Result { - Ok(module - .export_by_name("memory") - .ok_or_else(|| Error::InvalidMemoryReference)? - .as_memory() - .ok_or_else(|| Error::InvalidMemoryReference)? - .clone()) - } - - /// Find the global named `__heap_base` in the given wasm module instance and - /// tries to get its value. - fn get_heap_base(module: &ModuleRef) -> Result { - let heap_base_val = module - .export_by_name("__heap_base") - .ok_or_else(|| Error::HeapBaseNotFoundOrInvalid)? - .as_global() - .ok_or_else(|| Error::HeapBaseNotFoundOrInvalid)? - .get(); - - match heap_base_val { - wasmi::RuntimeValue::I32(v) => Ok(v as u32), - _ => Err(Error::HeapBaseNotFoundOrInvalid), - } - } - - /// Call a given method in the given wasm-module runtime. - pub fn call_in_wasm_module>( - &self, - ext: &mut E, - module_instance: &ModuleRef, - method: &str, - data: &[u8], - ) -> Result> { - self.call_in_wasm_module_with_custom_signature( - ext, - module_instance, - method, - |alloc| { - let offset = alloc(data)?; - Ok(vec![I32(offset as i32), I32(data.len() as i32)]) - }, - |res, memory| { - if let Some(I64(r)) = res { - let offset = r as u32; - let length = (r as u64 >> 32) as usize; - memory.get(offset, length).map_err(|_| Error::Runtime).map(Some) - } else { - Ok(None) - } - } - ) - } - - /// Call a given method in the given wasm-module runtime. - fn call_in_wasm_module_with_custom_signature< - E: Externalities, - F: FnOnce(&mut dyn FnMut(&[u8]) -> Result) -> Result>, - FR: FnOnce(Option, &MemoryRef) -> Result>, - R, - >( - &self, - ext: &mut E, - module_instance: &ModuleRef, - method: &str, - create_parameters: F, - filter_result: FR, - ) -> Result { - // extract a reference to a linear memory, optional reference to a table - // and then initialize FunctionExecutor. - let memory = Self::get_mem_instance(module_instance)?; - let table: Option = module_instance - .export_by_name("__indirect_function_table") - .and_then(|e| e.as_table().cloned()); - let heap_base = Self::get_heap_base(module_instance)?; - - let mut fec = FunctionExecutor::new( - memory.clone(), - heap_base, - table, - )?; - - let parameters = create_parameters(&mut |data: &[u8]| { - let offset = fec.allocate_memory(data.len() as u32)?; - fec.write_memory(offset, data).map(|_| offset.into()).map_err(Into::into) - })?; - - let result = runtime_io::with_externalities( - ext, - || module_instance.invoke_export(method, ¶meters, &mut fec), - ); - - match result { - Ok(val) => match filter_result(val, &memory)? { - Some(val) => Ok(val), - None => Err(Error::InvalidReturn), - }, - Err(e) => { - trace!( - target: "wasm-executor", - "Failed to execute code with {} pages", - memory.current_size().0 - ); - Err(e.into()) - }, - } - } - - /// Prepare module instance - pub fn instantiate_module( - heap_pages: usize, - module: &Module, - ) -> Result { - // start module instantiation. Don't run 'start' function yet. - let intermediate_instance = ModuleInstance::new( - module, - &ImportsBuilder::new() - .with_resolver("env", FunctionExecutor::resolver()) - )?; - - // Verify that the module has the heap base global variable. - let _ = Self::get_heap_base(intermediate_instance.not_started_instance())?; - - // Extract a reference to a linear memory. - let memory = Self::get_mem_instance(intermediate_instance.not_started_instance())?; - memory.grow(Pages(heap_pages)).map_err(|_| Error::Runtime)?; - - if intermediate_instance.has_start() { - // Runtime is not allowed to have the `start` function. - Err(Error::RuntimeHasStartFn) - } else { - Ok(intermediate_instance.assert_no_start()) - } +fn deadline_to_timestamp(deadline: u64) -> Option { + if deadline == 0 { + None + } else { + Some(offchain::Timestamp::from_unix_millis(deadline)) } } - -#[cfg(test)] -mod tests { - use super::*; - - use codec::Encode; - - use state_machine::TestExternalities as CoreTestExternalities; - use hex_literal::hex; - use primitives::map; - use runtime_test::WASM_BINARY; - use substrate_offchain::testing; - - type TestExternalities = CoreTestExternalities; - - #[test] - fn returning_should_work() { - let mut ext = TestExternalities::default(); - let test_code = WASM_BINARY; - - let output = WasmExecutor::new().call(&mut ext, 8, &test_code[..], "test_empty_return", &[]).unwrap(); - assert_eq!(output, vec![0u8; 0]); - } - - #[test] - fn panicking_should_work() { - let mut ext = TestExternalities::default(); - let test_code = WASM_BINARY; - - let output = WasmExecutor::new().call(&mut ext, 8, &test_code[..], "test_panic", &[]); - assert!(output.is_err()); - - let output = WasmExecutor::new().call(&mut ext, 8, &test_code[..], "test_conditional_panic", &[]); - assert_eq!(output.unwrap(), vec![0u8; 0]); - - let output = WasmExecutor::new().call(&mut ext, 8, &test_code[..], "test_conditional_panic", &[2]); - assert!(output.is_err()); - } - - #[test] - fn storage_should_work() { - let mut ext = TestExternalities::default(); - ext.set_storage(b"foo".to_vec(), b"bar".to_vec()); - let test_code = WASM_BINARY; - - let output = WasmExecutor::new().call(&mut ext, 8, &test_code[..], "test_data_in", b"Hello world").unwrap(); - - assert_eq!(output, b"all ok!".to_vec()); - - let expected = TestExternalities::new((map![ - b"input".to_vec() => b"Hello world".to_vec(), - b"foo".to_vec() => b"bar".to_vec(), - b"baz".to_vec() => b"bar".to_vec() - ], map![])); - assert_eq!(ext, expected); - } - - #[test] - fn clear_prefix_should_work() { - let mut ext = TestExternalities::default(); - ext.set_storage(b"aaa".to_vec(), b"1".to_vec()); - ext.set_storage(b"aab".to_vec(), b"2".to_vec()); - ext.set_storage(b"aba".to_vec(), b"3".to_vec()); - ext.set_storage(b"abb".to_vec(), b"4".to_vec()); - ext.set_storage(b"bbb".to_vec(), b"5".to_vec()); - let test_code = WASM_BINARY; - - // This will clear all entries which prefix is "ab". - let output = WasmExecutor::new().call(&mut ext, 8, &test_code[..], "test_clear_prefix", b"ab").unwrap(); - - assert_eq!(output, b"all ok!".to_vec()); - - let expected = TestExternalities::new((map![ - b"aaa".to_vec() => b"1".to_vec(), - b"aab".to_vec() => b"2".to_vec(), - b"bbb".to_vec() => b"5".to_vec() - ], map![])); - assert_eq!(expected, ext); - } - - #[test] - fn blake2_256_should_work() { - let mut ext = TestExternalities::default(); - let test_code = WASM_BINARY; - assert_eq!( - WasmExecutor::new().call(&mut ext, 8, &test_code[..], "test_blake2_256", &[]).unwrap(), - blake2_256(&b""[..]).encode() - ); - assert_eq!( - WasmExecutor::new().call(&mut ext, 8, &test_code[..], "test_blake2_256", b"Hello world!").unwrap(), - blake2_256(&b"Hello world!"[..]).encode() - ); - } - - #[test] - fn blake2_128_should_work() { - let mut ext = TestExternalities::default(); - let test_code = WASM_BINARY; - assert_eq!( - WasmExecutor::new().call(&mut ext, 8, &test_code[..], "test_blake2_128", &[]).unwrap(), - blake2_128(&b""[..]).encode() - ); - assert_eq!( - WasmExecutor::new().call(&mut ext, 8, &test_code[..], "test_blake2_128", b"Hello world!").unwrap(), - blake2_128(&b"Hello world!"[..]).encode() - ); - } - - #[test] - fn twox_256_should_work() { - let mut ext = TestExternalities::default(); - let test_code = WASM_BINARY; - assert_eq!( - WasmExecutor::new().call(&mut ext, 8, &test_code[..], "test_twox_256", &[]).unwrap(), - hex!("99e9d85137db46ef4bbea33613baafd56f963c64b1f3685a4eb4abd67ff6203a"), - ); - assert_eq!( - WasmExecutor::new().call(&mut ext, 8, &test_code[..], "test_twox_256", b"Hello world!").unwrap(), - hex!("b27dfd7f223f177f2a13647b533599af0c07f68bda23d96d059da2b451a35a74"), - ); - } - - #[test] - fn twox_128_should_work() { - let mut ext = TestExternalities::default(); - let test_code = WASM_BINARY; - assert_eq!( - WasmExecutor::new().call(&mut ext, 8, &test_code[..], "test_twox_128", &[]).unwrap(), - hex!("99e9d85137db46ef4bbea33613baafd5") - ); - assert_eq!( - WasmExecutor::new().call(&mut ext, 8, &test_code[..], "test_twox_128", b"Hello world!").unwrap(), - hex!("b27dfd7f223f177f2a13647b533599af") - ); - } - - #[test] - fn ed25519_verify_should_work() { - let mut ext = TestExternalities::::default(); - let test_code = WASM_BINARY; - let key = ed25519::Pair::from_seed(&blake2_256(b"test")); - let sig = key.sign(b"all ok!"); - let mut calldata = vec![]; - calldata.extend_from_slice(key.public().as_ref()); - calldata.extend_from_slice(sig.as_ref()); - - assert_eq!( - WasmExecutor::new().call(&mut ext, 8, &test_code[..], "test_ed25519_verify", &calldata).unwrap(), - vec![1] - ); - - let other_sig = key.sign(b"all is not ok!"); - let mut calldata = vec![]; - calldata.extend_from_slice(key.public().as_ref()); - calldata.extend_from_slice(other_sig.as_ref()); - - assert_eq!( - WasmExecutor::new().call(&mut ext, 8, &test_code[..], "test_ed25519_verify", &calldata).unwrap(), - vec![0] - ); - } - - #[test] - fn sr25519_verify_should_work() { - let mut ext = TestExternalities::::default(); - let test_code = WASM_BINARY; - let key = sr25519::Pair::from_seed(&blake2_256(b"test")); - let sig = key.sign(b"all ok!"); - let mut calldata = vec![]; - calldata.extend_from_slice(key.public().as_ref()); - calldata.extend_from_slice(sig.as_ref()); - - assert_eq!( - WasmExecutor::new().call(&mut ext, 8, &test_code[..], "test_sr25519_verify", &calldata).unwrap(), - vec![1] - ); - - let other_sig = key.sign(b"all is not ok!"); - let mut calldata = vec![]; - calldata.extend_from_slice(key.public().as_ref()); - calldata.extend_from_slice(other_sig.as_ref()); - - assert_eq!( - WasmExecutor::new().call(&mut ext, 8, &test_code[..], "test_sr25519_verify", &calldata).unwrap(), - vec![0] - ); - } - - #[test] - fn ordered_trie_root_should_work() { - let mut ext = TestExternalities::::default(); - let trie_input = vec![b"zero".to_vec(), b"one".to_vec(), b"two".to_vec()]; - let test_code = WASM_BINARY; - assert_eq!( - WasmExecutor::new().call(&mut ext, 8, &test_code[..], "test_ordered_trie_root", &[]).unwrap(), - Layout::::ordered_trie_root(trie_input.iter()).as_fixed_bytes().encode() - ); - } - - #[test] - fn offchain_local_storage_should_work() { - use substrate_client::backend::OffchainStorage; - - let mut ext = TestExternalities::::default(); - let (offchain, state) = testing::TestOffchainExt::new(); - ext.set_offchain_externalities(offchain); - let test_code = WASM_BINARY; - assert_eq!( - WasmExecutor::new().call(&mut ext, 8, &test_code[..], "test_offchain_local_storage", &[]).unwrap(), - vec![0] - ); - assert_eq!(state.read().persistent_storage.get(b"", b"test"), Some(vec![])); - } - - #[test] - fn offchain_http_should_work() { - let mut ext = TestExternalities::::default(); - let (offchain, state) = testing::TestOffchainExt::new(); - ext.set_offchain_externalities(offchain); - state.write().expect_request( - 0, - testing::PendingRequest { - method: "POST".into(), - uri: "http://localhost:12345".into(), - body: vec![1, 2, 3, 4], - headers: vec![("X-Auth".to_owned(), "test".to_owned())], - sent: true, - response: Some(vec![1, 2, 3]), - response_headers: vec![("X-Auth".to_owned(), "hello".to_owned())], - ..Default::default() - }, - ); - - let test_code = WASM_BINARY; - assert_eq!( - WasmExecutor::new().call(&mut ext, 8, &test_code[..], "test_offchain_http", &[]).unwrap(), - vec![0] - ); - } -} diff --git a/core/executor/src/lib.rs b/core/executor/src/lib.rs index b5c5027951..8b833c9b08 100644 --- a/core/executor/src/lib.rs +++ b/core/executor/src/lib.rs @@ -31,24 +31,24 @@ #[macro_use] mod wasm_utils; -mod wasm_executor; +mod wasmi_execution; #[macro_use] mod native_executor; mod sandbox; mod allocator; -mod wasm_runtimes_cache; +mod host_interface; +mod wasm_runtime; pub mod error; pub use wasmi; -pub use wasm_executor::WasmExecutor; pub use native_executor::{with_native_environment, NativeExecutor, NativeExecutionDispatch}; -pub use wasm_runtimes_cache::RuntimesCache; pub use runtime_version::{RuntimeVersion, NativeVersion}; pub use codec::Codec; #[doc(hidden)] pub use primitives::{Blake2Hasher, traits::Externalities}; #[doc(hidden)] pub use wasm_interface; +pub use wasm_runtime::WasmExecutionMethod; /// Provides runtime information. pub trait RuntimeInfo { diff --git a/core/executor/src/native_executor.rs b/core/executor/src/native_executor.rs index cdf0be7f76..5f4e91b16d 100644 --- a/core/executor/src/native_executor.rs +++ b/core/executor/src/native_executor.rs @@ -16,19 +16,20 @@ use std::{result, cell::RefCell, panic::UnwindSafe}; use crate::error::{Error, Result}; -use crate::wasm_executor::WasmExecutor; +use crate::wasm_runtime::{RuntimesCache, WasmExecutionMethod, WasmRuntime}; +use crate::RuntimeInfo; use runtime_version::{NativeVersion, RuntimeVersion}; use codec::{Decode, Encode}; -use crate::RuntimeInfo; use primitives::{Blake2Hasher, NativeOrEncoded, traits::{CodeExecutor, Externalities}}; use log::{trace, warn}; -use crate::RuntimesCache; - thread_local! { static RUNTIMES_CACHE: RefCell = RefCell::new(RuntimesCache::new()); } +/// Default num of pages for the heap +const DEFAULT_HEAP_PAGES: u64 = 1024; + fn safe_call(f: F) -> Result where F: UnwindSafe + FnOnce() -> U { @@ -65,31 +66,52 @@ pub trait NativeExecutionDispatch: Send + Sync { pub struct NativeExecutor { /// Dummy field to avoid the compiler complaining about us not using `D`. _dummy: ::std::marker::PhantomData, - /// The fallback executor in case native isn't available. - fallback: WasmExecutor, + /// Method used to execute fallback Wasm code. + fallback_method: WasmExecutionMethod, /// Native runtime version info. native_version: NativeVersion, /// The number of 64KB pages to allocate for Wasm execution. - default_heap_pages: Option, + default_heap_pages: u64, } impl NativeExecutor { /// Create new instance. - pub fn new(default_heap_pages: Option) -> Self { + /// + /// # Parameters + /// + /// `fallback_method` - Method used to execute fallback Wasm code. + /// + /// `default_heap_pages` - Number of 64KB pages to allocate for Wasm execution. + /// Defaults to `DEFAULT_HEAP_PAGES` if `None` is provided. + pub fn new(fallback_method: WasmExecutionMethod, default_heap_pages: Option) -> Self { NativeExecutor { _dummy: Default::default(), - fallback: WasmExecutor::new(), + fallback_method, native_version: D::native_version(), - default_heap_pages: default_heap_pages, + default_heap_pages: default_heap_pages.unwrap_or(DEFAULT_HEAP_PAGES), } } + + fn with_runtime( + &self, + ext: &mut E, + f: impl for <'a> FnOnce(&'a mut dyn WasmRuntime, &'a mut E) -> Result + ) -> Result + where E: Externalities + { + RUNTIMES_CACHE.with(|cache| { + let mut cache = cache.borrow_mut(); + let runtime = cache.fetch_runtime(ext, self.fallback_method, self.default_heap_pages)?; + f(runtime, ext) + }) + } } impl Clone for NativeExecutor { fn clone(&self) -> Self { NativeExecutor { _dummy: Default::default(), - fallback: self.fallback.clone(), + fallback_method: self.fallback_method, native_version: D::native_version(), default_heap_pages: self.default_heap_pages, } @@ -105,17 +127,13 @@ impl RuntimeInfo for NativeExecutor { &self, ext: &mut E, ) -> Option { - RUNTIMES_CACHE.with(|cache| { - let cache = &mut cache.borrow_mut(); - - match cache.fetch_runtime(&self.fallback, ext, self.default_heap_pages) { - Ok(runtime) => runtime.version(), - Err(e) => { - warn!(target: "executor", "Failed to fetch runtime: {:?}", e); - None - } + match self.with_runtime(ext, |runtime, _ext| Ok(runtime.version())) { + Ok(version) => version, + Err(e) => { + warn!(target: "executor", "Failed to fetch runtime: {:?}", e); + None } - }) + } } } @@ -135,15 +153,9 @@ impl CodeExecutor for NativeExecutor, ) -> (Result>, bool){ - RUNTIMES_CACHE.with(|cache| { - let cache = &mut cache.borrow_mut(); - let cached_runtime = match cache.fetch_runtime( - &self.fallback, ext, self.default_heap_pages, - ) { - Ok(cached_runtime) => cached_runtime, - Err(e) => return (Err(e), false), - }; - let onchain_version = cached_runtime.version(); + let mut used_native = false; + let result = self.with_runtime(ext, |runtime, ext| { + let onchain_version = runtime.version(); match ( use_native, onchain_version @@ -160,25 +172,9 @@ impl CodeExecutor for NativeExecutor".into(), |v| format!("{}", v)) ); - ( - cached_runtime.with(|module| - self.fallback - .call_in_wasm_module(ext, module, method, data) - .map(NativeOrEncoded::Encoded) - ), - false - ) - } - (false, _, _) => { - ( - cached_runtime.with(|module| - self.fallback - .call_in_wasm_module(ext, module, method, data) - .map(NativeOrEncoded::Encoded) - ), - false - ) + runtime.call(ext, method, data).map(NativeOrEncoded::Encoded) } + (false, _, _) => runtime.call(ext, method, data).map(NativeOrEncoded::Encoded), (true, true, Some(call)) => { trace!( target: "executor", @@ -188,11 +184,13 @@ impl CodeExecutor for NativeExecutor".into(), |v| format!("{}", v)) ); - ( - with_native_environment(ext, move || (call)()) - .and_then(|r| r.map(NativeOrEncoded::Native).map_err(|s| Error::ApiError(s.to_string()))), - true - ) + + used_native = true; + with_native_environment(ext, move || (call)()) + .and_then(|r| r + .map(NativeOrEncoded::Native) + .map_err(|s| Error::ApiError(s.to_string())) + ) } _ => { trace!( @@ -201,10 +199,13 @@ impl CodeExecutor for NativeExecutor".into(), |v| format!("{}", v)) ); - (D::dispatch(ext, method, data).map(NativeOrEncoded::Encoded), true) + + used_native = true; + D::dispatch(ext, method, data).map(NativeOrEncoded::Encoded) } } - }) + }); + (result, used_native) } } diff --git a/core/executor/src/sandbox.rs b/core/executor/src/sandbox.rs index f09c246679..de49cc9f7c 100644 --- a/core/executor/src/sandbox.rs +++ b/core/executor/src/sandbox.rs @@ -586,14 +586,27 @@ impl Store { #[cfg(test)] mod tests { use super::*; - use primitives::{Blake2Hasher}; - use crate::wasm_executor::WasmExecutor; + use primitives::{Blake2Hasher, traits::Externalities}; + use crate::wasm_runtime::WasmRuntime; + use crate::wasmi_execution; use state_machine::TestExternalities as CoreTestExternalities; use wabt; use runtime_test::WASM_BINARY; type TestExternalities = CoreTestExternalities; + fn call_wasm>( + ext: &mut E, + heap_pages: u64, + code: &[u8], + method: &str, + data: &[u8], + ) -> Result> { + let mut instance = wasmi_execution::create_instance(ext, code, heap_pages) + .map_err(|err| err.to_string())?; + instance.call(ext, method, data) + } + #[test] fn sandbox_should_work() { let mut ext = TestExternalities::::default(); @@ -621,7 +634,7 @@ mod tests { "#).unwrap(); assert_eq!( - WasmExecutor::new().call(&mut ext, 8, &test_code[..], "test_sandbox", &code).unwrap(), + call_wasm(&mut ext, 8, &test_code[..], "test_sandbox", &code).unwrap(), vec![1], ); } @@ -642,7 +655,7 @@ mod tests { "#).unwrap(); assert_eq!( - WasmExecutor::new().call(&mut ext, 8, &test_code[..], "test_sandbox", &code).unwrap(), + call_wasm(&mut ext, 8, &test_code[..], "test_sandbox", &code).unwrap(), vec![0], ); } @@ -662,7 +675,7 @@ mod tests { ) "#).unwrap(); - let res = WasmExecutor::new().call(&mut ext, 8, &test_code[..], "test_exhaust_heap", &code); + let res = call_wasm(&mut ext, 8, &test_code[..], "test_exhaust_heap", &code); assert_eq!(res.is_err(), true); if let Err(err) = res { assert_eq!( @@ -708,7 +721,7 @@ mod tests { "#).unwrap(); assert_eq!( - WasmExecutor::new().call(&mut ext, 8, &test_code[..], "test_sandbox", &code).unwrap(), + call_wasm(&mut ext, 8, &test_code[..], "test_sandbox", &code).unwrap(), vec![1], ); } @@ -742,7 +755,7 @@ mod tests { "#).unwrap(); assert_eq!( - WasmExecutor::new().call(&mut ext, 8, &test_code[..], "test_sandbox_args", &code).unwrap(), + call_wasm(&mut ext, 8, &test_code[..], "test_sandbox_args", &code).unwrap(), vec![1], ); } @@ -764,7 +777,7 @@ mod tests { "#).unwrap(); assert_eq!( - WasmExecutor::new().call(&mut ext, 8, &test_code[..], "test_sandbox_return_val", &code).unwrap(), + call_wasm(&mut ext, 8, &test_code[..], "test_sandbox_return_val", &code).unwrap(), vec![1], ); } @@ -784,7 +797,7 @@ mod tests { "#).unwrap(); assert_eq!( - WasmExecutor::new().call(&mut ext, 8, &test_code[..], "test_sandbox_instantiate", &code).unwrap(), + call_wasm(&mut ext, 8, &test_code[..], "test_sandbox_instantiate", &code).unwrap(), vec![1], ); } @@ -798,7 +811,7 @@ mod tests { let code = &[0, 0, 0, 0, 1, 0, 0, 0]; assert_eq!( - WasmExecutor::new().call(&mut ext, 8, &test_code[..], "test_sandbox_instantiate", code).unwrap(), + call_wasm(&mut ext, 8, &test_code[..], "test_sandbox_instantiate", code).unwrap(), vec![1], ); } @@ -821,7 +834,7 @@ mod tests { "#).unwrap(); assert_eq!( - WasmExecutor::new().call(&mut ext, 8, &test_code[..], "test_sandbox_instantiate", &code).unwrap(), + call_wasm(&mut ext, 8, &test_code[..], "test_sandbox_instantiate", &code).unwrap(), vec![0], ); } @@ -845,7 +858,7 @@ mod tests { "#).unwrap(); assert_eq!( - WasmExecutor::new().call(&mut ext, 8, &test_code[..], "test_sandbox_instantiate", &code).unwrap(), + call_wasm(&mut ext, 8, &test_code[..], "test_sandbox_instantiate", &code).unwrap(), vec![2], ); } diff --git a/core/executor/src/wasm_runtime.rs b/core/executor/src/wasm_runtime.rs new file mode 100644 index 0000000000..27b65d6551 --- /dev/null +++ b/core/executor/src/wasm_runtime.rs @@ -0,0 +1,173 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +//! Traits and accessor functions for calling into the Substrate Wasm runtime. +//! +//! The primary means of accessing the runtimes is through a cache which saves the reusable +//! components of the runtime that are expensive to initialize. + +use crate::error::{Error, WasmError}; +use crate::wasmi_execution; +use log::{trace, warn}; +use codec::Decode; +use primitives::{storage::well_known_keys, Blake2Hasher, traits::Externalities}; +use runtime_version::RuntimeVersion; +use std::{collections::hash_map::{Entry, HashMap}}; + +/// The Substrate Wasm runtime. +pub trait WasmRuntime { + /// Attempt to update the number of heap pages available during execution. + /// + /// Returns false if the update cannot be applied. The function is guaranteed to return true if + /// the heap pages would not change from its current value. + fn update_heap_pages(&mut self, heap_pages: u64) -> bool; + + /// Call a method in the Substrate runtime by name. Returns the encoded result on success. + fn call(&mut self, ext: &mut dyn Externalities, method: &str, data: &[u8]) + -> Result, Error>; + + /// Returns the version of this runtime. + /// + /// Returns `None` if the runtime doesn't provide the information or there was an error + /// while fetching it. + fn version(&self) -> Option; +} + +/// Specification of different methods of executing the runtime Wasm code. +#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)] +pub enum WasmExecutionMethod { + /// Uses the Wasmi interpreter. + Interpreted, +} + +/// Cache for the runtimes. +/// +/// When an instance is requested for the first time it is added to this cache. Metadata is kept +/// with the instance so that it can be efficiently reinitialized. +/// +/// When using the Wasmi interpreter execution method, the metadata includes the initial memory and +/// values of mutable globals. Follow-up requests to fetch a runtime return this one instance with +/// the memory reset to the initial memory. So, one runtime instance is reused for every fetch +/// request. +/// +/// For now the cache grows indefinitely, but that should be fine for now since runtimes can only be +/// upgraded rarely and there are no other ways to make the node to execute some other runtime. +pub struct RuntimesCache { + /// A cache of runtime instances along with metadata, ready to be reused. + /// + /// Instances are keyed by the Wasm execution method and the hash of their code. + instances: HashMap<(WasmExecutionMethod, [u8; 32]), Result, WasmError>>, +} + +impl RuntimesCache { + /// Creates a new instance of a runtimes cache. + pub fn new() -> RuntimesCache { + RuntimesCache { + instances: HashMap::new(), + } + } + + /// Fetches an instance of the runtime. + /// + /// On first use we create a new runtime instance, save it to the cache + /// and persist its initial memory. + /// + /// Each subsequent request will return this instance, with its memory restored + /// to the persisted initial memory. Thus, we reuse one single runtime instance + /// for every `fetch_runtime` invocation. + /// + /// # Parameters + /// + /// `ext` - Externalities to use for the runtime. This is used for setting + /// up an initial runtime instance. The parameter is only needed for calling + /// into the Wasm module to find out the `Core_version`. + /// + /// `default_heap_pages` - Number of 64KB pages to allocate for Wasm execution. + /// + /// # Return value + /// + /// If no error occurred a tuple `(wasmi::ModuleRef, Option)` is + /// returned. `RuntimeVersion` is contained if the call to `Core_version` returned + /// a version. + /// + /// In case of failure one of two errors can be returned: + /// + /// `Err::InvalidCode` is returned for runtime code issues. + /// + /// `Error::InvalidMemoryReference` is returned if no memory export with the + /// identifier `memory` can be found in the runtime. + pub fn fetch_runtime>( + &mut self, + ext: &mut E, + wasm_method: WasmExecutionMethod, + default_heap_pages: u64, + ) -> Result<&mut (dyn WasmRuntime + 'static), Error> { + let code_hash = ext + .original_storage_hash(well_known_keys::CODE) + .ok_or(Error::InvalidCode("`CODE` not found in storage.".into()))?; + + let heap_pages = ext + .storage(well_known_keys::HEAP_PAGES) + .and_then(|pages| u64::decode(&mut &pages[..]).ok()) + .unwrap_or(default_heap_pages); + + let result = match self.instances.entry((wasm_method, code_hash.into())) { + Entry::Occupied(o) => { + let result = o.into_mut(); + if let Ok(ref mut cached_runtime) = result { + if !cached_runtime.update_heap_pages(heap_pages) { + trace!( + target: "runtimes_cache", + "heap_pages were changed. Reinstantiating the instance" + ); + *result = create_wasm_runtime(ext, wasm_method, heap_pages); + if let Err(ref err) = result { + warn!(target: "runtimes_cache", "cannot create a runtime: {:?}", err); + } + } + } + result + }, + Entry::Vacant(v) => { + trace!(target: "runtimes_cache", "no instance found in cache, creating now."); + let result = create_wasm_runtime(ext, wasm_method, heap_pages); + if let Err(ref err) = result { + warn!(target: "runtimes_cache", "cannot create a runtime: {:?}", err); + } + v.insert(result) + } + }; + + result.as_mut() + .map(|runtime| runtime.as_mut()) + .map_err(|ref e| Error::InvalidCode(format!("{:?}", e))) + } +} + +fn create_wasm_runtime>( + ext: &mut E, + wasm_method: WasmExecutionMethod, + heap_pages: u64, +) -> Result, WasmError> { + let code = ext + .original_storage(well_known_keys::CODE) + .ok_or(WasmError::CodeNotFound)?; + match wasm_method { + WasmExecutionMethod::Interpreted => + wasmi_execution::create_instance(ext, &code, heap_pages) + .map(|runtime| -> Box { Box::new(runtime) }), + } +} diff --git a/core/executor/src/wasm_runtimes_cache.rs b/core/executor/src/wasm_runtimes_cache.rs deleted file mode 100644 index a615660777..0000000000 --- a/core/executor/src/wasm_runtimes_cache.rs +++ /dev/null @@ -1,353 +0,0 @@ -// Copyright 2019 Parity Technologies (UK) Ltd. -// This file is part of Substrate. - -// Substrate is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Substrate is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Substrate. If not, see . - -//! Implements a cache for pre-created Wasm runtime module instances. - -use crate::error::Error; -use crate::wasm_executor::WasmExecutor; -use log::{trace, warn}; -use codec::Decode; -use parity_wasm::elements::{deserialize_buffer, DataSegment, Instruction, Module as RawModule}; -use primitives::{storage::well_known_keys, Blake2Hasher, traits::Externalities}; -use runtime_version::RuntimeVersion; -use std::{collections::hash_map::{Entry, HashMap}, mem, rc::Rc}; -use wasmi::{Module as WasmModule, ModuleRef as WasmModuleInstanceRef, RuntimeValue}; - -#[derive(Debug)] -enum CacheError { - CodeNotFound, - ApplySnapshotFailed, - InvalidModule, - CantDeserializeWasm, - Instantiation(Error), -} - -/// A runtime along with its version and initial state snapshot. -#[derive(Clone)] -pub struct CachedRuntime { - /// A wasm module instance. - instance: WasmModuleInstanceRef, - /// Runtime version according to `Core_version`. - /// - /// Can be `None` if the runtime doesn't expose this function. - version: Option, - /// The snapshot of the instance's state taken just after the instantiation. - state_snapshot: StateSnapshot, -} - -impl CachedRuntime { - /// Perform an operation with the clean version of the runtime wasm instance. - pub fn with(&self, f: F) -> R - where - F: FnOnce(&WasmModuleInstanceRef) -> R, - { - self.state_snapshot.apply(&self.instance).expect( - "applying the snapshot can only fail if the passed instance is different - from the one that was used for creation of the snapshot; - we use the snapshot that is directly associated with the instance; - thus the snapshot was created using the instance; - qed", - ); - f(&self.instance) - } - - /// Returns the version of this cached runtime. - /// - /// Returns `None` if the runtime doesn't provide the information or there was an error - /// while fetching it. - pub fn version(&self) -> Option { - self.version.clone() - } -} - -/// A state snapshot of an instance taken just after instantiation. -/// -/// It is used for restoring the state of the module after execution. -#[derive(Clone)] -struct StateSnapshot { - /// The offset and the content of the memory segments that should be used to restore the snapshot - data_segments: Vec<(u32, Vec)>, - /// The list of all global mutable variables of the module in their sequential order. - global_mut_values: Vec, - heap_pages: u64, -} - -impl StateSnapshot { - // Returns `None` if instance is not valid. - fn take( - module_instance: &WasmModuleInstanceRef, - data_segments: Vec, - heap_pages: u64, - ) -> Option { - let prepared_segments = data_segments - .into_iter() - .map(|mut segment| { - // Just replace contents of the segment since the segments will be discarded later - // anyway. - let contents = mem::replace(segment.value_mut(), vec![]); - - let init_expr = match segment.offset() { - Some(offset) => offset.code(), - // Return if the segment is passive - None => return None - }; - - // [op, End] - if init_expr.len() != 2 { - return None; - } - let offset = match init_expr[0] { - Instruction::I32Const(v) => v as u32, - Instruction::GetGlobal(idx) => { - let global_val = module_instance.globals().get(idx as usize)?.get(); - match global_val { - RuntimeValue::I32(v) => v as u32, - _ => return None, - } - } - _ => return None, - }; - - Some((offset, contents)) - }) - .collect::>>()?; - - // Collect all values of mutable globals. - let global_mut_values = module_instance - .globals() - .iter() - .filter(|g| g.is_mutable()) - .map(|g| g.get()) - .collect(); - - Some(Self { - data_segments: prepared_segments, - global_mut_values, - heap_pages, - }) - } - - /// Reset the runtime instance to the initial version by restoring - /// the preserved memory and globals. - /// - /// Returns `Err` if applying the snapshot is failed. - fn apply(&self, instance: &WasmModuleInstanceRef) -> Result<(), CacheError> { - let memory = instance - .export_by_name("memory") - .ok_or(CacheError::ApplySnapshotFailed)? - .as_memory() - .cloned() - .ok_or(CacheError::ApplySnapshotFailed)?; - - // First, erase the memory and copy the data segments into it. - memory - .erase() - .map_err(|_| CacheError::ApplySnapshotFailed)?; - for (offset, contents) in &self.data_segments { - memory - .set(*offset, contents) - .map_err(|_| CacheError::ApplySnapshotFailed)?; - } - - // Second, restore the values of mutable globals. - for (global_ref, global_val) in instance - .globals() - .iter() - .filter(|g| g.is_mutable()) - .zip(self.global_mut_values.iter()) - { - // the instance should be the same as used for preserving and - // we iterate the same way it as we do it for preserving values that means that the - // types should be the same and all the values are mutable. So no error is expected/ - global_ref - .set(*global_val) - .map_err(|_| CacheError::ApplySnapshotFailed)?; - } - Ok(()) - } -} - -/// Default num of pages for the heap -const DEFAULT_HEAP_PAGES: u64 = 1024; - -/// Cache for the runtimes. -/// -/// When an instance is requested for the first time it is added to this -/// cache. Furthermore its initial memory and values of mutable globals are preserved here. Follow-up -/// requests to fetch a runtime return this one instance with the memory -/// reset to the initial memory. So, one runtime instance is reused for -/// every fetch request. -/// -/// For now the cache grows indefinitely, but that should be fine for now since runtimes can only be -/// upgraded rarely and there are no other ways to make the node to execute some other runtime. -pub struct RuntimesCache { - /// A cache of runtime instances along with metadata, ready to be reused. - /// - /// Instances are keyed by the hash of their code. - instances: HashMap<[u8; 32], Result, CacheError>>, -} - -impl RuntimesCache { - /// Creates a new instance of a runtimes cache. - pub fn new() -> RuntimesCache { - RuntimesCache { - instances: HashMap::new(), - } - } - - /// Fetches an instance of the runtime. - /// - /// On first use we create a new runtime instance, save it to the cache - /// and persist its initial memory. - /// - /// Each subsequent request will return this instance, with its memory restored - /// to the persisted initial memory. Thus, we reuse one single runtime instance - /// for every `fetch_runtime` invocation. - /// - /// # Parameters - /// - /// `wasm_executor`- Rust wasm executor. Executes the provided code in a - /// sandboxed Wasm runtime. - /// - /// `ext` - Externalities to use for the runtime. This is used for setting - /// up an initial runtime instance. The parameter is only needed for calling - /// into the Wasm module to find out the `Core_version`. - /// - /// `default_heap_pages` - Number of 64KB pages to allocate for Wasm execution. - /// Defaults to `DEFAULT_HEAP_PAGES` if `None` is provided. - /// - /// # Return value - /// - /// If no error occurred a tuple `(wasmi::ModuleRef, Option)` is - /// returned. `RuntimeVersion` is contained if the call to `Core_version` returned - /// a version. - /// - /// In case of failure one of two errors can be returned: - /// - /// `Err::InvalidCode` is returned for runtime code issues. - /// - /// `Error::InvalidMemoryReference` is returned if no memory export with the - /// identifier `memory` can be found in the runtime. - pub fn fetch_runtime>( - &mut self, - wasm_executor: &WasmExecutor, - ext: &mut E, - default_heap_pages: Option, - ) -> Result, Error> { - let code_hash = ext - .original_storage_hash(well_known_keys::CODE) - .ok_or(Error::InvalidCode("`CODE` not found in storage.".into()))?; - - let heap_pages = ext - .storage(well_known_keys::HEAP_PAGES) - .and_then(|pages| u64::decode(&mut &pages[..]).ok()) - .or(default_heap_pages) - .unwrap_or(DEFAULT_HEAP_PAGES); - - // This is direct result from fighting with borrowck. - let handle_result = - |cached_result: &Result, CacheError>| match *cached_result { - Err(ref e) => Err(Error::InvalidCode(format!("{:?}", e))), - Ok(ref cached_runtime) => Ok(Rc::clone(cached_runtime)), - }; - - match self.instances.entry(code_hash.into()) { - Entry::Occupied(mut o) => { - let result = o.get_mut(); - if let Ok(ref cached_runtime) = result { - if cached_runtime.state_snapshot.heap_pages != heap_pages { - trace!( - target: "runtimes_cache", - "heap_pages were changed. Reinstantiating the instance" - ); - *result = Self::create_wasm_instance(wasm_executor, ext, heap_pages); - if let Err(ref err) = result { - warn!(target: "runtimes_cache", "cannot create a runtime: {:?}", err); - } - } - } - handle_result(result) - }, - Entry::Vacant(v) => { - trace!(target: "runtimes_cache", "no instance found in cache, creating now."); - let result = Self::create_wasm_instance( - wasm_executor, - ext, - heap_pages, - ); - if let Err(ref err) = result { - warn!(target: "runtimes_cache", "cannot create a runtime: {:?}", err); - } - handle_result(v.insert(result)) - } - } - } - - fn create_wasm_instance>( - wasm_executor: &WasmExecutor, - ext: &mut E, - heap_pages: u64, - ) -> Result, CacheError> { - let code = ext - .original_storage(well_known_keys::CODE) - .ok_or(CacheError::CodeNotFound)?; - let module = WasmModule::from_buffer(&code).map_err(|_| CacheError::InvalidModule)?; - - // Extract the data segments from the wasm code. - // - // A return of this error actually indicates that there is a problem in logic, since - // we just loaded and validated the `module` above. - let data_segments = extract_data_segments(&code)?; - - // Instantiate this module. - let instance = WasmExecutor::instantiate_module(heap_pages as usize, &module) - .map_err(CacheError::Instantiation)?; - - // Take state snapshot before executing anything. - let state_snapshot = StateSnapshot::take(&instance, data_segments, heap_pages) - .expect( - "`take` returns `Err` if the module is not valid; - we already loaded module above, thus the `Module` is proven to be valid at this point; - qed - ", - ); - - let version = wasm_executor - .call_in_wasm_module(ext, &instance, "Core_version", &[]) - .ok() - .and_then(|v| RuntimeVersion::decode(&mut v.as_slice()).ok()); - Ok(Rc::new(CachedRuntime { - instance, - version, - state_snapshot, - })) - } -} - -/// Extract the data segments from the given wasm code. -/// -/// Returns `Err` if the given wasm code cannot be deserialized. -fn extract_data_segments(wasm_code: &[u8]) -> Result, CacheError> { - let raw_module: RawModule = deserialize_buffer(wasm_code) - .map_err(|_| CacheError::CantDeserializeWasm)?; - - let segments = raw_module - .data_section() - .map(|ds| ds.entries()) - .unwrap_or(&[]) - .to_vec(); - Ok(segments) -} diff --git a/core/executor/src/wasmi_execution.rs b/core/executor/src/wasmi_execution.rs new file mode 100644 index 0000000000..e228372bd3 --- /dev/null +++ b/core/executor/src/wasmi_execution.rs @@ -0,0 +1,902 @@ +// Copyright 2017-2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +//! Implementation of a Wasm runtime using the Wasmi interpreter. + +use std::{str, mem}; +use wasmi::{ + Module, ModuleInstance, MemoryInstance, MemoryRef, TableRef, ImportsBuilder, ModuleRef, + memory_units::Pages, RuntimeValue::{I32, I64, self}, +}; +use crate::error::{Error, WasmError}; +use codec::{Encode, Decode}; +use primitives::{sandbox as sandbox_primitives, Blake2Hasher, traits::Externalities}; +use crate::host_interface::SubstrateExternals; +use crate::sandbox; +use crate::allocator; +use crate::wasm_runtime::WasmRuntime; +use log::trace; +use parity_wasm::elements::{deserialize_buffer, DataSegment, Instruction, Module as RawModule}; +use runtime_version::RuntimeVersion; +use wasm_interface::{ + FunctionContext, HostFunctions, Pointer, WordSize, Sandbox, MemoryId, Result as WResult, +}; + +struct FunctionExecutor { + sandbox_store: sandbox::Store, + heap: allocator::FreeingBumpHeapAllocator, + memory: MemoryRef, + table: Option, +} + +impl FunctionExecutor { + fn new(m: MemoryRef, heap_base: u32, t: Option) -> Result { + Ok(FunctionExecutor { + sandbox_store: sandbox::Store::new(), + heap: allocator::FreeingBumpHeapAllocator::new(heap_base), + memory: m, + table: t, + }) + } +} + +impl sandbox::SandboxCapabilities for FunctionExecutor { + type SupervisorFuncRef = wasmi::FuncRef; + + fn store(&self) -> &sandbox::Store { + &self.sandbox_store + } + fn store_mut(&mut self) -> &mut sandbox::Store { + &mut self.sandbox_store + } + fn allocate(&mut self, len: WordSize) -> Result, Error> { + let heap = &mut self.heap; + self.memory.with_direct_access_mut(|mem| { + heap.allocate(mem, len) + }) + } + fn deallocate(&mut self, ptr: Pointer) -> Result<(), Error> { + let heap = &mut self.heap; + self.memory.with_direct_access_mut(|mem| { + heap.deallocate(mem, ptr) + }) + } + fn write_memory(&mut self, ptr: Pointer, data: &[u8]) -> Result<(), Error> { + self.memory.set(ptr.into(), data).map_err(Into::into) + } + fn read_memory(&self, ptr: Pointer, len: WordSize) -> Result, Error> { + self.memory.get(ptr.into(), len as usize).map_err(Into::into) + } + + fn invoke( + &mut self, + dispatch_thunk: &Self::SupervisorFuncRef, + invoke_args_ptr: Pointer, + invoke_args_len: WordSize, + state: u32, + func_idx: sandbox::SupervisorFuncIndex, + ) -> Result + { + let result = wasmi::FuncInstance::invoke( + dispatch_thunk, + &[ + RuntimeValue::I32(u32::from(invoke_args_ptr) as i32), + RuntimeValue::I32(invoke_args_len as i32), + RuntimeValue::I32(state as i32), + RuntimeValue::I32(usize::from(func_idx) as i32), + ], + self, + ); + match result { + Ok(Some(RuntimeValue::I64(val))) => Ok(val), + Ok(_) => return Err("Supervisor function returned unexpected result!".into()), + Err(err) => Err(Error::Trap(err)), + } + } +} + +impl FunctionContext for FunctionExecutor { + fn read_memory_into(&self, address: Pointer, dest: &mut [u8]) -> WResult<()> { + self.memory.get_into(address.into(), dest).map_err(|e| format!("{:?}", e)) + } + + fn write_memory(&mut self, address: Pointer, data: &[u8]) -> WResult<()> { + self.memory.set(address.into(), data).map_err(|e| format!("{:?}", e)) + } + + fn allocate_memory(&mut self, size: WordSize) -> WResult> { + let heap = &mut self.heap; + self.memory.with_direct_access_mut(|mem| { + heap.allocate(mem, size).map_err(|e| format!("{:?}", e)) + }) + } + + fn deallocate_memory(&mut self, ptr: Pointer) -> WResult<()> { + let heap = &mut self.heap; + self.memory.with_direct_access_mut(|mem| { + heap.deallocate(mem, ptr).map_err(|e| format!("{:?}", e)) + }) + } + + fn sandbox(&mut self) -> &mut dyn Sandbox { + self + } +} + +impl Sandbox for FunctionExecutor { + fn memory_get( + &self, + memory_id: MemoryId, + offset: WordSize, + buf_ptr: Pointer, + buf_len: WordSize, + ) -> WResult { + let sandboxed_memory = self.sandbox_store.memory(memory_id).map_err(|e| format!("{:?}", e))?; + + match MemoryInstance::transfer( + &sandboxed_memory, + offset as usize, + &self.memory, + buf_ptr.into(), + buf_len as usize, + ) { + Ok(()) => Ok(sandbox_primitives::ERR_OK), + Err(_) => Ok(sandbox_primitives::ERR_OUT_OF_BOUNDS), + } + } + + fn memory_set( + &mut self, + memory_id: MemoryId, + offset: WordSize, + val_ptr: Pointer, + val_len: WordSize, + ) -> WResult { + let sandboxed_memory = self.sandbox_store.memory(memory_id).map_err(|e| format!("{:?}", e))?; + + match MemoryInstance::transfer( + &self.memory, + val_ptr.into(), + &sandboxed_memory, + offset as usize, + val_len as usize, + ) { + Ok(()) => Ok(sandbox_primitives::ERR_OK), + Err(_) => Ok(sandbox_primitives::ERR_OUT_OF_BOUNDS), + } + } + + fn memory_teardown(&mut self, memory_id: MemoryId) -> WResult<()> { + self.sandbox_store.memory_teardown(memory_id).map_err(|e| format!("{:?}", e)) + } + + fn memory_new( + &mut self, + initial: u32, + maximum: u32, + ) -> WResult { + self.sandbox_store.new_memory(initial, maximum).map_err(|e| format!("{:?}", e)) + } + + fn invoke( + &mut self, + instance_id: u32, + export_name: &str, + args: &[u8], + return_val: Pointer, + return_val_len: WordSize, + state: u32, + ) -> WResult { + trace!(target: "sr-sandbox", "invoke, instance_idx={}", instance_id); + + // Deserialize arguments and convert them into wasmi types. + let args = Vec::::decode(&mut &args[..]) + .map_err(|_| "Can't decode serialized arguments for the invocation")? + .into_iter() + .map(Into::into) + .collect::>(); + + let instance = self.sandbox_store.instance(instance_id).map_err(|e| format!("{:?}", e))?; + let result = instance.invoke(export_name, &args, self, state); + + match result { + Ok(None) => Ok(sandbox_primitives::ERR_OK), + Ok(Some(val)) => { + // Serialize return value and write it back into the memory. + sandbox_primitives::ReturnValue::Value(val.into()).using_encoded(|val| { + if val.len() > return_val_len as usize { + Err("Return value buffer is too small")?; + } + self.write_memory(return_val, val).map_err(|_| "Return value buffer is OOB")?; + Ok(sandbox_primitives::ERR_OK) + }) + } + Err(_) => Ok(sandbox_primitives::ERR_EXECUTION), + } + } + + fn instance_teardown(&mut self, instance_id: u32) -> WResult<()> { + self.sandbox_store.instance_teardown(instance_id).map_err(|e| format!("{:?}", e)) + } + + fn instance_new( + &mut self, + dispatch_thunk_id: u32, + wasm: &[u8], + raw_env_def: &[u8], + state: u32, + ) -> WResult { + // Extract a dispatch thunk from instance's table by the specified index. + let dispatch_thunk = { + let table = self.table.as_ref() + .ok_or_else(|| "Runtime doesn't have a table; sandbox is unavailable")?; + table.get(dispatch_thunk_id) + .map_err(|_| "dispatch_thunk_idx is out of the table bounds")? + .ok_or_else(|| "dispatch_thunk_idx points on an empty table entry")? + .clone() + }; + + let instance_idx_or_err_code = + match sandbox::instantiate(self, dispatch_thunk, wasm, raw_env_def, state) { + Ok(instance_idx) => instance_idx, + Err(sandbox::InstantiationError::StartTrapped) => + sandbox_primitives::ERR_EXECUTION, + Err(_) => sandbox_primitives::ERR_MODULE, + }; + + Ok(instance_idx_or_err_code as u32) + } +} + +impl FunctionExecutor { + fn resolver() -> &'static dyn wasmi::ModuleImportResolver { + struct Resolver; + impl wasmi::ModuleImportResolver for Resolver { + fn resolve_func(&self, name: &str, signature: &wasmi::Signature) + -> std::result::Result + { + let signature = wasm_interface::Signature::from(signature); + + if let Some((index, func)) = SubstrateExternals::functions().iter() + .enumerate() + .find(|f| name == f.1.name()) + { + if signature == func.signature() { + Ok(wasmi::FuncInstance::alloc_host(signature.into(), index)) + } else { + Err(wasmi::Error::Instantiation( + format!( + "Invalid signature for function `{}` expected `{:?}`, got `{:?}`", + func.name(), + signature, + func.signature(), + ) + )) + } + } else { + Err(wasmi::Error::Instantiation( + format!("Export {} not found", name), + )) + } + } + } + &Resolver + } +} + +impl wasmi::Externals for FunctionExecutor { + fn invoke_index(&mut self, index: usize, args: wasmi::RuntimeArgs) + -> Result, wasmi::Trap> + { + let mut args = args.as_ref().iter().copied().map(Into::into); + let function = SubstrateExternals::functions().get(index).ok_or_else(|| + Error::from( + format!("Could not find host function with index: {}", index), + ) + )?; + + function.execute(self, &mut args) + .map_err(Error::FunctionExecution) + .map_err(wasmi::Trap::from) + .map(|v| v.map(Into::into)) + } +} + +fn get_mem_instance(module: &ModuleRef) -> Result { + Ok(module + .export_by_name("memory") + .ok_or_else(|| Error::InvalidMemoryReference)? + .as_memory() + .ok_or_else(|| Error::InvalidMemoryReference)? + .clone()) +} + +/// Find the global named `__heap_base` in the given wasm module instance and +/// tries to get its value. +fn get_heap_base(module: &ModuleRef) -> Result { + let heap_base_val = module + .export_by_name("__heap_base") + .ok_or_else(|| Error::HeapBaseNotFoundOrInvalid)? + .as_global() + .ok_or_else(|| Error::HeapBaseNotFoundOrInvalid)? + .get(); + + match heap_base_val { + wasmi::RuntimeValue::I32(v) => Ok(v as u32), + _ => Err(Error::HeapBaseNotFoundOrInvalid), + } +} + +/// Call a given method in the given wasm-module runtime. +fn call_in_wasm_module( + ext: &mut dyn Externalities, + module_instance: &ModuleRef, + method: &str, + data: &[u8], +) -> Result, Error> { + call_in_wasm_module_with_custom_signature( + ext, + module_instance, + method, + |alloc| { + let offset = alloc(data)?; + Ok(vec![I32(offset as i32), I32(data.len() as i32)]) + }, + |res, memory| { + if let Some(I64(r)) = res { + let offset = r as u32; + let length = (r as u64 >> 32) as usize; + memory.get(offset, length).map_err(|_| Error::Runtime).map(Some) + } else { + Ok(None) + } + } + ) +} + +/// Call a given method in the given wasm-module runtime. +fn call_in_wasm_module_with_custom_signature< + F: FnOnce(&mut dyn FnMut(&[u8]) -> Result) -> Result, Error>, + FR: FnOnce(Option, &MemoryRef) -> Result, Error>, + R, +>( + ext: &mut dyn Externalities, + module_instance: &ModuleRef, + method: &str, + create_parameters: F, + filter_result: FR, +) -> Result { + // extract a reference to a linear memory, optional reference to a table + // and then initialize FunctionExecutor. + let memory = get_mem_instance(module_instance)?; + let table: Option = module_instance + .export_by_name("__indirect_function_table") + .and_then(|e| e.as_table().cloned()); + let heap_base = get_heap_base(module_instance)?; + + let mut fec = FunctionExecutor::new( + memory.clone(), + heap_base, + table, + )?; + + let parameters = create_parameters(&mut |data: &[u8]| { + let offset = fec.allocate_memory(data.len() as u32)?; + fec.write_memory(offset, data).map(|_| offset.into()).map_err(Into::into) + })?; + + let result = runtime_io::with_externalities( + ext, + || module_instance.invoke_export(method, ¶meters, &mut fec), + ); + + match result { + Ok(val) => match filter_result(val, &memory)? { + Some(val) => Ok(val), + None => Err(Error::InvalidReturn), + }, + Err(e) => { + trace!( + target: "wasm-executor", + "Failed to execute code with {} pages", + memory.current_size().0 + ); + Err(e.into()) + }, + } +} + +/// Prepare module instance +fn instantiate_module( + heap_pages: usize, + module: &Module, +) -> Result { + // start module instantiation. Don't run 'start' function yet. + let intermediate_instance = ModuleInstance::new( + module, + &ImportsBuilder::new() + .with_resolver("env", FunctionExecutor::resolver()) + )?; + + // Verify that the module has the heap base global variable. + let _ = get_heap_base(intermediate_instance.not_started_instance())?; + + // Extract a reference to a linear memory. + let memory = get_mem_instance(intermediate_instance.not_started_instance())?; + memory.grow(Pages(heap_pages)).map_err(|_| Error::Runtime)?; + + if intermediate_instance.has_start() { + // Runtime is not allowed to have the `start` function. + Err(Error::RuntimeHasStartFn) + } else { + Ok(intermediate_instance.assert_no_start()) + } +} + +/// A state snapshot of an instance taken just after instantiation. +/// +/// It is used for restoring the state of the module after execution. +#[derive(Clone)] +struct StateSnapshot { + /// The offset and the content of the memory segments that should be used to restore the snapshot + data_segments: Vec<(u32, Vec)>, + /// The list of all global mutable variables of the module in their sequential order. + global_mut_values: Vec, + heap_pages: u64, +} + +impl StateSnapshot { + // Returns `None` if instance is not valid. + fn take( + module_instance: &ModuleRef, + data_segments: Vec, + heap_pages: u64, + ) -> Option { + let prepared_segments = data_segments + .into_iter() + .map(|mut segment| { + // Just replace contents of the segment since the segments will be discarded later + // anyway. + let contents = mem::replace(segment.value_mut(), vec![]); + + let init_expr = match segment.offset() { + Some(offset) => offset.code(), + // Return if the segment is passive + None => return None + }; + + // [op, End] + if init_expr.len() != 2 { + return None; + } + let offset = match init_expr[0] { + Instruction::I32Const(v) => v as u32, + Instruction::GetGlobal(idx) => { + let global_val = module_instance.globals().get(idx as usize)?.get(); + match global_val { + RuntimeValue::I32(v) => v as u32, + _ => return None, + } + } + _ => return None, + }; + + Some((offset, contents)) + }) + .collect::>>()?; + + // Collect all values of mutable globals. + let global_mut_values = module_instance + .globals() + .iter() + .filter(|g| g.is_mutable()) + .map(|g| g.get()) + .collect(); + + Some(Self { + data_segments: prepared_segments, + global_mut_values, + heap_pages, + }) + } + + /// Reset the runtime instance to the initial version by restoring + /// the preserved memory and globals. + /// + /// Returns `Err` if applying the snapshot is failed. + fn apply(&self, instance: &ModuleRef) -> Result<(), WasmError> { + let memory = instance + .export_by_name("memory") + .ok_or(WasmError::ApplySnapshotFailed)? + .as_memory() + .cloned() + .ok_or(WasmError::ApplySnapshotFailed)?; + + // First, erase the memory and copy the data segments into it. + memory + .erase() + .map_err(|_| WasmError::ApplySnapshotFailed)?; + for (offset, contents) in &self.data_segments { + memory + .set(*offset, contents) + .map_err(|_| WasmError::ApplySnapshotFailed)?; + } + + // Second, restore the values of mutable globals. + for (global_ref, global_val) in instance + .globals() + .iter() + .filter(|g| g.is_mutable()) + .zip(self.global_mut_values.iter()) + { + // the instance should be the same as used for preserving and + // we iterate the same way it as we do it for preserving values that means that the + // types should be the same and all the values are mutable. So no error is expected/ + global_ref + .set(*global_val) + .map_err(|_| WasmError::ApplySnapshotFailed)?; + } + Ok(()) + } +} + +/// A runtime along with its version and initial state snapshot. +#[derive(Clone)] +pub struct WasmiRuntime { + /// A wasm module instance. + instance: ModuleRef, + /// Runtime version according to `Core_version`. + /// + /// Can be `None` if the runtime doesn't expose this function. + version: Option, + /// The snapshot of the instance's state taken just after the instantiation. + state_snapshot: StateSnapshot, +} + +impl WasmiRuntime { + /// Perform an operation with the clean version of the runtime wasm instance. + fn with(&self, f: F) -> R + where + F: FnOnce(&ModuleRef) -> R, + { + self.state_snapshot.apply(&self.instance).expect( + "applying the snapshot can only fail if the passed instance is different + from the one that was used for creation of the snapshot; + we use the snapshot that is directly associated with the instance; + thus the snapshot was created using the instance; + qed", + ); + f(&self.instance) + } +} + +impl WasmRuntime for WasmiRuntime { + fn update_heap_pages(&mut self, heap_pages: u64) -> bool { + self.state_snapshot.heap_pages == heap_pages + } + + fn call(&mut self, ext: &mut dyn Externalities, method: &str, data: &[u8]) + -> Result, Error> + { + self.with(|module| { + call_in_wasm_module(ext, module, method, data) + }) + } + + fn version(&self) -> Option { + self.version.clone() + } +} + +pub fn create_instance>(ext: &mut E, code: &[u8], heap_pages: u64) + -> Result +{ + let module = Module::from_buffer(&code).map_err(|_| WasmError::InvalidModule)?; + + // Extract the data segments from the wasm code. + // + // A return of this error actually indicates that there is a problem in logic, since + // we just loaded and validated the `module` above. + let data_segments = extract_data_segments(&code)?; + + // Instantiate this module. + let instance = instantiate_module(heap_pages as usize, &module) + .map_err(WasmError::Instantiation)?; + + // Take state snapshot before executing anything. + let state_snapshot = StateSnapshot::take(&instance, data_segments, heap_pages) + .expect( + "`take` returns `Err` if the module is not valid; + we already loaded module above, thus the `Module` is proven to be valid at this point; + qed + ", + ); + + let version = call_in_wasm_module(ext, &instance, "Core_version", &[]) + .ok() + .and_then(|v| RuntimeVersion::decode(&mut v.as_slice()).ok()); + Ok(WasmiRuntime { + instance, + version, + state_snapshot, + }) +} + +/// Extract the data segments from the given wasm code. +/// +/// Returns `Err` if the given wasm code cannot be deserialized. +fn extract_data_segments(wasm_code: &[u8]) -> Result, WasmError> { + let raw_module: RawModule = deserialize_buffer(wasm_code) + .map_err(|_| WasmError::CantDeserializeWasm)?; + + let segments = raw_module + .data_section() + .map(|ds| ds.entries()) + .unwrap_or(&[]) + .to_vec(); + Ok(segments) +} + +#[cfg(test)] +mod tests { + use super::*; + + use state_machine::TestExternalities as CoreTestExternalities; + use hex_literal::hex; + use primitives::{blake2_128, blake2_256, ed25519, sr25519, map, Pair}; + use runtime_test::WASM_BINARY; + use substrate_offchain::testing; + use trie::{TrieConfiguration, trie_types::Layout}; + + type TestExternalities = CoreTestExternalities; + + fn call>( + ext: &mut E, + heap_pages: u64, + code: &[u8], + method: &str, + data: &[u8], + ) -> Result, Error> { + let mut instance = create_instance(ext, code, heap_pages) + .map_err(|err| err.to_string())?; + instance.call(ext, method, data) + } + + #[test] + fn returning_should_work() { + let mut ext = TestExternalities::default(); + let test_code = WASM_BINARY; + + let output = call(&mut ext, 8, &test_code[..], "test_empty_return", &[]).unwrap(); + assert_eq!(output, vec![0u8; 0]); + } + + #[test] + fn panicking_should_work() { + let mut ext = TestExternalities::default(); + let test_code = WASM_BINARY; + + let output = call(&mut ext, 8, &test_code[..], "test_panic", &[]); + assert!(output.is_err()); + + let output = call(&mut ext, 8, &test_code[..], "test_conditional_panic", &[]); + assert_eq!(output.unwrap(), vec![0u8; 0]); + + let output = call(&mut ext, 8, &test_code[..], "test_conditional_panic", &[2]); + assert!(output.is_err()); + } + + #[test] + fn storage_should_work() { + let mut ext = TestExternalities::default(); + ext.set_storage(b"foo".to_vec(), b"bar".to_vec()); + let test_code = WASM_BINARY; + + let output = call(&mut ext, 8, &test_code[..], "test_data_in", b"Hello world").unwrap(); + + assert_eq!(output, b"all ok!".to_vec()); + + let expected = TestExternalities::new((map![ + b"input".to_vec() => b"Hello world".to_vec(), + b"foo".to_vec() => b"bar".to_vec(), + b"baz".to_vec() => b"bar".to_vec() + ], map![])); + assert_eq!(ext, expected); + } + + #[test] + fn clear_prefix_should_work() { + let mut ext = TestExternalities::default(); + ext.set_storage(b"aaa".to_vec(), b"1".to_vec()); + ext.set_storage(b"aab".to_vec(), b"2".to_vec()); + ext.set_storage(b"aba".to_vec(), b"3".to_vec()); + ext.set_storage(b"abb".to_vec(), b"4".to_vec()); + ext.set_storage(b"bbb".to_vec(), b"5".to_vec()); + let test_code = WASM_BINARY; + + // This will clear all entries which prefix is "ab". + let output = call(&mut ext, 8, &test_code[..], "test_clear_prefix", b"ab").unwrap(); + + assert_eq!(output, b"all ok!".to_vec()); + + let expected = TestExternalities::new((map![ + b"aaa".to_vec() => b"1".to_vec(), + b"aab".to_vec() => b"2".to_vec(), + b"bbb".to_vec() => b"5".to_vec() + ], map![])); + assert_eq!(expected, ext); + } + + #[test] + fn blake2_256_should_work() { + let mut ext = TestExternalities::default(); + let test_code = WASM_BINARY; + assert_eq!( + call(&mut ext, 8, &test_code[..], "test_blake2_256", &[]).unwrap(), + blake2_256(&b""[..]).encode() + ); + assert_eq!( + call(&mut ext, 8, &test_code[..], "test_blake2_256", b"Hello world!").unwrap(), + blake2_256(&b"Hello world!"[..]).encode() + ); + } + + #[test] + fn blake2_128_should_work() { + let mut ext = TestExternalities::default(); + let test_code = WASM_BINARY; + assert_eq!( + call(&mut ext, 8, &test_code[..], "test_blake2_128", &[]).unwrap(), + blake2_128(&b""[..]).encode() + ); + assert_eq!( + call(&mut ext, 8, &test_code[..], "test_blake2_128", b"Hello world!").unwrap(), + blake2_128(&b"Hello world!"[..]).encode() + ); + } + + #[test] + fn twox_256_should_work() { + let mut ext = TestExternalities::default(); + let test_code = WASM_BINARY; + assert_eq!( + call(&mut ext, 8, &test_code[..], "test_twox_256", &[]).unwrap(), + hex!("99e9d85137db46ef4bbea33613baafd56f963c64b1f3685a4eb4abd67ff6203a"), + ); + assert_eq!( + call(&mut ext, 8, &test_code[..], "test_twox_256", b"Hello world!").unwrap(), + hex!("b27dfd7f223f177f2a13647b533599af0c07f68bda23d96d059da2b451a35a74"), + ); + } + + #[test] + fn twox_128_should_work() { + let mut ext = TestExternalities::default(); + let test_code = WASM_BINARY; + assert_eq!( + call(&mut ext, 8, &test_code[..], "test_twox_128", &[]).unwrap(), + hex!("99e9d85137db46ef4bbea33613baafd5") + ); + assert_eq!( + call(&mut ext, 8, &test_code[..], "test_twox_128", b"Hello world!").unwrap(), + hex!("b27dfd7f223f177f2a13647b533599af") + ); + } + + #[test] + fn ed25519_verify_should_work() { + let mut ext = TestExternalities::::default(); + let test_code = WASM_BINARY; + let key = ed25519::Pair::from_seed(&blake2_256(b"test")); + let sig = key.sign(b"all ok!"); + let mut calldata = vec![]; + calldata.extend_from_slice(key.public().as_ref()); + calldata.extend_from_slice(sig.as_ref()); + + assert_eq!( + call(&mut ext, 8, &test_code[..], "test_ed25519_verify", &calldata).unwrap(), + vec![1] + ); + + let other_sig = key.sign(b"all is not ok!"); + let mut calldata = vec![]; + calldata.extend_from_slice(key.public().as_ref()); + calldata.extend_from_slice(other_sig.as_ref()); + + assert_eq!( + call(&mut ext, 8, &test_code[..], "test_ed25519_verify", &calldata).unwrap(), + vec![0] + ); + } + + #[test] + fn sr25519_verify_should_work() { + let mut ext = TestExternalities::::default(); + let test_code = WASM_BINARY; + let key = sr25519::Pair::from_seed(&blake2_256(b"test")); + let sig = key.sign(b"all ok!"); + let mut calldata = vec![]; + calldata.extend_from_slice(key.public().as_ref()); + calldata.extend_from_slice(sig.as_ref()); + + assert_eq!( + call(&mut ext, 8, &test_code[..], "test_sr25519_verify", &calldata).unwrap(), + vec![1] + ); + + let other_sig = key.sign(b"all is not ok!"); + let mut calldata = vec![]; + calldata.extend_from_slice(key.public().as_ref()); + calldata.extend_from_slice(other_sig.as_ref()); + + assert_eq!( + call(&mut ext, 8, &test_code[..], "test_sr25519_verify", &calldata).unwrap(), + vec![0] + ); + } + + #[test] + fn ordered_trie_root_should_work() { + let mut ext = TestExternalities::::default(); + let trie_input = vec![b"zero".to_vec(), b"one".to_vec(), b"two".to_vec()]; + let test_code = WASM_BINARY; + assert_eq!( + call(&mut ext, 8, &test_code[..], "test_ordered_trie_root", &[]).unwrap(), + Layout::::ordered_trie_root(trie_input.iter()).as_fixed_bytes().encode() + ); + } + + #[test] + fn offchain_local_storage_should_work() { + use substrate_client::backend::OffchainStorage; + + let mut ext = TestExternalities::::default(); + let (offchain, state) = testing::TestOffchainExt::new(); + ext.set_offchain_externalities(offchain); + let test_code = WASM_BINARY; + assert_eq!( + call(&mut ext, 8, &test_code[..], "test_offchain_local_storage", &[]).unwrap(), + vec![0] + ); + assert_eq!(state.read().persistent_storage.get(b"", b"test"), Some(vec![])); + } + + #[test] + fn offchain_http_should_work() { + let mut ext = TestExternalities::::default(); + let (offchain, state) = testing::TestOffchainExt::new(); + ext.set_offchain_externalities(offchain); + state.write().expect_request( + 0, + testing::PendingRequest { + method: "POST".into(), + uri: "http://localhost:12345".into(), + body: vec![1, 2, 3, 4], + headers: vec![("X-Auth".to_owned(), "test".to_owned())], + sent: true, + response: Some(vec![1, 2, 3]), + response_headers: vec![("X-Auth".to_owned(), "hello".to_owned())], + ..Default::default() + }, + ); + + let test_code = WASM_BINARY; + assert_eq!( + call(&mut ext, 8, &test_code[..], "test_offchain_http", &[]).unwrap(), + vec![0] + ); + } +} diff --git a/core/service/src/builder.rs b/core/service/src/builder.rs index f0860de1c1..e4b02150bf 100644 --- a/core/service/src/builder.rs +++ b/core/service/src/builder.rs @@ -167,7 +167,10 @@ where TGen: RuntimeGenesis, TCSExt: Extension { pruning: config.pruning.clone(), }; - let executor = NativeExecutor::::new(config.default_heap_pages); + let executor = NativeExecutor::::new( + config.wasm_method, + config.default_heap_pages, + ); let fork_blocks = config.chain_spec .extensions() @@ -239,7 +242,10 @@ where TGen: RuntimeGenesis, TCSExt: Extension { pruning: config.pruning.clone(), }; - let executor = NativeExecutor::::new(config.default_heap_pages); + let executor = NativeExecutor::::new( + config.wasm_method, + config.default_heap_pages, + ); let db_storage = client_db::light::LightStorage::new(db_settings)?; let light_blockchain = client::light::new_light_blockchain(db_storage); diff --git a/core/service/src/config.rs b/core/service/src/config.rs index c4690e53f7..a1ba83753f 100644 --- a/core/service/src/config.rs +++ b/core/service/src/config.rs @@ -19,6 +19,7 @@ pub use client::ExecutionStrategies; pub use client_db::PruningMode; pub use network::config::{ExtTransport, NetworkConfiguration, Roles}; +pub use substrate_executor::WasmExecutionMethod; use std::{path::PathBuf, net::SocketAddr}; use transaction_pool; @@ -60,6 +61,8 @@ pub struct Configuration { pub custom: C, /// Node name. pub name: String, + /// Wasm execution method. + pub wasm_method: WasmExecutionMethod, /// Execution strategies. pub execution_strategies: ExecutionStrategies, /// RPC over HTTP binding address. `None` if disabled. @@ -116,6 +119,7 @@ impl Configuration where state_cache_child_ratio: Default::default(), custom: Default::default(), pruning: PruningMode::default(), + wasm_method: WasmExecutionMethod::Interpreted, execution_strategies: Default::default(), rpc_http: None, rpc_ws: None, diff --git a/core/service/test/src/lib.rs b/core/service/test/src/lib.rs index 2d064f965b..806996576f 100644 --- a/core/service/test/src/lib.rs +++ b/core/service/test/src/lib.rs @@ -178,6 +178,7 @@ fn node_config ( chain_spec: (*spec).clone(), custom: Default::default(), name: format!("Node {}", index), + wasm_method: service::config::WasmExecutionMethod::Interpreted, execution_strategies: Default::default(), rpc_http: None, rpc_ws: None, diff --git a/core/sr-api-macros/tests/runtime_calls.rs b/core/sr-api-macros/tests/runtime_calls.rs index f33a9e257a..ce6300bc41 100644 --- a/core/sr-api-macros/tests/runtime_calls.rs +++ b/core/sr-api-macros/tests/runtime_calls.rs @@ -186,7 +186,7 @@ fn record_proof_works() { // Use the proof backend to execute `execute_block`. let mut overlay = Default::default(); - let executor = NativeExecutor::::new(None); + let executor = NativeExecutor::::new(WasmExecutionMethod::Interpreted, None); execution_proof_check_on_trie_backend( &backend, &mut overlay, diff --git a/core/test-client/src/lib.rs b/core/test-client/src/lib.rs index a2baf11be2..dbe4431456 100644 --- a/core/test-client/src/lib.rs +++ b/core/test-client/src/lib.rs @@ -24,7 +24,7 @@ pub use client::{ExecutionStrategies, blockchain, backend, self}; pub use client_db::{Backend, self}; pub use client_ext::ClientExt; pub use consensus; -pub use executor::{NativeExecutor, self}; +pub use executor::{NativeExecutor, WasmExecutionMethod, self}; pub use keyring::{ AccountKeyring, ed25519::Keyring as Ed25519Keyring, @@ -198,7 +198,7 @@ impl TestClientBuilder } impl TestClientBuilder< - client::LocalCallExecutor>, + client::LocalCallExecutor>, Backend, G, > { @@ -209,18 +209,20 @@ impl TestClientBuilder< ) -> ( client::Client< Backend, - client::LocalCallExecutor>, + client::LocalCallExecutor>, Block, RuntimeApi >, client::LongestChain, ) where - I: Into>>, + I: Into>>, E: executor::NativeExecutionDispatch, Backend: client::backend::Backend, Block: BlockT::Out>, { - let executor = executor.into().unwrap_or_else(|| executor::NativeExecutor::new(None)); + let executor = executor.into().unwrap_or_else(|| + NativeExecutor::new(WasmExecutionMethod::Interpreted, None) + ); let executor = LocalCallExecutor::new(self.backend.clone(), executor, self.keystore.take()); self.build_with_executor(executor) diff --git a/core/test-runtime/client/src/lib.rs b/core/test-runtime/client/src/lib.rs index 722aa0b2b4..affbae62c2 100644 --- a/core/test-runtime/client/src/lib.rs +++ b/core/test-runtime/client/src/lib.rs @@ -39,7 +39,7 @@ pub mod prelude { // Client structs pub use super::{ TestClient, TestClientBuilder, Backend, LightBackend, - Executor, LightExecutor, LocalExecutor, NativeExecutor, + Executor, LightExecutor, LocalExecutor, NativeExecutor, WasmExecutionMethod, }; // Keyring pub use super::{AccountKeyring, Sr25519Keyring}; @@ -261,7 +261,7 @@ pub fn new_light() -> ( let storage = client_db::light::LightStorage::new_test(); let blockchain = Arc::new(client::light::blockchain::Blockchain::new(storage)); let backend = Arc::new(LightBackend::new(blockchain.clone())); - let executor = NativeExecutor::new(None); + let executor = NativeExecutor::new(WasmExecutionMethod::Interpreted, None); let local_call_executor = client::LocalCallExecutor::new(backend.clone(), executor, None); let call_executor = LightExecutor::new( backend.clone(), diff --git a/core/test-runtime/src/system.rs b/core/test-runtime/src/system.rs index e61e72f3a0..12a656cf31 100644 --- a/core/test-runtime/src/system.rs +++ b/core/test-runtime/src/system.rs @@ -322,8 +322,19 @@ mod tests { use runtime_io::{with_externalities, TestExternalities}; use substrate_test_runtime_client::{AccountKeyring, Sr25519Keyring}; use crate::{Header, Transfer, WASM_BINARY}; - use primitives::{Blake2Hasher, map}; - use substrate_executor::WasmExecutor; + use primitives::{Blake2Hasher, NeverNativeValue, map, traits::CodeExecutor}; + use substrate_executor::{NativeExecutor, WasmExecutionMethod, native_executor_instance}; + + // Declare an instance of the native executor dispatch for the test runtime. + native_executor_instance!( + NativeDispatch, + crate::api::dispatch, + crate::native_version + ); + + fn executor() -> NativeExecutor { + NativeExecutor::new(WasmExecutionMethod::Interpreted, None) + } fn new_test_ext() -> TestExternalities { let authorities = vec![ @@ -331,13 +342,19 @@ mod tests { Sr25519Keyring::Bob.to_raw_public(), Sr25519Keyring::Charlie.to_raw_public() ]; - TestExternalities::new((map![ - twox_128(b"latest").to_vec() => vec![69u8; 32], - twox_128(b"sys:auth").to_vec() => authorities.encode(), - blake2_256(&AccountKeyring::Alice.to_raw_public().to_keyed_vec(b"balance:")).to_vec() => { - vec![111u8, 0, 0, 0, 0, 0, 0, 0] - } - ], map![])) + TestExternalities::new_with_code( + WASM_BINARY, + ( + map![ + twox_128(b"latest").to_vec() => vec![69u8; 32], + twox_128(b"sys:auth").to_vec() => authorities.encode(), + blake2_256(&AccountKeyring::Alice.to_raw_public().to_keyed_vec(b"balance:")).to_vec() => { + vec![111u8, 0, 0, 0, 0, 0, 0, 0] + } + ], + map![], + ) + ) } fn block_import_works(block_executor: F) where F: Fn(Block, &mut TestExternalities) { @@ -370,7 +387,13 @@ mod tests { #[test] fn block_import_works_wasm() { block_import_works(|b, ext| { - WasmExecutor::new().call(ext, 8, &WASM_BINARY, "Core_execute_block", &b.encode()).unwrap(); + executor().call::<_, NeverNativeValue, fn() -> _>( + ext, + "Core_execute_block", + &b.encode(), + false, + None, + ).0.unwrap(); }) } @@ -458,7 +481,13 @@ mod tests { #[test] fn block_import_with_transaction_works_wasm() { block_import_with_transaction_works(|b, ext| { - WasmExecutor::new().call(ext, 8, &WASM_BINARY, "Core_execute_block", &b.encode()).unwrap(); + executor().call::<_, NeverNativeValue, fn() -> _>( + ext, + "Core_execute_block", + &b.encode(), + false, + None, + ).0.unwrap(); }) } } diff --git a/node/executor/src/lib.rs b/node/executor/src/lib.rs index 864b51d6c7..38656b7bd4 100644 --- a/node/executor/src/lib.rs +++ b/node/executor/src/lib.rs @@ -22,7 +22,6 @@ #[cfg(feature = "benchmarks")] extern crate test; pub use substrate_executor::NativeExecutor; -pub use substrate_executor::RuntimesCache; use substrate_executor::native_executor_instance; // Declare an instance of the native executor named `Executor`. Include the wasm binary as the @@ -53,6 +52,7 @@ mod tests { transaction_validity::InvalidTransaction, weights::{WeightMultiplier, GetDispatchInfo}, }; use contracts::ContractAddressFor; + use substrate_executor::{NativeExecutor, WasmExecutionMethod}; use system::{EventRecord, Phase}; use node_runtime::{ Header, Block, UncheckedExtrinsic, CheckedExtrinsic, Call, Runtime, Balances, BuildStorage, @@ -117,8 +117,8 @@ mod tests { Header::new(n, Default::default(), Default::default(), [69; 32].into(), Default::default()) } - fn executor() -> ::substrate_executor::NativeExecutor { - substrate_executor::NativeExecutor::new(None) + fn executor() -> NativeExecutor { + NativeExecutor::new(WasmExecutionMethod::Interpreted, None) } fn set_heap_pages>(ext: &mut E, heap_pages: u64) { -- GitLab From 348d27bfb0fa56555c92c79ddc40f5849bb90b7d Mon Sep 17 00:00:00 2001 From: Weiliang Li Date: Wed, 9 Oct 2019 00:16:24 +0900 Subject: [PATCH 023/167] gossip: save sender for kept messages (#3738) --- core/network/src/protocol/consensus_gossip.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/core/network/src/protocol/consensus_gossip.rs b/core/network/src/protocol/consensus_gossip.rs index d916e9aace..e23df7e1a5 100644 --- a/core/network/src/protocol/consensus_gossip.rs +++ b/core/network/src/protocol/consensus_gossip.rs @@ -89,6 +89,7 @@ struct MessageEntry { message_hash: B::Hash, topic: B::Hash, message: ConsensusMessage, + sender: Option, } /// Consensus message destination. @@ -322,12 +323,14 @@ impl ConsensusGossip { message_hash: B::Hash, topic: B::Hash, message: ConsensusMessage, + sender: Option, ) { if self.known_messages.insert(message_hash.clone(), ()).is_none() { self.messages.push(MessageEntry { message_hash, topic, message, + sender, }); } } @@ -343,7 +346,7 @@ impl ConsensusGossip { message: ConsensusMessage, ) { let message_hash = HashFor::::hash(&message.data[..]); - self.register_message_hashed(message_hash, topic, message); + self.register_message_hashed(message_hash, topic, message, None); } /// Call when a peer has been disconnected to stop tracking gossip status. @@ -429,7 +432,7 @@ impl ConsensusGossip { { tx.unbounded_send(TopicNotification { message: entry.message.data.clone(), - sender: None, + sender: entry.sender.clone(), }) .expect("receiver known to be live; qed"); } @@ -498,7 +501,7 @@ impl ConsensusGossip { } } if keep { - self.register_message_hashed(message_hash, topic, message); + self.register_message_hashed(message_hash, topic, message, Some(who.clone())); } } else { trace!(target:"gossip", "Ignored statement from unregistered peer {}", who); @@ -553,7 +556,7 @@ impl ConsensusGossip { force: bool, ) { let message_hash = HashFor::::hash(&message.data); - self.register_message_hashed(message_hash, topic, message.clone()); + self.register_message_hashed(message_hash, topic, message.clone(), None); let intent = if force { MessageIntent::ForcedBroadcast } else { MessageIntent::Broadcast }; propagate(protocol, iter::once((&message_hash, &topic, &message)), intent, &mut self.peers, &self.validators); } @@ -618,6 +621,7 @@ mod tests { message_hash: $hash, topic: $topic, message: ConsensusMessage { data: $m, engine_id: [0, 0, 0, 0]}, + sender: None, }); } } -- GitLab From f3a830d3e37d78a869c78c037cc2ac6f0c4e5ddd Mon Sep 17 00:00:00 2001 From: Ashley Date: Wed, 9 Oct 2019 04:31:39 +1300 Subject: [PATCH 024/167] Split off System random functions into a new Randomness module (#3699) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * split off system randomness functions into a new module * bump spec and impl version * Move randomness to bottom of construct_runtime calls, move initialization into on_initialize * Update srml/randomness/Cargo.toml Co-Authored-By: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update srml/randomness/src/lib.rs Co-Authored-By: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update srml/randomness/src/lib.rs Co-Authored-By: Bastian Köcher * Update srml/randomness/Cargo.toml Co-Authored-By: Bastian Köcher * Improve system example * Update Cargo.lock * Fix randomness example * Get rid of the stored index * Add tests * Add a random test * Improve docs * Fix executive test :^) * Add a utility function to tests * Update srml/randomness/Cargo.toml Co-Authored-By: Gavin Wood * Update srml/randomness/src/lib.rs Co-Authored-By: Bastian Köcher * Update srml/randomness/src/lib.rs Co-Authored-By: Bastian Köcher * Change interpretation of block numbers * rename crate * refactor randomess module usage * change random material len to a const * Update srml/randomness-collective-flip/src/lib.rs Co-Authored-By: Bastian Köcher * Update srml/randomness-collective-flip/src/lib.rs Co-Authored-By: Bastian Köcher --- Cargo.lock | 17 ++ Cargo.toml | 1 + node-template/runtime/Cargo.toml | 2 + node-template/runtime/src/lib.rs | 3 +- node/runtime/Cargo.toml | 2 + node/runtime/src/lib.rs | 7 +- srml/contracts/Cargo.toml | 3 + srml/contracts/src/exec.rs | 2 +- srml/executive/src/lib.rs | 2 +- srml/randomness-collective-flip/Cargo.toml | 28 ++ srml/randomness-collective-flip/src/lib.rs | 289 +++++++++++++++++++++ srml/system/src/lib.rs | 77 +----- 12 files changed, 352 insertions(+), 81 deletions(-) create mode 100644 srml/randomness-collective-flip/Cargo.toml create mode 100644 srml/randomness-collective-flip/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 170ed9e2f1..d63806fee4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2478,6 +2478,7 @@ dependencies = [ "srml-indices 2.0.0", "srml-membership 2.0.0", "srml-offences 1.0.0", + "srml-randomness-collective-flip 2.0.0", "srml-session 2.0.0", "srml-staking 2.0.0", "srml-staking-reward-curve 2.0.0", @@ -2544,6 +2545,7 @@ dependencies = [ "srml-executive 2.0.0", "srml-grandpa 2.0.0", "srml-indices 2.0.0", + "srml-randomness-collective-flip 2.0.0", "srml-sudo 2.0.0", "srml-support 2.0.0", "srml-system 2.0.0", @@ -4011,6 +4013,7 @@ dependencies = [ "sr-sandbox 2.0.0", "sr-std 2.0.0", "srml-balances 2.0.0", + "srml-randomness-collective-flip 2.0.0", "srml-support 2.0.0", "srml-system 2.0.0", "srml-timestamp 2.0.0", @@ -4224,6 +4227,20 @@ dependencies = [ "substrate-primitives 2.0.0", ] +[[package]] +name = "srml-randomness-collective-flip" +version = "2.0.0" +dependencies = [ + "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-io 2.0.0", + "sr-primitives 2.0.0", + "sr-std 2.0.0", + "srml-support 2.0.0", + "srml-system 2.0.0", + "substrate-primitives 2.0.0", +] + [[package]] name = "srml-scored-pool" version = "1.0.0" diff --git a/Cargo.toml b/Cargo.toml index 71ba1c17f1..62993397fd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -95,6 +95,7 @@ members = [ "srml/membership", "srml/metadata", "srml/offences", + "srml/randomness-collective-flip", "srml/scored-pool", "srml/session", "srml/staking", diff --git a/node-template/runtime/Cargo.toml b/node-template/runtime/Cargo.toml index 18948d503c..76821b6dfd 100644 --- a/node-template/runtime/Cargo.toml +++ b/node-template/runtime/Cargo.toml @@ -20,6 +20,7 @@ babe-primitives = { package = "substrate-consensus-babe-primitives", path = "../ executive = { package = "srml-executive", path = "../../srml/executive", default_features = false } indices = { package = "srml-indices", path = "../../srml/indices", default_features = false } grandpa = { package = "srml-grandpa", path = "../../srml/grandpa", default-features = false } +randomness-collective-flip = { package = "srml-randomness-collective-flip", path = "../../srml/randomness-collective-flip", default_features = false } system = { package = "srml-system", path = "../../srml/system", default_features = false } timestamp = { package = "srml-timestamp", path = "../../srml/timestamp", default_features = false } sudo = { package = "srml-sudo", path = "../../srml/sudo", default_features = false } @@ -46,6 +47,7 @@ std = [ "grandpa/std", "primitives/std", "sr-primitives/std", + "randomness-collective-flip/std", "system/std", "timestamp/std", "sudo/std", diff --git a/node-template/runtime/src/lib.rs b/node-template/runtime/src/lib.rs index 216cb0edc2..ba328c6e37 100644 --- a/node-template/runtime/src/lib.rs +++ b/node-template/runtime/src/lib.rs @@ -272,6 +272,7 @@ construct_runtime!( Sudo: sudo, // Used for the module template in `./template.rs` TemplateModule: template::{Module, Call, Storage, Event}, + RandomnessCollectiveFlip: randomness_collective_flip::{Module, Call, Storage}, } ); @@ -340,7 +341,7 @@ impl_runtime_apis! { } fn random_seed() -> ::Hash { - System::random_seed() + RandomnessCollectiveFlip::random_seed() } } diff --git a/node/runtime/Cargo.toml b/node/runtime/Cargo.toml index f256575086..a47d652100 100644 --- a/node/runtime/Cargo.toml +++ b/node/runtime/Cargo.toml @@ -40,6 +40,7 @@ im-online = { package = "srml-im-online", path = "../../srml/im-online", default indices = { package = "srml-indices", path = "../../srml/indices", default-features = false } membership = { package = "srml-membership", path = "../../srml/membership", default-features = false } offences = { package = "srml-offences", path = "../../srml/offences", default-features = false } +randomness-collective-flip = { package = "srml-randomness-collective-flip", path = "../../srml/randomness-collective-flip", default-features = false } session = { package = "srml-session", path = "../../srml/session", default-features = false, features = ["historical"] } staking = { package = "srml-staking", path = "../../srml/staking", default-features = false } srml-staking-reward-curve = { path = "../../srml/staking/reward-curve"} @@ -78,6 +79,7 @@ std = [ "offchain-primitives/std", "offences/std", "primitives/std", + "randomness-collective-flip/std", "rstd/std", "rustc-hex", "safe-mix/std", diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index 7495190464..ebe7b134e0 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -84,8 +84,8 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // and set impl_version to equal spec_version. If only runtime // implementation changes and behavior does not, then leave spec_version as // is and increment impl_version. - spec_version: 172, - impl_version: 172, + spec_version: 173, + impl_version: 173, apis: RUNTIME_API_VERSIONS, }; @@ -518,6 +518,7 @@ construct_runtime!( ImOnline: im_online::{Module, Call, Storage, Event, ValidateUnsigned, Config}, AuthorityDiscovery: authority_discovery::{Module, Call, Config}, Offences: offences::{Module, Call, Storage, Event}, + RandomnessCollectiveFlip: randomness_collective_flip::{Module, Call, Storage}, } ); @@ -589,7 +590,7 @@ impl_runtime_apis! { } fn random_seed() -> ::Hash { - System::random_seed() + RandomnessCollectiveFlip::random_seed() } } diff --git a/srml/contracts/Cargo.toml b/srml/contracts/Cargo.toml index f076f5feda..aad45df860 100644 --- a/srml/contracts/Cargo.toml +++ b/srml/contracts/Cargo.toml @@ -17,6 +17,8 @@ rstd = { package = "sr-std", path = "../../core/sr-std", default-features = fals sandbox = { package = "sr-sandbox", path = "../../core/sr-sandbox", default-features = false } support = { package = "srml-support", path = "../support", default-features = false } system = { package = "srml-system", path = "../system", default-features = false } +randomness-collective-flip = { package = "srml-randomness-collective-flip", path = "../randomness-collective-flip", default-features = false } +timestamp = { package = "srml-timestamp", path = "../timestamp", default-features = false } [dev-dependencies] wabt = "0.9.2" @@ -33,6 +35,7 @@ std = [ "codec/std", "primitives/std", "sr-primitives/std", + "randomness-collective-flip/std", "runtime-io/std", "rstd/std", "sandbox/std", diff --git a/srml/contracts/src/exec.rs b/srml/contracts/src/exec.rs index 94343c5fb9..e4c5539cec 100644 --- a/srml/contracts/src/exec.rs +++ b/srml/contracts/src/exec.rs @@ -753,7 +753,7 @@ where } fn random(&self, subject: &[u8]) -> SeedOf { - system::Module::::random(subject) + randomness_collective_flip::Module::::random(subject) } fn now(&self) -> &MomentOf { diff --git a/srml/executive/src/lib.rs b/srml/executive/src/lib.rs index ad9cb7bf80..ee11ffadf4 100644 --- a/srml/executive/src/lib.rs +++ b/srml/executive/src/lib.rs @@ -451,7 +451,7 @@ mod tests { header: Header { parent_hash: [69u8; 32].into(), number: 1, - state_root: hex!("3e51b47b6cc8449eece93eee4b01f03b00a0ca7981c0b6c0447b6e0d50ca886d").into(), + state_root: hex!("a6378d7fdd31029d13718d54bdff10a370e75cc624aaf94a90e7e7d4a24e0bcc").into(), extrinsics_root: hex!("03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314").into(), digest: Digest { logs: vec![], }, }, diff --git a/srml/randomness-collective-flip/Cargo.toml b/srml/randomness-collective-flip/Cargo.toml new file mode 100644 index 0000000000..5be9aad50f --- /dev/null +++ b/srml/randomness-collective-flip/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "srml-randomness-collective-flip" +version = "2.0.0" +authors = ["Parity Technologies "] +edition = "2018" + +[dependencies] +safe-mix = { version = "1.0", default-features = false } +codec = { package = "parity-scale-codec", version = "1.0.0", default-features = false, features = ["derive"] } +sr-primitives = { path = "../../core/sr-primitives", default-features = false } +support = { package = "srml-support", path = "../support", default-features = false } +system = { package = "srml-system", path = "../system", default-features = false } +rstd = { package = "sr-std", path = "../../core/sr-std", default-features = false } + +[dev-dependencies] +primitives = { package = "substrate-primitives", path = "../../core/primitives" } +runtime-io = { package = "sr-io", path = "../../core/sr-io" } + +[features] +default = ["std"] +std = [ + "safe-mix/std", + "system/std", + "codec/std", + "support/std", + "sr-primitives/std", + "rstd/std", +] diff --git a/srml/randomness-collective-flip/src/lib.rs b/srml/randomness-collective-flip/src/lib.rs new file mode 100644 index 0000000000..39dcf15ab4 --- /dev/null +++ b/srml/randomness-collective-flip/src/lib.rs @@ -0,0 +1,289 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +//! # Randomness Module +//! +//! The Randomness Collective Flip module provides a [`random`](./struct.Module.html#method.random) +//! function that generates low-influence random values based on the block hashes from the previous +//! `81` blocks. Low-influence randomness can be useful when defending against relatively weak +//! adversaries. +//! +//! ## Public Functions +//! +//! See the [`Module`](./struct.Module.html) struct for details of publicly available functions. +//! +//! ## Usage +//! +//! ### Prerequisites +//! +//! Import the Randomness Collective Flip module and derive your module's configuration trait from +//! the system trait. +//! +//! ### Example - Get random seed for the current block +//! +//! ``` +//! use support::{decl_module, dispatch::Result}; +//! +//! pub trait Trait: system::Trait {} +//! +//! decl_module! { +//! pub struct Module for enum Call where origin: T::Origin { +//! pub fn random_module_example(origin) -> Result { +//! let _random_seed = >::random_seed(); +//! Ok(()) +//! } +//! } +//! } +//! # fn main() { } +//! ``` + +#![cfg_attr(not(feature = "std"), no_std)] + +use rstd::{prelude::*, convert::TryInto}; +use sr_primitives::traits::Hash; +use support::{decl_module, decl_storage}; +use safe_mix::TripletMix; +use codec::Encode; +use system::Trait; + +const RANDOM_MATERIAL_LEN: u32 = 81; + +fn block_number_to_index(block_number: T::BlockNumber) -> usize { + // on_initialize is called on the first block after genesis + let index = (block_number - 1.into()) % RANDOM_MATERIAL_LEN.into(); + index.try_into().ok().expect("Something % 81 is always smaller than usize; qed") +} + +decl_module! { + pub struct Module for enum Call where origin: T::Origin { + fn on_initialize(block_number: T::BlockNumber) { + let parent_hash = >::parent_hash(); + + >::mutate(|ref mut values| if values.len() < RANDOM_MATERIAL_LEN as usize { + values.push(parent_hash) + } else { + let index = block_number_to_index::(block_number); + values[index] = parent_hash; + }); + } + } +} + +decl_storage! { + trait Store for Module as RandomnessCollectiveFlip { + /// Series of block headers from the last 81 blocks that acts as random seed material. This + /// is arranged as a ring buffer with `block_number % 81` being the index into the `Vec` of + /// the oldest hash. + RandomMaterial get(random_material): Vec; + } +} + +impl Module { + /// Get the basic random seed. + /// + /// In general you won't want to use this, but rather `Self::random` which allows you to give a + /// subject for the random result and whose value will be independently low-influence random + /// from any other such seeds. + pub fn random_seed() -> T::Hash { + Self::random(&[][..]) + } + + /// Get a low-influence "random" value. + /// + /// Being a deterministic block chain, real randomness is difficult to come by. This gives you + /// something that approximates it. `subject` is a context identifier and allows you to get a + /// different result to other callers of this function; use it like + /// `random(&b"my context"[..])`. This is initially implemented through a low-influence + /// "triplet mix" convolution of previous block hash values. In the future it will be generated + /// from a secure verifiable random function (VRF). + /// + /// ### Security Notes + /// + /// This randomness uses a low-influence function, drawing upon the block hashes from the + /// previous 81 blocks. Its result for any given subject will be known far in advance by anyone + /// observing the chain. Any block producer has significant influence over their block hashes + /// bounded only by their computational resources. Our low-influence function reduces the actual + /// block producer's influence over the randomness, but increases the influence of small + /// colluding groups of recent block producers. + /// + /// Some BABE blocks have VRF outputs where the block producer has exactly one bit of influence, + /// either they make the block or they do not make the block and thus someone else makes the + /// next block. Yet, this randomness is not fresh in all BABE blocks. + /// + /// If that is an insufficient security guarantee then two things can be used to improve this + /// randomness: + /// + /// - Name, in advance, the block number whose random value will be used; ensure your module + /// retains a buffer of previous random values for its subject and then index into these in + /// order to obviate the ability of your user to look up the parent hash and choose when to + /// transact based upon it. + /// - Require your user to first commit to an additional value by first posting its hash. + /// Require them to reveal the value to determine the final result, hashing it with the + /// output of this random function. This reduces the ability of a cabal of block producers + /// from conspiring against individuals. + /// + /// WARNING: Hashing the result of this function will remove any low-influence properties it has + /// and mean that all bits of the resulting value are entirely manipulatable by the author of + /// the parent block, who can determine the value of `parent_hash`. + pub fn random(subject: &[u8]) -> T::Hash { + let block_number = >::block_number(); + let index = block_number_to_index::(block_number); + + let hash_series = >::get(); + if !hash_series.is_empty() { + // Always the case after block 1 is initialised. + hash_series.iter() + .cycle() + .skip(index) + .take(RANDOM_MATERIAL_LEN as usize) + .enumerate() + .map(|(i, h)| (i as i8, subject, h).using_encoded(T::Hashing::hash)) + .triplet_mix() + } else { + T::Hash::default() + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use primitives::{H256, Blake2Hasher}; + use sr_primitives::{Perbill, traits::{BlakeTwo256, OnInitialize, Header as _, IdentityLookup}, testing::Header}; + use support::{impl_outer_origin, parameter_types}; + use runtime_io::with_externalities; + + #[derive(Clone, PartialEq, Eq)] + pub struct Test; + + impl_outer_origin! { + pub enum Origin for Test {} + } + + parameter_types! { + pub const BlockHashCount: u64 = 250; + pub const MaximumBlockWeight: u32 = 1024; + pub const MaximumBlockLength: u32 = 2 * 1024; + pub const AvailableBlockRatio: Perbill = Perbill::one(); + } + + 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; + type Lookup = IdentityLookup; + type Header = Header; + type WeightMultiplierUpdate = (); + type Event = (); + type BlockHashCount = BlockHashCount; + type MaximumBlockWeight = MaximumBlockWeight; + type AvailableBlockRatio = AvailableBlockRatio; + type MaximumBlockLength = MaximumBlockLength; + type Version = (); + } + + type System = system::Module; + type Randomness = Module; + + fn new_test_ext() -> runtime_io::TestExternalities { + let t = system::GenesisConfig::default().build_storage::().unwrap(); + t.into() + } + + #[test] + fn test_block_number_to_index() { + for i in 1 .. 1000 { + assert_eq!((i - 1) as usize % 81, block_number_to_index::(i)); + } + } + + fn setup_blocks(blocks: u64) { + let mut parent_hash = System::parent_hash(); + + for i in 1 .. (blocks + 1) { + System::initialize(&i, &parent_hash, &Default::default(), &Default::default()); + Randomness::on_initialize(i); + + let header = System::finalize(); + parent_hash = header.hash(); + System::set_block_number(*header.number()); + } + } + + #[test] + fn test_random_material_parital() { + with_externalities(&mut new_test_ext(), || { + let genesis_hash = System::parent_hash(); + + setup_blocks(38); + + let random_material = Randomness::random_material(); + + assert_eq!(random_material.len(), 38); + assert_eq!(random_material[0], genesis_hash); + }); + } + + #[test] + fn test_random_material_filled() { + with_externalities(&mut new_test_ext(), || { + let genesis_hash = System::parent_hash(); + + setup_blocks(81); + + let random_material = Randomness::random_material(); + + assert_eq!(random_material.len(), 81); + assert_ne!(random_material[0], random_material[1]); + assert_eq!(random_material[0], genesis_hash); + }); + } + + #[test] + fn test_random_material_filled_twice() { + with_externalities(&mut new_test_ext(), || { + let genesis_hash = System::parent_hash(); + + setup_blocks(162); + + let random_material = Randomness::random_material(); + + assert_eq!(random_material.len(), 81); + assert_ne!(random_material[0], random_material[1]); + assert_ne!(random_material[0], genesis_hash); + }); + } + + #[test] + fn test_random() { + with_externalities(&mut new_test_ext(), || { + setup_blocks(162); + + assert_eq!(System::block_number(), 162); + assert_eq!(Randomness::random_seed(), Randomness::random_seed()); + assert_ne!(Randomness::random(b"random_1"), Randomness::random(b"random_2")); + + let random = Randomness::random_seed(); + + assert_ne!(random, H256::zero()); + assert!(!Randomness::random_material().contains(&random)); + }); + } +} diff --git a/srml/system/src/lib.rs b/srml/system/src/lib.rs index 5a1115b90d..79782d5af4 100644 --- a/srml/system/src/lib.rs +++ b/srml/system/src/lib.rs @@ -65,7 +65,7 @@ //! //! Import the System module and derive your module's configuration trait from the system trait. //! -//! ### Example - Get random seed and extrinsic count for the current block +//! ### Example - Get extrinsic count and parent hash for the current block //! //! ``` //! use support::{decl_module, dispatch::Result}; @@ -77,8 +77,8 @@ //! pub struct Module for enum Call where origin: T::Origin { //! pub fn system_module_example(origin) -> Result { //! let _sender = ensure_signed(origin)?; -//! let _random_seed = >::random_seed(); //! let _extrinsic_count = >::extrinsic_count(); +//! let _parent_hash = >::parent_hash(); //! Ok(()) //! } //! } @@ -114,7 +114,6 @@ use support::{ decl_module, decl_event, decl_storage, decl_error, storage, Parameter, traits::{Contains, Get}, }; -use safe_mix::TripletMix; use codec::{Encode, Decode}; #[cfg(any(feature = "std", test))] @@ -389,9 +388,6 @@ decl_storage! { pub BlockHash get(block_hash) build(|_| vec![(T::BlockNumber::zero(), hash69())]): map T::BlockNumber => T::Hash; /// Extrinsics data for the current block (maps an extrinsic's index to its data). ExtrinsicData get(extrinsic_data): map u32 => Vec; - /// Series of block headers from the last 81 blocks that acts as random seed material. This is arranged as a - /// ring buffer with the `i8` prefix being the index into the `Vec` of the oldest hash. - RandomMaterial get(random_material): (i8, Vec); /// The current block number being processed. Set by `execute_block`. Number get(block_number) build(|_| 1.into()): T::BlockNumber; /// Hash of the previous block. @@ -641,12 +637,6 @@ impl Module { >::put(parent_hash); >::insert(*number - One::one(), parent_hash); >::put(txs_root); - >::mutate(|&mut(ref mut index, ref mut values)| if values.len() < 81 { - values.push(parent_hash.clone()) - } else { - values[*index as usize] = parent_hash.clone(); - *index = (*index + 1) % 81; - }); >::kill(); EventCount::kill(); >::remove_prefix(&()); @@ -736,69 +726,6 @@ impl Module { /// Return the chain's current runtime version. pub fn runtime_version() -> RuntimeVersion { T::Version::get() } - /// Get the basic random seed. - /// - /// In general you won't want to use this, but rather `Self::random` which - /// allows you to give a subject for the random result and whose value will - /// be independently low-influence random from any other such seeds. - pub fn random_seed() -> T::Hash { - Self::random(&[][..]) - } - - /// Get a low-influence "random" value. - /// - /// Being a deterministic block chain, real randomness is difficult to come - /// by. This gives you something that approximates it. `subject` is a - /// context identifier and allows you to get a different result to other - /// callers of this function; use it like `random(&b"my context"[..])`. - /// - /// This is initially implemented through a low-influence "triplet mix" - /// convolution of previous block hash values. In the future it will be - /// generated from a secure verifiable random function (VRF). - /// - /// ### Security Notes - /// - /// This randomness uses a low-influence function, drawing upon the block - /// hashes from the previous 81 blocks. Its result for any given subject - /// will be known in advance by the block producer of this block (and, - /// indeed, anyone who knows the block's `parent_hash`). However, it is - /// mostly impossible for the producer of this block *alone* to influence - /// the value of this hash. A sizable minority of dishonest and coordinating - /// block producers would be required in order to affect this value. If that - /// is an insufficient security guarantee then two things can be used to - /// improve this randomness: - /// - /// - Name, in advance, the block number whose random value will be used; - /// ensure your module retains a buffer of previous random values for its - /// subject and then index into these in order to obviate the ability of - /// your user to look up the parent hash and choose when to transact based - /// upon it. - /// - Require your user to first commit to an additional value by first - /// posting its hash. Require them to reveal the value to determine the - /// final result, hashing it with the output of this random function. This - /// reduces the ability of a cabal of block producers from conspiring - /// against individuals. - /// - /// WARNING: Hashing the result of this function will remove any - /// low-influnce properties it has and mean that all bits of the resulting - /// value are entirely manipulatable by the author of the parent block, who - /// can determine the value of `parent_hash`. - pub fn random(subject: &[u8]) -> T::Hash { - let (index, hash_series) = >::get(); - if hash_series.len() > 0 { - // Always the case after block 1 is initialised. - hash_series.iter() - .cycle() - .skip(index as usize) - .take(81) - .enumerate() - .map(|(i, h)| (i as i8, subject, h).using_encoded(T::Hashing::hash)) - .triplet_mix() - } else { - T::Hash::default() - } - } - /// Increment a particular account's nonce by 1. pub fn inc_account_nonce(who: &T::AccountId) { >::insert(who, Self::account_nonce(who) + T::Index::one()); -- GitLab From 82bd785c9c3f64eed744e4602fac5eb4a96a2c9b Mon Sep 17 00:00:00 2001 From: Demi Obenour <48690212+DemiMarie-parity@users.noreply.github.com> Date: Tue, 8 Oct 2019 15:09:05 -0400 Subject: [PATCH 025/167] Update dependencies, respecting semver (#3784) --- Cargo.lock | 154 +++++++++++++++++++++++++++-------------------------- 1 file changed, 78 insertions(+), 76 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d63806fee4..ba762f1393 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -38,7 +38,7 @@ dependencies = [ [[package]] name = "ahash" -version = "0.2.13" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "const-random 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -366,7 +366,7 @@ dependencies = [ "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -532,7 +532,7 @@ dependencies = [ "rayon-core 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "tinytemplate 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -751,13 +751,14 @@ dependencies = [ [[package]] name = "ed25519-dalek" -version = "1.0.0-pre.1" +version = "1.0.0-pre.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "curve25519-dalek 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -890,7 +891,7 @@ dependencies = [ "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "libz-sys 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", - "miniz_oxide 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "miniz_oxide 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1159,10 +1160,10 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "ahash 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", + "ahash 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)", "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1382,7 +1383,7 @@ name = "impl-trait-for-tuples" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1459,7 +1460,7 @@ dependencies = [ "jsonrpc-pubsub 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "websocket 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1474,7 +1475,7 @@ dependencies = [ "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1683,7 +1684,7 @@ dependencies = [ "asn1_der 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "bs58 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "ed25519-dalek 1.0.0-pre.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ed25519-dalek 1.0.0-pre.2 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1703,7 +1704,7 @@ dependencies = [ "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "unsigned-varint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "unsigned-varint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "wasm-timer 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1774,7 +1775,7 @@ dependencies = [ "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "unsigned-varint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "unsigned-varint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "wasm-timer 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1801,7 +1802,7 @@ dependencies = [ "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "uint 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "unsigned-varint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "unsigned-varint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "wasm-timer 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1841,7 +1842,7 @@ dependencies = [ "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "unsigned-varint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "unsigned-varint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2043,7 +2044,7 @@ dependencies = [ [[package]] name = "libsecp256k1" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2051,6 +2052,7 @@ dependencies = [ "hmac-drbg 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "subtle 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2164,7 +2166,7 @@ version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "hash-db 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", - "hashbrown 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hashbrown 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-util-mem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2194,7 +2196,7 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "adler32 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2264,7 +2266,7 @@ dependencies = [ "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "unsigned-varint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "unsigned-varint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2283,9 +2285,9 @@ dependencies = [ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl 0.10.24 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl 0.10.25 (registry+https://github.com/rust-lang/crates.io-index)", "openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.49 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.50 (registry+https://github.com/rust-lang/crates.io-index)", "schannel 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", "security-framework 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "security-framework-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2680,7 +2682,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "openssl" -version = "0.10.24" +version = "0.10.25" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2688,7 +2690,7 @@ dependencies = [ "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.49 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.50 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2698,7 +2700,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "openssl-sys" -version = "0.9.49" +version = "0.9.50" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2742,7 +2744,7 @@ dependencies = [ "parity-multihash 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "unsigned-varint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "unsigned-varint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2757,7 +2759,7 @@ dependencies = [ "sha-1 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "sha3 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", - "unsigned-varint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "unsigned-varint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2909,7 +2911,7 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro-hack 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3001,7 +3003,7 @@ name = "proc-macro-hack" version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3016,7 +3018,7 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3119,7 +3121,7 @@ name = "quote" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3447,7 +3449,7 @@ name = "rustversion" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3591,14 +3593,14 @@ name = "serde_derive" version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_json" -version = "1.0.40" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3698,7 +3700,7 @@ dependencies = [ "chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", "erased-serde 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "slog 2.5.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3792,7 +3794,7 @@ dependencies = [ "substrate-state-machine 2.0.0", "substrate-test-runtime-client 2.0.0", "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", - "trybuild 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", + "trybuild 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3801,7 +3803,7 @@ version = "2.0.0" dependencies = [ "environmental 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "hash-db 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libsecp256k1 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libsecp256k1 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "sr-std 2.0.0", @@ -3824,7 +3826,7 @@ dependencies = [ "primitive-types 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 2.0.0", "sr-std 2.0.0", "substrate-application-crypto 2.0.0", @@ -4305,7 +4307,7 @@ name = "srml-staking-reward-curve" version = "2.0.0" dependencies = [ "proc-macro-crate 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4388,7 +4390,7 @@ dependencies = [ "srml-support 2.0.0", "substrate-inherents 2.0.0", "substrate-primitives 2.0.0", - "trybuild 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", + "trybuild 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -4582,7 +4584,7 @@ dependencies = [ "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "prost 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "prost-build 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", "substrate-authority-discovery-primitives 2.0.0", "substrate-client 2.0.0", @@ -4638,7 +4640,7 @@ version = "2.0.0" dependencies = [ "impl-trait-for-tuples 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", "substrate-chain-spec-derive 2.0.0", "substrate-network 2.0.0", @@ -4651,7 +4653,7 @@ name = "substrate-chain-spec-derive" version = "2.0.0" dependencies = [ "proc-macro-crate 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -4675,7 +4677,7 @@ dependencies = [ "names 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rpassword 4.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", "structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", "substrate-client 2.0.0", @@ -4964,7 +4966,7 @@ dependencies = [ "derive_more 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "hex-literal 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libsecp256k1 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libsecp256k1 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "parity-wasm 0.40.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4998,7 +5000,7 @@ dependencies = [ "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", "srml-finality-tracker 2.0.0", "substrate-client 2.0.0", @@ -5069,7 +5071,7 @@ dependencies = [ "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "substrate-application-crypto 2.0.0", "substrate-primitives 2.0.0", "subtle 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -5102,7 +5104,7 @@ dependencies = [ "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "slog 2.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "slog_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -5120,7 +5122,7 @@ dependencies = [ "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "unsigned-varint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "unsigned-varint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "zeroize 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -5179,7 +5181,7 @@ dependencies = [ "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "lru-cache 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -5243,7 +5245,7 @@ dependencies = [ "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 2.0.0", "sr-primitives 2.0.0", "sr-version 2.0.0", @@ -5275,7 +5277,7 @@ dependencies = [ "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "sr-version 2.0.0", "substrate-primitives 2.0.0", "substrate-rpc-primitives 2.0.0", @@ -5300,7 +5302,7 @@ dependencies = [ "jsonrpc-ws-server 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", ] @@ -5321,7 +5323,7 @@ name = "substrate-serializer" version = "2.0.0" dependencies = [ "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -5341,7 +5343,7 @@ dependencies = [ "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "slog 2.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 2.0.0", "sr-primitives 2.0.0", @@ -5619,7 +5621,7 @@ name = "syn" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -5741,7 +5743,7 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -6006,7 +6008,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "elastic-array 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", "hash-db 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", - "hashbrown 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hashbrown 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -6035,13 +6037,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "trybuild" -version = "1.0.15" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -6138,7 +6140,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "unsigned-varint" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", @@ -6207,7 +6209,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "wabt-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -6263,7 +6265,7 @@ dependencies = [ "bumpalo 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "wasm-bindgen-shared 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", @@ -6295,7 +6297,7 @@ name = "wasm-bindgen-macro-support" version = "0.2.51" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "wasm-bindgen-backend 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", @@ -6315,7 +6317,7 @@ dependencies = [ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "wasm-bindgen-backend 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", @@ -6563,7 +6565,7 @@ dependencies = [ "checksum aes-ctr 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d2e5b0458ea3beae0d1d8c0f3946564f8e10f90646cf78c06b4351052058d1ee" "checksum aes-soft 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cfd7e7ae3f9a1fb5c03b389fc6bb9a51400d0c13053f0dca698c832bfd893a0d" "checksum aesni 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f70a6b5f971e473091ab7cfb5ffac6cde81666c4556751d8d5620ead8abf100" -"checksum ahash 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "b58aeefd9396419a4f4f2b9778f2d832a11851b55010e231c5390cf2b1c416b4" +"checksum ahash 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)" = "b35dfc96a657c1842b4eb73180b65e37152d4b94d0eb5cb51708aee7826950b4" "checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d" "checksum aio-limited 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c4dddf55b0b2da9acb7512f21c0a4f1c0871522ec4ab7fb919d0da807d1e32b3" "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" @@ -6646,7 +6648,7 @@ dependencies = [ "checksum dns-parser 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c4d33be9473d06f75f58220f71f7a9317aca647dc061dbd3c361b0bef505fbea" "checksum doc-comment 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "923dea538cea0aa3025e8685b20d6ee21ef99c4f77e954a30febbaac5ec73a97" "checksum ed25519-dalek 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d07e8b8a8386c3b89a7a4b329fdfa4cb545de2545e9e2ebbc3dd3929253e426" -"checksum ed25519-dalek 1.0.0-pre.1 (registry+https://github.com/rust-lang/crates.io-index)" = "81956bcf7ef761fb4e1d88de3fa181358a0d26cbcb9755b587a08f9119824b86" +"checksum ed25519-dalek 1.0.0-pre.2 (registry+https://github.com/rust-lang/crates.io-index)" = "845aaacc16f01178f33349e7c992ecd0cee095aa5e577f0f4dee35971bd36455" "checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" "checksum elastic-array 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "073be79b6538296faf81c631872676600616073817dd9a440c477ad09b408983" "checksum env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3" @@ -6693,7 +6695,7 @@ dependencies = [ "checksum hash-db 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d23bd4e7b5eda0d0f3a307e8b381fdc8ba9000f26fbe912250c0a4cc3956364a" "checksum hash256-std-hasher 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)" = "92c171d55b98633f4ed3860808f004099b36c1cc29c42cfc53aa8591b21efcf2" "checksum hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3bae29b6653b3412c2e71e9d486db9f9df5d701941d86683005efb9f2d28e3da" -"checksum hashbrown 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2bcea5b597dd98e6d1f1ec171744cc5dee1a30d1c23c5b98e3cf9d4fbdf8a526" +"checksum hashbrown 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6587d09be37fb98a11cb08b9000a3f592451c1b1b613ca69d949160e313a430a" "checksum hashmap_core 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "2d6852e5a86250521973b0c1d39677166d8a9c0047c908d7e04f1aa04177973c" "checksum heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1679e6ea370dee694f91f1dc469bf94cf8f52051d147aec3e1f9497c6fc22461" "checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" @@ -6767,7 +6769,7 @@ dependencies = [ "checksum libp2p-yamux 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a37bed07c8ee0ceeecdfb90d703aa6b1cec99a69b4157e5f7f2c03acacbfca15" "checksum librocksdb-sys 5.18.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d19778314deaa7048f2ea7d07b8aa12e1c227acebe975a37eeab6d2f8c74e41b" "checksum libsecp256k1 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "688e8d65e495567c2c35ea0001b26b9debf0b4ea11f8cccc954233b75fc3428a" -"checksum libsecp256k1 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf0a4113e7b18b72b9b65d5b35335d99865ef059034426e4b85ad63adddf996" +"checksum libsecp256k1 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "63cc09b49bf0cc55885982347b174ad89855e97a12284d2c9dcc6da2e20c28f5" "checksum libz-sys 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "2eb5e43362e38e2bca2fd5f5134c4d4564a23a5c28e9b95411652021a8675ebe" "checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83" "checksum linked_hash_set 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3c7c91c4c7bbeb4f2f7c4e5be11e6a05bd6830bc37249c47ce1ad86ad453ff9c" @@ -6785,7 +6787,7 @@ dependencies = [ "checksum memory_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "71d96e3f3c0b6325d8ccd83c33b28acb183edcb6c67938ba104ec546854b0882" "checksum merlin 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "de2d16d3b15fec5943d1144f861f61f279d165fdd60998ca262913b9bf1c8adb" "checksum mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0" -"checksum miniz_oxide 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7108aff85b876d06f22503dcce091e29f76733b2bfdd91eebce81f5e68203a10" +"checksum miniz_oxide 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "304f66c19be2afa56530fa7c39796192eef38618da8d19df725ad7c6d6b2aaae" "checksum mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)" = "83f51996a3ed004ef184e16818edc51fadffe8e7ca68be67f9dee67d84d0ff23" "checksum mio-extras 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "46e73a04c2fa6250b8d802134d56d554a9ec2922bf977777c805ea5def61ce40" "checksum mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "966257a94e196b11bb43aca423754d87429960a768de9414f3691d6957abf125" @@ -6808,9 +6810,9 @@ dependencies = [ "checksum once_cell 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "532c29a261168a45ce28948f9537ddd7a5dd272cc513b3017b1e82a88f962c37" "checksum once_cell 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d584f08c2d717d5c23a6414fc2822b71c651560713e54fa7eace675f758a355e" "checksum opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" -"checksum openssl 0.10.24 (registry+https://github.com/rust-lang/crates.io-index)" = "8152bb5a9b5b721538462336e3bef9a539f892715e5037fda0f984577311af15" +"checksum openssl 0.10.25 (registry+https://github.com/rust-lang/crates.io-index)" = "2f372b2b53ce10fb823a337aaa674e3a7d072b957c6264d0f4ff0bd86e657449" "checksum openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" -"checksum openssl-sys 0.9.49 (registry+https://github.com/rust-lang/crates.io-index)" = "f4fad9e54bd23bd4cbbe48fdc08a1b8091707ac869ef8508edea2fec77dcc884" +"checksum openssl-sys 0.9.50 (registry+https://github.com/rust-lang/crates.io-index)" = "2c42dcccb832556b5926bc9ae61e8775f2a61e725ab07ab3d1e7fcf8ae62c3b6" "checksum output_vt100 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53cdc5b785b7a58c5aad8216b3dfa114df64b0b06ae6e1501cef91df2fbdf8f9" "checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13" "checksum parity-bytes 0.1.0 (git+https://github.com/paritytech/parity-common?rev=b0317f649ab2c665b7987b8475878fc4d2e1f81d)" = "" @@ -6845,7 +6847,7 @@ dependencies = [ "checksum proc-macro-crate 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e10d4b51f154c8a7fb96fd6dad097cb74b863943ec010ac94b9fd1be8861fe1e" "checksum proc-macro-hack 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "114cdf1f426eb7f550f01af5f53a33c0946156f6814aec939b3bd77e844f9a9d" "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" -"checksum proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "afdc77cc74ec70ed262262942ebb7dac3d479e9e5cfa2da1841c0806f6cdabcc" +"checksum proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "90cf5f418035b98e655e9cdb225047638296b862b42411c4e45bb88d700f7fc0" "checksum prost 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96d14b1c185652833d24aaad41c5832b0be5616a590227c1fbff57c616754b23" "checksum prost-build 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "eb788126ea840817128183f8f603dce02cb7aea25c2a0b764359d8e20010702e" "checksum prost-derive 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5e7dc378b94ac374644181a2247cebf59a6ec1c88b49ac77f3a94b86b79d0e11" @@ -6911,7 +6913,7 @@ dependencies = [ "checksum send_wrapper 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a0eddf2e8f50ced781f288c19f18621fa72a3779e3cb58dbf23b07469b0abeb4" "checksum serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "9796c9b7ba2ffe7a9ce53c2287dfc48080f4b2b362fcc245a259b3a7201119dd" "checksum serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "4b133a43a1ecd55d4086bd5b4dc6c1751c68b1bfbeba7a5040442022c7e7c02e" -"checksum serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704" +"checksum serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)" = "2f72eb2a68a7dc3f9a691bfda9305a1c017a6215e5a4545c258500d2099a37c2" "checksum sha-1 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "23962131a91661d643c98940b20fcaffe62d776a823247be80a48fcb8b6fce68" "checksum sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" "checksum sha2 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d963c78ce367df26d7ea8b8cc655c651b42e8a1e584e869c1e17dae3ccb116a" @@ -6982,7 +6984,7 @@ dependencies = [ "checksum trie-root 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0b779f7c1c8fe9276365d9d5be5c4b5adeacf545117bb3f64c974305789c5c0b" "checksum trie-standardmap 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3161ba520ab28cd8e6b68e1126f1009f6e335339d1a73b978139011703264c8" "checksum try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382" -"checksum trybuild 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)" = "9fc69705e261edf3b9a87012b2353a49f49c0465186b5ab96e95f6983d6984aa" +"checksum trybuild 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)" = "10d8f366221c5a5ff8a62faa005e186fdce758949d34a9140b64a062951bae68" "checksum twofish 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712d261e83e727c8e2dbb75dacac67c36e35db36a958ee504f2164fc052434e1" "checksum twox-hash 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3bfd5b7557925ce778ff9b9ef90e3ade34c524b5ff10e239c69a42d546d2af56" "checksum typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887" @@ -6996,7 +6998,7 @@ dependencies = [ "checksum unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" -"checksum unsigned-varint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2c64cdf40b4a9645534a943668681bcb219faf51874d4b65d2e0abda1b10a2ab" +"checksum unsigned-varint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a7f0023a96687fe169081e8adce3f65e3874426b7886e9234d490af2dc077959" "checksum untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "55cd1f4b4e96b46aeb8d4855db4a7a9bd96eeeb5c6a1ab54593328761642ce2f" "checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" "checksum url 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "75b414f6c464c879d7f9babf951f23bc3743fb7313c081b2e6ca719067ea9d61" -- GitLab From bebe88a64c7199fcbcfdfae0ba6eb72e9e797b8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= Date: Tue, 8 Oct 2019 20:56:22 +0100 Subject: [PATCH 026/167] babe: verify slots are strictly increasing (#3785) * babe: re-use code to propose and import test block * babe: add failing test for slot validation * babe: verify slot numbers are strictly increasing --- core/consensus/babe/src/lib.rs | 39 ++++-- core/consensus/babe/src/tests.rs | 220 +++++++++++++++++-------------- 2 files changed, 144 insertions(+), 115 deletions(-) diff --git a/core/consensus/babe/src/lib.rs b/core/consensus/babe/src/lib.rs index 4f69c176ce..0eacf1407e 100644 --- a/core/consensus/babe/src/lib.rs +++ b/core/consensus/babe/src/lib.rs @@ -795,6 +795,31 @@ impl BlockImport for BabeBlockImport(&parent_header) + .map(|d| d.slot_number()) + .expect("parent is non-genesis; valid BABE headers contain a pre-digest; \ + header has already been verified; qed"); + + // make sure that slot number is strictly increasing + if slot_number <= parent_slot { + return Err( + ConsensusError::ClientImport(babe_err!( + "Slot number must increase: parent slot: {}, this slot: {}", + parent_slot, + slot_number + )) + ); + } + let mut epoch_changes = self.epoch_changes.lock(); // check if there's any epoch change expected to happen at this slot. @@ -803,20 +828,6 @@ impl BlockImport for BabeBlockImport(&parent_header) - .map(|d| d.slot_number()) - .expect("parent is non-genesis; valid BABE headers contain a pre-digest; \ - header has already been verified; qed"); - let parent_weight = if *parent_header.number() == Zero::zero() { 0 } else { diff --git a/core/consensus/babe/src/tests.rs b/core/consensus/babe/src/tests.rs index 46c038b187..e6883977a0 100644 --- a/core/consensus/babe/src/tests.rs +++ b/core/consensus/babe/src/tests.rs @@ -525,35 +525,33 @@ fn can_author_block() { } } -#[test] -fn importing_block_one_sets_genesis_epoch() { - let mut net = BabeTestNet::new(1); - - let peer = net.peer(0); - let data = peer.data.as_ref().expect("babe link set up during initialization"); - let client = peer.client().as_full().expect("Only full clients are used in tests").clone(); - - let mut environ = DummyFactory { - client: client.clone(), - config: data.link.config.clone(), - epoch_changes: data.link.epoch_changes.clone(), - mutator: Arc::new(|_, _| ()), - }; - - let genesis_header = client.header(&BlockId::Number(0)).unwrap().unwrap(); - - let mut proposer = environ.init(&genesis_header).unwrap(); - let babe_claim = Item::babe_pre_digest(babe_primitives::BabePreDigest::Secondary { - authority_index: 0, - slot_number: 999, +// Propose and import a new BABE block on top of the given parent. +fn propose_and_import_block( + parent: &TestHeader, + slot_number: Option, + proposer_factory: &mut DummyFactory, + block_import: &mut BoxBlockImport, +) -> H256 { + let mut proposer = proposer_factory.init(parent).unwrap(); + + let slot_number = slot_number.unwrap_or_else(|| { + let parent_pre_digest = find_pre_digest(parent).unwrap(); + parent_pre_digest.slot_number() + 1 }); - let pre_digest = sr_primitives::generic::Digest { logs: vec![babe_claim] }; - let genesis_epoch = data.link.config.genesis_epoch(999); + let pre_digest = sr_primitives::generic::Digest { + logs: vec![ + Item::babe_pre_digest( + BabePreDigest::Secondary { + authority_index: 0, + slot_number, + }, + ), + ], + }; let mut block = futures::executor::block_on(proposer.propose_with(pre_digest)).unwrap(); - // seal by alice. let seal = { // sign the pre-sealed hash of the block and then // add it to a digest item. @@ -569,18 +567,14 @@ fn importing_block_one_sets_genesis_epoch() { block.header.digest_mut().pop(); h }; - assert_eq!(*block.header.number(), 1); - let (header, body) = block.deconstruct(); - let post_digests = vec![seal]; - let mut block_import = data.block_import.lock().take().expect("import set up during init"); - block_import.import_block( + let import_result = block_import.import_block( BlockImportParams { origin: BlockOrigin::Own, - header, + header: block.header, justification: None, - post_digests, - body: Some(body), + post_digests: vec![seal], + body: Some(block.extrinsics), finalized: false, auxiliary: Vec::new(), fork_choice: ForkChoiceStrategy::LongestChain, @@ -588,14 +582,51 @@ fn importing_block_one_sets_genesis_epoch() { Default::default(), ).unwrap(); + match import_result { + ImportResult::Imported(_) => {}, + _ => panic!("expected block to be imported"), + } + + post_hash +} + +#[test] +fn importing_block_one_sets_genesis_epoch() { + let mut net = BabeTestNet::new(1); + + let peer = net.peer(0); + let data = peer.data.as_ref().expect("babe link set up during initialization"); + let client = peer.client().as_full().expect("Only full clients are used in tests").clone(); + + let mut proposer_factory = DummyFactory { + client: client.clone(), + config: data.link.config.clone(), + epoch_changes: data.link.epoch_changes.clone(), + mutator: Arc::new(|_, _| ()), + }; + + let mut block_import = data.block_import.lock().take().expect("import set up during init"); + + let genesis_header = client.header(&BlockId::Number(0)).unwrap().unwrap(); + + let block_hash = propose_and_import_block( + &genesis_header, + Some(999), + &mut proposer_factory, + &mut block_import, + ); + + let genesis_epoch = data.link.config.genesis_epoch(999); + let epoch_changes = data.link.epoch_changes.lock(); let epoch_for_second_block = epoch_changes.epoch_for_child_of( descendent_query(&*client), - &post_hash, + &block_hash, 1, 1000, |slot| data.link.config.genesis_epoch(slot), ).unwrap().unwrap().into_inner(); + assert_eq!(epoch_for_second_block, genesis_epoch); } @@ -612,81 +643,28 @@ fn importing_epoch_change_block_prunes_tree() { let mut block_import = data.block_import.lock().take().expect("import set up during init"); let epoch_changes = data.link.epoch_changes.clone(); - // This is just boilerplate code for proposing and importing a valid BABE - // block that's built on top of the given parent. The proposer takes care - // of producing epoch change digests according to the epoch duration (which - // is set to 6 slots in the test runtime). - let mut propose_and_import_block = |parent_header| { - let mut environ = DummyFactory { - client: client.clone(), - config: data.link.config.clone(), - epoch_changes: data.link.epoch_changes.clone(), - mutator: Arc::new(|_, _| ()), - }; - - let mut proposer = environ.init(&parent_header).unwrap(); - let parent_pre_digest = find_pre_digest(&parent_header).unwrap(); - - let pre_digest = sr_primitives::generic::Digest { - logs: vec![ - Item::babe_pre_digest( - BabePreDigest::Secondary { - authority_index: 0, - slot_number: parent_pre_digest.slot_number() + 1, - }, - ), - ], - }; - - let mut block = futures::executor::block_on(proposer.propose_with(pre_digest)).unwrap(); - - let seal = { - // sign the pre-sealed hash of the block and then - // add it to a digest item. - let pair = AuthorityPair::from_seed(&[1; 32]); - let pre_hash = block.header.hash(); - let signature = pair.sign(pre_hash.as_ref()); - Item::babe_seal(signature) - }; - - let post_hash = { - block.header.digest_mut().push(seal.clone()); - let h = block.header.hash(); - block.header.digest_mut().pop(); - h - }; - - let next_epoch_digest = - find_next_epoch_digest::(&block.header).unwrap(); - - let import_result = block_import.import_block( - BlockImportParams { - origin: BlockOrigin::Own, - header: block.header, - justification: None, - post_digests: vec![seal], - body: Some(block.extrinsics), - finalized: false, - auxiliary: Vec::new(), - fork_choice: ForkChoiceStrategy::LongestChain, - }, - Default::default(), - ).unwrap(); - - match import_result { - ImportResult::Imported(_) => {}, - _ => panic!("expected block to be imported"), - } - - (post_hash, next_epoch_digest) + let mut proposer_factory = DummyFactory { + client: client.clone(), + config: data.link.config.clone(), + epoch_changes: data.link.epoch_changes.clone(), + mutator: Arc::new(|_, _| ()), }; + // This is just boilerplate code for proposing and importing n valid BABE + // blocks that are built on top of the given parent. The proposer takes care + // of producing epoch change digests according to the epoch duration (which + // is set to 6 slots in the test runtime). let mut propose_and_import_blocks = |parent_id, n| { let mut hashes = Vec::new(); let mut parent_header = client.header(&parent_id).unwrap().unwrap(); for _ in 0..n { - let (block_hash, _) = propose_and_import_block(parent_header); + let block_hash = propose_and_import_block( + &parent_header, + None, + &mut proposer_factory, + &mut block_import, + ); hashes.push(block_hash); parent_header = client.header(&BlockId::Hash(block_hash)).unwrap().unwrap(); } @@ -758,3 +736,43 @@ fn importing_epoch_change_block_prunes_tree() { epoch_changes.lock().tree().iter().map(|(h, _, _)| h).any(|h| fork_3.contains(h)), ); } + +#[test] +#[should_panic] +fn verify_slots_are_strictly_increasing() { + let mut net = BabeTestNet::new(1); + + let peer = net.peer(0); + let data = peer.data.as_ref().expect("babe link set up during initialization"); + + let client = peer.client().as_full().expect("Only full clients are used in tests").clone(); + let mut block_import = data.block_import.lock().take().expect("import set up during init"); + + let mut proposer_factory = DummyFactory { + client: client.clone(), + config: data.link.config.clone(), + epoch_changes: data.link.epoch_changes.clone(), + mutator: Arc::new(|_, _| ()), + }; + + let genesis_header = client.header(&BlockId::Number(0)).unwrap().unwrap(); + + // we should have no issue importing this block + let b1 = propose_and_import_block( + &genesis_header, + Some(999), + &mut proposer_factory, + &mut block_import, + ); + + let b1 = client.header(&BlockId::Hash(b1)).unwrap().unwrap(); + + // we should fail to import this block since the slot number didn't increase. + // we will panic due to the `PanickingBlockImport` defined above. + propose_and_import_block( + &b1, + Some(999), + &mut proposer_factory, + &mut block_import, + ); +} -- GitLab From 79c776afa2d4893efabfc19da7b0786c88090569 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 9 Oct 2019 15:50:30 +0200 Subject: [PATCH 027/167] Move `Externalities` into its own crate (#3775) * Move `Externalities` into `substrate-externalities` - `Externalities` now support generic extensions - Split of `primtives-storage` for storage primitive types * Move the externalities scoping into `substrate-externalities` * Fix compilation * Review feedback * Adds macro for declaring extensions * Fix benchmarks * Introduce `ExtensionStore` trait * Last review comments * Implement it for `ExtensionStore` --- Cargo.lock | 27 ++- Cargo.toml | 1 + core/application-crypto/src/ed25519.rs | 9 +- core/application-crypto/src/sr25519.rs | 9 +- core/client/db/src/lib.rs | 5 +- core/client/src/call_executor.rs | 41 ++-- core/client/src/client.rs | 52 +++-- core/client/src/genesis.rs | 14 +- core/client/src/light/call_executor.rs | 70 ++++--- core/client/src/light/fetcher.rs | 7 +- core/client/src/light/mod.rs | 4 +- core/executor/Cargo.toml | 1 + core/executor/src/lib.rs | 4 +- core/executor/src/native_executor.rs | 22 +-- core/executor/src/sandbox.rs | 24 +-- core/executor/src/wasm_runtime.rs | 10 +- core/executor/src/wasmi_execution.rs | 34 ++-- core/externalities/Cargo.toml | 12 ++ core/externalities/src/extensions.rs | 127 ++++++++++++ core/externalities/src/lib.rs | 139 +++++++++++++ core/externalities/src/scope_limited.rs | 37 ++++ core/finality-grandpa/src/finality_proof.rs | 4 +- core/primitives/Cargo.toml | 6 +- core/primitives/src/child_storage_key.rs | 68 ------- core/primitives/src/lib.rs | 5 +- core/primitives/src/offchain.rs | 114 +---------- core/primitives/src/testing.rs | 7 +- core/primitives/src/traits.rs | 126 +----------- core/primitives/storage/Cargo.toml | 15 ++ .../{src/storage.rs => storage/src/lib.rs} | 78 ++++++-- core/rpc/src/author/tests.rs | 8 +- core/rpc/src/state/state_full.rs | 10 +- core/sr-io/Cargo.toml | 4 +- core/sr-io/src/lib.rs | 7 +- core/sr-io/with_std.rs | 90 ++++----- core/sr-primitives/Cargo.toml | 2 + core/sr-primitives/src/lib.rs | 3 + core/sr-primitives/src/offchain/http.rs | 12 +- core/state-machine/Cargo.toml | 1 + core/state-machine/src/basic.rs | 61 +++--- core/state-machine/src/ext.rs | 169 +++++++++------- core/state-machine/src/lib.rs | 184 ++++++++++-------- core/state-machine/src/overlayed_changes.rs | 10 +- core/state-machine/src/proving_backend.rs | 2 +- core/state-machine/src/testing.rs | 84 ++++---- core/test-runtime/src/system.rs | 29 +-- node-template/runtime/src/template.rs | 14 +- node/executor/src/lib.rs | 27 ++- srml/assets/src/lib.rs | 26 +-- srml/aura/src/mock.rs | 4 +- srml/aura/src/tests.rs | 4 +- srml/authority-discovery/src/lib.rs | 26 +-- srml/authorship/src/lib.rs | 19 +- srml/babe/src/mock.rs | 2 +- srml/babe/src/tests.rs | 13 +- srml/balances/src/mock.rs | 4 +- srml/balances/src/tests.rs | 90 ++++----- srml/collective/src/lib.rs | 28 +-- srml/contracts/src/exec.rs | 60 +++--- srml/contracts/src/tests.rs | 55 +++--- srml/council/src/lib.rs | 1 - srml/democracy/src/lib.rs | 79 ++++---- srml/elections-phragmen/src/lib.rs | 86 ++++---- srml/elections/src/mock.rs | 12 +- srml/elections/src/tests.rs | 114 +++++------ srml/example/src/lib.rs | 15 +- srml/executive/src/lib.rs | 26 +-- srml/finality-tracker/src/lib.rs | 15 +- srml/generic-asset/src/mock.rs | 6 +- srml/generic-asset/src/tests.rs | 92 ++++----- srml/grandpa/src/mock.rs | 4 +- srml/grandpa/src/tests.rs | 16 +- srml/im-online/src/mock.rs | 4 +- srml/im-online/src/tests.rs | 17 +- srml/indices/src/mock.rs | 4 +- srml/indices/src/tests.rs | 10 +- srml/membership/src/lib.rs | 18 +- srml/offences/src/mock.rs | 4 +- srml/offences/src/tests.rs | 16 +- srml/randomness-collective-flip/src/lib.rs | 18 +- srml/scored-pool/src/mock.rs | 4 +- srml/scored-pool/src/tests.rs | 35 ++-- srml/session/src/historical.rs | 13 +- srml/session/src/lib.rs | 28 ++- srml/staking/src/mock.rs | 6 +- srml/staking/src/tests.rs | 92 +++++---- srml/support/src/lib.rs | 23 ++- srml/support/src/storage/storage_items.rs | 16 +- srml/support/test/Cargo.toml | 2 + srml/support/test/tests/instance.rs | 14 +- srml/system/benches/bench.rs | 11 +- srml/system/src/lib.rs | 36 ++-- srml/timestamp/src/lib.rs | 13 +- srml/treasury/src/lib.rs | 40 ++-- srml/utility/src/lib.rs | 10 +- 95 files changed, 1600 insertions(+), 1420 deletions(-) create mode 100644 core/externalities/Cargo.toml create mode 100644 core/externalities/src/extensions.rs create mode 100644 core/externalities/src/lib.rs create mode 100644 core/externalities/src/scope_limited.rs delete mode 100644 core/primitives/src/child_storage_key.rs create mode 100644 core/primitives/storage/Cargo.toml rename core/primitives/{src/storage.rs => storage/src/lib.rs} (62%) diff --git a/Cargo.lock b/Cargo.lock index ba762f1393..a1f3ba2983 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3801,12 +3801,12 @@ dependencies = [ name = "sr-io" version = "2.0.0" dependencies = [ - "environmental 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "hash-db 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", "libsecp256k1 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "sr-std 2.0.0", + "substrate-externalities 2.0.0", "substrate-primitives 2.0.0", "substrate-state-machine 2.0.0", "substrate-trie 2.0.0", @@ -3830,6 +3830,7 @@ dependencies = [ "sr-io 2.0.0", "sr-std 2.0.0", "substrate-application-crypto 2.0.0", + "substrate-externalities 2.0.0", "substrate-offchain 2.0.0", "substrate-primitives 2.0.0", ] @@ -4387,6 +4388,7 @@ dependencies = [ "pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 2.0.0", + "sr-primitives 2.0.0", "srml-support 2.0.0", "substrate-inherents 2.0.0", "substrate-primitives 2.0.0", @@ -4974,6 +4976,7 @@ dependencies = [ "sr-io 2.0.0", "sr-version 2.0.0", "substrate-client 2.0.0", + "substrate-externalities 2.0.0", "substrate-offchain 2.0.0", "substrate-panic-handler 2.0.0", "substrate-primitives 2.0.0", @@ -4987,6 +4990,16 @@ dependencies = [ "wasmi 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "substrate-externalities" +version = "2.0.0" +dependencies = [ + "environmental 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "primitive-types 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-std 2.0.0", + "substrate-primitives-storage 2.0.0", +] + [[package]] name = "substrate-finality-grandpa" version = "2.0.0" @@ -5224,6 +5237,8 @@ dependencies = [ "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "sr-std 2.0.0", "substrate-bip39 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "substrate-externalities 2.0.0", + "substrate-primitives-storage 2.0.0", "substrate-serializer 2.0.0", "tiny-bip39 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "twox-hash 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -5231,6 +5246,15 @@ dependencies = [ "zeroize 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "substrate-primitives-storage" +version = "2.0.0" +dependencies = [ + "impl-serde 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-std 2.0.0", +] + [[package]] name = "substrate-rpc" version = "2.0.0" @@ -5425,6 +5449,7 @@ dependencies = [ "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "substrate-externalities 2.0.0", "substrate-panic-handler 2.0.0", "substrate-primitives 2.0.0", "substrate-trie 2.0.0", diff --git a/Cargo.toml b/Cargo.toml index 62993397fd..7e34a0bd6c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,6 +36,7 @@ members = [ "core/consensus/pow", "core/executor", "core/executor/runtime-test", + "core/externalities", "core/finality-grandpa", "core/finality-grandpa/primitives", "core/inherents", diff --git a/core/application-crypto/src/ed25519.rs b/core/application-crypto/src/ed25519.rs index d5c4fd7bad..b0113718b5 100644 --- a/core/application-crypto/src/ed25519.rs +++ b/core/application-crypto/src/ed25519.rs @@ -53,14 +53,7 @@ impl RuntimePublic for Public { #[cfg(test)] mod tests { use sr_primitives::{generic::BlockId, traits::ProvideRuntimeApi}; - use primitives::{ - testing::{ - KeyStore, - ED25519, - }, - crypto::Pair, - traits::BareCryptoStore as _, - }; + use primitives::{testing::{KeyStore, ED25519}, crypto::Pair}; use test_client::{ TestClientBuilder, DefaultTestClientBuilderExt, TestClientBuilderExt, runtime::{TestAPI, app_crypto::ed25519::{AppPair, AppPublic}}, diff --git a/core/application-crypto/src/sr25519.rs b/core/application-crypto/src/sr25519.rs index 93565a628f..40f6c6b22e 100644 --- a/core/application-crypto/src/sr25519.rs +++ b/core/application-crypto/src/sr25519.rs @@ -53,14 +53,7 @@ impl RuntimePublic for Public { #[cfg(test)] mod tests { use sr_primitives::{generic::BlockId, traits::ProvideRuntimeApi}; - use primitives::{ - testing::{ - KeyStore, - SR25519, - }, - crypto::Pair, - traits::BareCryptoStore as _, - }; + use primitives::{testing::{KeyStore, SR25519}, crypto::Pair}; use test_client::{ TestClientBuilder, DefaultTestClientBuilderExt, TestClientBuilderExt, runtime::{TestAPI, app_crypto::sr25519::{AppPair, AppPublic}}, diff --git a/core/client/db/src/lib.rs b/core/client/db/src/lib.rs index 7061e9d29a..1f7fa604a4 100644 --- a/core/client/db/src/lib.rs +++ b/core/client/db/src/lib.rs @@ -224,7 +224,7 @@ pub fn new_client( > where Block: BlockT, - E: CodeExecutor + RuntimeInfo, + E: CodeExecutor + RuntimeInfo, S: BuildStorage, { let backend = Arc::new(Backend::new(settings, CANONICALIZATION_DELAY)?); @@ -456,8 +456,7 @@ impl BlockImportOperation { } impl client::backend::BlockImportOperation -for BlockImportOperation -where Block: BlockT, + for BlockImportOperation where Block: BlockT, { type State = CachingState, Block>; diff --git a/core/client/src/call_executor.rs b/core/client/src/call_executor.rs index ebb882709d..05a2a8eba1 100644 --- a/core/client/src/call_executor.rs +++ b/core/client/src/call_executor.rs @@ -26,8 +26,8 @@ use state_machine::{ use executor::{RuntimeVersion, RuntimeInfo, NativeVersion}; use hash_db::Hasher; use primitives::{ - offchain::{self, NeverOffchainExt}, H256, Blake2Hasher, NativeOrEncoded, NeverNativeValue, - traits::CodeExecutor, + offchain::OffchainExt, H256, Blake2Hasher, NativeOrEncoded, NeverNativeValue, + traits::{CodeExecutor, KeystoreExt}, }; use crate::runtime_api::{ProofRecorder, InitializeBlock}; @@ -47,15 +47,13 @@ where /// Execute a call to a contract on top of state in a block of given hash. /// /// No changes are made. - fn call< - O: offchain::Externalities, - >( + fn call( &self, id: &BlockId, method: &str, call_data: &[u8], strategy: ExecutionStrategy, - side_effects_handler: Option<&mut O>, + side_effects_handler: Option, ) -> Result, error::Error>; /// Execute a contextual call on top of state in a block of a given hash. @@ -65,7 +63,6 @@ where /// of the execution context. fn contextual_call< 'a, - O: offchain::Externalities, IB: Fn() -> error::Result<()>, EM: Fn( Result, Self::Error>, @@ -83,7 +80,7 @@ where initialize_block: InitializeBlock<'a, B>, execution_manager: ExecutionManager, native_call: Option, - side_effects_handler: Option<&mut O>, + side_effects_handler: Option, proof_recorder: &Option>>>, enable_keystore: bool, ) -> error::Result> where ExecutionManager: Clone; @@ -97,11 +94,10 @@ where /// /// No changes are made. fn call_at_state< - O: offchain::Externalities, S: state_machine::Backend, F: FnOnce( Result, Self::Error>, - Result, Self::Error> + Result, Self::Error>, ) -> Result, Self::Error>, R: Encode + Decode + PartialEq, NC: FnOnce() -> result::Result + UnwindSafe, @@ -112,7 +108,7 @@ where call_data: &[u8], manager: ExecutionManager, native_call: Option, - side_effects_handler: Option<&mut O>, + side_effects_handler: Option, ) -> Result< ( NativeOrEncoded, @@ -191,18 +187,18 @@ impl Clone for LocalCallExecutor where E: Clone { impl CallExecutor for LocalCallExecutor where B: backend::Backend, - E: CodeExecutor + RuntimeInfo, + E: CodeExecutor + RuntimeInfo, Block: BlockT, { type Error = E::Error; - fn call( + fn call( &self, id: &BlockId, method: &str, call_data: &[u8], strategy: ExecutionStrategy, - side_effects_handler: Option<&mut O>, + side_effects_handler: Option, ) -> error::Result> { let mut changes = OverlayedChanges::default(); let state = self.backend.state_at(*id)?; @@ -214,7 +210,7 @@ where &self.executor, method, call_data, - self.keystore.clone(), + self.keystore.clone().map(KeystoreExt), ).execute_using_consensus_failure_handler::<_, NeverNativeValue, fn() -> _>( strategy.get_manager(), false, @@ -227,7 +223,6 @@ where fn contextual_call< 'a, - O: offchain::Externalities, IB: Fn() -> error::Result<()>, EM: Fn( Result, Self::Error>, @@ -245,7 +240,7 @@ where initialize_block: InitializeBlock<'a, Block>, execution_manager: ExecutionManager, native_call: Option, - side_effects_handler: Option<&mut O>, + side_effects_handler: Option, recorder: &Option>>>, enable_keystore: bool, ) -> Result, error::Error> where ExecutionManager: Clone { @@ -259,7 +254,7 @@ where } let keystore = if enable_keystore { - self.keystore.clone() + self.keystore.clone().map(KeystoreExt) } else { None }; @@ -326,7 +321,6 @@ where &mut overlay, &state, self.backend.changes_trie_storage(), - NeverOffchainExt::new(), None, ); let version = self.executor.runtime_version(&mut ext); @@ -335,11 +329,10 @@ where } fn call_at_state< - O: offchain::Externalities, S: state_machine::Backend, F: FnOnce( Result, Self::Error>, - Result, Self::Error> + Result, Self::Error>, ) -> Result, Self::Error>, R: Encode + Decode + PartialEq, NC: FnOnce() -> result::Result + UnwindSafe, @@ -350,7 +343,7 @@ where call_data: &[u8], manager: ExecutionManager, native_call: Option, - side_effects_handler: Option<&mut O>, + side_effects_handler: Option, ) -> error::Result<( NativeOrEncoded, (S::Transaction, ::Out), @@ -364,7 +357,7 @@ where &self.executor, method, call_data, - self.keystore.clone(), + self.keystore.clone().map(KeystoreExt), ).execute_using_consensus_failure_handler( manager, true, @@ -391,7 +384,7 @@ where &self.executor, method, call_data, - self.keystore.clone(), + self.keystore.clone().map(KeystoreExt), ) .map_err(Into::into) } diff --git a/core/client/src/client.rs b/core/client/src/client.rs index aff099233a..34334b1388 100644 --- a/core/client/src/client.rs +++ b/core/client/src/client.rs @@ -28,7 +28,7 @@ use hash_db::{Hasher, Prefix}; use primitives::{ Blake2Hasher, H256, ChangesTrieConfiguration, convert_hash, NeverNativeValue, ExecutionContext, NativeOrEncoded, storage::{StorageKey, StorageData, well_known_keys}, - offchain::{NeverOffchainExt, self}, traits::CodeExecutor, + offchain::{OffchainExt, self}, traits::CodeExecutor, }; use substrate_telemetry::{telemetry, SUBSTRATE_INFO}; use sr_primitives::{ @@ -248,7 +248,7 @@ pub fn new_in_mem( Block, RA >> where - E: CodeExecutor + RuntimeInfo, + E: CodeExecutor + RuntimeInfo, S: BuildStorage, Block: BlockT, { @@ -264,7 +264,7 @@ pub fn new_with_backend( keystore: Option, ) -> error::Result, Block, RA>> where - E: CodeExecutor + RuntimeInfo, + E: CodeExecutor + RuntimeInfo, S: BuildStorage, Block: BlockT, B: backend::LocalBackend @@ -1058,18 +1058,27 @@ impl Client where }), } }; - let (_, storage_update, changes_update) = self.executor.call_at_state::<_, _, _, NeverNativeValue, fn() -> _>( - transaction_state, - &mut overlay, - "Core_execute_block", - &::new(import_headers.pre().clone(), body.unwrap_or_default()).encode(), - match origin { - BlockOrigin::NetworkInitialSync => get_execution_manager(self.execution_strategies().syncing), - _ => get_execution_manager(self.execution_strategies().importing), - }, - None, - NeverOffchainExt::new(), - )?; + + let encoded_block = ::new( + import_headers.pre().clone(), + body.unwrap_or_default(), + ).encode(); + + let (_, storage_update, changes_update) = self.executor + .call_at_state::<_, _, NeverNativeValue, fn() -> _>( + transaction_state, + &mut overlay, + "Core_execute_block", + &encoded_block, + match origin { + BlockOrigin::NetworkInitialSync => get_execution_manager( + self.execution_strategies().syncing, + ), + _ => get_execution_manager(self.execution_strategies().importing), + }, + None, + None, + )?; overlay.commit_prospective(); @@ -1460,12 +1469,13 @@ impl CallRuntimeAt for Client where }; let capabilities = context.capabilities(); - let mut offchain_extensions = match context { - ExecutionContext::OffchainCall(ext) => ext.map(|x| x.0), - _ => None, - }.map(|ext| offchain::LimitedExternalities::new(capabilities, ext)); + let offchain_extensions = if let ExecutionContext::OffchainCall(Some(ext)) = context { + Some(OffchainExt::new(offchain::LimitedExternalities::new(capabilities, ext.0))) + } else { + None + }; - self.executor.contextual_call::<_, _, fn(_,_) -> _,_,_>( + self.executor.contextual_call::<_, fn(_,_) -> _,_,_>( || core_api.initialize_block(at, &self.prepare_environment_block(at)?), at, function, @@ -1474,7 +1484,7 @@ impl CallRuntimeAt for Client where initialize_block, manager, native_call, - offchain_extensions.as_mut(), + offchain_extensions, recorder, capabilities.has(offchain::Capability::Keystore), ) diff --git a/core/client/src/genesis.rs b/core/client/src/genesis.rs index 51e0536613..031b2dc0ad 100644 --- a/core/client/src/genesis.rs +++ b/core/client/src/genesis.rs @@ -53,7 +53,7 @@ mod tests { runtime::{Hash, Transfer, Block, BlockNumber, Header, Digest}, AccountKeyring, Sr25519Keyring, }; - use primitives::{Blake2Hasher, map, offchain::NeverOffchainExt}; + use primitives::{Blake2Hasher, map}; use hex_literal::*; native_executor_instance!( @@ -93,7 +93,7 @@ mod tests { StateMachine::new( backend, Some(&InMemoryChangesTrieStorage::<_, u64>::new()), - NeverOffchainExt::new(), + None, &mut overlay, &executor(), "Core_initialize_block", @@ -107,7 +107,7 @@ mod tests { StateMachine::new( backend, Some(&InMemoryChangesTrieStorage::<_, u64>::new()), - NeverOffchainExt::new(), + None, &mut overlay, &executor(), "BlockBuilder_apply_extrinsic", @@ -121,7 +121,7 @@ mod tests { let (ret_data, _, _) = StateMachine::new( backend, Some(&InMemoryChangesTrieStorage::<_, u64>::new()), - NeverOffchainExt::new(), + None, &mut overlay, &executor(), "BlockBuilder_finalize_block", @@ -169,7 +169,7 @@ mod tests { let _ = StateMachine::new( &backend, Some(&InMemoryChangesTrieStorage::<_, u64>::new()), - NeverOffchainExt::new(), + None, &mut overlay, &executor(), "Core_execute_block", @@ -199,7 +199,7 @@ mod tests { let _ = StateMachine::new( &backend, Some(&InMemoryChangesTrieStorage::<_, u64>::new()), - NeverOffchainExt::new(), + None, &mut overlay, &executor(), "Core_execute_block", @@ -229,7 +229,7 @@ mod tests { let r = StateMachine::new( &backend, Some(&InMemoryChangesTrieStorage::<_, u64>::new()), - NeverOffchainExt::new(), + None, &mut overlay, &executor(), "Core_execute_block", diff --git a/core/client/src/light/call_executor.rs b/core/client/src/light/call_executor.rs index d969c39a5a..65776bcfe0 100644 --- a/core/client/src/light/call_executor.rs +++ b/core/client/src/light/call_executor.rs @@ -23,11 +23,12 @@ use std::{ use codec::{Encode, Decode}; use primitives::{ - offchain, H256, Blake2Hasher, convert_hash, NativeOrEncoded, + offchain::OffchainExt, H256, Blake2Hasher, convert_hash, NativeOrEncoded, traits::CodeExecutor, }; -use sr_primitives::generic::BlockId; -use sr_primitives::traits::{One, Block as BlockT, Header as HeaderT, NumberFor}; +use sr_primitives::{ + generic::BlockId, traits::{One, Block as BlockT, Header as HeaderT, NumberFor}, +}; use state_machine::{ self, Backend as StateBackend, OverlayedChanges, ExecutionStrategy, create_proof_check_backend, execution_proof_check_on_trie_backend, ExecutionManager, ChangesTrieTransaction, @@ -74,15 +75,13 @@ impl CallExecutor for { type Error = ClientError; - fn call< - O: offchain::Externalities, - >( + fn call( &self, id: &BlockId, method: &str, call_data: &[u8], strategy: ExecutionStrategy, - side_effects_handler: Option<&mut O>, + side_effects_handler: Option, ) -> ClientResult> { match self.backend.is_local_state_available(id) { true => self.local.call(id, method, call_data, strategy, side_effects_handler), @@ -92,7 +91,6 @@ impl CallExecutor for fn contextual_call< 'a, - O: offchain::Externalities, IB: Fn() -> ClientResult<()>, EM: Fn( Result, Self::Error>, @@ -110,7 +108,7 @@ impl CallExecutor for initialize_block: InitializeBlock<'a, Block>, _manager: ExecutionManager, native_call: Option, - side_effects_handler: Option<&mut O>, + side_effects_handler: Option, recorder: &Option>>>, enable_keystore: bool, ) -> ClientResult> where ExecutionManager: Clone { @@ -119,7 +117,6 @@ impl CallExecutor for match self.backend.is_local_state_available(at) { true => CallExecutor::contextual_call::< - _, _, fn( Result, Local::Error>, @@ -153,7 +150,6 @@ impl CallExecutor for } fn call_at_state< - O: offchain::Externalities, S: StateBackend, FF: FnOnce( Result, Self::Error>, @@ -168,7 +164,7 @@ impl CallExecutor for _call_data: &[u8], _manager: ExecutionManager, _native_call: Option, - _side_effects_handler: Option<&mut O>, + _side_effects_handler: Option, ) -> ClientResult<( NativeOrEncoded, (S::Transaction, ::Out), @@ -242,11 +238,10 @@ pub fn check_execution_proof( ) -> ClientResult> where Header: HeaderT, - E: CodeExecutor, - H: Hasher, - H::Out: Ord + 'static, + E: CodeExecutor, + H: Hasher, { - check_execution_proof_with_make_header( + check_execution_proof_with_make_header::( executor, request, remote_proof, @@ -268,9 +263,8 @@ fn check_execution_proof_with_make_header ClientResult> where Header: HeaderT, - E: CodeExecutor, - H: Hasher, - H::Out: Ord + 'static, + E: CodeExecutor, + H: Hasher, { let local_state_root = request.header.state_root(); let root: H::Out = convert_hash(&local_state_root); @@ -301,33 +295,32 @@ fn check_execution_proof_with_make_header for DummyCallExecutor { type Error = ClientError; - fn call( + fn call( &self, _id: &BlockId, _method: &str, _call_data: &[u8], _strategy: ExecutionStrategy, - _side_effects_handler: Option<&mut O>, + _side_effects_handler: Option, ) -> Result, ClientError> { Ok(vec![42]) } fn contextual_call< 'a, - O: offchain::Externalities, IB: Fn() -> ClientResult<()>, EM: Fn( Result, Self::Error>, @@ -345,7 +338,7 @@ mod tests { _initialize_block: InitializeBlock<'a, Block>, _execution_manager: ExecutionManager, _native_call: Option, - _side_effects_handler: Option<&mut O>, + _side_effects_handler: Option, _proof_recorder: &Option>>>, _enable_keystore: bool, ) -> ClientResult> where ExecutionManager: Clone { @@ -357,7 +350,6 @@ mod tests { } fn call_at_state< - O: offchain::Externalities, S: state_machine::Backend, F: FnOnce( Result, Self::Error>, @@ -372,7 +364,7 @@ mod tests { _call_data: &[u8], _manager: ExecutionManager, _native_call: Option, - _side_effects_handler: Option<&mut O>, + _side_effects_handler: Option, ) -> Result< ( NativeOrEncoded, @@ -417,13 +409,17 @@ mod tests { ).unwrap(); // check remote execution proof locally - let local_result = check_execution_proof(&local_executor(), &RemoteCallRequest { - block: test_client::runtime::Hash::default(), - header: remote_header, - method: method.into(), - call_data: vec![], - retry_count: None, - }, remote_execution_proof).unwrap(); + let local_result = check_execution_proof::<_, _, Blake2Hasher>( + &local_executor(), + &RemoteCallRequest { + block: test_client::runtime::Hash::default(), + header: remote_header, + method: method.into(), + call_data: vec![], + retry_count: None, + }, + remote_execution_proof, + ).unwrap(); (remote_result, local_result) } @@ -440,7 +436,7 @@ mod tests { ).unwrap(); // check remote execution proof locally - let execution_result = check_execution_proof_with_make_header( + let execution_result = check_execution_proof_with_make_header::<_, _, Blake2Hasher, _>( &local_executor(), &RemoteCallRequest { block: test_client::runtime::Hash::default(), @@ -518,7 +514,7 @@ mod tests { "test_method", &[], ExecutionStrategy::NativeElseWasm, - NeverOffchainExt::new(), + None, ).unwrap(), vec![42], ); @@ -528,7 +524,7 @@ mod tests { "test_method", &[], ExecutionStrategy::NativeElseWasm, - NeverOffchainExt::new(), + None, ); match call_on_unavailable { diff --git a/core/client/src/light/fetcher.rs b/core/client/src/light/fetcher.rs index 51e1ed3b81..dbf6d41c38 100644 --- a/core/client/src/light/fetcher.rs +++ b/core/client/src/light/fetcher.rs @@ -23,7 +23,7 @@ use std::future::Future; use hash_db::{HashDB, Hasher, EMPTY_PREFIX}; use codec::{Decode, Encode}; -use primitives::{ChangesTrieConfiguration, convert_hash, traits::CodeExecutor}; +use primitives::{ChangesTrieConfiguration, convert_hash, traits::CodeExecutor, H256}; use sr_primitives::traits::{ Block as BlockT, Header as HeaderT, Hash, HashFor, NumberFor, SimpleArithmetic, CheckedConversion, Zero, @@ -370,9 +370,8 @@ impl> LightDataChecker { impl FetchChecker for LightDataChecker where Block: BlockT, - E: CodeExecutor, - H: Hasher, - H::Out: Ord + 'static, + E: CodeExecutor, + H: Hasher, S: BlockchainStorage, { fn check_header_proof( diff --git a/core/client/src/light/mod.rs b/core/client/src/light/mod.rs index c9d2e6040b..d06a9ae9dd 100644 --- a/core/client/src/light/mod.rs +++ b/core/client/src/light/mod.rs @@ -63,7 +63,7 @@ pub fn new_light( B: BlockT, S: BlockchainStorage + 'static, GS: BuildStorage, - E: CodeExecutor + RuntimeInfo, + E: CodeExecutor + RuntimeInfo, { let local_executor = LocalCallExecutor::new(backend.clone(), code_executor, None); let executor = GenesisCallExecutor::new(backend.clone(), local_executor); @@ -76,7 +76,7 @@ pub fn new_fetch_checker>( executor: E, ) -> LightDataChecker where - E: CodeExecutor, + E: CodeExecutor, { LightDataChecker::new(blockchain, executor) } diff --git a/core/executor/Cargo.toml b/core/executor/Cargo.toml index 1f53cd4099..cf3ea4ff7a 100644 --- a/core/executor/Cargo.toml +++ b/core/executor/Cargo.toml @@ -17,6 +17,7 @@ wasmi = "0.5.1" parity-wasm = "0.40.3" lazy_static = "1.4.0" wasm-interface = { package = "substrate-wasm-interface", path = "../wasm-interface" } +externalities = { package = "substrate-externalities", path = "../externalities" } parking_lot = "0.9.0" log = "0.4.8" libsecp256k1 = "0.3.0" diff --git a/core/executor/src/lib.rs b/core/executor/src/lib.rs index 8b833c9b08..ccc78afdb4 100644 --- a/core/executor/src/lib.rs +++ b/core/executor/src/lib.rs @@ -45,7 +45,7 @@ pub use native_executor::{with_native_environment, NativeExecutor, NativeExecuti pub use runtime_version::{RuntimeVersion, NativeVersion}; pub use codec::Codec; #[doc(hidden)] -pub use primitives::{Blake2Hasher, traits::Externalities}; +pub use primitives::traits::Externalities; #[doc(hidden)] pub use wasm_interface; pub use wasm_runtime::WasmExecutionMethod; @@ -56,7 +56,7 @@ pub trait RuntimeInfo { fn native_version(&self) -> &NativeVersion; /// Extract RuntimeVersion of given :code block - fn runtime_version> ( + fn runtime_version ( &self, ext: &mut E, ) -> Option; diff --git a/core/executor/src/native_executor.rs b/core/executor/src/native_executor.rs index 5f4e91b16d..7323703ed9 100644 --- a/core/executor/src/native_executor.rs +++ b/core/executor/src/native_executor.rs @@ -20,7 +20,7 @@ use crate::wasm_runtime::{RuntimesCache, WasmExecutionMethod, WasmRuntime}; use crate::RuntimeInfo; use runtime_version::{NativeVersion, RuntimeVersion}; use codec::{Decode, Encode}; -use primitives::{Blake2Hasher, NativeOrEncoded, traits::{CodeExecutor, Externalities}}; +use primitives::{NativeOrEncoded, traits::{CodeExecutor, Externalities}}; use log::{trace, warn}; thread_local! { @@ -41,10 +41,10 @@ fn safe_call(f: F) -> Result /// Set up the externalities and safe calling environment to execute calls to a native runtime. /// /// If the inner closure panics, it will be caught and return an error. -pub fn with_native_environment(ext: &mut dyn Externalities, f: F) -> Result +pub fn with_native_environment(ext: &mut dyn Externalities, f: F) -> Result where F: UnwindSafe + FnOnce() -> U { - runtime_io::with_externalities(ext, move || safe_call(f)) + externalities::set_and_run_with_externalities(ext, move || safe_call(f)) } /// Delegate for dispatching a CodeExecutor call. @@ -54,7 +54,7 @@ pub trait NativeExecutionDispatch: Send + Sync { /// Dispatch a method in the runtime. /// /// If the method with the specified name doesn't exist then `Err` is returned. - fn dispatch(ext: &mut dyn Externalities, method: &str, data: &[u8]) -> Result>; + fn dispatch(ext: &mut dyn Externalities, method: &str, data: &[u8]) -> Result>; /// Provide native runtime version. fn native_version() -> NativeVersion; @@ -95,10 +95,8 @@ impl NativeExecutor { fn with_runtime( &self, ext: &mut E, - f: impl for <'a> FnOnce(&'a mut dyn WasmRuntime, &'a mut E) -> Result - ) -> Result - where E: Externalities - { + f: impl for <'a> FnOnce(&'a mut dyn WasmRuntime, &'a mut E) -> Result, + ) -> Result where E: Externalities { RUNTIMES_CACHE.with(|cache| { let mut cache = cache.borrow_mut(); let runtime = cache.fetch_runtime(ext, self.fallback_method, self.default_heap_pages)?; @@ -123,7 +121,7 @@ impl RuntimeInfo for NativeExecutor { &self.native_version } - fn runtime_version>( + fn runtime_version( &self, ext: &mut E, ) -> Option { @@ -137,12 +135,12 @@ impl RuntimeInfo for NativeExecutor { } } -impl CodeExecutor for NativeExecutor { +impl CodeExecutor for NativeExecutor { type Error = Error; fn call < - E: Externalities, + E: Externalities, R:Decode + Encode + PartialEq, NC: FnOnce() -> result::Result + UnwindSafe >( @@ -220,7 +218,7 @@ macro_rules! native_executor_instance { (IMPL $name:ident, $dispatcher:path, $version:path) => { impl $crate::NativeExecutionDispatch for $name { fn dispatch( - ext: &mut $crate::Externalities<$crate::Blake2Hasher>, + ext: &mut $crate::Externalities, method: &str, data: &[u8] ) -> $crate::error::Result> { diff --git a/core/executor/src/sandbox.rs b/core/executor/src/sandbox.rs index de49cc9f7c..3a213ccdf0 100644 --- a/core/executor/src/sandbox.rs +++ b/core/executor/src/sandbox.rs @@ -593,9 +593,9 @@ mod tests { use wabt; use runtime_test::WASM_BINARY; - type TestExternalities = CoreTestExternalities; + type TestExternalities = CoreTestExternalities; - fn call_wasm>( + fn call_wasm( ext: &mut E, heap_pages: u64, code: &[u8], @@ -609,7 +609,7 @@ mod tests { #[test] fn sandbox_should_work() { - let mut ext = TestExternalities::::default(); + let mut ext = TestExternalities::default(); let test_code = WASM_BINARY; let code = wabt::wat2wasm(r#" @@ -641,7 +641,7 @@ mod tests { #[test] fn sandbox_trap() { - let mut ext = TestExternalities::::default(); + let mut ext = TestExternalities::default(); let test_code = WASM_BINARY; let code = wabt::wat2wasm(r#" @@ -662,7 +662,7 @@ mod tests { #[test] fn sandbox_should_trap_when_heap_exhausted() { - let mut ext = TestExternalities::::default(); + let mut ext = TestExternalities::default(); let test_code = WASM_BINARY; let code = wabt::wat2wasm(r#" @@ -690,7 +690,7 @@ mod tests { #[test] fn start_called() { - let mut ext = TestExternalities::::default(); + let mut ext = TestExternalities::default(); let test_code = WASM_BINARY; let code = wabt::wat2wasm(r#" @@ -728,7 +728,7 @@ mod tests { #[test] fn invoke_args() { - let mut ext = TestExternalities::::default(); + let mut ext = TestExternalities::default(); let test_code = WASM_BINARY; let code = wabt::wat2wasm(r#" @@ -762,7 +762,7 @@ mod tests { #[test] fn return_val() { - let mut ext = TestExternalities::::default(); + let mut ext = TestExternalities::default(); let test_code = WASM_BINARY; let code = wabt::wat2wasm(r#" @@ -784,7 +784,7 @@ mod tests { #[test] fn unlinkable_module() { - let mut ext = TestExternalities::::default(); + let mut ext = TestExternalities::default(); let test_code = WASM_BINARY; let code = wabt::wat2wasm(r#" @@ -804,7 +804,7 @@ mod tests { #[test] fn corrupted_module() { - let mut ext = TestExternalities::::default(); + let mut ext = TestExternalities::default(); let test_code = WASM_BINARY; // Corrupted wasm file @@ -818,7 +818,7 @@ mod tests { #[test] fn start_fn_ok() { - let mut ext = TestExternalities::::default(); + let mut ext = TestExternalities::default(); let test_code = WASM_BINARY; let code = wabt::wat2wasm(r#" @@ -841,7 +841,7 @@ mod tests { #[test] fn start_fn_traps() { - let mut ext = TestExternalities::::default(); + let mut ext = TestExternalities::default(); let test_code = WASM_BINARY; let code = wabt::wat2wasm(r#" diff --git a/core/executor/src/wasm_runtime.rs b/core/executor/src/wasm_runtime.rs index 27b65d6551..d88ae7b9ed 100644 --- a/core/executor/src/wasm_runtime.rs +++ b/core/executor/src/wasm_runtime.rs @@ -23,7 +23,7 @@ use crate::error::{Error, WasmError}; use crate::wasmi_execution; use log::{trace, warn}; use codec::Decode; -use primitives::{storage::well_known_keys, Blake2Hasher, traits::Externalities}; +use primitives::{storage::well_known_keys, traits::Externalities}; use runtime_version::RuntimeVersion; use std::{collections::hash_map::{Entry, HashMap}}; @@ -36,8 +36,8 @@ pub trait WasmRuntime { fn update_heap_pages(&mut self, heap_pages: u64) -> bool; /// Call a method in the Substrate runtime by name. Returns the encoded result on success. - fn call(&mut self, ext: &mut dyn Externalities, method: &str, data: &[u8]) - -> Result, Error>; + fn call(&mut self, ext: &mut dyn Externalities, method: &str, data: &[u8]) + -> Result, Error>; /// Returns the version of this runtime. /// @@ -109,7 +109,7 @@ impl RuntimesCache { /// /// `Error::InvalidMemoryReference` is returned if no memory export with the /// identifier `memory` can be found in the runtime. - pub fn fetch_runtime>( + pub fn fetch_runtime( &mut self, ext: &mut E, wasm_method: WasmExecutionMethod, @@ -157,7 +157,7 @@ impl RuntimesCache { } } -fn create_wasm_runtime>( +fn create_wasm_runtime( ext: &mut E, wasm_method: WasmExecutionMethod, heap_pages: u64, diff --git a/core/executor/src/wasmi_execution.rs b/core/executor/src/wasmi_execution.rs index e228372bd3..0719ff4d40 100644 --- a/core/executor/src/wasmi_execution.rs +++ b/core/executor/src/wasmi_execution.rs @@ -23,7 +23,7 @@ use wasmi::{ }; use crate::error::{Error, WasmError}; use codec::{Encode, Decode}; -use primitives::{sandbox as sandbox_primitives, Blake2Hasher, traits::Externalities}; +use primitives::{sandbox as sandbox_primitives, traits::Externalities}; use crate::host_interface::SubstrateExternals; use crate::sandbox; use crate::allocator; @@ -342,7 +342,7 @@ fn get_heap_base(module: &ModuleRef) -> Result { /// Call a given method in the given wasm-module runtime. fn call_in_wasm_module( - ext: &mut dyn Externalities, + ext: &mut dyn Externalities, module_instance: &ModuleRef, method: &str, data: &[u8], @@ -373,7 +373,7 @@ fn call_in_wasm_module_with_custom_signature< FR: FnOnce(Option, &MemoryRef) -> Result, Error>, R, >( - ext: &mut dyn Externalities, + ext: &mut dyn Externalities, module_instance: &ModuleRef, method: &str, create_parameters: F, @@ -398,7 +398,7 @@ fn call_in_wasm_module_with_custom_signature< fec.write_memory(offset, data).map(|_| offset.into()).map_err(Into::into) })?; - let result = runtime_io::with_externalities( + let result = externalities::set_and_run_with_externalities( ext, || module_instance.invoke_export(method, ¶meters, &mut fec), ); @@ -588,7 +588,7 @@ impl WasmRuntime for WasmiRuntime { self.state_snapshot.heap_pages == heap_pages } - fn call(&mut self, ext: &mut dyn Externalities, method: &str, data: &[u8]) + fn call(&mut self, ext: &mut dyn Externalities, method: &str, data: &[u8]) -> Result, Error> { self.with(|module| { @@ -601,7 +601,7 @@ impl WasmRuntime for WasmiRuntime { } } -pub fn create_instance>(ext: &mut E, code: &[u8], heap_pages: u64) +pub fn create_instance(ext: &mut E, code: &[u8], heap_pages: u64) -> Result { let module = Module::from_buffer(&code).map_err(|_| WasmError::InvalidModule)?; @@ -656,14 +656,16 @@ mod tests { use state_machine::TestExternalities as CoreTestExternalities; use hex_literal::hex; - use primitives::{blake2_128, blake2_256, ed25519, sr25519, map, Pair}; + use primitives::{ + Blake2Hasher, blake2_128, blake2_256, ed25519, sr25519, map, Pair, offchain::OffchainExt, + }; use runtime_test::WASM_BINARY; use substrate_offchain::testing; use trie::{TrieConfiguration, trie_types::Layout}; - type TestExternalities = CoreTestExternalities; + type TestExternalities = CoreTestExternalities; - fn call>( + fn call( ext: &mut E, heap_pages: u64, code: &[u8], @@ -798,7 +800,7 @@ mod tests { #[test] fn ed25519_verify_should_work() { - let mut ext = TestExternalities::::default(); + let mut ext = TestExternalities::default(); let test_code = WASM_BINARY; let key = ed25519::Pair::from_seed(&blake2_256(b"test")); let sig = key.sign(b"all ok!"); @@ -824,7 +826,7 @@ mod tests { #[test] fn sr25519_verify_should_work() { - let mut ext = TestExternalities::::default(); + let mut ext = TestExternalities::default(); let test_code = WASM_BINARY; let key = sr25519::Pair::from_seed(&blake2_256(b"test")); let sig = key.sign(b"all ok!"); @@ -850,7 +852,7 @@ mod tests { #[test] fn ordered_trie_root_should_work() { - let mut ext = TestExternalities::::default(); + let mut ext = TestExternalities::default(); let trie_input = vec![b"zero".to_vec(), b"one".to_vec(), b"two".to_vec()]; let test_code = WASM_BINARY; assert_eq!( @@ -863,9 +865,9 @@ mod tests { fn offchain_local_storage_should_work() { use substrate_client::backend::OffchainStorage; - let mut ext = TestExternalities::::default(); + let mut ext = TestExternalities::default(); let (offchain, state) = testing::TestOffchainExt::new(); - ext.set_offchain_externalities(offchain); + ext.register_extension(OffchainExt::new(offchain)); let test_code = WASM_BINARY; assert_eq!( call(&mut ext, 8, &test_code[..], "test_offchain_local_storage", &[]).unwrap(), @@ -876,9 +878,9 @@ mod tests { #[test] fn offchain_http_should_work() { - let mut ext = TestExternalities::::default(); + let mut ext = TestExternalities::default(); let (offchain, state) = testing::TestOffchainExt::new(); - ext.set_offchain_externalities(offchain); + ext.register_extension(OffchainExt::new(offchain)); state.write().expect_request( 0, testing::PendingRequest { diff --git a/core/externalities/Cargo.toml b/core/externalities/Cargo.toml new file mode 100644 index 0000000000..97ece5439a --- /dev/null +++ b/core/externalities/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "substrate-externalities" +version = "2.0.0" +license = "GPL-3.0" +authors = ["Parity Technologies "] +edition = "2018" + +[dependencies] +primitive-types = { version = "0.5.1", features = ["codec"] } +primitives-storage = { package = "substrate-primitives-storage", path = "../primitives/storage" } +rstd = { package = "sr-std", path = "../sr-std" } +environmental = { version = "1.0.2" } diff --git a/core/externalities/src/extensions.rs b/core/externalities/src/extensions.rs new file mode 100644 index 0000000000..c7d7bc4853 --- /dev/null +++ b/core/externalities/src/extensions.rs @@ -0,0 +1,127 @@ +// Copyright 2017-2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +//! Externalities extensions storage. +//! +//! Externalities support to register a wide variety custom extensions. The [`Extensions`] provides +//! some convenience functionality to store and retrieve these extensions. +//! +//! It is required that each extension implements the [`Extension`] trait. + +use std::{collections::HashMap, any::{Any, TypeId}, ops::DerefMut}; + +/// Marker trait for types that should be registered as [`Externalities`](crate::Externalities) extension. +/// +/// As extensions are stored as `Box`, this trait should give more confidence that the correct +/// type is registered and requested. +pub trait Extension: Sized {} + +/// Macro for declaring an extension that usable with [`Extensions`]. +/// +/// The extension will be an unit wrapper struct that implements [`Extension`], `Deref` and +/// `DerefMut`. The wrapped type is given by the user. +/// +/// # Example +/// ``` +/// # use substrate_externalities::decl_extension; +/// decl_extension! { +/// /// Some test extension +/// struct TestExt(String); +/// } +/// ``` +#[macro_export] +macro_rules! decl_extension { + ( + $( #[ $attr:meta ] )* + $vis:vis struct $ext_name:ident ($inner:ty); + ) => { + $( #[ $attr ] )* + $vis struct $ext_name (pub $inner); + + impl $crate::Extension for $ext_name {} + + impl std::ops::Deref for $ext_name { + type Target = $inner; + + fn deref(&self) -> &Self::Target { + &self.0 + } + } + + impl std::ops::DerefMut for $ext_name { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + } +} + +/// Something that provides access to the [`Extensions`] store. +/// +/// This is a super trait of the [`Externalities`](crate::Externalities). +pub trait ExtensionStore { + /// Tries to find a registered extension by the given `type_id` and returns it as a `&mut dyn Any`. + /// + /// It is advised to use [`ExternalitiesExt::extension`](crate::ExternalitiesExt::extension) + /// instead of this function to get type system support and automatic type downcasting. + fn extension_by_type_id(&mut self, type_id: TypeId) -> Option<&mut dyn Any>; +} + +/// Stores extensions that should be made available through the externalities. +#[derive(Default)] +pub struct Extensions { + extensions: HashMap>, +} + +impl Extensions { + /// Create new instance of `Self`. + pub fn new() -> Self { + Self::default() + } + + /// Register the given extension. + pub fn register(&mut self, ext: E) { + self.extensions.insert(ext.type_id(), Box::new(ext)); + } + + /// Return a mutable reference to the requested extension. + pub fn get_mut(&mut self, ext_type_id: TypeId) -> Option<&mut dyn Any> { + self.extensions.get_mut(&ext_type_id).map(DerefMut::deref_mut) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + struct DummyExt(u32); + impl Extension for DummyExt {} + + struct DummyExt2(u32); + impl Extension for DummyExt2 {} + + #[test] + fn register_and_retrieve_extension() { + let mut exts = Extensions::new(); + exts.register(DummyExt(1)); + exts.register(DummyExt2(2)); + + let ext = exts.get_mut(TypeId::of::()).expect("Extension is registered"); + let ext_ty = ext.downcast_mut::().expect("Downcasting works"); + + assert_eq!(ext_ty.0, 1); + } +} diff --git a/core/externalities/src/lib.rs b/core/externalities/src/lib.rs new file mode 100644 index 0000000000..ecd5f7a7a7 --- /dev/null +++ b/core/externalities/src/lib.rs @@ -0,0 +1,139 @@ +// Copyright 2017-2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +//! Substrate externalities abstraction +//! +//! The externalities mainly provide access to storage and to registered extensions. Extensions +//! are for example the keystore or the offchain externalities. These externalities are used to +//! access the node from the runtime via the runtime interfaces. +//! +//! This crate exposes the main [`Externalities`] trait. + +use primitive_types::H256; + +use std::any::{Any, TypeId}; + +use primitives_storage::ChildStorageKey; + +pub use scope_limited::{set_and_run_with_externalities, with_externalities}; +pub use extensions::{Extension, Extensions, ExtensionStore}; + +mod extensions; +mod scope_limited; + +/// The Substrate externalities. +/// +/// Provides access to the storage and to other registered extensions. +pub trait Externalities: ExtensionStore { + /// Read runtime storage. + fn storage(&self, key: &[u8]) -> Option>; + + /// Get storage value hash. This may be optimized for large values. + fn storage_hash(&self, key: &[u8]) -> Option; + + /// Get child storage value hash. This may be optimized for large values. + fn child_storage_hash(&self, storage_key: ChildStorageKey, key: &[u8]) -> Option; + + /// Read original runtime storage, ignoring any overlayed changes. + fn original_storage(&self, key: &[u8]) -> Option>; + + /// Read original runtime child storage, ignoring any overlayed changes. + fn original_child_storage(&self, storage_key: ChildStorageKey, key: &[u8]) -> Option>; + + /// Get original storage value hash, ignoring any overlayed changes. + /// This may be optimized for large values. + fn original_storage_hash(&self, key: &[u8]) -> Option; + + /// Get original child storage value hash, ignoring any overlayed changes. + /// This may be optimized for large values. + fn original_child_storage_hash(&self, storage_key: ChildStorageKey, key: &[u8]) -> Option; + + /// Read child runtime storage. + fn child_storage(&self, storage_key: ChildStorageKey, key: &[u8]) -> Option>; + + /// Set storage entry `key` of current contract being called (effective immediately). + fn set_storage(&mut self, key: Vec, value: Vec) { + self.place_storage(key, Some(value)); + } + + /// Set child storage entry `key` of current contract being called (effective immediately). + fn set_child_storage(&mut self, storage_key: ChildStorageKey, key: Vec, value: Vec) { + self.place_child_storage(storage_key, key, Some(value)) + } + + /// Clear a storage entry (`key`) of current contract being called (effective immediately). + fn clear_storage(&mut self, key: &[u8]) { + self.place_storage(key.to_vec(), None); + } + + /// Clear a child storage entry (`key`) of current contract being called (effective immediately). + fn clear_child_storage(&mut self, storage_key: ChildStorageKey, key: &[u8]) { + self.place_child_storage(storage_key, key.to_vec(), None) + } + + /// Whether a storage entry exists. + fn exists_storage(&self, key: &[u8]) -> bool { + self.storage(key).is_some() + } + + /// Whether a child storage entry exists. + fn exists_child_storage(&self, storage_key: ChildStorageKey, key: &[u8]) -> bool { + self.child_storage(storage_key, key).is_some() + } + + /// Clear an entire child storage. + fn kill_child_storage(&mut self, storage_key: ChildStorageKey); + + /// Clear storage entries which keys are start with the given prefix. + fn clear_prefix(&mut self, prefix: &[u8]); + + /// Clear child storage entries which keys are start with the given prefix. + fn clear_child_prefix(&mut self, storage_key: ChildStorageKey, prefix: &[u8]); + + /// Set or clear a storage entry (`key`) of current contract being called (effective immediately). + fn place_storage(&mut self, key: Vec, value: Option>); + + /// Set or clear a child storage entry. Return whether the operation succeeds. + fn place_child_storage(&mut self, storage_key: ChildStorageKey, key: Vec, value: Option>); + + /// Get the identity of the chain. + fn chain_id(&self) -> u64; + + /// Get the trie root of the current storage map. This will also update all child storage keys + /// in the top-level storage map. + fn storage_root(&mut self) -> H256; + + /// Get the trie root of a child storage map. This will also update the value of the child + /// storage keys in the top-level storage map. + /// If the storage root equals the default hash as defined by the trie, the key in the top-level + /// storage map will be removed. + fn child_storage_root(&mut self, storage_key: ChildStorageKey) -> Vec; + + /// Get the change trie root of the current storage overlay at a block with given parent. + fn storage_changes_root(&mut self, parent: H256) -> Result, ()>; +} + +/// Extension for the [`Externalities`] trait. +pub trait ExternalitiesExt { + /// Tries to find a registered extension and returns a mutable reference. + fn extension(&mut self) -> Option<&mut T>; +} + +impl ExternalitiesExt for T { + fn extension(&mut self) -> Option<&mut A> { + self.extension_by_type_id(TypeId::of::()).and_then(Any::downcast_mut) + } +} diff --git a/core/externalities/src/scope_limited.rs b/core/externalities/src/scope_limited.rs new file mode 100644 index 0000000000..ae185449be --- /dev/null +++ b/core/externalities/src/scope_limited.rs @@ -0,0 +1,37 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +//! Stores the externalities in an `environmental` value to make it scope limited available. + +use crate::Externalities; + +environmental::environmental!(ext: trait Externalities); + +/// Set the given externalities while executing the given closure. To get access to the externalities +/// while executing the given closure [`with_externalities`] grants access to them. The externalities +/// are only set for the same thread this function was called from. +pub fn set_and_run_with_externalities(ext: &mut dyn Externalities, f: F) -> R + where F: FnOnce() -> R +{ + ext::using(ext, f) +} + +/// Execute the given closure with the currently set externalities. +/// +/// Returns `None` if no externalities are set or `Some(_)` with the result of the closure. +pub fn with_externalities R, R>(f: F) -> Option { + ext::with(f) +} diff --git a/core/finality-grandpa/src/finality_proof.rs b/core/finality-grandpa/src/finality_proof.rs index bae6c8ebc0..da5732f2f6 100644 --- a/core/finality-grandpa/src/finality_proof.rs +++ b/core/finality-grandpa/src/finality_proof.rs @@ -48,7 +48,7 @@ use sr_primitives::{ Justification, generic::BlockId, traits::{NumberFor, Block as BlockT, Header as HeaderT, One}, }; -use primitives::{H256, Blake2Hasher, offchain::NeverOffchainExt}; +use primitives::{H256, Blake2Hasher}; use substrate_telemetry::{telemetry, CONSENSUS_INFO}; use fg_primitives::AuthorityId; @@ -78,7 +78,7 @@ impl, RA> AuthoritySetForFinalityProver fo "GrandpaApi_grandpa_authorities", &[], ExecutionStrategy::NativeElseWasm, - NeverOffchainExt::new(), + None, ).and_then(|call_result| Decode::decode(&mut &call_result[..]) .map_err(|err| ClientError::CallResultDecode( "failed to decode GRANDPA authorities set proof".into(), err diff --git a/core/primitives/Cargo.toml b/core/primitives/Cargo.toml index 461a8fe7e3..a527f16c1c 100644 --- a/core/primitives/Cargo.toml +++ b/core/primitives/Cargo.toml @@ -31,6 +31,8 @@ num-traits = { version = "0.2.8", default-features = false } zeroize = "0.10.1" lazy_static = { version = "1.4.0", optional = true } parking_lot = { version = "0.9.0", optional = true } +externalities = { package = "substrate-externalities", path = "../externalities", optional = true } +primitives-storage = { package = "substrate-primitives-storage", path = "storage", default-features = false } [dev-dependencies] substrate-serializer = { path = "../serializer" } @@ -52,7 +54,7 @@ std = [ "log", "wasmi", "lazy_static", - "parking_lot", + "parking_lot", "primitive-types/std", "primitive-types/serde", "primitive-types/byteorder", @@ -79,4 +81,6 @@ std = [ "schnorrkel", "regex", "num-traits/std", + "externalities", + "primitives-storage/std", ] diff --git a/core/primitives/src/child_storage_key.rs b/core/primitives/src/child_storage_key.rs deleted file mode 100644 index eba34c1ef9..0000000000 --- a/core/primitives/src/child_storage_key.rs +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2019 Parity Technologies (UK) Ltd. -// This file is part of Substrate. - -// Substrate is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Substrate is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Substrate. If not, see . - -//! Provides a wrapper around a child storage key. - -use crate::storage::well_known_keys::is_child_trie_key_valid; -use rstd::{borrow::Cow, vec::Vec}; - -/// A wrapper around a child storage key. -/// -/// This wrapper ensures that the child storage key is correct and properly used. It is -/// impossible to create an instance of this struct without providing a correct `storage_key`. -pub struct ChildStorageKey<'a> { - storage_key: Cow<'a, [u8]>, -} - -impl<'a> ChildStorageKey<'a> { - fn new(storage_key: Cow<'a, [u8]>) -> Option { - if is_child_trie_key_valid(&storage_key) { - Some(ChildStorageKey { storage_key }) - } else { - None - } - } - - /// Create a new `ChildStorageKey` from a vector. - /// - /// `storage_key` need to start with `:child_storage:default:` - /// See `is_child_trie_key_valid` for more details. - pub fn from_vec(key: Vec) -> Option { - Self::new(Cow::Owned(key)) - } - - /// Create a new `ChildStorageKey` from a slice. - /// - /// `storage_key` need to start with `:child_storage:default:` - /// See `is_child_trie_key_valid` for more details. - pub fn from_slice(key: &'a [u8]) -> Option { - Self::new(Cow::Borrowed(key)) - } - - /// Get access to the byte representation of the storage key. - /// - /// This key is guaranteed to be correct. - pub fn as_ref(&self) -> &[u8] { - &*self.storage_key - } - - /// Destruct this instance into an owned vector that represents the storage key. - /// - /// This key is guaranteed to be correct. - pub fn into_owned(self) -> Vec { - self.storage_key.into_owned() - } -} diff --git a/core/primitives/src/lib.rs b/core/primitives/src/lib.rs index 310f0133ef..b1ce6e2f97 100644 --- a/core/primitives/src/lib.rs +++ b/core/primitives/src/lib.rs @@ -54,16 +54,15 @@ pub mod crypto; pub mod u32_trait; -pub mod child_storage_key; pub mod ed25519; pub mod sr25519; pub mod hash; mod hasher; pub mod offchain; pub mod sandbox; -pub mod storage; pub mod uint; mod changes_trie; +#[cfg(feature = "std")] pub mod traits; pub mod testing; @@ -81,6 +80,8 @@ pub use hash_db::Hasher; // pub use self::hasher::blake::BlakeHasher; pub use self::hasher::blake2::Blake2Hasher; +pub use primitives_storage as storage; + /// Context for executing a call into the runtime. pub enum ExecutionContext { /// Context for general importing (including own blocks). diff --git a/core/primitives/src/offchain.rs b/core/primitives/src/offchain.rs index 6403a20dbd..84fee530f6 100644 --- a/core/primitives/src/offchain.rs +++ b/core/primitives/src/offchain.rs @@ -17,8 +17,7 @@ //! Offchain workers types use codec::{Encode, Decode}; -use rstd::prelude::{Vec, Box}; -use rstd::convert::TryFrom; +use rstd::{prelude::{Vec, Box}, convert::TryFrom}; pub use crate::crypto::KeyTypeId; @@ -663,110 +662,17 @@ impl Externalities for LimitedExternalities { } } -/// An implementation of offchain extensions that should never be triggered. -pub enum NeverOffchainExt {} - -impl NeverOffchainExt { - /// Create new offchain extensions. - pub fn new<'a>() -> Option<&'a mut Self> { - None - } +#[cfg(feature = "std")] +externalities::decl_extension! { + /// The offchain extension that will be registered at the Substrate externalities. + pub struct OffchainExt(Box); } -impl Externalities for NeverOffchainExt { - fn is_validator(&self) -> bool { - unreachable!() - } - - fn submit_transaction(&mut self, _extrinsic: Vec) -> Result<(), ()> { - unreachable!() - } - - fn network_state( - &self, - ) -> Result { - unreachable!() - } - - fn timestamp(&mut self) -> Timestamp { - unreachable!() - } - - fn sleep_until(&mut self, _deadline: Timestamp) { - unreachable!() - } - - fn random_seed(&mut self) -> [u8; 32] { - unreachable!() - } - - fn local_storage_set(&mut self, _kind: StorageKind, _key: &[u8], _value: &[u8]) { - unreachable!() - } - - fn local_storage_compare_and_set( - &mut self, - _kind: StorageKind, - _key: &[u8], - _old_value: Option<&[u8]>, - _new_value: &[u8], - ) -> bool { - unreachable!() - } - - fn local_storage_get(&mut self, _kind: StorageKind, _key: &[u8]) -> Option> { - unreachable!() - } - - fn http_request_start( - &mut self, - _method: &str, - _uri: &str, - _meta: &[u8] - ) -> Result { - unreachable!() - } - - fn http_request_add_header( - &mut self, - _request_id: HttpRequestId, - _name: &str, - _value: &str - ) -> Result<(), ()> { - unreachable!() - } - - fn http_request_write_body( - &mut self, - _request_id: HttpRequestId, - _chunk: &[u8], - _deadline: Option - ) -> Result<(), HttpError> { - unreachable!() - } - - fn http_response_wait( - &mut self, - _ids: &[HttpRequestId], - _deadline: Option - ) -> Vec { - unreachable!() - } - - fn http_response_headers( - &mut self, - _request_id: HttpRequestId - ) -> Vec<(Vec, Vec)> { - unreachable!() - } - - fn http_response_read_body( - &mut self, - _request_id: HttpRequestId, - _buffer: &mut [u8], - _deadline: Option - ) -> Result { - unreachable!() +#[cfg(feature = "std")] +impl OffchainExt { + /// Create a new instance of `Self`. + pub fn new(offchain: O) -> Self { + Self(Box::new(offchain)) } } diff --git a/core/primitives/src/testing.rs b/core/primitives/src/testing.rs index ccfc36af73..7fdefd8fe0 100644 --- a/core/primitives/src/testing.rs +++ b/core/primitives/src/testing.rs @@ -18,8 +18,7 @@ #[cfg(feature = "std")] use crate::{ed25519, sr25519, crypto::{Public, Pair}}; -use crate::crypto::KeyTypeId; // No idea why this import had to move from - // the previous line, but now the compiler is happy +use crate::crypto::KeyTypeId; /// Key type for generic Ed25519 key. pub const ED25519: KeyTypeId = KeyTypeId(*b"ed25"); @@ -37,7 +36,7 @@ pub struct KeyStore { #[cfg(feature = "std")] impl KeyStore { /// Creates a new instance of `Self`. - pub fn new() -> std::sync::Arc> { + pub fn new() -> crate::traits::BareCryptoStorePtr { std::sync::Arc::new(parking_lot::RwLock::new(Self::default())) } } @@ -133,7 +132,7 @@ impl crate::traits::BareCryptoStore for KeyStore { #[cfg(test)] mod tests { use super::*; - use crate::{sr25519, traits::BareCryptoStore}; + use crate::sr25519; use crate::testing::{ED25519, SR25519}; diff --git a/core/primitives/src/traits.rs b/core/primitives/src/traits.rs index b173d8512c..1ef665032e 100644 --- a/core/primitives/src/traits.rs +++ b/core/primitives/src/traits.rs @@ -16,15 +16,13 @@ //! Shareable Substrate traits. -#[cfg(feature = "std")] -use crate::{crypto::KeyTypeId, ed25519, sr25519, child_storage_key::ChildStorageKey}; -#[cfg(feature = "std")] +use crate::{crypto::KeyTypeId, ed25519, sr25519}; + use std::{fmt::{Debug, Display}, panic::UnwindSafe}; -#[cfg(feature = "std")] -use hash_db::Hasher; + +pub use externalities::{Externalities, ExternalitiesExt}; /// Something that generates, stores and provides access to keys. -#[cfg(feature = "std")] pub trait BareCryptoStore: Send + Sync { /// Returns all sr25519 public keys for the given key type. fn sr25519_public_keys(&self, id: KeyTypeId) -> Vec; @@ -70,128 +68,22 @@ pub trait BareCryptoStore: Send + Sync { } /// A pointer to the key store. -#[cfg(feature = "std")] pub type BareCryptoStorePtr = std::sync::Arc>; -/// Externalities: pinned to specific active address. -#[cfg(feature = "std")] -pub trait Externalities { - /// Read runtime storage. - fn storage(&self, key: &[u8]) -> Option>; - - /// Get storage value hash. This may be optimized for large values. - fn storage_hash(&self, key: &[u8]) -> Option { - self.storage(key).map(|v| H::hash(&v)) - } - - /// Get child storage value hash. This may be optimized for large values. - fn child_storage_hash(&self, storage_key: ChildStorageKey, key: &[u8]) -> Option { - self.child_storage(storage_key, key).map(|v| H::hash(&v)) - } - - /// Read original runtime storage, ignoring any overlayed changes. - fn original_storage(&self, key: &[u8]) -> Option>; - - /// Read original runtime child storage, ignoring any overlayed changes. - fn original_child_storage(&self, storage_key: ChildStorageKey, key: &[u8]) -> Option>; - - /// Get original storage value hash, ignoring any overlayed changes. - /// This may be optimized for large values. - fn original_storage_hash(&self, key: &[u8]) -> Option { - self.original_storage(key).map(|v| H::hash(&v)) - } - - /// Get original child storage value hash, ignoring any overlayed changes. - /// This may be optimized for large values. - fn original_child_storage_hash( - &self, - storage_key: ChildStorageKey, - key: &[u8], - ) -> Option { - self.original_child_storage(storage_key, key).map(|v| H::hash(&v)) - } - - /// Read child runtime storage. - fn child_storage(&self, storage_key: ChildStorageKey, key: &[u8]) -> Option>; - - /// Set storage entry `key` of current contract being called (effective immediately). - fn set_storage(&mut self, key: Vec, value: Vec) { - self.place_storage(key, Some(value)); - } - - /// Set child storage entry `key` of current contract being called (effective immediately). - fn set_child_storage(&mut self, storage_key: ChildStorageKey, key: Vec, value: Vec) { - self.place_child_storage(storage_key, key, Some(value)) - } - - /// Clear a storage entry (`key`) of current contract being called (effective immediately). - fn clear_storage(&mut self, key: &[u8]) { - self.place_storage(key.to_vec(), None); - } - - /// Clear a child storage entry (`key`) of current contract being called (effective immediately). - fn clear_child_storage(&mut self, storage_key: ChildStorageKey, key: &[u8]) { - self.place_child_storage(storage_key, key.to_vec(), None) - } - - /// Whether a storage entry exists. - fn exists_storage(&self, key: &[u8]) -> bool { - self.storage(key).is_some() - } - - /// Whether a child storage entry exists. - fn exists_child_storage(&self, storage_key: ChildStorageKey, key: &[u8]) -> bool { - self.child_storage(storage_key, key).is_some() - } - - /// Clear an entire child storage. - fn kill_child_storage(&mut self, storage_key: ChildStorageKey); - - /// Clear storage entries which keys are start with the given prefix. - fn clear_prefix(&mut self, prefix: &[u8]); - - /// Clear child storage entries which keys are start with the given prefix. - fn clear_child_prefix(&mut self, storage_key: ChildStorageKey, prefix: &[u8]); - - /// Set or clear a storage entry (`key`) of current contract being called (effective immediately). - fn place_storage(&mut self, key: Vec, value: Option>); - - /// Set or clear a child storage entry. Return whether the operation succeeds. - fn place_child_storage(&mut self, storage_key: ChildStorageKey, key: Vec, value: Option>); - - /// Get the identity of the chain. - fn chain_id(&self) -> u64; - - /// Get the trie root of the current storage map. This will also update all child storage keys - /// in the top-level storage map. - fn storage_root(&mut self) -> H::Out where H::Out: Ord; - - /// Get the trie root of a child storage map. This will also update the value of the child - /// storage keys in the top-level storage map. - /// If the storage root equals the default hash as defined by the trie, the key in the top-level - /// storage map will be removed. - fn child_storage_root(&mut self, storage_key: ChildStorageKey) -> Vec; - - /// Get the change trie root of the current storage overlay at a block with given parent. - fn storage_changes_root(&mut self, parent: H::Out) -> Result, ()> where H::Out: Ord; - - /// Returns offchain externalities extension if present. - fn offchain(&mut self) -> Option<&mut dyn crate::offchain::Externalities>; - - /// Returns the keystore. - fn keystore(&self) -> Option; +externalities::decl_extension! { + /// The keystore extension to register/retrieve from the externalities. + pub struct KeystoreExt(BareCryptoStorePtr); } /// Code execution engine. -#[cfg(feature = "std")] -pub trait CodeExecutor: Sized + Send + Sync { +pub trait CodeExecutor: Sized + Send + Sync { /// Externalities error type. type Error: Display + Debug + Send + 'static; /// Call a given method in the runtime. Returns a tuple of the result (either the output data /// or an execution error) together with a `bool`, which is true if native execution was used. fn call< - E: Externalities, + E: Externalities, R: codec::Codec + PartialEq, NC: FnOnce() -> Result + UnwindSafe, >( diff --git a/core/primitives/storage/Cargo.toml b/core/primitives/storage/Cargo.toml new file mode 100644 index 0000000000..5b1ed37d6a --- /dev/null +++ b/core/primitives/storage/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "substrate-primitives-storage" +version = "2.0.0" +authors = ["Parity Technologies "] +edition = "2018" +description = "Storage related primitives" + +[dependencies] +rstd = { package = "sr-std", path = "../../sr-std", default-features = false } +serde = { version = "1.0.101", optional = true, features = ["derive"] } +impl-serde = { version = "0.2.1", optional = true } + +[features] +default = [ "std" ] +std = [ "rstd/std", "serde", "impl-serde" ] diff --git a/core/primitives/src/storage.rs b/core/primitives/storage/src/lib.rs similarity index 62% rename from core/primitives/src/storage.rs rename to core/primitives/storage/src/lib.rs index 14c49bfaa9..334779ed5f 100644 --- a/core/primitives/src/storage.rs +++ b/core/primitives/storage/src/lib.rs @@ -14,23 +14,30 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -//! Contract execution data. +//! Primitive types for storage related stuff. + +#![cfg_attr(not(feature = "std"), no_std)] #[cfg(feature = "std")] use serde::{Serialize, Deserialize}; -#[cfg(feature = "std")] -use crate::bytes; -use rstd::vec::Vec; -/// Contract storage key. +use rstd::{vec::Vec, borrow::Cow}; + +/// Storage key. #[derive(PartialEq, Eq)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug, Hash, PartialOrd, Ord, Clone))] -pub struct StorageKey(#[cfg_attr(feature = "std", serde(with="bytes"))] pub Vec); +pub struct StorageKey( + #[cfg_attr(feature = "std", serde(with="impl_serde::serialize"))] + pub Vec, +); -/// Contract storage entry data. +/// Storage data associated to a [`StorageKey`]. #[derive(PartialEq, Eq)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug, Hash, PartialOrd, Ord, Clone))] -pub struct StorageData(#[cfg_attr(feature = "std", serde(with="bytes"))] pub Vec); +pub struct StorageData( + #[cfg_attr(feature = "std", serde(with="impl_serde::serialize"))] + pub Vec, +); /// Storage change set #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug, PartialEq, Eq))] @@ -39,15 +46,11 @@ pub struct StorageChangeSet { /// Block hash pub block: Hash, /// A list of changes - pub changes: Vec<( - StorageKey, - Option, - )>, + pub changes: Vec<(StorageKey, Option)>, } /// List of all well known keys and prefixes in storage. pub mod well_known_keys { - /// Wasm code of the runtime. /// /// Stored as a raw byte vector. Required by substrate. @@ -94,3 +97,52 @@ pub mod well_known_keys { has_right_prefix } } + +/// A wrapper around a child storage key. +/// +/// This wrapper ensures that the child storage key is correct and properly used. It is +/// impossible to create an instance of this struct without providing a correct `storage_key`. +pub struct ChildStorageKey<'a> { + storage_key: Cow<'a, [u8]>, +} + +impl<'a> ChildStorageKey<'a> { + /// Create new instance of `Self`. + fn new(storage_key: Cow<'a, [u8]>) -> Option { + if well_known_keys::is_child_trie_key_valid(&storage_key) { + Some(ChildStorageKey { storage_key }) + } else { + None + } + } + + /// Create a new `ChildStorageKey` from a vector. + /// + /// `storage_key` need to start with `:child_storage:default:` + /// See `is_child_trie_key_valid` for more details. + pub fn from_vec(key: Vec) -> Option { + Self::new(Cow::Owned(key)) + } + + /// Create a new `ChildStorageKey` from a slice. + /// + /// `storage_key` need to start with `:child_storage:default:` + /// See `is_child_trie_key_valid` for more details. + pub fn from_slice(key: &'a [u8]) -> Option { + Self::new(Cow::Borrowed(key)) + } + + /// Get access to the byte representation of the storage key. + /// + /// This key is guaranteed to be correct. + pub fn as_ref(&self) -> &[u8] { + &*self.storage_key + } + + /// Destruct this instance into an owned vector that represents the storage key. + /// + /// This key is guaranteed to be correct. + pub fn into_owned(self) -> Vec { + self.storage_key.into_owned() + } +} diff --git a/core/rpc/src/author/tests.rs b/core/rpc/src/author/tests.rs index 57d3929d92..202dab4940 100644 --- a/core/rpc/src/author/tests.rs +++ b/core/rpc/src/author/tests.rs @@ -24,8 +24,8 @@ use transaction_pool::{ FullChainApi, }; use primitives::{ - H256, blake2_256, hexdisplay::HexDisplay, traits::BareCryptoStore, - testing::{ED25519, SR25519, KeyStore}, ed25519, crypto::Pair + H256, blake2_256, hexdisplay::HexDisplay, testing::{ED25519, SR25519, KeyStore}, ed25519, + crypto::Pair, }; use test_client::{ self, AccountKeyring, runtime::{Extrinsic, Transfer, SessionKeys}, DefaultTestClientBuilderExt, @@ -212,7 +212,9 @@ fn should_insert_key() { fn should_rotate_keys() { let runtime = runtime::Runtime::new().unwrap(); let keystore = KeyStore::new(); - let client = Arc::new(test_client::TestClientBuilder::new().set_keystore(keystore.clone()).build()); + let client = Arc::new( + test_client::TestClientBuilder::new().set_keystore(keystore.clone()).build(), + ); let p = Author { client: client.clone(), pool: Arc::new(Pool::new(Default::default(), FullChainApi::new(client))), diff --git a/core/rpc/src/state/state_full.rs b/core/rpc/src/state/state_full.rs index 6f0472163f..cd05093c3a 100644 --- a/core/rpc/src/state/state_full.rs +++ b/core/rpc/src/state/state_full.rs @@ -33,8 +33,7 @@ use client::{ backend::Backend, error::Result as ClientResult, }; use primitives::{ - H256, Blake2Hasher, Bytes, offchain::NeverOffchainExt, - storage::{well_known_keys, StorageKey, StorageData, StorageChangeSet}, + H256, Blake2Hasher, Bytes, storage::{well_known_keys, StorageKey, StorageData, StorageChangeSet}, }; use runtime_version::RuntimeVersion; use state_machine::ExecutionStrategy; @@ -240,13 +239,16 @@ impl StateBackend for FullState FutureResult { Box::new(result( self.block_or_best(block) - .and_then(|block| self.client.executor() + .and_then(|block| + self + .client + .executor() .call( &BlockId::Hash(block), &method, &*call_data, ExecutionStrategy::NativeElseWasm, - NeverOffchainExt::new(), + None, ) .map(Into::into)) .map_err(client_err))) diff --git a/core/sr-io/Cargo.toml b/core/sr-io/Cargo.toml index 65b080b86d..e2b681b75b 100644 --- a/core/sr-io/Cargo.toml +++ b/core/sr-io/Cargo.toml @@ -15,9 +15,9 @@ codec = { package = "parity-scale-codec", version = "1.0.0", default-features = hash-db = { version = "0.15.2", default-features = false } libsecp256k1 = { version = "0.3.0", optional = true } tiny-keccak = { version = "1.5.0", optional = true } -environmental = { version = "1.0.2", optional = true } substrate-state-machine = { path = "../state-machine", optional = true } trie = { package = "substrate-trie", path = "../trie", optional = true } +externalities = { package = "substrate-externalities", path = "../externalities", optional = true } [features] default = ["std"] @@ -27,10 +27,10 @@ std = [ "rstd/std", "hash-db/std", "trie", - "environmental", "substrate-state-machine", "libsecp256k1", "tiny-keccak", + "externalities", ] nightly = [] strict = [] diff --git a/core/sr-io/src/lib.rs b/core/sr-io/src/lib.rs index 4b00a84231..24f964c7b5 100644 --- a/core/sr-io/src/lib.rs +++ b/core/sr-io/src/lib.rs @@ -368,13 +368,10 @@ mod imp { } #[cfg(feature = "std")] -pub use self::imp::{ - StorageOverlay, ChildrenStorageOverlay, with_storage, - with_externalities -}; +pub use self::imp::{StorageOverlay, ChildrenStorageOverlay, with_storage}; #[cfg(not(feature = "std"))] pub use self::imp::ext::*; /// Type alias for Externalities implementation used in tests. #[cfg(feature = "std")] -pub type TestExternalities = self::imp::TestExternalities; +pub type TestExternalities = self::imp::TestExternalities; diff --git a/core/sr-io/with_std.rs b/core/sr-io/with_std.rs index 919f4a913a..e431ae1f6e 100644 --- a/core/sr-io/with_std.rs +++ b/core/sr-io/with_std.rs @@ -16,19 +16,18 @@ use primitives::{ blake2_128, blake2_256, twox_128, twox_256, twox_64, ed25519, Blake2Hasher, sr25519, Pair, H256, - traits::Externalities, child_storage_key::ChildStorageKey, hexdisplay::HexDisplay, offchain, - Hasher, + traits::KeystoreExt, storage::ChildStorageKey, hexdisplay::HexDisplay, Hasher, + offchain::{self, OffchainExt}, }; // Switch to this after PoC-3 // pub use primitives::BlakeHasher; pub use substrate_state_machine::{BasicExternalities, TestExternalities}; -use environmental::environmental; use trie::{TrieConfiguration, trie_types::Layout}; use std::{collections::HashMap, convert::TryFrom}; -environmental!(ext: trait Externalities); +use externalities::{with_externalities, set_and_run_with_externalities, ExternalitiesExt}; /// Additional bounds for `Hasher` trait for with_std. pub trait HasherBounds {} @@ -48,12 +47,12 @@ fn child_storage_key_or_panic(storage_key: &[u8]) -> ChildStorageKey { impl StorageApi for () { fn storage(key: &[u8]) -> Option> { - ext::with(|ext| ext.storage(key).map(|s| s.to_vec())) + with_externalities(|ext| ext.storage(key).map(|s| s.to_vec())) .expect("storage cannot be called outside of an Externalities-provided environment.") } fn read_storage(key: &[u8], value_out: &mut [u8], value_offset: usize) -> Option { - ext::with(|ext| ext.storage(key).map(|value| { + with_externalities(|ext| ext.storage(key).map(|value| { let data = &value[value_offset.min(value.len())..]; let written = std::cmp::min(data.len(), value_out.len()); value_out[..written].copy_from_slice(&data[..written]); @@ -62,7 +61,7 @@ impl StorageApi for () { } fn child_storage(storage_key: &[u8], key: &[u8]) -> Option> { - ext::with(|ext| { + with_externalities(|ext| { let storage_key = child_storage_key_or_panic(storage_key); ext.child_storage(storage_key, key).map(|s| s.to_vec()) }) @@ -70,7 +69,7 @@ impl StorageApi for () { } fn set_storage(key: &[u8], value: &[u8]) { - ext::with(|ext| + with_externalities(|ext| ext.set_storage(key.to_vec(), value.to_vec()) ); } @@ -81,7 +80,7 @@ impl StorageApi for () { value_out: &mut [u8], value_offset: usize, ) -> Option { - ext::with(|ext| { + with_externalities(|ext| { let storage_key = child_storage_key_or_panic(storage_key); ext.child_storage(storage_key, key) .map(|value| { @@ -95,73 +94,71 @@ impl StorageApi for () { } fn set_child_storage(storage_key: &[u8], key: &[u8], value: &[u8]) { - ext::with(|ext| { + with_externalities(|ext| { let storage_key = child_storage_key_or_panic(storage_key); ext.set_child_storage(storage_key, key.to_vec(), value.to_vec()) }); } fn clear_storage(key: &[u8]) { - ext::with(|ext| + with_externalities(|ext| ext.clear_storage(key) ); } fn clear_child_storage(storage_key: &[u8], key: &[u8]) { - ext::with(|ext| { + with_externalities(|ext| { let storage_key = child_storage_key_or_panic(storage_key); ext.clear_child_storage(storage_key, key) }); } fn kill_child_storage(storage_key: &[u8]) { - ext::with(|ext| { + with_externalities(|ext| { let storage_key = child_storage_key_or_panic(storage_key); ext.kill_child_storage(storage_key) }); } fn exists_storage(key: &[u8]) -> bool { - ext::with(|ext| + with_externalities(|ext| ext.exists_storage(key) ).unwrap_or(false) } fn exists_child_storage(storage_key: &[u8], key: &[u8]) -> bool { - ext::with(|ext| { + with_externalities(|ext| { let storage_key = child_storage_key_or_panic(storage_key); ext.exists_child_storage(storage_key, key) }).unwrap_or(false) } fn clear_prefix(prefix: &[u8]) { - ext::with(|ext| - ext.clear_prefix(prefix) - ); + with_externalities(|ext| ext.clear_prefix(prefix)); } fn clear_child_prefix(storage_key: &[u8], prefix: &[u8]) { - ext::with(|ext| { + with_externalities(|ext| { let storage_key = child_storage_key_or_panic(storage_key); ext.clear_child_prefix(storage_key, prefix) }); } fn storage_root() -> [u8; 32] { - ext::with(|ext| + with_externalities(|ext| ext.storage_root() ).unwrap_or(H256::zero()).into() } fn child_storage_root(storage_key: &[u8]) -> Vec { - ext::with(|ext| { + with_externalities(|ext| { let storage_key = child_storage_key_or_panic(storage_key); ext.child_storage_root(storage_key) }).expect("child_storage_root cannot be called outside of an Externalities-provided environment.") } fn storage_changes_root(parent_hash: [u8; 32]) -> Option<[u8; 32]> { - ext::with(|ext| + with_externalities(|ext| ext.storage_changes_root(parent_hash.into()).map(|h| h.map(|h| h.into())) ).unwrap_or(Ok(None)).expect("Invalid parent hash passed to storage_changes_root") } @@ -177,7 +174,7 @@ impl StorageApi for () { impl OtherApi for () { fn chain_id() -> u64 { - ext::with(|ext| + with_externalities(|ext| ext.chain_id() ).unwrap_or(0) } @@ -199,8 +196,8 @@ impl OtherApi for () { impl CryptoApi for () { fn ed25519_public_keys(id: KeyTypeId) -> Vec { - ext::with(|ext| { - ext.keystore() + with_externalities(|ext| { + ext.extension::() .expect("No `keystore` associated for the current context!") .read() .ed25519_public_keys(id) @@ -208,8 +205,8 @@ impl CryptoApi for () { } fn ed25519_generate(id: KeyTypeId, seed: Option<&str>) -> ed25519::Public { - ext::with(|ext| { - ext.keystore() + with_externalities(|ext| { + ext.extension::() .expect("No `keystore` associated for the current context!") .write() .ed25519_generate_new(id, seed) @@ -224,8 +221,8 @@ impl CryptoApi for () { ) -> Option { let pub_key = ed25519::Public::try_from(pubkey.as_ref()).ok()?; - ext::with(|ext| { - ext.keystore() + with_externalities(|ext| { + ext.extension::() .expect("No `keystore` associated for the current context!") .read() .ed25519_key_pair(id, &pub_key) @@ -238,8 +235,8 @@ impl CryptoApi for () { } fn sr25519_public_keys(id: KeyTypeId) -> Vec { - ext::with(|ext| { - ext.keystore() + with_externalities(|ext| { + ext.extension::() .expect("No `keystore` associated for the current context!") .read() .sr25519_public_keys(id) @@ -247,8 +244,8 @@ impl CryptoApi for () { } fn sr25519_generate(id: KeyTypeId, seed: Option<&str>) -> sr25519::Public { - ext::with(|ext| { - ext.keystore() + with_externalities(|ext| { + ext.extension::() .expect("No `keystore` associated for the current context!") .write() .sr25519_generate_new(id, seed) @@ -263,8 +260,8 @@ impl CryptoApi for () { ) -> Option { let pub_key = sr25519::Public::try_from(pubkey.as_ref()).ok()?; - ext::with(|ext| { - ext.keystore() + with_externalities(|ext| { + ext.extension::() .expect("No `keystore` associated for the current context!") .read() .sr25519_key_pair(id, &pub_key) @@ -316,9 +313,9 @@ impl HashingApi for () { } fn with_offchain(f: impl FnOnce(&mut dyn offchain::Externalities) -> R, msg: &'static str) -> R { - ext::with(|ext| ext - .offchain() - .map(|ext| f(ext)) + with_externalities(|ext| ext + .extension::() + .map(|ext| f(&mut **ext)) .expect(msg) ).expect("offchain-worker functions cannot be called outside of an Externalities-provided environment.") } @@ -443,13 +440,6 @@ impl OffchainApi for () { impl Api for () {} -/// Execute the given closure with global function available whose functionality routes into the -/// externalities `ext`. Forwards the value that the closure returns. -// NOTE: need a concrete hasher here due to limitations of the `environmental!` macro, otherwise a type param would have been fine I think. -pub fn with_externalities R>(ext: &mut dyn Externalities, f: F) -> R { - ext::using(ext, f) -} - /// A set of key value pairs for storage. pub type StorageOverlay = HashMap, Vec>; @@ -467,7 +457,7 @@ pub fn with_storage R>( rstd::mem::swap(&mut alt_storage, storage); let mut ext = BasicExternalities::new(alt_storage.0, alt_storage.1); - let r = ext::using(&mut ext, f); + let r = set_and_run_with_externalities(&mut ext, f); *storage = ext.into_storages(); @@ -482,7 +472,7 @@ mod std_tests { #[test] fn storage_works() { let mut t = BasicExternalities::default(); - assert!(with_externalities(&mut t, || { + assert!(set_and_run_with_externalities(&mut t, || { assert_eq!(storage(b"hello"), None); set_storage(b"hello", b"world"); assert_eq!(storage(b"hello"), Some(b"world".to_vec())); @@ -493,7 +483,7 @@ mod std_tests { t = BasicExternalities::new(map![b"foo".to_vec() => b"bar".to_vec()], map![]); - assert!(!with_externalities(&mut t, || { + assert!(!set_and_run_with_externalities(&mut t, || { assert_eq!(storage(b"hello"), None); assert_eq!(storage(b"foo"), Some(b"bar".to_vec())); false @@ -506,7 +496,7 @@ mod std_tests { b":test".to_vec() => b"\x0b\0\0\0Hello world".to_vec() ], map![]); - with_externalities(&mut t, || { + set_and_run_with_externalities(&mut t, || { let mut v = [0u8; 4]; assert!(read_storage(b":test", &mut v[..], 0).unwrap() >= 4); assert_eq!(v, [11u8, 0, 0, 0]); @@ -525,7 +515,7 @@ mod std_tests { b":abdd".to_vec() => b"\x0b\0\0\0Hello world".to_vec() ], map![]); - with_externalities(&mut t, || { + set_and_run_with_externalities(&mut t, || { clear_prefix(b":abc"); assert!(storage(b":a").is_some()); diff --git a/core/sr-primitives/Cargo.toml b/core/sr-primitives/Cargo.toml index fc8b744d37..ab81df2b53 100644 --- a/core/sr-primitives/Cargo.toml +++ b/core/sr-primitives/Cargo.toml @@ -16,6 +16,7 @@ runtime_io = { package = "sr-io", path = "../sr-io", default-features = false } log = { version = "0.4.8", optional = true } paste = "0.1.6" rand = { version = "0.7.2", optional = true } +externalities = { package = "substrate-externalities", path = "../externalities", optional = true } impl-trait-for-tuples = "0.1.2" [dev-dependencies] @@ -36,4 +37,5 @@ std = [ "primitives/std", "app-crypto/std", "rand", + "externalities", ] diff --git a/core/sr-primitives/src/lib.rs b/core/sr-primitives/src/lib.rs index bdcbfb0b46..36d785f9a6 100644 --- a/core/sr-primitives/src/lib.rs +++ b/core/sr-primitives/src/lib.rs @@ -67,6 +67,9 @@ pub use sr_arithmetic::{ /// Re-export 128 bit helpers from sr_arithmetic pub use sr_arithmetic::helpers_128bit; +#[cfg(feature = "std")] +pub use externalities::set_and_run_with_externalities; + /// An abstraction over justification for a block's validity under a consensus algorithm. /// /// Essentially a finality proof. The exact formulation will vary between consensus diff --git a/core/sr-primitives/src/offchain/http.rs b/core/sr-primitives/src/offchain/http.rs index 6df18da83e..2d84f175d1 100644 --- a/core/sr-primitives/src/offchain/http.rs +++ b/core/sr-primitives/src/offchain/http.rs @@ -512,16 +512,18 @@ impl<'a> HeadersIterator<'a> { #[cfg(test)] mod tests { use super::*; - use runtime_io::{TestExternalities, with_externalities}; + use crate::set_and_run_with_externalities; + use runtime_io::TestExternalities; use substrate_offchain::testing; + use primitives::offchain::OffchainExt; #[test] fn should_send_a_basic_request_and_get_response() { let (offchain, state) = testing::TestOffchainExt::new(); let mut t = TestExternalities::default(); - t.set_offchain_externalities(offchain); + t.register_extension(OffchainExt::new(offchain)); - with_externalities(&mut t, || { + set_and_run_with_externalities(&mut t, || { let request: Request = Request::get("http://localhost:1234"); let pending = request .add_header("X-Auth", "hunter2") @@ -560,9 +562,9 @@ mod tests { fn should_send_a_post_request() { let (offchain, state) = testing::TestOffchainExt::new(); let mut t = TestExternalities::default(); - t.set_offchain_externalities(offchain); + t.register_extension(OffchainExt::new(offchain)); - with_externalities(&mut t, || { + set_and_run_with_externalities(&mut t, || { let pending = Request::default() .method(Method::Post) .url("http://localhost:1234") diff --git a/core/state-machine/Cargo.toml b/core/state-machine/Cargo.toml index 914fa04db8..7cd8601a3b 100644 --- a/core/state-machine/Cargo.toml +++ b/core/state-machine/Cargo.toml @@ -17,6 +17,7 @@ panic-handler = { package = "substrate-panic-handler", path = "../panic-handler" codec = { package = "parity-scale-codec", version = "1.0.0" } num-traits = "0.2.8" rand = "0.7.2" +externalities = { package = "substrate-externalities", path = "../externalities" } [dev-dependencies] hex-literal = "0.2.1" diff --git a/core/state-machine/src/basic.rs b/core/state-machine/src/basic.rs index e45af45c9f..c2d1a0e395 100644 --- a/core/state-machine/src/basic.rs +++ b/core/state-machine/src/basic.rs @@ -16,15 +16,14 @@ //! Basic implementation for Externalities. -use std::collections::HashMap; -use std::iter::FromIterator; +use std::{collections::HashMap, any::{TypeId, Any}, iter::FromIterator}; use crate::backend::{Backend, InMemory}; use hash_db::Hasher; use trie::{TrieConfiguration, default_child_trie_root}; use trie::trie_types::Layout; use primitives::{ - storage::well_known_keys::is_child_storage_key, child_storage_key::ChildStorageKey, offchain, - traits::Externalities, + storage::{well_known_keys::is_child_storage_key, ChildStorageKey}, + traits::Externalities, Blake2Hasher, hash::H256, }; use log::warn; @@ -88,21 +87,37 @@ impl From, Vec>> for BasicExternalities { } } -impl Externalities for BasicExternalities where H::Out: Ord { +impl Externalities for BasicExternalities { fn storage(&self, key: &[u8]) -> Option> { self.top.get(key).cloned() } + fn storage_hash(&self, key: &[u8]) -> Option { + self.storage(key).map(|v| Blake2Hasher::hash(&v)) + } + fn original_storage(&self, key: &[u8]) -> Option> { - Externalities::::storage(self, key) + self.storage(key) + } + + fn original_storage_hash(&self, key: &[u8]) -> Option { + self.storage_hash(key) } fn child_storage(&self, storage_key: ChildStorageKey, key: &[u8]) -> Option> { self.children.get(storage_key.as_ref()).and_then(|child| child.get(key)).cloned() } + fn child_storage_hash(&self, storage_key: ChildStorageKey, key: &[u8]) -> Option { + self.child_storage(storage_key, key).map(|v| Blake2Hasher::hash(&v)) + } + + fn original_child_storage_hash(&self, storage_key: ChildStorageKey, key: &[u8]) -> Option { + self.child_storage_hash(storage_key, key) + } + fn original_child_storage(&self, storage_key: ChildStorageKey, key: &[u8]) -> Option> { - Externalities::::child_storage(self, storage_key, key) + Externalities::child_storage(self, storage_key, key) } fn place_storage(&mut self, key: Vec, maybe_value: Option>) { @@ -155,16 +170,15 @@ impl Externalities for BasicExternalities where H::Out: Ord { fn chain_id(&self) -> u64 { 42 } - fn storage_root(&mut self) -> H::Out { + fn storage_root(&mut self) -> H256 { let mut top = self.top.clone(); let keys: Vec<_> = self.children.keys().map(|k| k.to_vec()).collect(); // Single child trie implementation currently allows using the same child // empty root for all child trie. Using null storage key until multiple // type of child trie support. - let empty_hash = default_child_trie_root::>(&[]); + let empty_hash = default_child_trie_root::>(&[]); for storage_key in keys { - let child_root = Externalities::::child_storage_root( - self, + let child_root = self.child_storage_root( ChildStorageKey::from_slice(storage_key.as_slice()) .expect("Map only feed by valid keys; qed"), ); @@ -175,30 +189,27 @@ impl Externalities for BasicExternalities where H::Out: Ord { } } - Layout::::trie_root(self.top.clone()) + Layout::::trie_root(self.top.clone()) } fn child_storage_root(&mut self, storage_key: ChildStorageKey) -> Vec { if let Some(child) = self.children.get(storage_key.as_ref()) { let delta = child.clone().into_iter().map(|(k, v)| (k, Some(v))); - InMemory::::default().child_storage_root(storage_key.as_ref(), delta).0 + InMemory::::default().child_storage_root(storage_key.as_ref(), delta).0 } else { - default_child_trie_root::>(storage_key.as_ref()) + default_child_trie_root::>(storage_key.as_ref()) } } - fn storage_changes_root(&mut self, _parent: H::Out) -> Result, ()> { + fn storage_changes_root(&mut self, _parent: H256) -> Result, ()> { Ok(None) } +} - fn offchain(&mut self) -> Option<&mut dyn offchain::Externalities> { - warn!("Call to non-existent offchain externalities set."); - None - } - - fn keystore(&self) -> Option { - warn!("Call to non-existent keystore."); +impl externalities::ExtensionStore for BasicExternalities { + fn extension_by_type_id(&mut self, _: TypeId) -> Option<&mut dyn Any> { + warn!("Extensions are not supported by `BasicExternalities`."); None } } @@ -206,14 +217,13 @@ impl Externalities for BasicExternalities where H::Out: Ord { #[cfg(test)] mod tests { use super::*; - use primitives::{Blake2Hasher, H256, map}; + use primitives::{H256, map}; use primitives::storage::well_known_keys::CODE; use hex_literal::hex; #[test] fn commit_should_work() { let mut ext = BasicExternalities::default(); - let ext = &mut ext as &mut dyn Externalities; ext.set_storage(b"doe".to_vec(), b"reindeer".to_vec()); ext.set_storage(b"dog".to_vec(), b"puppy".to_vec()); ext.set_storage(b"dogglesworth".to_vec(), b"cat".to_vec()); @@ -225,7 +235,6 @@ mod tests { #[test] fn set_and_retrieve_code() { let mut ext = BasicExternalities::default(); - let ext = &mut ext as &mut dyn Externalities; let code = vec![1, 2, 3]; ext.set_storage(CODE.to_vec(), code.clone()); @@ -246,8 +255,6 @@ mod tests { ] ); - let ext = &mut ext as &mut dyn Externalities; - let child = || ChildStorageKey::from_vec(child_storage.clone()).unwrap(); assert_eq!(ext.child_storage(child(), b"doe"), Some(b"reindeer".to_vec())); diff --git a/core/state-machine/src/ext.rs b/core/state-machine/src/ext.rs index c4a2bd7f63..3433aee92c 100644 --- a/core/state-machine/src/ext.rs +++ b/core/state-machine/src/ext.rs @@ -16,22 +16,24 @@ //! Concrete externalities implementation. -use std::{error, fmt, cmp::Ord}; -use log::{warn, trace}; use crate::{ backend::Backend, OverlayedChanges, changes_trie::{ Storage as ChangesTrieStorage, CacheAction as ChangesTrieCacheAction, build_changes_trie, }, }; + use hash_db::Hasher; use primitives::{ - offchain, storage::well_known_keys::is_child_storage_key, - traits::{BareCryptoStorePtr, Externalities}, child_storage_key::ChildStorageKey, - hexdisplay::HexDisplay, + storage::{ChildStorageKey, well_known_keys::is_child_storage_key}, + traits::Externalities, hexdisplay::HexDisplay, hash::H256, }; -use trie::{MemoryDB, default_child_trie_root}; -use trie::trie_types::Layout; +use trie::{trie_types::Layout, MemoryDB, default_child_trie_root}; +use externalities::Extensions; + +use std::{error, fmt, any::{Any, TypeId}}; + +use log::{warn, trace}; const EXT_NOT_ALLOWED_TO_FAIL: &str = "Externalities not allowed to fail within runtime"; @@ -65,11 +67,7 @@ impl error::Error for Error { } /// Wraps a read-only backend, call executor, and current overlayed changes. -pub struct Ext<'a, H, N, B, T, O> -where - H: Hasher, - B: 'a + Backend, -{ +pub struct Ext<'a, H, N, B, T> where H: Hasher, B: 'a + Backend { /// The overlayed changes to write to. overlay: &'a mut OverlayedChanges, /// The storage backend to read from. @@ -86,25 +84,19 @@ where /// `storage_changes_root` is called matters + we need to remember additional /// data at this moment (block number). changes_trie_transaction: Option<(MemoryDB, H::Out, ChangesTrieCacheAction)>, - /// Additional externalities for offchain workers. - /// - /// If None, some methods from the trait might not be supported. - offchain_externalities: Option<&'a mut O>, - /// The keystore that manages the keys of the node. - keystore: Option, /// Pseudo-unique id used for tracing. pub id: u16, /// Dummy usage of N arg. - _phantom: ::std::marker::PhantomData, + _phantom: std::marker::PhantomData, + /// Extensions registered with this instance. + extensions: Option<&'a mut Extensions>, } -impl<'a, H, N, B, T, O> Ext<'a, H, N, B, T, O> +impl<'a, H, N, B, T> Ext<'a, H, N, B, T> where - H: Hasher, + H: Hasher, B: 'a + Backend, T: 'a + ChangesTrieStorage, - O: 'a + offchain::Externalities, - H::Out: Ord + 'static, N: crate::changes_trie::BlockNumber, { /// Create a new `Ext` from overlayed changes and read-only backend @@ -112,8 +104,7 @@ where overlay: &'a mut OverlayedChanges, backend: &'a B, changes_trie_storage: Option<&'a T>, - offchain_externalities: Option<&'a mut O>, - keystore: Option, + extensions: Option<&'a mut Extensions>, ) -> Self { Ext { overlay, @@ -121,21 +112,25 @@ where storage_transaction: None, changes_trie_storage, changes_trie_transaction: None, - offchain_externalities, - keystore, id: rand::random(), _phantom: Default::default(), + extensions, } } /// Get the transaction necessary to update the backend. - pub fn transaction(mut self) -> ((B::Transaction, H::Out), Option>) { + pub fn transaction(&mut self) -> ( + (B::Transaction, H256), + Option>, + ) { let _ = self.storage_root(); let (storage_transaction, changes_trie_transaction) = ( self.storage_transaction + .take() .expect("storage_transaction always set after calling storage root; qed"), self.changes_trie_transaction + .take() .map(|(tx, _, cache)| (tx, cache)), ); @@ -151,16 +146,14 @@ where fn mark_dirty(&mut self) { self.storage_transaction = None; } - } #[cfg(test)] -impl<'a, H, N, B, T, O> Ext<'a, H, N, B, T, O> +impl<'a, H, N, B, T> Ext<'a, H, N, B, T> where - H: Hasher, + H: Hasher, B: 'a + Backend, T: 'a + ChangesTrieStorage, - O: 'a + offchain::Externalities, N: crate::changes_trie::BlockNumber, { pub fn storage_pairs(&self) -> Vec<(Vec, Vec)> { @@ -177,13 +170,12 @@ where } } -impl<'a, B, T, H, N, O> Externalities for Ext<'a, H, N, B, T, O> -where H: Hasher, +impl<'a, H, B, T, N> Externalities for Ext<'a, H, N, B, T> +where + H: Hasher, B: 'a + Backend, T: 'a + ChangesTrieStorage, - H::Out: Ord + 'static, N: crate::changes_trie::BlockNumber, - O: 'a + offchain::Externalities, { fn storage(&self, key: &[u8]) -> Option> { let _guard = panic_handler::AbortGuard::force_abort(); @@ -197,10 +189,14 @@ where H: Hasher, result } - fn storage_hash(&self, key: &[u8]) -> Option { + fn storage_hash(&self, key: &[u8]) -> Option { let _guard = panic_handler::AbortGuard::force_abort(); - let result = self.overlay.storage(key).map(|x| x.map(|x| H::hash(x))).unwrap_or_else(|| - self.backend.storage_hash(key).expect(EXT_NOT_ALLOWED_TO_FAIL)); + let result = self.overlay + .storage(key) + .map(|x| x.map(|x| H::hash(x))) + .unwrap_or_else(|| + self.backend.storage_hash(key).expect(EXT_NOT_ALLOWED_TO_FAIL) + ); trace!(target: "state-trace", "{:04x}: Hash {}={:?}", self.id, HexDisplay::from(&key), @@ -220,7 +216,7 @@ where H: Hasher, result } - fn original_storage_hash(&self, key: &[u8]) -> Option { + fn original_storage_hash(&self, key: &[u8]) -> Option { let _guard = panic_handler::AbortGuard::force_abort(); let result = self.backend.storage_hash(key).expect(EXT_NOT_ALLOWED_TO_FAIL); trace!(target: "state-trace", "{:04x}: GetOriginalHash {}={:?}", @@ -233,33 +229,48 @@ where H: Hasher, fn child_storage(&self, storage_key: ChildStorageKey, key: &[u8]) -> Option> { let _guard = panic_handler::AbortGuard::force_abort(); - let result = self.overlay.child_storage(storage_key.as_ref(), key).map(|x| x.map(|x| x.to_vec())).unwrap_or_else(|| - self.backend.child_storage(storage_key.as_ref(), key).expect(EXT_NOT_ALLOWED_TO_FAIL)); + let result = self.overlay + .child_storage(storage_key.as_ref(), key) + .map(|x| x.map(|x| x.to_vec())) + .unwrap_or_else(|| + self.backend.child_storage(storage_key.as_ref(), key).expect(EXT_NOT_ALLOWED_TO_FAIL) + ); + trace!(target: "state-trace", "{:04x}: GetChild({}) {}={:?}", self.id, HexDisplay::from(&storage_key.as_ref()), HexDisplay::from(&key), result.as_ref().map(HexDisplay::from) ); + result } - fn child_storage_hash(&self, storage_key: ChildStorageKey, key: &[u8]) -> Option { + fn child_storage_hash(&self, storage_key: ChildStorageKey, key: &[u8]) -> Option { let _guard = panic_handler::AbortGuard::force_abort(); - let result = self.overlay.child_storage(storage_key.as_ref(), key).map(|x| x.map(|x| H::hash(x))).unwrap_or_else(|| - self.backend.storage_hash(key).expect(EXT_NOT_ALLOWED_TO_FAIL)); + let result = self.overlay + .child_storage(storage_key.as_ref(), key) + .map(|x| x.map(|x| H::hash(x))) + .unwrap_or_else(|| + self.backend.storage_hash(key).expect(EXT_NOT_ALLOWED_TO_FAIL) + ); + trace!(target: "state-trace", "{:04x}: ChildHash({}) {}={:?}", self.id, HexDisplay::from(&storage_key.as_ref()), HexDisplay::from(&key), result, ); + result } fn original_child_storage(&self, storage_key: ChildStorageKey, key: &[u8]) -> Option> { let _guard = panic_handler::AbortGuard::force_abort(); - let result = self.backend.child_storage(storage_key.as_ref(), key).expect(EXT_NOT_ALLOWED_TO_FAIL); + let result = self.backend + .child_storage(storage_key.as_ref(), key) + .expect(EXT_NOT_ALLOWED_TO_FAIL); + trace!(target: "state-trace", "{:04x}: ChildOriginal({}) {}={:?}", self.id, HexDisplay::from(&storage_key.as_ref()), @@ -269,9 +280,12 @@ where H: Hasher, result } - fn original_child_storage_hash(&self, storage_key: ChildStorageKey, key: &[u8]) -> Option { + fn original_child_storage_hash(&self, storage_key: ChildStorageKey, key: &[u8]) -> Option { let _guard = panic_handler::AbortGuard::force_abort(); - let result = self.backend.child_storage_hash(storage_key.as_ref(), key).expect(EXT_NOT_ALLOWED_TO_FAIL); + let result = self.backend + .child_storage_hash(storage_key.as_ref(), key) + .expect(EXT_NOT_ALLOWED_TO_FAIL); + trace!(target: "state-trace", "{}: ChildHashOriginal({}) {}={:?}", self.id, HexDisplay::from(&storage_key.as_ref()), @@ -287,6 +301,7 @@ where H: Hasher, Some(x) => x.is_some(), _ => self.backend.exists_storage(key).expect(EXT_NOT_ALLOWED_TO_FAIL), }; + trace!(target: "state-trace", "{:04x}: Exists {}={:?}", self.id, HexDisplay::from(&key), @@ -301,8 +316,11 @@ where H: Hasher, let result = match self.overlay.child_storage(storage_key.as_ref(), key) { Some(x) => x.is_some(), - _ => self.backend.exists_child_storage(storage_key.as_ref(), key).expect(EXT_NOT_ALLOWED_TO_FAIL), + _ => self.backend + .exists_child_storage(storage_key.as_ref(), key) + .expect(EXT_NOT_ALLOWED_TO_FAIL), }; + trace!(target: "state-trace", "{:04x}: ChildExists({}) {}={:?}", self.id, HexDisplay::from(&storage_key.as_ref()), @@ -328,7 +346,12 @@ where H: Hasher, self.overlay.set_storage(key, value); } - fn place_child_storage(&mut self, storage_key: ChildStorageKey, key: Vec, value: Option>) { + fn place_child_storage( + &mut self, + storage_key: ChildStorageKey, + key: Vec, + value: Option>, + ) { trace!(target: "state-trace", "{:04x}: PutChild({}) {}={:?}", self.id, HexDisplay::from(&storage_key.as_ref()), @@ -392,7 +415,7 @@ where H: Hasher, 42 } - fn storage_root(&mut self) -> H::Out { + fn storage_root(&mut self) -> H256 { let _guard = panic_handler::AbortGuard::force_abort(); if let Some((_, ref root)) = self.storage_transaction { trace!(target: "state-trace", "{:04x}: Root (cached) {}", @@ -465,7 +488,7 @@ where H: Hasher, } } - fn storage_changes_root(&mut self, parent_hash: H::Out) -> Result, ()> { + fn storage_changes_root(&mut self, parent_hash: H256) -> Result, ()> { let _guard = panic_handler::AbortGuard::force_abort(); self.changes_trie_transaction = build_changes_trie::<_, T, H, N>( self.backend, @@ -481,32 +504,36 @@ where H: Hasher, ); result } +} - fn offchain(&mut self) -> Option<&mut dyn offchain::Externalities> { - self.offchain_externalities.as_mut().map(|x| &mut **x as _) - } - - fn keystore(&self) -> Option { - self.keystore.clone() +impl<'a, H, B, T, N> externalities::ExtensionStore for Ext<'a, H, N, B, T> +where + H: Hasher, + B: 'a + Backend, + T: 'a + ChangesTrieStorage, + N: crate::changes_trie::BlockNumber, +{ + fn extension_by_type_id(&mut self, type_id: TypeId) -> Option<&mut dyn Any> { + self.extensions.as_mut().and_then(|exts| exts.get_mut(type_id)) } - } #[cfg(test)] mod tests { + use super::*; use hex_literal::hex; use codec::Encode; - use primitives::{Blake2Hasher}; - use primitives::storage::well_known_keys::EXTRINSIC_INDEX; - use crate::backend::InMemory; - use crate::changes_trie::{Configuration as ChangesTrieConfiguration, - InMemoryStorage as InMemoryChangesTrieStorage}; - use crate::overlayed_changes::OverlayedValue; - use super::*; + use primitives::{Blake2Hasher, storage::well_known_keys::EXTRINSIC_INDEX}; + use crate::{ + changes_trie::{ + Configuration as ChangesTrieConfiguration, + InMemoryStorage as InMemoryChangesTrieStorage, + }, backend::InMemory, overlayed_changes::OverlayedValue, + }; type TestBackend = InMemory; type TestChangesTrieStorage = InMemoryChangesTrieStorage; - type TestExt<'a> = Ext<'a, Blake2Hasher, u64, TestBackend, TestChangesTrieStorage, crate::NeverOffchainExt>; + type TestExt<'a> = Ext<'a, Blake2Hasher, u64, TestBackend, TestChangesTrieStorage>; fn prepare_overlay_with_changes() -> OverlayedChanges { OverlayedChanges { @@ -532,7 +559,7 @@ mod tests { fn storage_changes_root_is_none_when_storage_is_not_provided() { let mut overlay = prepare_overlay_with_changes(); let backend = TestBackend::default(); - let mut ext = TestExt::new(&mut overlay, &backend, None, None, None); + let mut ext = TestExt::new(&mut overlay, &backend, None, None); assert_eq!(ext.storage_changes_root(Default::default()).unwrap(), None); } @@ -542,7 +569,7 @@ mod tests { overlay.changes_trie_config = None; let storage = TestChangesTrieStorage::with_blocks(vec![(100, Default::default())]); let backend = TestBackend::default(); - let mut ext = TestExt::new(&mut overlay, &backend, Some(&storage), None, None); + let mut ext = TestExt::new(&mut overlay, &backend, Some(&storage), None); assert_eq!(ext.storage_changes_root(Default::default()).unwrap(), None); } @@ -551,7 +578,7 @@ mod tests { let mut overlay = prepare_overlay_with_changes(); let storage = TestChangesTrieStorage::with_blocks(vec![(99, Default::default())]); let backend = TestBackend::default(); - let mut ext = TestExt::new(&mut overlay, &backend, Some(&storage), None, None); + let mut ext = TestExt::new(&mut overlay, &backend, Some(&storage), None); assert_eq!( ext.storage_changes_root(Default::default()).unwrap(), Some(hex!("bb0c2ef6e1d36d5490f9766cfcc7dfe2a6ca804504c3bb206053890d6dd02376").into()), @@ -564,7 +591,7 @@ mod tests { overlay.prospective.top.get_mut(&vec![1]).unwrap().value = None; let storage = TestChangesTrieStorage::with_blocks(vec![(99, Default::default())]); let backend = TestBackend::default(); - let mut ext = TestExt::new(&mut overlay, &backend, Some(&storage), None, None); + let mut ext = TestExt::new(&mut overlay, &backend, Some(&storage), None); assert_eq!( ext.storage_changes_root(Default::default()).unwrap(), Some(hex!("96f5aae4690e7302737b6f9b7f8567d5bbb9eac1c315f80101235a92d9ec27f4").into()), diff --git a/core/state-machine/src/lib.rs b/core/state-machine/src/lib.rs index 5220b4b31d..c3092367f0 100644 --- a/core/state-machine/src/lib.rs +++ b/core/state-machine/src/lib.rs @@ -18,18 +18,16 @@ #![warn(missing_docs)] -use std::{ - fmt, result, collections::HashMap, - marker::PhantomData, panic::UnwindSafe, -}; +use std::{fmt, result, collections::HashMap, panic::UnwindSafe, marker::PhantomData}; use log::{warn, trace}; use hash_db::Hasher; use codec::{Decode, Encode}; use primitives::{ - storage::well_known_keys, NativeOrEncoded, NeverNativeValue, offchain::{self, NeverOffchainExt}, - traits::{BareCryptoStorePtr, CodeExecutor}, - hexdisplay::HexDisplay, + storage::well_known_keys, NativeOrEncoded, NeverNativeValue, offchain::OffchainExt, + traits::{KeystoreExt, CodeExecutor}, hexdisplay::HexDisplay, hash::H256, }; +use overlayed_changes::OverlayedChangeSet; +use externalities::Extensions; pub mod backend; mod changes_trie; @@ -42,9 +40,7 @@ mod proving_backend; mod trie_backend; mod trie_backend_essence; -use overlayed_changes::OverlayedChangeSet; -pub use trie::{TrieMut, DBValue, MemoryDB}; -pub use trie::trie_types::{Layout, TrieDBMut}; +pub use trie::{trie_types::{Layout, TrieDBMut}, TrieMut, DBValue, MemoryDB}; pub use testing::TestExternalities; pub use basic::BasicExternalities; pub use ext::Ext; @@ -167,48 +163,54 @@ fn always_untrusted_wasm() -> ExecutionManager { - backend: B, - changes_trie_storage: Option<&'a T>, - offchain_ext: Option<&'a mut O>, - overlay: &'a mut OverlayedChanges, +pub struct StateMachine<'a, B, H, N, T, Exec> where H: Hasher, B: Backend { + backend: &'a B, exec: &'a Exec, method: &'a str, call_data: &'a [u8], - keystore: Option, - _hasher: PhantomData<(H, N)>, + overlay: &'a mut OverlayedChanges, + extensions: Extensions, + changes_trie_storage: Option<&'a T>, + _marker: PhantomData<(H, N)>, } -impl<'a, B, H, N, T, O, Exec> StateMachine<'a, B, H, N, T, O, Exec> where - H: Hasher, - Exec: CodeExecutor, +impl<'a, B, H, N, T, Exec> StateMachine<'a, B, H, N, T, Exec> where + H: Hasher, + Exec: CodeExecutor, B: Backend, T: ChangesTrieStorage, - O: offchain::Externalities, - H::Out: Ord + 'static, N: crate::changes_trie::BlockNumber, { /// Creates new substrate state machine. pub fn new( - backend: B, + backend: &'a B, changes_trie_storage: Option<&'a T>, - offchain_ext: Option<&'a mut O>, + offchain_ext: Option, overlay: &'a mut OverlayedChanges, exec: &'a Exec, method: &'a str, call_data: &'a [u8], - keystore: Option, + keystore: Option, ) -> Self { + let mut extensions = Extensions::new(); + + if let Some(keystore) = keystore { + extensions.register(keystore); + } + + if let Some(offchain) = offchain_ext { + extensions.register(offchain); + } + Self { backend, - changes_trie_storage, - offchain_ext, - overlay, exec, method, call_data, - keystore, - _hasher: PhantomData, + extensions, + overlay, + changes_trie_storage, + _marker: PhantomData, } } @@ -220,10 +222,10 @@ impl<'a, B, H, N, T, O, Exec> StateMachine<'a, B, H, N, T, O, Exec> where /// /// Note: changes to code will be in place if this call is made again. For running partial /// blocks (e.g. a transaction at a time), ensure a different method is used. - pub fn execute( - &mut self, - strategy: ExecutionStrategy, - ) -> Result<(Vec, (B::Transaction, H::Out), Option>), Box> { + pub fn execute(&mut self, strategy: ExecutionStrategy) -> Result< + (Vec, (B::Transaction, H::Out), Option>), + Box, + > { // We are not giving a native call and thus we are sure that the result can never be a native // value. self.execute_using_consensus_failure_handler::<_, NeverNativeValue, fn() -> _>( @@ -252,38 +254,44 @@ impl<'a, B, H, N, T, O, Exec> StateMachine<'a, B, H, N, T, O, Exec> where R: Decode + Encode + PartialEq, NC: FnOnce() -> result::Result + UnwindSafe, { - let mut externalities = ext::Ext::new( + let mut ext = Ext::new( self.overlay, - &self.backend, - self.changes_trie_storage, - self.offchain_ext.as_mut().map(|x| &mut **x), - self.keystore.clone(), + self.backend, + self.changes_trie_storage.clone(), + Some(&mut self.extensions), ); - let id = externalities.id; - trace!(target: "state-trace", "{:04x}: Call {} at {:?}. Input={:?}", + + let id = ext.id; + trace!( + target: "state-trace", "{:04x}: Call {} at {:?}. Input={:?}", id, self.method, self.backend, HexDisplay::from(&self.call_data), ); + let (result, was_native) = self.exec.call( - &mut externalities, + &mut ext, self.method, self.call_data, use_native, native_call, ); + let (storage_delta, changes_delta) = if compute_tx { - let (storage_delta, changes_delta) = externalities.transaction(); + let (storage_delta, changes_delta) = ext.transaction(); (Some(storage_delta), changes_delta) } else { (None, None) }; - trace!(target: "state-trace", "{:04x}: Return. Native={:?}, Result={:?}", + + trace!( + target: "state-trace", "{:04x}: Return. Native={:?}, Result={:?}", id, was_native, result, ); + (result, was_native, storage_delta, changes_delta) } @@ -293,12 +301,16 @@ impl<'a, B, H, N, T, O, Exec> StateMachine<'a, B, H, N, T, O, Exec> where mut native_call: Option, orig_prospective: OverlayedChangeSet, on_consensus_failure: Handler, - ) -> (CallResult, Option<(B::Transaction, H::Out)>, Option>) where + ) -> ( + CallResult, + Option<(B::Transaction, H::Out)>, + Option>, + ) where R: Decode + Encode + PartialEq, NC: FnOnce() -> result::Result + UnwindSafe, Handler: FnOnce( CallResult, - CallResult + CallResult, ) -> CallResult { let (result, was_native, storage_delta, changes_delta) = self.execute_aux( @@ -317,7 +329,8 @@ impl<'a, B, H, N, T, O, Exec> StateMachine<'a, B, H, N, T, O, Exec> where if (result.is_ok() && wasm_result.is_ok() && result.as_ref().ok() == wasm_result.as_ref().ok()) - || result.is_err() && wasm_result.is_err() { + || result.is_err() && wasm_result.is_err() + { (result, storage_delta, changes_delta) } else { (on_consensus_failure(wasm_result, result), wasm_storage_delta, wasm_changes_delta) @@ -332,7 +345,11 @@ impl<'a, B, H, N, T, O, Exec> StateMachine<'a, B, H, N, T, O, Exec> where compute_tx: bool, mut native_call: Option, orig_prospective: OverlayedChangeSet, - ) -> (CallResult, Option<(B::Transaction, H::Out)>, Option>) where + ) -> ( + CallResult, + Option<(B::Transaction, H::Out)>, + Option>, + ) where R: Decode + Encode + PartialEq, NC: FnOnce() -> result::Result + UnwindSafe, { @@ -431,7 +448,7 @@ impl<'a, B, H, N, T, O, Exec> StateMachine<'a, B, H, N, T, O, Exec> where }; if result.is_ok() { - init_overlay(self.overlay, true, &self.backend)?; + init_overlay(self.overlay, true, self.backend)?; } result.map_err(|e| Box::new(e) as _) @@ -445,13 +462,12 @@ pub fn prove_execution( exec: &Exec, method: &str, call_data: &[u8], - keystore: Option, + keystore: Option, ) -> Result<(Vec, Vec>), Box> where B: Backend, - H: Hasher, - Exec: CodeExecutor, - H::Out: Ord + 'static, + H: Hasher, + Exec: CodeExecutor, { let trie_backend = backend.as_trie_backend() .ok_or_else(|| Box::new(ExecutionError::UnableToGenerateProof) as Box)?; @@ -473,17 +489,16 @@ pub fn prove_execution_on_trie_backend( exec: &Exec, method: &str, call_data: &[u8], - keystore: Option, + keystore: Option, ) -> Result<(Vec, Vec>), Box> where S: trie_backend_essence::TrieBackendStorage, - H: Hasher, - Exec: CodeExecutor, - H::Out: Ord + 'static, + H: Hasher, + Exec: CodeExecutor, { let proving_backend = proving_backend::ProvingBackend::new(trie_backend); - let mut sm = StateMachine::<_, H, _, InMemoryChangesTrieStorage, _, Exec>::new( - proving_backend, None, NeverOffchainExt::new(), overlay, exec, method, call_data, keystore, + let mut sm = StateMachine::<_, H, _, InMemoryChangesTrieStorage, Exec>::new( + &proving_backend, None, None, overlay, exec, method, call_data, keystore, ); let (result, _, _) = sm.execute_using_consensus_failure_handler::<_, NeverNativeValue, fn() -> _>( @@ -503,11 +518,11 @@ pub fn execution_proof_check( exec: &Exec, method: &str, call_data: &[u8], - keystore: Option, + keystore: Option, ) -> Result, Box> where - H: Hasher, - Exec: CodeExecutor, + H: Hasher, + Exec: CodeExecutor, H::Out: Ord + 'static, { let trie_backend = create_proof_check_backend::(root.into(), proof)?; @@ -521,15 +536,14 @@ pub fn execution_proof_check_on_trie_backend( exec: &Exec, method: &str, call_data: &[u8], - keystore: Option, + keystore: Option, ) -> Result, Box> where - H: Hasher, - Exec: CodeExecutor, - H::Out: Ord + 'static, + H: Hasher, + Exec: CodeExecutor, { - let mut sm = StateMachine::<_, H, _, InMemoryChangesTrieStorage, _, Exec>::new( - trie_backend, None, NeverOffchainExt::new(), overlay, exec, method, call_data, keystore, + let mut sm = StateMachine::<_, H, _, InMemoryChangesTrieStorage, Exec>::new( + trie_backend, None, None, overlay, exec, method, call_data, keystore, ); sm.execute_using_consensus_failure_handler::<_, NeverNativeValue, fn() -> _>( @@ -546,7 +560,7 @@ pub fn prove_read( ) -> Result>, Box> where B: Backend, - H: Hasher, + H: Hasher, H::Out: Ord, I: IntoIterator, I::Item: AsRef<[u8]>, @@ -741,7 +755,7 @@ mod tests { InMemoryStorage as InMemoryChangesTrieStorage, Configuration as ChangesTrieConfig, }; - use primitives::{Blake2Hasher, map, traits::Externalities, child_storage_key::ChildStorageKey}; + use primitives::{Blake2Hasher, map, traits::Externalities, storage::ChildStorageKey}; struct DummyCodeExecutor { change_changes_trie_config: bool, @@ -750,10 +764,14 @@ mod tests { fallback_succeeds: bool, } - impl CodeExecutor for DummyCodeExecutor { + impl CodeExecutor for DummyCodeExecutor { type Error = u8; - fn call, R: Encode + Decode + PartialEq, NC: FnOnce() -> result::Result>( + fn call< + E: Externalities, + R: Encode + Decode + PartialEq, + NC: FnOnce() -> result::Result, + >( &self, ext: &mut E, _method: &str, @@ -800,9 +818,9 @@ mod tests { let changes_trie_storage = InMemoryChangesTrieStorage::::new(); let mut state_machine = StateMachine::new( - backend, + &backend, Some(&changes_trie_storage), - NeverOffchainExt::new(), + None, &mut overlayed_changes, &DummyCodeExecutor { change_changes_trie_config: false, @@ -829,9 +847,9 @@ mod tests { let changes_trie_storage = InMemoryChangesTrieStorage::::new(); let mut state_machine = StateMachine::new( - backend, + &backend, Some(&changes_trie_storage), - NeverOffchainExt::new(), + None, &mut overlayed_changes, &DummyCodeExecutor { change_changes_trie_config: false, @@ -855,9 +873,9 @@ mod tests { let changes_trie_storage = InMemoryChangesTrieStorage::::new(); let mut state_machine = StateMachine::new( - backend, + &backend, Some(&changes_trie_storage), - NeverOffchainExt::new(), + None, &mut overlayed_changes, &DummyCodeExecutor { change_changes_trie_config: false, @@ -948,7 +966,6 @@ mod tests { &mut overlay, backend, Some(&changes_trie_storage), - NeverOffchainExt::new(), None, ); ext.clear_prefix(b"ab"); @@ -979,7 +996,6 @@ mod tests { &mut overlay, backend, Some(&changes_trie_storage), - NeverOffchainExt::new(), None, ); @@ -1067,9 +1083,9 @@ mod tests { let changes_trie_storage = InMemoryChangesTrieStorage::::new(); let mut state_machine = StateMachine::new( - backend, + &backend, Some(&changes_trie_storage), - NeverOffchainExt::new(), + None, &mut overlayed_changes, &DummyCodeExecutor { change_changes_trie_config: true, @@ -1092,9 +1108,9 @@ mod tests { let changes_trie_storage = InMemoryChangesTrieStorage::::new(); let mut state_machine = StateMachine::new( - backend, + &backend, Some(&changes_trie_storage), - NeverOffchainExt::new(), + None, &mut overlayed_changes, &DummyCodeExecutor { change_changes_trie_config: true, diff --git a/core/state-machine/src/overlayed_changes.rs b/core/state-machine/src/overlayed_changes.rs index a4952ddf73..53a66dc49e 100644 --- a/core/state-machine/src/overlayed_changes.rs +++ b/core/state-machine/src/overlayed_changes.rs @@ -420,7 +420,6 @@ mod tests { &mut overlay, &backend, Some(&changes_trie_storage), - crate::NeverOffchainExt::new(), None, ); const ROOT: [u8; 32] = hex!("39245109cef3758c2eed2ccba8d9b370a917850af3824bc8348d505df2c298fa"); @@ -432,9 +431,12 @@ mod tests { fn changes_trie_configuration_is_saved() { let mut overlay = OverlayedChanges::default(); assert!(overlay.changes_trie_config.is_none()); - assert_eq!(overlay.set_changes_trie_config(ChangesTrieConfig { - digest_interval: 4, digest_levels: 1, - }), true); + assert_eq!( + overlay.set_changes_trie_config( + ChangesTrieConfig { digest_interval: 4, digest_levels: 1, }, + ), + true, + ); assert!(overlay.changes_trie_config.is_some()); } diff --git a/core/state-machine/src/proving_backend.rs b/core/state-machine/src/proving_backend.rs index 3908f62eaa..c6c4ef1ec8 100644 --- a/core/state-machine/src/proving_backend.rs +++ b/core/state-machine/src/proving_backend.rs @@ -250,7 +250,7 @@ mod tests { use crate::backend::{InMemory}; use crate::trie_backend::tests::test_trie; use super::*; - use primitives::{Blake2Hasher, child_storage_key::ChildStorageKey}; + use primitives::{Blake2Hasher, storage::ChildStorageKey}; fn test_proving<'a>( trie_backend: &'a TrieBackend,Blake2Hasher>, diff --git a/core/state-machine/src/testing.rs b/core/state-machine/src/testing.rs index 160f7d2a47..ea63eac021 100644 --- a/core/state-machine/src/testing.rs +++ b/core/state-machine/src/testing.rs @@ -16,7 +16,7 @@ //! Test implementation for Externalities. -use std::collections::{HashMap}; +use std::{collections::HashMap, any::{Any, TypeId}}; use hash_db::Hasher; use crate::{ backend::{InMemory, Backend}, OverlayedChanges, @@ -26,25 +26,28 @@ use crate::{ }, }; use primitives::{ - storage::well_known_keys::{CHANGES_TRIE_CONFIG, CODE, HEAP_PAGES, is_child_storage_key}, - traits::{BareCryptoStorePtr, Externalities}, offchain, child_storage_key::ChildStorageKey, + storage::{ + ChildStorageKey, + well_known_keys::{CHANGES_TRIE_CONFIG, CODE, HEAP_PAGES, is_child_storage_key} + }, + traits::Externalities, hash::H256, Blake2Hasher, }; use codec::Encode; +use externalities::{Extensions, Extension}; const EXT_NOT_ALLOWED_TO_FAIL: &str = "Externalities not allowed to fail within runtime"; type StorageTuple = (HashMap, Vec>, HashMap, HashMap, Vec>>); /// Simple HashMap-based Externalities impl. -pub struct TestExternalities { +pub struct TestExternalities=Blake2Hasher, N: ChangesTrieBlockNumber=u64> { overlay: OverlayedChanges, backend: InMemory, changes_trie_storage: ChangesTrieInMemoryStorage, - offchain: Option>, - keystore: Option, + extensions: Extensions, } -impl TestExternalities { +impl, N: ChangesTrieBlockNumber> TestExternalities { /// Create a new instance of `TestExternalities` with storage. pub fn new(storage: StorageTuple) -> Self { Self::new_with_code(&[], storage) @@ -75,8 +78,7 @@ impl TestExternalities { overlay, changes_trie_storage: ChangesTrieInMemoryStorage::new(), backend: backend.into(), - offchain: None, - keystore: None, + extensions: Default::default(), } } @@ -85,14 +87,9 @@ impl TestExternalities { self.backend = self.backend.update(vec![(None, k, Some(v))]); } - /// Set offchain externaltiies. - pub fn set_offchain_externalities(&mut self, offchain: impl offchain::Externalities + 'static) { - self.offchain = Some(Box::new(offchain)); - } - - /// Set keystore. - pub fn set_keystore(&mut self, keystore: BareCryptoStorePtr) { - self.keystore = Some(keystore); + /// Registers the given extension for this instance. + pub fn register_extension(&mut self, ext: E) { + self.extensions.register(ext); } /// Get mutable reference to changes trie storage. @@ -118,13 +115,13 @@ impl TestExternalities { } } -impl std::fmt::Debug for TestExternalities { +impl, N: ChangesTrieBlockNumber> std::fmt::Debug for TestExternalities { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { write!(f, "overlay: {:?}\nbackend: {:?}", self.overlay, self.backend.pairs()) } } -impl PartialEq for TestExternalities { +impl, N: ChangesTrieBlockNumber> PartialEq for TestExternalities { /// This doesn't test if they are in the same state, only if they contains the /// same data at this state fn eq(&self, other: &TestExternalities) -> bool { @@ -132,30 +129,37 @@ impl PartialEq for TestExternalities } } -impl Default for TestExternalities { +impl, N: ChangesTrieBlockNumber> Default for TestExternalities { fn default() -> Self { Self::new(Default::default()) } } -impl From for TestExternalities { +impl, N: ChangesTrieBlockNumber> From for TestExternalities { fn from(storage: StorageTuple) -> Self { Self::new(storage) } } -impl Externalities for TestExternalities where - H: Hasher, +impl Externalities for TestExternalities where + H: Hasher, N: ChangesTrieBlockNumber, - H::Out: Ord + 'static, { fn storage(&self, key: &[u8]) -> Option> { self.overlay.storage(key).map(|x| x.map(|x| x.to_vec())).unwrap_or_else(|| self.backend.storage(key).expect(EXT_NOT_ALLOWED_TO_FAIL)) } + fn storage_hash(&self, key: &[u8]) -> Option { + self.storage(key).map(|v| H::hash(&v)) + } + fn original_storage(&self, key: &[u8]) -> Option> { self.backend.storage(key).expect(EXT_NOT_ALLOWED_TO_FAIL) } + fn original_storage_hash(&self, key: &[u8]) -> Option { + self.storage_hash(key) + } + fn child_storage(&self, storage_key: ChildStorageKey, key: &[u8]) -> Option> { self.overlay .child_storage(storage_key.as_ref(), key) @@ -166,6 +170,10 @@ impl Externalities for TestExternalities where ) } + fn child_storage_hash(&self, storage_key: ChildStorageKey, key: &[u8]) -> Option { + self.child_storage(storage_key, key).map(|v| H::hash(&v)) + } + fn original_child_storage(&self, storage_key: ChildStorageKey, key: &[u8]) -> Option> { self.backend .child_storage(storage_key.as_ref(), key) @@ -173,6 +181,10 @@ impl Externalities for TestExternalities where .expect(EXT_NOT_ALLOWED_TO_FAIL) } + fn original_child_storage_hash(&self, storage_key: ChildStorageKey, key: &[u8]) -> Option { + self.child_storage_hash(storage_key, key) + } + fn place_storage(&mut self, key: Vec, maybe_value: Option>) { if is_child_storage_key(&key) { panic!("Refuse to directly set child storage key"); @@ -185,7 +197,7 @@ impl Externalities for TestExternalities where &mut self, storage_key: ChildStorageKey, key: Vec, - value: Option> + value: Option>, ) { self.overlay.set_child_storage(storage_key.into_owned(), key, value); } @@ -215,7 +227,6 @@ impl Externalities for TestExternalities where } fn clear_child_prefix(&mut self, storage_key: ChildStorageKey, prefix: &[u8]) { - self.overlay.clear_child_prefix(storage_key.as_ref(), prefix); let backend = &self.backend; @@ -227,8 +238,7 @@ impl Externalities for TestExternalities where fn chain_id(&self) -> u64 { 42 } - fn storage_root(&mut self) -> H::Out { - + fn storage_root(&mut self) -> H256 { let child_storage_keys = self.overlay.prospective.children.keys() .chain(self.overlay.committed.children.keys()); @@ -246,7 +256,6 @@ impl Externalities for TestExternalities where let delta = self.overlay.committed.top.iter().map(|(k, v)| (k.clone(), v.value.clone())) .chain(self.overlay.prospective.top.iter().map(|(k, v)| (k.clone(), v.value.clone()))); self.backend.full_storage_root(delta, child_delta_iter).0 - } fn child_storage_root(&mut self, storage_key: ChildStorageKey) -> Vec { @@ -270,7 +279,7 @@ impl Externalities for TestExternalities where root } - fn storage_changes_root(&mut self, parent: H::Out) -> Result, ()> { + fn storage_changes_root(&mut self, parent: H256) -> Result, ()> { Ok(build_changes_trie::<_, _, H, N>( &self.backend, Some(&self.changes_trie_storage), @@ -278,15 +287,14 @@ impl Externalities for TestExternalities where parent, )?.map(|(_, root, _)| root)) } +} - fn offchain(&mut self) -> Option<&mut dyn offchain::Externalities> { - self.offchain - .as_mut() - .map(|x| &mut **x as _) - } - - fn keystore(&self) -> Option { - self.keystore.clone() +impl externalities::ExtensionStore for TestExternalities where + H: Hasher, + N: ChangesTrieBlockNumber, +{ + fn extension_by_type_id(&mut self, type_id: TypeId) -> Option<&mut dyn Any> { + self.extensions.get_mut(type_id) } } diff --git a/core/test-runtime/src/system.rs b/core/test-runtime/src/system.rs index 12a656cf31..81bca2fad3 100644 --- a/core/test-runtime/src/system.rs +++ b/core/test-runtime/src/system.rs @@ -319,10 +319,11 @@ fn info_expect_equal_hash(given: &Hash, expected: &Hash) { mod tests { use super::*; - use runtime_io::{with_externalities, TestExternalities}; + use runtime_io::TestExternalities; use substrate_test_runtime_client::{AccountKeyring, Sr25519Keyring}; + use sr_primitives::set_and_run_with_externalities; use crate::{Header, Transfer, WASM_BINARY}; - use primitives::{Blake2Hasher, NeverNativeValue, map, traits::CodeExecutor}; + use primitives::{NeverNativeValue, map, traits::CodeExecutor}; use substrate_executor::{NativeExecutor, WasmExecutionMethod, native_executor_instance}; // Declare an instance of the native executor dispatch for the test runtime. @@ -336,7 +337,7 @@ mod tests { NativeExecutor::new(WasmExecutionMethod::Interpreted, None) } - fn new_test_ext() -> TestExternalities { + fn new_test_ext() -> TestExternalities { let authorities = vec![ Sr25519Keyring::Alice.to_raw_public(), Sr25519Keyring::Bob.to_raw_public(), @@ -357,7 +358,7 @@ mod tests { ) } - fn block_import_works(block_executor: F) where F: Fn(Block, &mut TestExternalities) { + fn block_import_works(block_executor: F) where F: Fn(Block, &mut TestExternalities) { let h = Header { parent_hash: [69u8; 32].into(), number: 1, @@ -370,7 +371,7 @@ mod tests { extrinsics: vec![], }; - with_externalities(&mut new_test_ext(), || polish_block(&mut b)); + set_and_run_with_externalities(&mut new_test_ext(), || polish_block(&mut b)); block_executor(b, &mut new_test_ext()); } @@ -378,7 +379,7 @@ mod tests { #[test] fn block_import_works_native() { block_import_works(|b, ext| { - with_externalities(ext, || { + set_and_run_with_externalities(ext, || { execute_block(b); }); }); @@ -397,7 +398,9 @@ mod tests { }) } - fn block_import_with_transaction_works(block_executor: F) where F: Fn(Block, &mut TestExternalities) { + fn block_import_with_transaction_works(block_executor: F) + where F: Fn(Block, &mut TestExternalities) + { let mut b1 = Block { header: Header { parent_hash: [69u8; 32].into(), @@ -417,7 +420,7 @@ mod tests { }; let mut dummy_ext = new_test_ext(); - with_externalities(&mut dummy_ext, || polish_block(&mut b1)); + set_and_run_with_externalities(&mut dummy_ext, || polish_block(&mut b1)); let mut b2 = Block { header: Header { @@ -443,26 +446,26 @@ mod tests { ], }; - with_externalities(&mut dummy_ext, || polish_block(&mut b2)); + set_and_run_with_externalities(&mut dummy_ext, || polish_block(&mut b2)); drop(dummy_ext); let mut t = new_test_ext(); - with_externalities(&mut t, || { + set_and_run_with_externalities(&mut t, || { assert_eq!(balance_of(AccountKeyring::Alice.into()), 111); assert_eq!(balance_of(AccountKeyring::Bob.into()), 0); }); block_executor(b1, &mut t); - with_externalities(&mut t, || { + set_and_run_with_externalities(&mut t, || { assert_eq!(balance_of(AccountKeyring::Alice.into()), 42); assert_eq!(balance_of(AccountKeyring::Bob.into()), 69); }); block_executor(b2, &mut t); - with_externalities(&mut t, || { + set_and_run_with_externalities(&mut t, || { assert_eq!(balance_of(AccountKeyring::Alice.into()), 0); assert_eq!(balance_of(AccountKeyring::Bob.into()), 42); assert_eq!(balance_of(AccountKeyring::Charlie.into()), 69); @@ -472,7 +475,7 @@ mod tests { #[test] fn block_import_with_transaction_works_native() { block_import_with_transaction_works(|b, ext| { - with_externalities(ext, || { + set_and_run_with_externalities(ext, || { execute_block(b); }); }); diff --git a/node-template/runtime/src/template.rs b/node-template/runtime/src/template.rs index 5a4225e63a..0266890dd8 100644 --- a/node-template/runtime/src/template.rs +++ b/node-template/runtime/src/template.rs @@ -69,12 +69,12 @@ decl_event!( mod tests { use super::*; - use runtime_io::with_externalities; - use primitives::{H256, Blake2Hasher}; + use primitives::H256; use support::{impl_outer_origin, assert_ok, parameter_types}; - use sr_primitives::{traits::{BlakeTwo256, IdentityLookup}, testing::Header}; - use sr_primitives::weights::Weight; - use sr_primitives::Perbill; + use sr_primitives::{ + set_and_run_with_externalities, traits::{BlakeTwo256, IdentityLookup}, testing::Header, + weights::Weight, Perbill, + }; impl_outer_origin! { pub enum Origin for Test {} @@ -116,13 +116,13 @@ mod tests { // This function basically just builds a genesis storage key/value store according to // our desired mockup. - fn new_test_ext() -> runtime_io::TestExternalities { + fn new_test_ext() -> runtime_io::TestExternalities { system::GenesisConfig::default().build_storage::().unwrap().into() } #[test] fn it_works_for_default_value() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { // Just a dummy test for the dummy funtion `do_something` // calling the `do_something` function with a value 42 assert_ok!(TemplateModule::do_something(Origin::signed(1), 42)); diff --git a/node/executor/src/lib.rs b/node/executor/src/lib.rs index 38656b7bd4..40c1e08f9b 100644 --- a/node/executor/src/lib.rs +++ b/node/executor/src/lib.rs @@ -36,7 +36,6 @@ native_executor_instance!( mod tests { use super::Executor; use {balances, contracts, indices, system, timestamp}; - use runtime_io; use codec::{Encode, Decode, Joiner}; use runtime_support::{ Hashable, StorageValue, StorageMap, traits::Currency, @@ -121,7 +120,7 @@ mod tests { NativeExecutor::new(WasmExecutionMethod::Interpreted, None) } - fn set_heap_pages>(ext: &mut E, heap_pages: u64) { + fn set_heap_pages(ext: &mut E, heap_pages: u64) { ext.place_storage(well_known_keys::HEAP_PAGES.to_vec(), Some(heap_pages.encode())); } @@ -227,7 +226,7 @@ mod tests { ).0; assert!(r.is_ok()); - runtime_io::with_externalities(&mut t, || { + sr_primitives::set_and_run_with_externalities(&mut t, || { assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - transfer_fee(&xt())); assert_eq!(Balances::total_balance(&bob()), 69 * DOLLARS); }); @@ -263,7 +262,7 @@ mod tests { ).0; assert!(r.is_ok()); - runtime_io::with_externalities(&mut t, || { + sr_primitives::set_and_run_with_externalities(&mut t, || { assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - transfer_fee(&xt())); assert_eq!(Balances::total_balance(&bob()), 69 * DOLLARS); }); @@ -434,7 +433,7 @@ mod tests { None, ).0.unwrap(); - runtime_io::with_externalities(&mut t, || { + sr_primitives::set_and_run_with_externalities(&mut t, || { assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - transfer_fee(&xt())); assert_eq!(Balances::total_balance(&bob()), 169 * DOLLARS); let events = vec![ @@ -469,7 +468,7 @@ mod tests { None, ).0.unwrap(); - runtime_io::with_externalities(&mut t, || { + sr_primitives::set_and_run_with_externalities(&mut t, || { // NOTE: fees differ slightly in tests that execute more than one block due to the // weight update. Hence, using `assert_eq_error_rate`. assert_eq_error_rate!( @@ -541,7 +540,7 @@ mod tests { None, ).0.unwrap(); - runtime_io::with_externalities(&mut t, || { + sr_primitives::set_and_run_with_externalities(&mut t, || { assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - transfer_fee(&xt())); assert_eq!(Balances::total_balance(&bob()), 169 * DOLLARS); }); @@ -554,7 +553,7 @@ mod tests { None, ).0.unwrap(); - runtime_io::with_externalities(&mut t, || { + sr_primitives::set_and_run_with_externalities(&mut t, || { assert_eq_error_rate!( Balances::total_balance(&alice()), 32 * DOLLARS - 2 * transfer_fee(&xt()), @@ -716,7 +715,7 @@ mod tests { None, ).0.unwrap(); - runtime_io::with_externalities(&mut t, || { + sr_primitives::set_and_run_with_externalities(&mut t, || { // Verify that the contract constructor worked well and code of TRANSFER contract is actually deployed. assert_eq!( &contracts::ContractInfoOf::::get(addr) @@ -837,7 +836,7 @@ mod tests { .expect("Extrinsic could be applied") .expect("Extrinsic did not fail"); - runtime_io::with_externalities(&mut t, || { + sr_primitives::set_and_run_with_externalities(&mut t, || { assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - 1 * transfer_fee(&xt())); assert_eq!(Balances::total_balance(&bob()), 69 * DOLLARS); }); @@ -896,7 +895,7 @@ mod tests { let mut prev_multiplier = WeightMultiplier::default(); - runtime_io::with_externalities(&mut t, || { + sr_primitives::set_and_run_with_externalities(&mut t, || { assert_eq!(System::next_weight_multiplier(), prev_multiplier); }); @@ -948,7 +947,7 @@ mod tests { ).0.unwrap(); // weight multiplier is increased for next block. - runtime_io::with_externalities(&mut t, || { + sr_primitives::set_and_run_with_externalities(&mut t, || { let fm = System::next_weight_multiplier(); println!("After a big block: {:?} -> {:?}", prev_multiplier, fm); assert!(fm > prev_multiplier); @@ -965,7 +964,7 @@ mod tests { ).0.unwrap(); // weight multiplier is increased for next block. - runtime_io::with_externalities(&mut t, || { + sr_primitives::set_and_run_with_externalities(&mut t, || { let fm = System::next_weight_multiplier(); println!("After a small block: {:?} -> {:?}", prev_multiplier, fm); assert!(fm < prev_multiplier); @@ -1019,7 +1018,7 @@ mod tests { ).0; assert!(r.is_ok()); - runtime_io::with_externalities(&mut t, || { + sr_primitives::set_and_run_with_externalities(&mut t, || { assert_eq!(Balances::total_balance(&bob()), (10 + 69) * DOLLARS); // Components deducted from alice's balances: // - Weight fee diff --git a/srml/assets/src/lib.rs b/srml/assets/src/lib.rs index 2a4245176a..e7f258483f 100644 --- a/srml/assets/src/lib.rs +++ b/srml/assets/src/lib.rs @@ -240,12 +240,14 @@ impl Module { mod tests { use super::*; - use runtime_io::with_externalities; use support::{impl_outer_origin, assert_ok, assert_noop, parameter_types}; - use primitives::{H256, Blake2Hasher}; + use primitives::H256; // The testing primitives are very useful for avoiding having to work with signatures // or public keys. `u64` is used as the `AccountId` and no `Signature`s are required. - use sr_primitives::{Perbill, traits::{BlakeTwo256, IdentityLookup}, testing::Header}; + use sr_primitives::{ + Perbill, traits::{BlakeTwo256, IdentityLookup}, testing::Header, + set_and_run_with_externalities, + }; impl_outer_origin! { pub enum Origin for Test {} @@ -289,13 +291,13 @@ mod tests { // This function basically just builds a genesis storage key/value store according to // our desired mockup. - fn new_test_ext() -> runtime_io::TestExternalities { + fn new_test_ext() -> runtime_io::TestExternalities { system::GenesisConfig::default().build_storage::().unwrap().into() } #[test] fn issuing_asset_units_to_issuer_should_work() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { assert_ok!(Assets::issue(Origin::signed(1), 100)); assert_eq!(Assets::balance(0, 1), 100); }); @@ -303,7 +305,7 @@ mod tests { #[test] fn querying_total_supply_should_work() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { assert_ok!(Assets::issue(Origin::signed(1), 100)); assert_eq!(Assets::balance(0, 1), 100); assert_ok!(Assets::transfer(Origin::signed(1), 0, 2, 50)); @@ -320,7 +322,7 @@ mod tests { #[test] fn transferring_amount_above_available_balance_should_work() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { assert_ok!(Assets::issue(Origin::signed(1), 100)); assert_eq!(Assets::balance(0, 1), 100); assert_ok!(Assets::transfer(Origin::signed(1), 0, 2, 50)); @@ -331,7 +333,7 @@ mod tests { #[test] fn transferring_amount_less_than_available_balance_should_not_work() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { assert_ok!(Assets::issue(Origin::signed(1), 100)); assert_eq!(Assets::balance(0, 1), 100); assert_ok!(Assets::transfer(Origin::signed(1), 0, 2, 50)); @@ -345,7 +347,7 @@ mod tests { #[test] fn transferring_less_than_one_unit_should_not_work() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { assert_ok!(Assets::issue(Origin::signed(1), 100)); assert_eq!(Assets::balance(0, 1), 100); assert_noop!(Assets::transfer(Origin::signed(1), 0, 2, 0), "transfer amount should be non-zero"); @@ -354,7 +356,7 @@ mod tests { #[test] fn transferring_more_units_than_total_supply_should_not_work() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { assert_ok!(Assets::issue(Origin::signed(1), 100)); assert_eq!(Assets::balance(0, 1), 100); assert_noop!(Assets::transfer(Origin::signed(1), 0, 2, 101), "origin account balance must be greater than or equal to the transfer amount"); @@ -363,7 +365,7 @@ mod tests { #[test] fn destroying_asset_balance_with_positive_balance_should_work() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { assert_ok!(Assets::issue(Origin::signed(1), 100)); assert_eq!(Assets::balance(0, 1), 100); assert_ok!(Assets::destroy(Origin::signed(1), 0)); @@ -372,7 +374,7 @@ mod tests { #[test] fn destroying_asset_balance_with_zero_balance_should_not_work() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { assert_ok!(Assets::issue(Origin::signed(1), 100)); assert_eq!(Assets::balance(0, 2), 0); assert_noop!(Assets::destroy(Origin::signed(2), 0), "origin balance should be non-zero"); diff --git a/srml/aura/src/mock.rs b/srml/aura/src/mock.rs index 6dc8953e88..7ebfd2a533 100644 --- a/srml/aura/src/mock.rs +++ b/srml/aura/src/mock.rs @@ -26,7 +26,7 @@ use sr_primitives::{ }; use support::{impl_outer_origin, parameter_types}; use runtime_io; -use primitives::{H256, Blake2Hasher}; +use primitives::H256; impl_outer_origin!{ pub enum Origin for Test {} @@ -73,7 +73,7 @@ impl Trait for Test { type AuthorityId = AuthorityId; } -pub fn new_test_ext(authorities: Vec) -> runtime_io::TestExternalities { +pub fn new_test_ext(authorities: Vec) -> runtime_io::TestExternalities { let mut t = system::GenesisConfig::default().build_storage::().unwrap(); GenesisConfig::{ authorities: authorities.into_iter().map(|a| UintAuthorityId(a).to_public_key()).collect(), diff --git a/srml/aura/src/tests.rs b/srml/aura/src/tests.rs index a90eddf18f..0537fc8b64 100644 --- a/srml/aura/src/tests.rs +++ b/srml/aura/src/tests.rs @@ -18,12 +18,12 @@ #![cfg(test)] -use runtime_io::with_externalities; +use sr_primitives::set_and_run_with_externalities; use crate::mock::{Aura, new_test_ext}; #[test] fn initial_values() { - with_externalities(&mut new_test_ext(vec![0, 1, 2, 3]), || { + set_and_run_with_externalities(&mut new_test_ext(vec![0, 1, 2, 3]), || { assert_eq!(Aura::last(), 0u64); assert_eq!(Aura::authorities().len(), 4); }); diff --git a/srml/authority-discovery/src/lib.rs b/srml/authority-discovery/src/lib.rs index 2ec9e98835..38d587ba05 100644 --- a/srml/authority-discovery/src/lib.rs +++ b/srml/authority-discovery/src/lib.rs @@ -135,12 +135,12 @@ impl session::OneSessionHandler for Module { mod tests { use super::*; use app_crypto::Pair; - use primitives::testing::KeyStore; - use primitives::{crypto::key_types, sr25519, traits::BareCryptoStore, H256}; - use runtime_io::{with_externalities, TestExternalities}; - use sr_primitives::testing::{Header, UintAuthorityId}; - use sr_primitives::traits::{ConvertInto, IdentityLookup, OpaqueKeys}; - use sr_primitives::Perbill; + use primitives::{testing::KeyStore, crypto::key_types, sr25519, H256, traits::KeystoreExt}; + use runtime_io::TestExternalities; + use sr_primitives::{ + testing::{Header, UintAuthorityId}, traits::{ConvertInto, IdentityLookup, OpaqueKeys}, + Perbill, set_and_run_with_externalities, + }; use support::{impl_outer_origin, parameter_types}; type AuthorityDiscovery = Module; @@ -261,9 +261,9 @@ mod tests { // Create externalities. let mut externalities = TestExternalities::new(t); - externalities.set_keystore(key_store); + externalities.register_extension(KeystoreExt(key_store)); - with_externalities(&mut externalities, || { + set_and_run_with_externalities(&mut externalities, || { assert_eq!( authority_id, AuthorityDiscovery::authority_id().expect("Retrieving public key.") @@ -298,9 +298,9 @@ mod tests { // Create externalities. let mut externalities = TestExternalities::new(t); - externalities.set_keystore(key_store); + externalities.register_extension(KeystoreExt(key_store)); - with_externalities(&mut externalities, || { + set_and_run_with_externalities(&mut externalities, || { assert_eq!(None, AuthorityDiscovery::authority_id()); }); } @@ -335,9 +335,9 @@ mod tests { // Create externalities. let mut externalities = TestExternalities::new(t); - externalities.set_keystore(key_store); + externalities.register_extension(KeystoreExt(key_store)); - with_externalities(&mut externalities, || { + set_and_run_with_externalities(&mut externalities, || { let payload = String::from("test payload").into_bytes(); let (sig, authority_id) = AuthorityDiscovery::sign(&payload).expect("signature"); @@ -350,7 +350,7 @@ mod tests { assert!(!AuthorityDiscovery::verify( &String::from("other payload").into_bytes(), sig, - authority_id + authority_id, )) }); } diff --git a/srml/authorship/src/lib.rs b/srml/authorship/src/lib.rs index 490774c734..0033e53221 100644 --- a/srml/authorship/src/lib.rs +++ b/srml/authorship/src/lib.rs @@ -412,12 +412,11 @@ impl ProvideInherent for Module { #[cfg(test)] mod tests { use super::*; - use runtime_io::with_externalities; - use primitives::{H256, Blake2Hasher}; - use sr_primitives::traits::{BlakeTwo256, IdentityLookup}; - use sr_primitives::testing::Header; - use sr_primitives::generic::DigestItem; - use sr_primitives::Perbill; + use primitives::H256; + use sr_primitives::{ + set_and_run_with_externalities, traits::{BlakeTwo256, IdentityLookup}, testing::Header, + generic::DigestItem, Perbill, + }; use support::{parameter_types, impl_outer_origin, ConsensusEngineId}; impl_outer_origin!{ @@ -535,7 +534,7 @@ mod tests { ) } - fn new_test_ext() -> runtime_io::TestExternalities { + fn new_test_ext() -> runtime_io::TestExternalities { let t = system::GenesisConfig::default().build_storage::().unwrap(); t.into() } @@ -543,7 +542,7 @@ mod tests { #[test] fn prune_old_uncles_works() { use UncleEntryItem::*; - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { let hash = Default::default(); let author = Default::default(); let uncles = vec![ @@ -562,7 +561,7 @@ mod tests { #[test] fn rejects_bad_uncles() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { let author_a = 69; struct CanonChain { @@ -675,7 +674,7 @@ mod tests { #[test] fn sets_author_lazily() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { let author = 42; let mut header = seal_header( create_header(1, Default::default(), [1; 32].into()), diff --git a/srml/babe/src/mock.rs b/srml/babe/src/mock.rs index acc08c7a3b..582299f11c 100644 --- a/srml/babe/src/mock.rs +++ b/srml/babe/src/mock.rs @@ -101,7 +101,7 @@ impl Trait for Test { type EpochChangeTrigger = crate::ExternalTrigger; } -pub fn new_test_ext(authorities: Vec) -> runtime_io::TestExternalities { +pub fn new_test_ext(authorities: Vec) -> runtime_io::TestExternalities { let mut t = system::GenesisConfig::default().build_storage::().unwrap(); GenesisConfig { authorities: authorities.into_iter().map(|a| (UintAuthorityId(a).to_public_key(), 1)).collect(), diff --git a/srml/babe/src/tests.rs b/srml/babe/src/tests.rs index ef449485b7..0a165b3854 100644 --- a/srml/babe/src/tests.rs +++ b/srml/babe/src/tests.rs @@ -17,9 +17,10 @@ //! Consensus extension module tests for BABE consensus. use super::*; -use runtime_io::with_externalities; use mock::{new_test_ext, Babe, Test}; -use sr_primitives::{traits::OnFinalize, testing::{Digest, DigestItem}}; +use sr_primitives::{ + set_and_run_with_externalities, traits::OnFinalize, testing::{Digest, DigestItem}, +}; use session::ShouldEndSession; const EMPTY_RANDOMNESS: [u8; 32] = [ @@ -53,14 +54,14 @@ fn empty_randomness_is_correct() { #[test] fn initial_values() { - with_externalities(&mut new_test_ext(vec![0, 1, 2, 3]), || { + set_and_run_with_externalities(&mut new_test_ext(vec![0, 1, 2, 3]), || { assert_eq!(Babe::authorities().len(), 4) }) } #[test] fn check_module() { - with_externalities(&mut new_test_ext(vec![0, 1, 2, 3]), || { + set_and_run_with_externalities(&mut new_test_ext(vec![0, 1, 2, 3]), || { assert!(!Babe::should_end_session(0), "Genesis does not change sessions"); assert!(!Babe::should_end_session(200000), "BABE does not include the block number in epoch calculations"); @@ -71,7 +72,7 @@ type System = system::Module; #[test] fn first_block_epoch_zero_start() { - with_externalities(&mut new_test_ext(vec![0, 1, 2, 3]), || { + set_and_run_with_externalities(&mut new_test_ext(vec![0, 1, 2, 3]), || { let genesis_slot = 100; let first_vrf = [1; 32]; let pre_digest = make_pre_digest( @@ -119,7 +120,7 @@ fn first_block_epoch_zero_start() { #[test] fn authority_index() { - with_externalities(&mut new_test_ext(vec![0, 1, 2, 3]), || { + set_and_run_with_externalities(&mut new_test_ext(vec![0, 1, 2, 3]), || { assert_eq!( Babe::find_author((&[(BABE_ENGINE_ID, &[][..])]).into_iter().cloned()), None, "Trivially invalid authorities are ignored") diff --git a/srml/balances/src/mock.rs b/srml/balances/src/mock.rs index 12a49fc90d..a909795178 100644 --- a/srml/balances/src/mock.rs +++ b/srml/balances/src/mock.rs @@ -20,7 +20,7 @@ use sr_primitives::{Perbill, traits::{Convert, IdentityLookup}, testing::Header, weights::{DispatchInfo, Weight}}; -use primitives::{H256, Blake2Hasher}; +use primitives::H256; use runtime_io; use support::{impl_outer_origin, parameter_types}; use support::traits::Get; @@ -179,7 +179,7 @@ impl ExtBuilder { TRANSACTION_BYTE_FEE.with(|v| *v.borrow_mut() = self.transaction_byte_fee); WEIGHT_TO_FEE.with(|v| *v.borrow_mut() = self.weight_to_fee); } - pub fn build(self) -> runtime_io::TestExternalities { + pub fn build(self) -> runtime_io::TestExternalities { self.set_associated_consts(); let mut t = system::GenesisConfig::default().build_storage::().unwrap(); GenesisConfig:: { diff --git a/srml/balances/src/tests.rs b/srml/balances/src/tests.rs index 8e9f6acdd8..b4745c2253 100644 --- a/srml/balances/src/tests.rs +++ b/srml/balances/src/tests.rs @@ -20,7 +20,7 @@ use super::*; use mock::{Balances, ExtBuilder, Runtime, System, info_from_weight, CALL}; -use runtime_io::with_externalities; +use sr_primitives::set_and_run_with_externalities; use support::{ assert_noop, assert_ok, assert_err, traits::{LockableCurrency, LockIdentifier, WithdrawReason, WithdrawReasons, @@ -34,7 +34,7 @@ const ID_3: LockIdentifier = *b"3 "; #[test] fn basic_locking_should_work() { - with_externalities(&mut ExtBuilder::default().existential_deposit(1).monied(true).build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().existential_deposit(1).monied(true).build(), || { assert_eq!(Balances::free_balance(&1), 10); Balances::set_lock(ID_1, &1, 9, u64::max_value(), WithdrawReasons::all()); assert_noop!( @@ -46,7 +46,7 @@ fn basic_locking_should_work() { #[test] fn partial_locking_should_work() { - with_externalities(&mut ExtBuilder::default().existential_deposit(1).monied(true).build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().existential_deposit(1).monied(true).build(), || { Balances::set_lock(ID_1, &1, 5, u64::max_value(), WithdrawReasons::all()); assert_ok!(>::transfer(&1, &2, 1)); }); @@ -54,7 +54,7 @@ fn partial_locking_should_work() { #[test] fn lock_removal_should_work() { - with_externalities(&mut ExtBuilder::default().existential_deposit(1).monied(true).build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().existential_deposit(1).monied(true).build(), || { Balances::set_lock(ID_1, &1, u64::max_value(), u64::max_value(), WithdrawReasons::all()); Balances::remove_lock(ID_1, &1); assert_ok!(>::transfer(&1, &2, 1)); @@ -63,7 +63,7 @@ fn lock_removal_should_work() { #[test] fn lock_replacement_should_work() { - with_externalities(&mut ExtBuilder::default().existential_deposit(1).monied(true).build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().existential_deposit(1).monied(true).build(), || { Balances::set_lock(ID_1, &1, u64::max_value(), u64::max_value(), WithdrawReasons::all()); Balances::set_lock(ID_1, &1, 5, u64::max_value(), WithdrawReasons::all()); assert_ok!(>::transfer(&1, &2, 1)); @@ -72,7 +72,7 @@ fn lock_replacement_should_work() { #[test] fn double_locking_should_work() { - with_externalities(&mut ExtBuilder::default().existential_deposit(1).monied(true).build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().existential_deposit(1).monied(true).build(), || { Balances::set_lock(ID_1, &1, 5, u64::max_value(), WithdrawReasons::all()); Balances::set_lock(ID_2, &1, 5, u64::max_value(), WithdrawReasons::all()); assert_ok!(>::transfer(&1, &2, 1)); @@ -81,7 +81,7 @@ fn double_locking_should_work() { #[test] fn combination_locking_should_work() { - with_externalities(&mut ExtBuilder::default().existential_deposit(1).monied(true).build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().existential_deposit(1).monied(true).build(), || { Balances::set_lock(ID_1, &1, u64::max_value(), 0, WithdrawReasons::none()); Balances::set_lock(ID_2, &1, 0, u64::max_value(), WithdrawReasons::none()); Balances::set_lock(ID_3, &1, 0, 0, WithdrawReasons::all()); @@ -91,7 +91,7 @@ fn combination_locking_should_work() { #[test] fn lock_value_extension_should_work() { - with_externalities(&mut ExtBuilder::default().existential_deposit(1).monied(true).build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().existential_deposit(1).monied(true).build(), || { Balances::set_lock(ID_1, &1, 5, u64::max_value(), WithdrawReasons::all()); assert_noop!( >::transfer(&1, &2, 6), @@ -112,7 +112,7 @@ fn lock_value_extension_should_work() { #[test] fn lock_reasons_should_work() { - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default() .existential_deposit(1) .monied(true).transaction_fees(0, 1, 0) @@ -163,7 +163,7 @@ fn lock_reasons_should_work() { #[test] fn lock_block_number_should_work() { - with_externalities(&mut ExtBuilder::default().existential_deposit(1).monied(true).build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().existential_deposit(1).monied(true).build(), || { Balances::set_lock(ID_1, &1, 10, 2, WithdrawReasons::all()); assert_noop!( >::transfer(&1, &2, 1), @@ -177,7 +177,7 @@ fn lock_block_number_should_work() { #[test] fn lock_block_number_extension_should_work() { - with_externalities(&mut ExtBuilder::default().existential_deposit(1).monied(true).build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().existential_deposit(1).monied(true).build(), || { Balances::set_lock(ID_1, &1, 10, 2, WithdrawReasons::all()); assert_noop!( >::transfer(&1, &2, 6), @@ -199,7 +199,7 @@ fn lock_block_number_extension_should_work() { #[test] fn lock_reasons_extension_should_work() { - with_externalities(&mut ExtBuilder::default().existential_deposit(1).monied(true).build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().existential_deposit(1).monied(true).build(), || { Balances::set_lock(ID_1, &1, 10, 10, WithdrawReason::Transfer.into()); assert_noop!( >::transfer(&1, &2, 6), @@ -220,7 +220,7 @@ fn lock_reasons_extension_should_work() { #[test] fn default_indexing_on_new_accounts_should_not_work2() { - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default() .existential_deposit(10) .creation_fee(50) @@ -242,7 +242,7 @@ fn default_indexing_on_new_accounts_should_not_work2() { #[test] fn reserved_balance_should_prevent_reclaim_count() { - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default() .existential_deposit(256 * 1) .monied(true) @@ -281,7 +281,7 @@ fn reserved_balance_should_prevent_reclaim_count() { #[test] fn reward_should_work() { - with_externalities(&mut ExtBuilder::default().monied(true).build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().monied(true).build(), || { assert_eq!(Balances::total_balance(&1), 10); assert_ok!(Balances::deposit_into_existing(&1, 10).map(drop)); assert_eq!(Balances::total_balance(&1), 20); @@ -291,7 +291,7 @@ fn reward_should_work() { #[test] fn dust_account_removal_should_work() { - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default() .existential_deposit(100) .monied(true) @@ -311,7 +311,7 @@ fn dust_account_removal_should_work() { #[test] fn dust_account_removal_should_work2() { - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default() .existential_deposit(100) .creation_fee(50) @@ -332,7 +332,7 @@ fn dust_account_removal_should_work2() { #[test] fn balance_works() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { let _ = Balances::deposit_creating(&1, 42); assert_eq!(Balances::free_balance(&1), 42); assert_eq!(Balances::reserved_balance(&1), 0); @@ -345,7 +345,7 @@ fn balance_works() { #[test] fn balance_transfer_works() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { let _ = Balances::deposit_creating(&1, 111); assert_ok!(Balances::transfer(Some(1).into(), 2, 69)); assert_eq!(Balances::total_balance(&1), 42); @@ -355,7 +355,7 @@ fn balance_transfer_works() { #[test] fn force_transfer_works() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { let _ = Balances::deposit_creating(&1, 111); assert_noop!( Balances::force_transfer(Some(2).into(), 1, 2, 69), @@ -369,7 +369,7 @@ fn force_transfer_works() { #[test] fn reserving_balance_should_work() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { let _ = Balances::deposit_creating(&1, 111); assert_eq!(Balances::total_balance(&1), 111); @@ -386,7 +386,7 @@ fn reserving_balance_should_work() { #[test] fn balance_transfer_when_reserved_should_not_work() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { let _ = Balances::deposit_creating(&1, 111); assert_ok!(Balances::reserve(&1, 69)); assert_noop!( @@ -398,7 +398,7 @@ fn balance_transfer_when_reserved_should_not_work() { #[test] fn deducting_balance_should_work() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { let _ = Balances::deposit_creating(&1, 111); assert_ok!(Balances::reserve(&1, 69)); assert_eq!(Balances::free_balance(&1), 42); @@ -407,7 +407,7 @@ fn deducting_balance_should_work() { #[test] fn refunding_balance_should_work() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { let _ = Balances::deposit_creating(&1, 42); Balances::set_reserved_balance(&1, 69); Balances::unreserve(&1, 69); @@ -418,7 +418,7 @@ fn refunding_balance_should_work() { #[test] fn slashing_balance_should_work() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { let _ = Balances::deposit_creating(&1, 111); assert_ok!(Balances::reserve(&1, 69)); assert!(Balances::slash(&1, 69).1.is_zero()); @@ -430,7 +430,7 @@ fn slashing_balance_should_work() { #[test] fn slashing_incomplete_balance_should_work() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { let _ = Balances::deposit_creating(&1, 42); assert_ok!(Balances::reserve(&1, 21)); assert_eq!(Balances::slash(&1, 69).1, 27); @@ -442,7 +442,7 @@ fn slashing_incomplete_balance_should_work() { #[test] fn unreserving_balance_should_work() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { let _ = Balances::deposit_creating(&1, 111); assert_ok!(Balances::reserve(&1, 111)); Balances::unreserve(&1, 42); @@ -453,7 +453,7 @@ fn unreserving_balance_should_work() { #[test] fn slashing_reserved_balance_should_work() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { let _ = Balances::deposit_creating(&1, 111); assert_ok!(Balances::reserve(&1, 111)); assert_eq!(Balances::slash_reserved(&1, 42).1, 0); @@ -465,7 +465,7 @@ fn slashing_reserved_balance_should_work() { #[test] fn slashing_incomplete_reserved_balance_should_work() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { let _ = Balances::deposit_creating(&1, 111); assert_ok!(Balances::reserve(&1, 42)); assert_eq!(Balances::slash_reserved(&1, 69).1, 27); @@ -477,7 +477,7 @@ fn slashing_incomplete_reserved_balance_should_work() { #[test] fn transferring_reserved_balance_should_work() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { let _ = Balances::deposit_creating(&1, 110); let _ = Balances::deposit_creating(&2, 1); assert_ok!(Balances::reserve(&1, 110)); @@ -491,7 +491,7 @@ fn transferring_reserved_balance_should_work() { #[test] fn transferring_reserved_balance_to_nonexistent_should_fail() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { let _ = Balances::deposit_creating(&1, 111); assert_ok!(Balances::reserve(&1, 111)); assert_noop!(Balances::repatriate_reserved(&1, &2, 42), "beneficiary account must pre-exist"); @@ -500,7 +500,7 @@ fn transferring_reserved_balance_to_nonexistent_should_fail() { #[test] fn transferring_incomplete_reserved_balance_should_work() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { let _ = Balances::deposit_creating(&1, 110); let _ = Balances::deposit_creating(&2, 1); assert_ok!(Balances::reserve(&1, 41)); @@ -514,7 +514,7 @@ fn transferring_incomplete_reserved_balance_should_work() { #[test] fn transferring_too_high_value_should_not_panic() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { >::insert(1, u64::max_value()); >::insert(2, 1); @@ -530,7 +530,7 @@ fn transferring_too_high_value_should_not_panic() { #[test] fn account_create_on_free_too_low_with_other() { - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default().existential_deposit(100).build(), || { let _ = Balances::deposit_creating(&1, 100); @@ -547,7 +547,7 @@ fn account_create_on_free_too_low_with_other() { #[test] fn account_create_on_free_too_low() { - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default().existential_deposit(100).build(), || { // No-op. @@ -560,7 +560,7 @@ fn account_create_on_free_too_low() { #[test] fn account_removal_on_free_too_low() { - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default().existential_deposit(100).build(), || { assert_eq!(>::get(), 0); @@ -590,7 +590,7 @@ fn account_removal_on_free_too_low() { #[test] fn transfer_overflow_isnt_exploitable() { - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default().creation_fee(50).build(), || { // Craft a value that will overflow if summed with `creation_fee`. @@ -606,7 +606,7 @@ fn transfer_overflow_isnt_exploitable() { #[test] fn check_vesting_status() { - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default() .existential_deposit(256) .monied(true) @@ -669,7 +669,7 @@ fn check_vesting_status() { #[test] fn unvested_balance_should_not_transfer() { - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default() .existential_deposit(10) .monied(true) @@ -691,7 +691,7 @@ fn unvested_balance_should_not_transfer() { #[test] fn vested_balance_should_transfer() { - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default() .existential_deposit(10) .monied(true) @@ -710,7 +710,7 @@ fn vested_balance_should_transfer() { #[test] fn extra_balance_should_transfer() { - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default() .existential_deposit(10) .monied(true) @@ -740,7 +740,7 @@ fn extra_balance_should_transfer() { #[test] fn liquid_funds_should_transfer_with_delayed_vesting() { - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default() .existential_deposit(256) .monied(true) @@ -770,7 +770,7 @@ fn liquid_funds_should_transfer_with_delayed_vesting() { #[test] fn signed_extension_take_fees_work() { - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default() .existential_deposit(10) .transaction_fees(10, 1, 5) @@ -788,7 +788,7 @@ fn signed_extension_take_fees_work() { #[test] fn signed_extension_take_fees_is_bounded() { - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default() .existential_deposit(1000) .transaction_fees(0, 0, 1) @@ -810,7 +810,7 @@ fn signed_extension_take_fees_is_bounded() { #[test] fn burn_must_work() { - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default() .monied(true) .build(), diff --git a/srml/collective/src/lib.rs b/srml/collective/src/lib.rs index 4a157569c0..7ae352266a 100644 --- a/srml/collective/src/lib.rs +++ b/srml/collective/src/lib.rs @@ -382,10 +382,10 @@ mod tests { use support::{Hashable, assert_ok, assert_noop, parameter_types}; use system::{EventRecord, Phase}; use hex_literal::hex; - use runtime_io::with_externalities; - use primitives::{H256, Blake2Hasher}; + use primitives::H256; use sr_primitives::{ - Perbill, traits::{BlakeTwo256, IdentityLookup, Block as BlockT}, testing::Header, BuildStorage + set_and_run_with_externalities, Perbill, + traits::{BlakeTwo256, IdentityLookup, Block as BlockT}, testing::Header, BuildStorage, }; use crate as collective; @@ -439,7 +439,7 @@ mod tests { } ); - fn make_ext() -> runtime_io::TestExternalities { + fn make_ext() -> runtime_io::TestExternalities { GenesisConfig { collective_Instance1: Some(collective::GenesisConfig { members: vec![1, 2, 3], @@ -451,7 +451,7 @@ mod tests { #[test] fn motions_basic_environment_works() { - with_externalities(&mut make_ext(), || { + set_and_run_with_externalities(&mut make_ext(), || { System::set_block_number(1); assert_eq!(Collective::members(), vec![1, 2, 3]); assert_eq!(Collective::proposals(), Vec::::new()); @@ -464,7 +464,7 @@ mod tests { #[test] fn removal_of_old_voters_votes_works() { - with_externalities(&mut make_ext(), || { + set_and_run_with_externalities(&mut make_ext(), || { System::set_block_number(1); let proposal = make_proposal(42); let hash = BlakeTwo256::hash_of(&proposal); @@ -498,7 +498,7 @@ mod tests { #[test] fn removal_of_old_voters_votes_works_with_set_members() { - with_externalities(&mut make_ext(), || { + set_and_run_with_externalities(&mut make_ext(), || { System::set_block_number(1); let proposal = make_proposal(42); let hash = BlakeTwo256::hash_of(&proposal); @@ -532,7 +532,7 @@ mod tests { #[test] fn propose_works() { - with_externalities(&mut make_ext(), || { + set_and_run_with_externalities(&mut make_ext(), || { System::set_block_number(1); let proposal = make_proposal(42); let hash = proposal.blake2_256().into(); @@ -561,7 +561,7 @@ mod tests { #[test] fn motions_ignoring_non_collective_proposals_works() { - with_externalities(&mut make_ext(), || { + set_and_run_with_externalities(&mut make_ext(), || { System::set_block_number(1); let proposal = make_proposal(42); assert_noop!( @@ -573,7 +573,7 @@ mod tests { #[test] fn motions_ignoring_non_collective_votes_works() { - with_externalities(&mut make_ext(), || { + set_and_run_with_externalities(&mut make_ext(), || { System::set_block_number(1); let proposal = make_proposal(42); let hash: H256 = proposal.blake2_256().into(); @@ -584,7 +584,7 @@ mod tests { #[test] fn motions_ignoring_bad_index_collective_vote_works() { - with_externalities(&mut make_ext(), || { + set_and_run_with_externalities(&mut make_ext(), || { System::set_block_number(3); let proposal = make_proposal(42); let hash: H256 = proposal.blake2_256().into(); @@ -595,7 +595,7 @@ mod tests { #[test] fn motions_revoting_works() { - with_externalities(&mut make_ext(), || { + set_and_run_with_externalities(&mut make_ext(), || { System::set_block_number(1); let proposal = make_proposal(42); let hash: H256 = proposal.blake2_256().into(); @@ -640,7 +640,7 @@ mod tests { #[test] fn motions_disapproval_works() { - with_externalities(&mut make_ext(), || { + set_and_run_with_externalities(&mut make_ext(), || { System::set_block_number(1); let proposal = make_proposal(42); let hash: H256 = proposal.blake2_256().into(); @@ -683,7 +683,7 @@ mod tests { #[test] fn motions_approval_works() { - with_externalities(&mut make_ext(), || { + set_and_run_with_externalities(&mut make_ext(), || { System::set_block_number(1); let proposal = make_proposal(42); let hash: H256 = proposal.blake2_256().into(); diff --git a/srml/contracts/src/exec.rs b/srml/contracts/src/exec.rs index e4c5539cec..0cb0ee2679 100644 --- a/srml/contracts/src/exec.rs +++ b/srml/contracts/src/exec.rs @@ -803,16 +803,12 @@ mod tests { BalanceOf, ExecFeeToken, ExecutionContext, Ext, Loader, TransferFeeKind, TransferFeeToken, Vm, ExecResult, RawEvent, DeferredAction, }; - use crate::account_db::AccountDb; - use crate::exec::{ExecReturnValue, ExecError, STATUS_SUCCESS}; - use crate::gas::GasMeter; - use crate::tests::{ExtBuilder, Test}; - use crate::{CodeHash, Config}; - use runtime_io::with_externalities; - use std::cell::RefCell; - use std::rc::Rc; - use std::collections::HashMap; - use std::marker::PhantomData; + use crate::{ + account_db::AccountDb, gas::GasMeter, tests::{ExtBuilder, Test}, + exec::{ExecReturnValue, ExecError, STATUS_SUCCESS}, CodeHash, Config, + }; + use sr_primitives::set_and_run_with_externalities; + use std::{cell::RefCell, rc::Rc, collections::HashMap, marker::PhantomData}; use assert_matches::assert_matches; const ALICE: u64 = 1; @@ -937,7 +933,7 @@ mod tests { exec_success() }); - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { let cfg = Config::preload(); let mut ctx = ExecutionContext::top_level(ALICE, &cfg, &vm, &loader); ctx.overlay.instantiate_contract(&BOB, exec_ch).unwrap(); @@ -957,7 +953,7 @@ mod tests { let dest = BOB; // This test verifies that base fee for call is taken. - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { let vm = MockVm::new(); let loader = MockLoader::empty(); let cfg = Config::preload(); @@ -975,7 +971,7 @@ mod tests { }); // This test verifies that base fee for instantiation is taken. - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { let mut loader = MockLoader::empty(); let code = loader.insert(|_| exec_success()); @@ -1005,7 +1001,7 @@ mod tests { let vm = MockVm::new(); let loader = MockLoader::empty(); - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { let cfg = Config::preload(); let mut ctx = ExecutionContext::top_level(origin, &cfg, &vm, &loader); ctx.overlay.set_balance(&origin, 100); @@ -1037,7 +1033,7 @@ mod tests { |_| Ok(ExecReturnValue { status: 1, data: Vec::new() }) ); - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { let cfg = Config::preload(); let mut ctx = ExecutionContext::top_level(origin, &cfg, &vm, &loader); ctx.overlay.instantiate_contract(&BOB, return_ch).unwrap(); @@ -1065,7 +1061,7 @@ mod tests { // This test sends 50 units of currency to a non-existent account. // This should lead to creation of a new account thus // a fee should be charged. - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default().existential_deposit(15).build(), || { let vm = MockVm::new(); @@ -1094,7 +1090,7 @@ mod tests { // This one is similar to the previous one but transfer to an existing account. // In this test we expect that a regular transfer fee is charged. - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default().existential_deposit(15).build(), || { let vm = MockVm::new(); @@ -1123,7 +1119,7 @@ mod tests { // This test sends 50 units of currency as an endownment to a newly // instantiated contract. - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default().existential_deposit(15).build(), || { let mut loader = MockLoader::empty(); @@ -1164,7 +1160,7 @@ mod tests { let vm = MockVm::new(); let loader = MockLoader::empty(); - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { let cfg = Config::preload(); let mut ctx = ExecutionContext::top_level(origin, &cfg, &vm, &loader); ctx.overlay.set_balance(&origin, 0); @@ -1198,7 +1194,7 @@ mod tests { |_| Ok(ExecReturnValue { status: STATUS_SUCCESS, data: vec![1, 2, 3, 4] }) ); - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { let cfg = Config::preload(); let mut ctx = ExecutionContext::top_level(origin, &cfg, &vm, &loader); ctx.overlay.instantiate_contract(&BOB, return_ch).unwrap(); @@ -1229,7 +1225,7 @@ mod tests { |_| Ok(ExecReturnValue { status: 1, data: vec![1, 2, 3, 4] }) ); - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { let cfg = Config::preload(); let mut ctx = ExecutionContext::top_level(origin, &cfg, &vm, &loader); ctx.overlay.instantiate_contract(&BOB, return_ch).unwrap(); @@ -1257,7 +1253,7 @@ mod tests { }); // This one tests passing the input data into a contract via call. - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { let cfg = Config::preload(); let mut ctx = ExecutionContext::top_level(ALICE, &cfg, &vm, &loader); ctx.overlay.instantiate_contract(&BOB, input_data_ch).unwrap(); @@ -1282,7 +1278,7 @@ mod tests { }); // This one tests passing the input data into a contract via instantiate. - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { let cfg = Config::preload(); let mut ctx = ExecutionContext::top_level(ALICE, &cfg, &vm, &loader); @@ -1326,7 +1322,7 @@ mod tests { exec_success() }); - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { let cfg = Config::preload(); let mut ctx = ExecutionContext::top_level(ALICE, &cfg, &vm, &loader); ctx.overlay.instantiate_contract(&BOB, recurse_ch).unwrap(); @@ -1370,7 +1366,7 @@ mod tests { exec_success() }); - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { let cfg = Config::preload(); let mut ctx = ExecutionContext::top_level(origin, &cfg, &vm, &loader); @@ -1412,7 +1408,7 @@ mod tests { exec_success() }); - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { let cfg = Config::preload(); let mut ctx = ExecutionContext::top_level(ALICE, &cfg, &vm, &loader); ctx.overlay.instantiate_contract(&BOB, bob_ch).unwrap(); @@ -1436,7 +1432,7 @@ mod tests { let mut loader = MockLoader::empty(); let dummy_ch = loader.insert(|_| exec_success()); - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default().existential_deposit(15).build(), || { let cfg = Config::preload(); @@ -1464,7 +1460,7 @@ mod tests { |_| Ok(ExecReturnValue { status: STATUS_SUCCESS, data: vec![80, 65, 83, 83] }) ); - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default().existential_deposit(15).build(), || { let cfg = Config::preload(); @@ -1507,7 +1503,7 @@ mod tests { |_| Ok(ExecReturnValue { status: 1, data: vec![70, 65, 73, 76] }) ); - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default().existential_deposit(15).build(), || { let cfg = Config::preload(); @@ -1555,7 +1551,7 @@ mod tests { } }); - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default().existential_deposit(15).build(), || { let cfg = Config::preload(); @@ -1617,7 +1613,7 @@ mod tests { } }); - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default().existential_deposit(15).build(), || { let cfg = Config::preload(); @@ -1653,7 +1649,7 @@ mod tests { exec_success() }); - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { let cfg = Config::preload(); let mut ctx = ExecutionContext::top_level(ALICE, &cfg, &vm, &loader); diff --git a/srml/contracts/src/tests.rs b/srml/contracts/src/tests.rs index f2ef8a275d..a92d11e4d4 100644 --- a/srml/contracts/src/tests.rs +++ b/srml/contracts/src/tests.rs @@ -19,21 +19,18 @@ #![allow(unused)] -use crate::account_db::{AccountDb, DirectAccountDb, OverlayAccountDb}; use crate::{ BalanceOf, ComputeDispatchFee, ContractAddressFor, ContractInfo, ContractInfoOf, GenesisConfig, Module, RawAliveContractInfo, RawEvent, Trait, TrieId, TrieIdFromParentCounter, Schedule, - TrieIdGenerator, CheckBlockGasLimit, + TrieIdGenerator, CheckBlockGasLimit, account_db::{AccountDb, DirectAccountDb, OverlayAccountDb}, }; use assert_matches::assert_matches; use hex_literal::*; use codec::{Decode, Encode, KeyedVec}; -use runtime_io; -use runtime_io::with_externalities; use sr_primitives::{ Perbill, BuildStorage, transaction_validity::{InvalidTransaction, ValidTransaction}, traits::{BlakeTwo256, Hash, IdentityLookup, SignedExtension}, - weights::{DispatchInfo, DispatchClass}, + weights::{DispatchInfo, DispatchClass}, set_and_run_with_externalities, testing::{Digest, DigestItem, Header, UintAuthorityId, H256}, }; use support::{ @@ -41,7 +38,7 @@ use support::{ storage::child, StorageMap, StorageValue, traits::{Currency, Get}, }; use std::{cell::RefCell, sync::atomic::{AtomicUsize, Ordering}}; -use primitives::{storage::well_known_keys, Blake2Hasher}; +use primitives::storage::well_known_keys; use system::{self, EventRecord, Phase}; mod contract { @@ -275,7 +272,7 @@ impl ExtBuilder { INSTANTIATION_FEE.with(|v| *v.borrow_mut() = self.instantiation_fee); BLOCK_GAS_LIMIT.with(|v| *v.borrow_mut() = self.block_gas_limit); } - pub fn build(self) -> runtime_io::TestExternalities { + pub fn build(self) -> runtime_io::TestExternalities { self.set_associated_consts(); let mut t = system::GenesisConfig::default().build_storage::().unwrap(); balances::GenesisConfig:: { @@ -307,7 +304,7 @@ fn compile_module(wabt_module: &str) // Then we check that the all unused gas is refunded. #[test] fn refunds_unused_gas() { - with_externalities(&mut ExtBuilder::default().gas_price(2).build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().gas_price(2).build(), || { Balances::deposit_creating(&ALICE, 100_000_000); assert_ok!(Contract::call(Origin::signed(ALICE), BOB, 0, 100_000, Vec::new())); @@ -319,7 +316,7 @@ fn refunds_unused_gas() { #[test] fn account_removal_removes_storage() { - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default().existential_deposit(100).build(), || { let trie_id1 = ::TrieIdGenerator::trie_id(&1); @@ -419,7 +416,7 @@ const CODE_RETURN_FROM_START_FN: &str = r#" fn instantiate_and_call_and_deposit_event() { let (wasm, code_hash) = compile_module::(CODE_RETURN_FROM_START_FN).unwrap(); - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default().existential_deposit(100).build(), || { Balances::deposit_creating(&ALICE, 1_000_000); @@ -502,7 +499,7 @@ fn dispatch_call() { let (wasm, code_hash) = compile_module::(CODE_DISPATCH_CALL).unwrap(); - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default().existential_deposit(50).build(), || { Balances::deposit_creating(&ALICE, 1_000_000); @@ -623,7 +620,7 @@ fn dispatch_call_not_dispatched_after_top_level_transaction_failure() { let (wasm, code_hash) = compile_module::(CODE_DISPATCH_CALL_THEN_TRAP).unwrap(); - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default().existential_deposit(50).build(), || { Balances::deposit_creating(&ALICE, 1_000_000); @@ -826,7 +823,7 @@ fn test_set_rent_code_and_hash() { let (wasm, code_hash) = compile_module::(CODE_SET_RENT).unwrap(); - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default().existential_deposit(50).build(), || { Balances::deposit_creating(&ALICE, 1_000_000); @@ -855,7 +852,7 @@ fn storage_size() { let (wasm, code_hash) = compile_module::(CODE_SET_RENT).unwrap(); // Storage size - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default().existential_deposit(50).build(), || { // Create @@ -885,7 +882,7 @@ fn storage_size() { fn deduct_blocks() { let (wasm, code_hash) = compile_module::(CODE_SET_RENT).unwrap(); - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default().existential_deposit(50).build(), || { // Create @@ -982,7 +979,7 @@ fn claim_surcharge_malus() { fn claim_surcharge(blocks: u64, trigger_call: impl Fn() -> bool, removes: bool) { let (wasm, code_hash) = compile_module::(CODE_SET_RENT).unwrap(); - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default().existential_deposit(50).build(), || { // Create @@ -1018,7 +1015,7 @@ fn removals(trigger_call: impl Fn() -> bool) { let (wasm, code_hash) = compile_module::(CODE_SET_RENT).unwrap(); // Balance reached and superior to subsistence threshold - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default().existential_deposit(50).build(), || { // Create @@ -1057,7 +1054,7 @@ fn removals(trigger_call: impl Fn() -> bool) { ); // Allowance exceeded - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default().existential_deposit(50).build(), || { // Create @@ -1095,7 +1092,7 @@ fn removals(trigger_call: impl Fn() -> bool) { ); // Balance reached and inferior to subsistence threshold - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default().existential_deposit(50).build(), || { // Create @@ -1142,7 +1139,7 @@ fn call_removed_contract() { let (wasm, code_hash) = compile_module::(CODE_SET_RENT).unwrap(); // Balance reached and superior to subsistence threshold - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default().existential_deposit(50).build(), || { // Create @@ -1230,7 +1227,7 @@ const CODE_CHECK_DEFAULT_RENT_ALLOWANCE: &str = r#" fn default_rent_allowance_on_instantiate() { let (wasm, code_hash) = compile_module::(CODE_CHECK_DEFAULT_RENT_ALLOWANCE).unwrap(); - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default().existential_deposit(50).build(), || { // Create @@ -1347,7 +1344,7 @@ fn restoration(test_different_storage: bool, test_restore_to_with_dirty_storage: let (restoration_wasm, restoration_code_hash) = compile_module::(CODE_RESTORATION).unwrap(); - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default().existential_deposit(50).build(), || { Balances::deposit_creating(&ALICE, 1_000_000); @@ -1533,7 +1530,7 @@ const CODE_STORAGE_SIZE: &str = r#" fn storage_max_value_limit() { let (wasm, code_hash) = compile_module::(CODE_STORAGE_SIZE).unwrap(); - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default().existential_deposit(50).build(), || { // Create @@ -1900,7 +1897,7 @@ fn deploy_and_call_other_contract() { let (callee_wasm, callee_code_hash) = compile_module::(CODE_RETURN_WITH_DATA).unwrap(); let (caller_wasm, caller_code_hash) = compile_module::(CODE_CALLER_CONTRACT).unwrap(); - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default().existential_deposit(50).build(), || { // Create @@ -2031,7 +2028,7 @@ const CODE_SELF_DESTRUCT: &str = r#" #[test] fn self_destruct_by_draining_balance() { let (wasm, code_hash) = compile_module::(CODE_SELF_DESTRUCT).unwrap(); - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default().existential_deposit(50).build(), || { Balances::deposit_creating(&ALICE, 1_000_000); @@ -2070,7 +2067,7 @@ fn self_destruct_by_draining_balance() { #[test] fn cannot_self_destruct_while_live() { let (wasm, code_hash) = compile_module::(CODE_SELF_DESTRUCT).unwrap(); - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default().existential_deposit(50).build(), || { Balances::deposit_creating(&ALICE, 1_000_000); @@ -2272,7 +2269,7 @@ fn destroy_contract_and_transfer_funds() { let (callee_wasm, callee_code_hash) = compile_module::(CODE_SELF_DESTRUCT).unwrap(); let (caller_wasm, caller_code_hash) = compile_module::(CODE_DESTROY_AND_TRANSFER).unwrap(); - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default().existential_deposit(50).build(), || { // Create @@ -2371,7 +2368,7 @@ const CODE_SELF_DESTRUCTING_CONSTRUCTOR: &str = r#" #[test] fn cannot_self_destruct_in_constructor() { let (wasm, code_hash) = compile_module::(CODE_SELF_DESTRUCTING_CONSTRUCTOR).unwrap(); - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default().existential_deposit(50).build(), || { Balances::deposit_creating(&ALICE, 1_000_000); @@ -2395,7 +2392,7 @@ fn cannot_self_destruct_in_constructor() { #[test] fn check_block_gas_limit_works() { - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default().block_gas_limit(50).build(), || { let info = DispatchInfo { weight: 100, class: DispatchClass::Normal }; diff --git a/srml/council/src/lib.rs b/srml/council/src/lib.rs index aa27bcde21..e65cf9ace1 100644 --- a/srml/council/src/lib.rs +++ b/srml/council/src/lib.rs @@ -38,7 +38,6 @@ impl OnMembersChanged for () { mod tests { // These re-exports are here for a reason, edit with care pub use super::*; - pub use runtime_io::with_externalities; use support::{impl_outer_origin, impl_outer_event, impl_outer_dispatch, parameter_types}; use support::traits::Get; pub use primitives::{H256, Blake2Hasher, u32_trait::{_1, _2, _3, _4}}; diff --git a/srml/democracy/src/lib.rs b/srml/democracy/src/lib.rs index b93f6f893a..477e6818c9 100644 --- a/srml/democracy/src/lib.rs +++ b/srml/democracy/src/lib.rs @@ -971,14 +971,15 @@ impl OnFreeBalanceZero for Module { #[cfg(test)] mod tests { use super::*; - use runtime_io::with_externalities; use support::{ impl_outer_origin, impl_outer_dispatch, assert_noop, assert_ok, parameter_types, traits::Contains }; - use primitives::{H256, Blake2Hasher}; - use sr_primitives::{traits::{BlakeTwo256, IdentityLookup, Bounded}, testing::Header}; - use sr_primitives::Perbill; + use primitives::H256; + use sr_primitives::{ + set_and_run_with_externalities, traits::{BlakeTwo256, IdentityLookup, Bounded}, + testing::Header, Perbill, + }; use balances::BalanceLock; use system::EnsureSignedBy; @@ -1084,7 +1085,7 @@ mod tests { type CooloffPeriod = CooloffPeriod; } - fn new_test_ext() -> runtime_io::TestExternalities { + fn new_test_ext() -> runtime_io::TestExternalities { let mut t = system::GenesisConfig::default().build_storage::().unwrap(); balances::GenesisConfig::{ balances: vec![(1, 10), (2, 20), (3, 30), (4, 40), (5, 50), (6, 60)], @@ -1100,7 +1101,7 @@ mod tests { #[test] fn params_should_work() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { assert_eq!(Democracy::referendum_count(), 0); assert_eq!(Balances::free_balance(&42), 0); assert_eq!(Balances::total_issuance(), 210); @@ -1132,7 +1133,7 @@ mod tests { #[test] fn external_and_public_interleaving_works() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { System::set_block_number(0); assert_ok!(Democracy::external_propose( Origin::signed(2), @@ -1245,7 +1246,7 @@ mod tests { #[test] fn emergency_cancel_should_work() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { System::set_block_number(0); let r = Democracy::inject_referendum( 2, @@ -1274,7 +1275,7 @@ mod tests { #[test] fn veto_external_works() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { System::set_block_number(0); assert_ok!(Democracy::external_propose( Origin::signed(2), @@ -1334,7 +1335,7 @@ mod tests { #[test] fn external_referendum_works() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { System::set_block_number(0); assert_noop!(Democracy::external_propose( Origin::signed(1), @@ -1363,7 +1364,7 @@ mod tests { #[test] fn external_majority_referendum_works() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { System::set_block_number(0); assert_noop!(Democracy::external_propose_majority( Origin::signed(1), @@ -1388,7 +1389,7 @@ mod tests { #[test] fn external_default_referendum_works() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { System::set_block_number(0); assert_noop!(Democracy::external_propose_default( Origin::signed(3), @@ -1413,7 +1414,7 @@ mod tests { #[test] fn fast_track_referendum_works() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { System::set_block_number(0); let h = BlakeTwo256::hash_of(&set_balance_proposal(2)); assert_noop!(Democracy::fast_track(Origin::signed(5), h, 3, 2), "no proposal made"); @@ -1437,7 +1438,7 @@ mod tests { #[test] fn fast_track_referendum_fails_when_no_simple_majority() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { System::set_block_number(0); let h = BlakeTwo256::hash_of(&set_balance_proposal(2)); assert_ok!(Democracy::external_propose( @@ -1453,7 +1454,7 @@ mod tests { #[test] fn locked_for_should_work() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { System::set_block_number(1); assert_ok!(propose_set_balance(1, 2, 2)); assert_ok!(propose_set_balance(1, 4, 4)); @@ -1466,7 +1467,7 @@ mod tests { #[test] fn single_proposal_should_work() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { System::set_block_number(0); assert_ok!(propose_set_balance(1, 2, 1)); assert!(Democracy::referendum_info(0).is_none()); @@ -1513,7 +1514,7 @@ mod tests { #[test] fn cancel_queued_should_work() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { System::set_block_number(0); assert_ok!(propose_set_balance(1, 2, 1)); @@ -1537,7 +1538,7 @@ mod tests { #[test] fn proxy_should_work() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { assert_eq!(Democracy::proxy(10), None); assert_ok!(Democracy::set_proxy(Origin::signed(1), 10)); assert_eq!(Democracy::proxy(10), Some(1)); @@ -1567,7 +1568,7 @@ mod tests { #[test] fn single_proposal_should_work_with_proxy() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { System::set_block_number(0); assert_ok!(propose_set_balance(1, 2, 1)); @@ -1587,7 +1588,7 @@ mod tests { #[test] fn single_proposal_should_work_with_delegation() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { System::set_block_number(0); assert_ok!(propose_set_balance(1, 2, 1)); @@ -1612,7 +1613,7 @@ mod tests { #[test] fn single_proposal_should_work_with_cyclic_delegation() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { System::set_block_number(0); assert_ok!(propose_set_balance(1, 2, 1)); @@ -1639,7 +1640,7 @@ mod tests { #[test] /// If transactor already voted, delegated vote is overwriten. fn single_proposal_should_work_with_vote_and_delegation() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { System::set_block_number(0); assert_ok!(propose_set_balance(1, 2, 1)); @@ -1665,7 +1666,7 @@ mod tests { #[test] fn single_proposal_should_work_with_undelegation() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { System::set_block_number(0); assert_ok!(propose_set_balance(1, 2, 1)); @@ -1694,7 +1695,7 @@ mod tests { #[test] /// If transactor voted, delegated vote is overwriten. fn single_proposal_should_work_with_delegation_and_vote() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { System::set_block_number(0); assert_ok!(propose_set_balance(1, 2, 1)); @@ -1725,7 +1726,7 @@ mod tests { #[test] fn deposit_for_proposals_should_be_taken() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { System::set_block_number(1); assert_ok!(propose_set_balance(1, 2, 5)); assert_ok!(Democracy::second(Origin::signed(2), 0)); @@ -1740,7 +1741,7 @@ mod tests { #[test] fn deposit_for_proposals_should_be_returned() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { System::set_block_number(1); assert_ok!(propose_set_balance(1, 2, 5)); assert_ok!(Democracy::second(Origin::signed(2), 0)); @@ -1756,7 +1757,7 @@ mod tests { #[test] fn proposal_with_deposit_below_minimum_should_not_work() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { System::set_block_number(1); assert_noop!(propose_set_balance(1, 2, 0), "value too low"); }); @@ -1764,7 +1765,7 @@ mod tests { #[test] fn poor_proposer_should_not_work() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { System::set_block_number(1); assert_noop!(propose_set_balance(1, 2, 11), "proposer\'s balance too low"); }); @@ -1772,7 +1773,7 @@ mod tests { #[test] fn poor_seconder_should_not_work() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { System::set_block_number(1); assert_ok!(propose_set_balance(2, 2, 11)); assert_noop!(Democracy::second(Origin::signed(1), 0), "seconder\'s balance too low"); @@ -1781,7 +1782,7 @@ mod tests { #[test] fn runners_up_should_come_after() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { System::set_block_number(0); assert_ok!(propose_set_balance(1, 2, 2)); assert_ok!(propose_set_balance(1, 4, 4)); @@ -1797,7 +1798,7 @@ mod tests { #[test] fn simple_passing_should_work() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { System::set_block_number(1); let r = Democracy::inject_referendum( 1, @@ -1820,7 +1821,7 @@ mod tests { #[test] fn cancel_referendum_should_work() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { System::set_block_number(1); let r = Democracy::inject_referendum( 1, @@ -1840,7 +1841,7 @@ mod tests { #[test] fn simple_failing_should_work() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { System::set_block_number(1); let r = Democracy::inject_referendum( 1, @@ -1863,7 +1864,7 @@ mod tests { #[test] fn controversial_voting_should_work() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { System::set_block_number(1); let r = Democracy::inject_referendum( 1, @@ -1889,7 +1890,7 @@ mod tests { #[test] fn delayed_enactment_should_work() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { System::set_block_number(1); let r = Democracy::inject_referendum( 1, @@ -1917,7 +1918,7 @@ mod tests { #[test] fn controversial_low_turnout_voting_should_work() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { System::set_block_number(1); let r = Democracy::inject_referendum( 1, @@ -1939,7 +1940,7 @@ mod tests { #[test] fn passing_low_turnout_voting_should_work() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { assert_eq!(Balances::free_balance(&42), 0); assert_eq!(Balances::total_issuance(), 210); @@ -1965,7 +1966,7 @@ mod tests { #[test] fn lock_voting_should_work() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { System::set_block_number(0); let r = Democracy::inject_referendum( 1, @@ -2025,7 +2026,7 @@ mod tests { #[test] fn lock_voting_should_work_with_delegation() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { System::set_block_number(1); let r = Democracy::inject_referendum( 1, diff --git a/srml/elections-phragmen/src/lib.rs b/srml/elections-phragmen/src/lib.rs index 58c0f11340..1405536267 100644 --- a/srml/elections-phragmen/src/lib.rs +++ b/srml/elections-phragmen/src/lib.rs @@ -591,10 +591,10 @@ mod tests { use super::*; use std::cell::RefCell; use srml_support::{assert_ok, assert_noop, parameter_types, assert_eq_uvec}; - use runtime_io::with_externalities; - use primitives::{H256, Blake2Hasher}; - use sr_primitives::{Perbill, testing::Header, BuildStorage, - traits::{BlakeTwo256, IdentityLookup, Block as BlockT} + use primitives::H256; + use sr_primitives::{ + Perbill, testing::Header, BuildStorage, + traits::{BlakeTwo256, IdentityLookup, Block as BlockT}, set_and_run_with_externalities }; use crate as elections; @@ -730,7 +730,7 @@ mod tests { self.desired_runners_up = count; self } - pub fn build(self) -> runtime_io::TestExternalities { + pub fn build(self) -> runtime_io::TestExternalities { VOTING_BOND.with(|v| *v.borrow_mut() = self.voter_bond); GenesisConfig { balances: Some(balances::GenesisConfig::{ @@ -770,7 +770,7 @@ mod tests { #[test] fn params_should_work() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { System::set_block_number(1); assert_eq!(Elections::desired_members(), 2); assert_eq!(Elections::term_duration(), 5); @@ -790,7 +790,7 @@ mod tests { #[test] fn simple_candidate_submission_should_work() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { assert_eq!(Elections::candidates(), Vec::::new()); assert!(Elections::is_candidate(&1).is_err()); assert!(Elections::is_candidate(&2).is_err()); @@ -817,7 +817,7 @@ mod tests { #[test] fn simple_candidate_submission_with_no_votes_should_work() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { assert_eq!(Elections::candidates(), Vec::::new()); assert_ok!(Elections::submit_candidacy(Origin::signed(1))); @@ -844,7 +844,7 @@ mod tests { #[test] fn dupe_candidate_submission_should_not_work() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { assert_eq!(Elections::candidates(), Vec::::new()); assert_ok!(Elections::submit_candidacy(Origin::signed(1))); assert_eq!(Elections::candidates(), vec![1]); @@ -858,7 +858,7 @@ mod tests { #[test] fn member_candidacy_submission_should_not_work() { // critically important to make sure that outgoing candidates and losers are not mixed up. - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { assert_ok!(Elections::submit_candidacy(Origin::signed(5))); assert_ok!(Elections::vote(Origin::signed(2), vec![5], 20)); @@ -878,7 +878,7 @@ mod tests { #[test] fn poor_candidate_submission_should_not_work() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { assert_eq!(Elections::candidates(), Vec::::new()); assert_noop!( Elections::submit_candidacy(Origin::signed(7)), @@ -889,7 +889,7 @@ mod tests { #[test] fn simple_voting_should_work() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { assert_eq!(Elections::candidates(), Vec::::new()); assert_eq!(balances(&2), (20, 0)); @@ -903,7 +903,7 @@ mod tests { #[test] fn can_vote_with_custom_stake() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { assert_eq!(Elections::candidates(), Vec::::new()); assert_eq!(balances(&2), (20, 0)); @@ -917,7 +917,7 @@ mod tests { #[test] fn can_update_votes_and_stake() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { assert_eq!(balances(&2), (20, 0)); assert_ok!(Elections::submit_candidacy(Origin::signed(5))); @@ -938,7 +938,7 @@ mod tests { #[test] fn cannot_vote_for_no_candidate() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { assert_noop!( Elections::vote(Origin::signed(2), vec![], 20), "cannot vote when no candidates or members exist" @@ -949,7 +949,7 @@ mod tests { #[test] fn can_vote_for_old_members_even_when_no_new_candidates() { // let allowed_votes = candidates_count as usize + Self::members().len() - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { assert_ok!(Elections::submit_candidacy(Origin::signed(5))); assert_ok!(Elections::submit_candidacy(Origin::signed(4))); @@ -967,7 +967,7 @@ mod tests { #[test] fn cannot_vote_for_more_than_candidates() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { assert_ok!(Elections::submit_candidacy(Origin::signed(5))); assert_ok!(Elections::submit_candidacy(Origin::signed(4))); @@ -980,7 +980,7 @@ mod tests { #[test] fn cannot_vote_for_less_than_ed() { - with_externalities(&mut ExtBuilder::default().voter_bond(8).build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().voter_bond(8).build(), || { assert_ok!(Elections::submit_candidacy(Origin::signed(5))); assert_ok!(Elections::submit_candidacy(Origin::signed(4))); @@ -993,7 +993,7 @@ mod tests { #[test] fn can_vote_for_more_than_total_balance_but_moot() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { assert_ok!(Elections::submit_candidacy(Origin::signed(5))); assert_ok!(Elections::submit_candidacy(Origin::signed(4))); @@ -1006,7 +1006,7 @@ mod tests { #[test] fn remove_voter_should_work() { - with_externalities(&mut ExtBuilder::default().voter_bond(8).build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().voter_bond(8).build(), || { assert_ok!(Elections::submit_candidacy(Origin::signed(5))); assert_ok!(Elections::vote(Origin::signed(2), vec![5], 20)); @@ -1031,14 +1031,14 @@ mod tests { #[test] fn non_voter_remove_should_not_work() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { assert_noop!(Elections::remove_voter(Origin::signed(3)), "must be a voter"); }); } #[test] fn dupe_remove_should_fail() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { assert_ok!(Elections::submit_candidacy(Origin::signed(5))); assert_ok!(Elections::vote(Origin::signed(2), vec![5], 20)); @@ -1051,7 +1051,7 @@ mod tests { #[test] fn removed_voter_should_not_be_counted() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { assert_ok!(Elections::submit_candidacy(Origin::signed(5))); assert_ok!(Elections::submit_candidacy(Origin::signed(4))); assert_ok!(Elections::submit_candidacy(Origin::signed(3))); @@ -1071,7 +1071,7 @@ mod tests { #[test] fn reporter_must_be_voter() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { assert_noop!( Elections::report_defunct_voter(Origin::signed(1), 2), "reporter must be a voter", @@ -1081,7 +1081,7 @@ mod tests { #[test] fn can_detect_defunct_voter() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { assert_ok!(Elections::submit_candidacy(Origin::signed(5))); assert_ok!(Elections::submit_candidacy(Origin::signed(4))); @@ -1116,7 +1116,7 @@ mod tests { #[test] fn report_voter_should_work_and_earn_reward() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { assert_ok!(Elections::submit_candidacy(Origin::signed(5))); assert_ok!(Elections::submit_candidacy(Origin::signed(4))); @@ -1148,8 +1148,8 @@ mod tests { #[test] fn report_voter_should_slash_when_bad_report() { - with_externalities(&mut ExtBuilder::default().build(), || { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { assert_ok!(Elections::submit_candidacy(Origin::signed(5))); assert_ok!(Elections::submit_candidacy(Origin::signed(4))); @@ -1180,7 +1180,7 @@ mod tests { #[test] fn simple_voting_rounds_should_work() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { assert_ok!(Elections::submit_candidacy(Origin::signed(5))); assert_ok!(Elections::submit_candidacy(Origin::signed(4))); assert_ok!(Elections::submit_candidacy(Origin::signed(3))); @@ -1215,7 +1215,7 @@ mod tests { #[test] fn defunct_voter_will_be_counted() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { assert_ok!(Elections::submit_candidacy(Origin::signed(5))); // This guy's vote is pointless for this round. @@ -1243,7 +1243,7 @@ mod tests { #[test] fn only_desired_seats_are_chosen() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { assert_ok!(Elections::submit_candidacy(Origin::signed(5))); assert_ok!(Elections::submit_candidacy(Origin::signed(4))); assert_ok!(Elections::submit_candidacy(Origin::signed(3))); @@ -1264,7 +1264,7 @@ mod tests { #[test] fn phragmen_should_not_self_vote() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { assert_ok!(Elections::submit_candidacy(Origin::signed(5))); assert_ok!(Elections::submit_candidacy(Origin::signed(4))); @@ -1279,7 +1279,7 @@ mod tests { #[test] fn runners_up_should_be_kept() { - with_externalities(&mut ExtBuilder::default().desired_runners_up(2).build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().desired_runners_up(2).build(), || { assert_ok!(Elections::submit_candidacy(Origin::signed(5))); assert_ok!(Elections::submit_candidacy(Origin::signed(4))); assert_ok!(Elections::submit_candidacy(Origin::signed(3))); @@ -1306,7 +1306,7 @@ mod tests { #[test] fn runners_up_should_be_next_candidates() { - with_externalities(&mut ExtBuilder::default().desired_runners_up(2).build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().desired_runners_up(2).build(), || { assert_ok!(Elections::submit_candidacy(Origin::signed(5))); assert_ok!(Elections::submit_candidacy(Origin::signed(4))); assert_ok!(Elections::submit_candidacy(Origin::signed(3))); @@ -1333,7 +1333,7 @@ mod tests { #[test] fn runners_up_lose_bond_once_outgoing() { - with_externalities(&mut ExtBuilder::default().desired_runners_up(1).build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().desired_runners_up(1).build(), || { assert_ok!(Elections::submit_candidacy(Origin::signed(5))); assert_ok!(Elections::submit_candidacy(Origin::signed(4))); assert_ok!(Elections::submit_candidacy(Origin::signed(2))); @@ -1364,7 +1364,7 @@ mod tests { #[test] fn current_members_are_always_implicitly_next_candidate() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { assert_ok!(Elections::submit_candidacy(Origin::signed(5))); assert_ok!(Elections::submit_candidacy(Origin::signed(4))); @@ -1400,7 +1400,7 @@ mod tests { fn election_state_is_uninterrupted() { // what I mean by uninterrupted: // given no input or stimulants the same members are re-elected. - with_externalities(&mut ExtBuilder::default().desired_runners_up(2).build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().desired_runners_up(2).build(), || { assert_ok!(Elections::submit_candidacy(Origin::signed(5))); assert_ok!(Elections::submit_candidacy(Origin::signed(4))); assert_ok!(Elections::submit_candidacy(Origin::signed(3))); @@ -1433,7 +1433,7 @@ mod tests { #[test] fn remove_members_triggers_election() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { assert_ok!(Elections::submit_candidacy(Origin::signed(5))); assert_ok!(Elections::submit_candidacy(Origin::signed(4))); @@ -1459,7 +1459,7 @@ mod tests { #[test] fn seats_should_be_released_when_no_vote() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { assert_ok!(Elections::submit_candidacy(Origin::signed(5))); assert_ok!(Elections::submit_candidacy(Origin::signed(4))); assert_ok!(Elections::submit_candidacy(Origin::signed(3))); @@ -1493,7 +1493,7 @@ mod tests { #[test] fn outgoing_will_get_the_bond_back() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { assert_eq!(balances(&5), (50, 0)); assert_ok!(Elections::submit_candidacy(Origin::signed(5))); @@ -1519,7 +1519,7 @@ mod tests { #[test] fn losers_will_lose_the_bond() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { assert_ok!(Elections::submit_candidacy(Origin::signed(5))); assert_ok!(Elections::submit_candidacy(Origin::signed(3))); @@ -1542,7 +1542,7 @@ mod tests { #[test] fn incoming_outgoing_are_reported() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { assert_ok!(Elections::submit_candidacy(Origin::signed(4))); assert_ok!(Elections::submit_candidacy(Origin::signed(5))); @@ -1587,7 +1587,7 @@ mod tests { #[test] fn invalid_votes_are_moot() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { assert_ok!(Elections::submit_candidacy(Origin::signed(4))); assert_ok!(Elections::submit_candidacy(Origin::signed(3))); diff --git a/srml/elections/src/mock.rs b/srml/elections/src/mock.rs index 161da35e6a..b9e548e1ed 100644 --- a/srml/elections/src/mock.rs +++ b/srml/elections/src/mock.rs @@ -23,11 +23,9 @@ use support::{ StorageValue, StorageMap, parameter_types, assert_ok, traits::{Get, ChangeMembers, Currency} }; -use runtime_io::with_externalities; -use primitives::{H256, Blake2Hasher}; +use primitives::H256; use sr_primitives::{ - Perbill, BuildStorage, - testing::Header, + Perbill, BuildStorage, set_and_run_with_externalities, testing::Header, traits::{BlakeTwo256, IdentityLookup, Block as BlockT}, }; use crate as elections; @@ -213,7 +211,7 @@ impl ExtBuilder { self.desired_seats = seats; self } - pub fn build(self) -> runtime_io::TestExternalities { + pub fn build(self) -> runtime_io::TestExternalities { VOTER_BOND.with(|v| *v.borrow_mut() = self.voter_bond); VOTING_FEE.with(|v| *v.borrow_mut() = self.voting_fee); PRESENT_SLASH_PER_VOTER.with(|v| *v.borrow_mut() = self.bad_presentation_punishment); @@ -283,9 +281,9 @@ pub(crate) fn locks(who: &u64) -> Vec { Balances::locks(who).iter().map(|l| l.amount).collect::>() } -pub(crate) fn new_test_ext_with_candidate_holes() -> runtime_io::TestExternalities { +pub(crate) fn new_test_ext_with_candidate_holes() -> runtime_io::TestExternalities { let mut t = ExtBuilder::default().build(); - with_externalities(&mut t, || { + set_and_run_with_externalities(&mut t, || { >::put(vec![0, 0, 1]); elections::CandidateCount::put(1); >::insert(1, (0, 2)); diff --git a/srml/elections/src/tests.rs b/srml/elections/src/tests.rs index c6f4f9a0b3..149e534a2f 100644 --- a/srml/elections/src/tests.rs +++ b/srml/elections/src/tests.rs @@ -22,11 +22,11 @@ use crate::mock::*; use crate::*; use support::{assert_ok, assert_err, assert_noop}; -use runtime_io::with_externalities; +use sr_primitives::set_and_run_with_externalities; #[test] fn params_should_work() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { System::set_block_number(1); assert_eq!(Elections::next_vote_from(1), 4); assert_eq!(Elections::next_vote_from(4), 4); @@ -53,7 +53,7 @@ fn params_should_work() { #[test] fn chunking_bool_to_flag_should_work() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { assert_eq!(Elections::bool_to_flag(vec![]), vec![]); assert_eq!(Elections::bool_to_flag(vec![false]), vec![0]); assert_eq!(Elections::bool_to_flag(vec![true]), vec![1]); @@ -98,7 +98,7 @@ fn chunking_bool_to_flag_should_work() { #[test] fn chunking_voter_set_growth_should_work() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); // create 65. 64 (set0) + 1 (set1) @@ -122,7 +122,7 @@ fn chunking_voter_set_growth_should_work() { #[test] fn chunking_voter_set_reclaim_should_work() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); (1..=129).for_each(|i| vote(i, 0)); @@ -159,7 +159,7 @@ fn chunking_voter_set_reclaim_should_work() { #[test] fn chunking_approvals_set_growth_should_work() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { // create candidates and voters. (1..=250).for_each(|i| create_candidate(i, (i-1) as u32)); (1..=250).for_each(|i| vote(i, i as usize)); @@ -221,7 +221,7 @@ fn chunking_approvals_set_growth_should_work() { #[test] fn chunking_cell_status_works() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); (1..=63).for_each(|i| vote(i, 0)); @@ -240,7 +240,7 @@ fn chunking_cell_status_works() { #[test] fn chunking_voter_index_does_not_take_holes_into_account() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); // create 65. 64 (set0) + 1 (set1) @@ -265,7 +265,7 @@ fn chunking_voter_index_does_not_take_holes_into_account() { #[test] fn chunking_approval_storage_should_work() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); assert_ok!(Elections::submit_candidacy(Origin::signed(3), 1)); @@ -285,7 +285,7 @@ fn chunking_approval_storage_should_work() { #[test] fn voting_initial_set_approvals_ignores_voter_index() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); // Last argument is essentially irrelevant. You might get or miss a tip. @@ -299,7 +299,7 @@ fn voting_initial_set_approvals_ignores_voter_index() { } #[test] fn voting_bad_approval_index_slashes_voters_and_bond_reduces_stake() { - with_externalities(&mut ExtBuilder::default().voting_fee(5).voter_bond(2).build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().voting_fee(5).voter_bond(2).build(), || { assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); (1..=63).for_each(|i| vote(i, 0)); @@ -329,7 +329,7 @@ fn voting_bad_approval_index_slashes_voters_and_bond_reduces_stake() { #[test] fn voting_subsequent_set_approvals_checks_voter_index() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); assert_ok!(Elections::set_approvals(Origin::signed(3), vec![], 0, 0, 30)); @@ -353,7 +353,7 @@ fn voting_subsequent_set_approvals_checks_voter_index() { #[test] fn voting_cannot_lock_less_than_limit() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); assert_noop!( @@ -366,7 +366,7 @@ fn voting_cannot_lock_less_than_limit() { #[test] fn voting_locking_more_than_total_balance_is_moot() { - with_externalities(&mut ExtBuilder::default().voter_bond(2).build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().voter_bond(2).build(), || { assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); assert_eq!(balances(&3), (30, 0)); @@ -382,7 +382,7 @@ fn voting_locking_more_than_total_balance_is_moot() { #[test] fn voting_locking_stake_and_reserving_bond_works() { - with_externalities(&mut ExtBuilder::default().voter_bond(2).build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().voter_bond(2).build(), || { assert_ok!(Elections::submit_candidacy(Origin::signed(5), 0)); assert_eq!(balances(&2), (20, 0)); @@ -408,7 +408,7 @@ fn voting_locking_stake_and_reserving_bond_works() { #[test] fn voting_without_any_candidate_count_should_not_work() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { System::set_block_number(1); assert_eq!(Elections::candidates().len(), 0); @@ -422,7 +422,7 @@ fn voting_without_any_candidate_count_should_not_work() { #[test] fn voting_setting_an_approval_vote_count_more_than_candidate_count_should_not_work() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { System::set_block_number(1); assert_ok!(Elections::submit_candidacy(Origin::signed(5), 0)); @@ -437,7 +437,7 @@ fn voting_setting_an_approval_vote_count_more_than_candidate_count_should_not_wo #[test] fn voting_resubmitting_approvals_should_work() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { System::set_block_number(1); assert_ok!(Elections::submit_candidacy(Origin::signed(5), 0)); @@ -456,7 +456,7 @@ fn voting_resubmitting_approvals_should_work() { #[test] fn voting_retracting_voter_should_work() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { System::set_block_number(1); assert_ok!(Elections::submit_candidacy(Origin::signed(5), 0)); @@ -501,7 +501,7 @@ fn voting_retracting_voter_should_work() { #[test] fn voting_invalid_retraction_index_should_not_work() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { System::set_block_number(1); assert_ok!(Elections::submit_candidacy(Origin::signed(3), 0)); @@ -514,7 +514,7 @@ fn voting_invalid_retraction_index_should_not_work() { #[test] fn voting_overflow_retraction_index_should_not_work() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { System::set_block_number(1); assert_ok!(Elections::submit_candidacy(Origin::signed(3), 0)); @@ -525,7 +525,7 @@ fn voting_overflow_retraction_index_should_not_work() { #[test] fn voting_non_voter_retraction_should_not_work() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { System::set_block_number(1); assert_ok!(Elections::submit_candidacy(Origin::signed(3), 0)); @@ -536,7 +536,7 @@ fn voting_non_voter_retraction_should_not_work() { #[test] fn retracting_inactive_voter_should_work() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { System::set_block_number(4); assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); assert_ok!(Elections::set_approvals(Origin::signed(2), vec![true], 0, 0, 20)); @@ -570,7 +570,7 @@ fn retracting_inactive_voter_should_work() { #[test] fn retracting_inactive_voter_with_other_candidates_in_slots_should_work() { - with_externalities(&mut ExtBuilder::default().voter_bond(2).build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().voter_bond(2).build(), || { System::set_block_number(4); assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); assert_ok!(Elections::set_approvals(Origin::signed(2), vec![true], 0, 0, 20)); @@ -605,7 +605,7 @@ fn retracting_inactive_voter_with_other_candidates_in_slots_should_work() { #[test] fn retracting_inactive_voter_with_bad_reporter_index_should_not_work() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { System::set_block_number(4); assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); assert_ok!(Elections::set_approvals(Origin::signed(2), vec![true], 0, 0, 20)); @@ -634,7 +634,7 @@ fn retracting_inactive_voter_with_bad_reporter_index_should_not_work() { #[test] fn retracting_inactive_voter_with_bad_target_index_should_not_work() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { System::set_block_number(4); assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); assert_ok!(Elections::set_approvals(Origin::signed(2), vec![true], 0, 0, 20)); @@ -663,7 +663,7 @@ fn retracting_inactive_voter_with_bad_target_index_should_not_work() { #[test] fn retracting_active_voter_should_slash_reporter() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { System::set_block_number(4); assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); assert_ok!(Elections::submit_candidacy(Origin::signed(3), 1)); @@ -711,7 +711,7 @@ fn retracting_active_voter_should_slash_reporter() { #[test] fn retracting_inactive_voter_by_nonvoter_should_not_work() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { System::set_block_number(4); assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); assert_ok!(Elections::set_approvals(Origin::signed(2), vec![true], 0, 0, 20)); @@ -740,7 +740,7 @@ fn retracting_inactive_voter_by_nonvoter_should_not_work() { #[test] fn candidacy_simple_candidate_submission_should_work() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { System::set_block_number(1); assert_eq!(Elections::candidates(), Vec::::new()); assert_eq!(Elections::candidate_reg_info(1), None); @@ -768,7 +768,7 @@ fn candidacy_simple_candidate_submission_should_work() { fn candidacy_submission_using_free_slot_should_work() { let mut t = new_test_ext_with_candidate_holes(); - with_externalities(&mut t, || { + set_and_run_with_externalities(&mut t, || { System::set_block_number(1); assert_eq!(Elections::candidates(), vec![0, 0, 1]); @@ -784,7 +784,7 @@ fn candidacy_submission_using_free_slot_should_work() { fn candidacy_submission_using_alternative_free_slot_should_work() { let mut t = new_test_ext_with_candidate_holes(); - with_externalities(&mut t, || { + set_and_run_with_externalities(&mut t, || { System::set_block_number(1); assert_eq!(Elections::candidates(), vec![0, 0, 1]); @@ -800,7 +800,7 @@ fn candidacy_submission_using_alternative_free_slot_should_work() { fn candidacy_submission_not_using_free_slot_should_not_work() { let mut t = new_test_ext_with_candidate_holes(); - with_externalities(&mut t, || { + set_and_run_with_externalities(&mut t, || { System::set_block_number(1); assert_noop!( Elections::submit_candidacy(Origin::signed(4), 3), @@ -811,7 +811,7 @@ fn candidacy_submission_not_using_free_slot_should_not_work() { #[test] fn candidacy_bad_candidate_slot_submission_should_not_work() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { System::set_block_number(1); assert_eq!(Elections::candidates(), Vec::::new()); assert_noop!( @@ -823,7 +823,7 @@ fn candidacy_bad_candidate_slot_submission_should_not_work() { #[test] fn candidacy_non_free_candidate_slot_submission_should_not_work() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { System::set_block_number(1); assert_eq!(Elections::candidates(), Vec::::new()); assert_ok!(Elections::submit_candidacy(Origin::signed(1), 0)); @@ -837,7 +837,7 @@ fn candidacy_non_free_candidate_slot_submission_should_not_work() { #[test] fn candidacy_dupe_candidate_submission_should_not_work() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { System::set_block_number(1); assert_eq!(Elections::candidates(), Vec::::new()); assert_ok!(Elections::submit_candidacy(Origin::signed(1), 0)); @@ -851,7 +851,7 @@ fn candidacy_dupe_candidate_submission_should_not_work() { #[test] fn candidacy_poor_candidate_submission_should_not_work() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { System::set_block_number(1); assert_eq!(Elections::candidates(), Vec::::new()); assert_noop!( @@ -863,7 +863,7 @@ fn candidacy_poor_candidate_submission_should_not_work() { #[test] fn election_voting_should_work() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { System::set_block_number(1); assert_ok!(Elections::submit_candidacy(Origin::signed(5), 0)); @@ -892,7 +892,7 @@ fn election_voting_should_work() { #[test] fn election_proxy_voting_should_work() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { System::set_block_number(1); assert_ok!(Elections::submit_candidacy(Origin::signed(5), 0)); @@ -933,7 +933,7 @@ fn election_proxy_voting_should_work() { #[test] fn election_simple_tally_should_work() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { System::set_block_number(4); assert!(!Elections::presentation_active()); @@ -972,7 +972,7 @@ fn election_simple_tally_should_work() { #[test] fn election_seats_should_be_released() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { System::set_block_number(4); assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); assert_ok!(Elections::submit_candidacy(Origin::signed(5), 1)); @@ -1006,7 +1006,7 @@ fn election_seats_should_be_released() { #[test] fn election_presentations_with_zero_staked_deposit_should_not_work() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { System::set_block_number(4); assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); assert_ok!(Elections::set_approvals(Origin::signed(2), vec![true], 0, 0, 20)); @@ -1022,7 +1022,7 @@ fn election_presentations_with_zero_staked_deposit_should_not_work() { #[test] fn election_double_presentations_should_be_punished() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { assert!(Balances::can_slash(&4, 10)); System::set_block_number(4); @@ -1045,7 +1045,7 @@ fn election_double_presentations_should_be_punished() { #[test] fn election_presenting_for_double_election_should_not_work() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { System::set_block_number(4); assert_eq!(Elections::submit_candidacy(Origin::signed(2), 0), Ok(())); assert_ok!(Elections::set_approvals(Origin::signed(2), vec![true], 0, 0, 20)); @@ -1072,7 +1072,7 @@ fn election_presenting_for_double_election_should_not_work() { #[test] fn election_presenting_loser_should_not_work() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { System::set_block_number(4); assert_ok!(Elections::submit_candidacy(Origin::signed(1), 0)); assert_ok!(Elections::set_approvals(Origin::signed(6), vec![true], 0, 0, 60)); @@ -1105,7 +1105,7 @@ fn election_presenting_loser_should_not_work() { #[test] fn election_presenting_loser_first_should_not_matter() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { System::set_block_number(4); assert_ok!(Elections::submit_candidacy(Origin::signed(1), 0)); assert_ok!(Elections::set_approvals(Origin::signed(6), vec![true], 0, 0, 60)); @@ -1137,7 +1137,7 @@ fn election_presenting_loser_first_should_not_matter() { #[test] fn election_present_outside_of_presentation_period_should_not_work() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { System::set_block_number(4); assert!(!Elections::presentation_active()); assert_noop!( @@ -1149,7 +1149,7 @@ fn election_present_outside_of_presentation_period_should_not_work() { #[test] fn election_present_with_invalid_vote_index_should_not_work() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { System::set_block_number(4); assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); assert_ok!(Elections::submit_candidacy(Origin::signed(5), 1)); @@ -1165,7 +1165,7 @@ fn election_present_with_invalid_vote_index_should_not_work() { #[test] fn election_present_when_presenter_is_poor_should_not_work() { let test_present = |p| { - with_externalities(&mut ExtBuilder::default() + set_and_run_with_externalities(&mut ExtBuilder::default() .voting_fee(5) .voter_bond(2) .bad_presentation_punishment(p) @@ -1199,7 +1199,7 @@ fn election_present_when_presenter_is_poor_should_not_work() { #[test] fn election_invalid_present_tally_should_slash() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { System::set_block_number(4); assert!(!Elections::presentation_active()); assert_eq!(Balances::total_balance(&4), 40); @@ -1219,7 +1219,7 @@ fn election_invalid_present_tally_should_slash() { #[test] fn election_runners_up_should_be_kept() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { System::set_block_number(4); assert!(!Elections::presentation_active()); @@ -1280,7 +1280,7 @@ fn election_runners_up_should_be_kept() { #[test] fn election_second_tally_should_use_runners_up() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { System::set_block_number(4); assert_ok!(Elections::submit_candidacy(Origin::signed(1), 0)); assert_ok!(Elections::set_approvals(Origin::signed(6), vec![true], 0, 0, 60)); @@ -1335,7 +1335,7 @@ fn election_second_tally_should_use_runners_up() { #[test] fn election_loser_candidates_bond_gets_slashed() { - with_externalities(&mut ExtBuilder::default().desired_seats(1).build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().desired_seats(1).build(), || { System::set_block_number(4); assert!(!Elections::presentation_active()); @@ -1374,7 +1374,7 @@ fn election_loser_candidates_bond_gets_slashed() { #[test] fn pot_accumulating_weight_and_decaying_should_work() { - with_externalities(&mut ExtBuilder::default().balance_factor(10).build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().balance_factor(10).build(), || { System::set_block_number(4); assert!(!Elections::presentation_active()); @@ -1502,7 +1502,7 @@ fn pot_accumulating_weight_and_decaying_should_work() { #[test] fn pot_winning_resets_accumulated_pot() { - with_externalities(&mut ExtBuilder::default().balance_factor(10).build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().balance_factor(10).build(), || { System::set_block_number(4); assert!(!Elections::presentation_active()); @@ -1564,7 +1564,7 @@ fn pot_winning_resets_accumulated_pot() { #[test] fn pot_resubmitting_approvals_stores_pot() { - with_externalities(&mut ExtBuilder::default() + set_and_run_with_externalities(&mut ExtBuilder::default() .voter_bond(0) .voting_fee(0) .balance_factor(10) @@ -1629,7 +1629,7 @@ fn pot_resubmitting_approvals_stores_pot() { #[test] fn pot_get_offset_should_work() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { assert_eq!(Elections::get_offset(100, 0), 0); assert_eq!(Elections::get_offset(100, 1), 96); assert_eq!(Elections::get_offset(100, 2), 96 + 93); @@ -1653,7 +1653,7 @@ fn pot_get_offset_should_work() { #[test] fn pot_get_offset_with_zero_decay() { - with_externalities(&mut ExtBuilder::default().decay_ratio(0).build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().decay_ratio(0).build(), || { assert_eq!(Elections::get_offset(100, 0), 0); assert_eq!(Elections::get_offset(100, 1), 0); assert_eq!(Elections::get_offset(100, 2), 0); diff --git a/srml/example/src/lib.rs b/srml/example/src/lib.rs index ef8eead7ba..08adf9efa7 100644 --- a/srml/example/src/lib.rs +++ b/srml/example/src/lib.rs @@ -634,15 +634,12 @@ mod tests { use super::*; use support::{assert_ok, impl_outer_origin, parameter_types}; - use runtime_io::with_externalities; - use primitives::{H256, Blake2Hasher}; + use primitives::H256; // The testing primitives are very useful for avoiding having to work with signatures // or public keys. `u64` is used as the `AccountId` and no `Signature`s are required. use sr_primitives::{ - Perbill, + set_and_run_with_externalities, Perbill, weights::GetDispatchInfo, testing::Header, traits::{BlakeTwo256, OnInitialize, OnFinalize, IdentityLookup}, - weights::GetDispatchInfo, - testing::Header }; impl_outer_origin! { @@ -707,7 +704,7 @@ mod tests { // This function basically just builds a genesis storage key/value store according to // our desired mockup. - fn new_test_ext() -> runtime_io::TestExternalities { + fn new_test_ext() -> runtime_io::TestExternalities { let mut t = system::GenesisConfig::default().build_storage::().unwrap(); // We use default for brevity, but you can configure as desired if needed. balances::GenesisConfig::::default().assimilate_storage(&mut t).unwrap(); @@ -722,7 +719,7 @@ mod tests { #[test] fn it_works_for_optional_value() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { // Check that GenesisBuilder works properly. assert_eq!(Example::dummy(), Some(42)); @@ -743,7 +740,7 @@ mod tests { #[test] fn it_works_for_default_value() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { assert_eq!(Example::foo(), 24); assert_ok!(Example::accumulate_foo(Origin::signed(1), 1)); assert_eq!(Example::foo(), 25); @@ -752,7 +749,7 @@ mod tests { #[test] fn signed_ext_watch_dummy_works() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { let call = >::set_dummy(10); let info = DispatchInfo::default(); diff --git a/srml/executive/src/lib.rs b/srml/executive/src/lib.rs index ee11ffadf4..f1509f1760 100644 --- a/srml/executive/src/lib.rs +++ b/srml/executive/src/lib.rs @@ -293,12 +293,12 @@ where #[cfg(test)] mod tests { use super::*; - use runtime_io::with_externalities; - use primitives::{H256, Blake2Hasher}; + use primitives::H256; use sr_primitives::{ generic::Era, Perbill, DispatchError, weights::Weight, testing::{Digest, Header, Block}, traits::{Bounded, Header as HeaderT, BlakeTwo256, IdentityLookup, ConvertInto}, transaction_validity::{InvalidTransaction, UnknownTransaction}, ApplyError, + set_and_run_with_externalities, }; use support::{ impl_outer_event, impl_outer_origin, parameter_types, impl_outer_dispatch, @@ -419,8 +419,8 @@ mod tests { }.assimilate_storage(&mut t).unwrap(); let xt = sr_primitives::testing::TestXt(sign_extra(1, 0, 0), Call::Balances(BalancesCall::transfer(2, 69))); let weight = xt.get_dispatch_info().weight as u64; - let mut t = runtime_io::TestExternalities::::new(t); - with_externalities(&mut t, || { + let mut t = runtime_io::TestExternalities::new(t); + set_and_run_with_externalities(&mut t, || { Executive::initialize_block(&Header::new( 1, H256::default(), @@ -435,7 +435,7 @@ mod tests { }); } - fn new_test_ext(balance_factor: u64) -> runtime_io::TestExternalities { + fn new_test_ext(balance_factor: u64) -> runtime_io::TestExternalities { let mut t = system::GenesisConfig::default().build_storage::().unwrap(); balances::GenesisConfig:: { balances: vec![(1, 111 * balance_factor)], @@ -446,7 +446,7 @@ mod tests { #[test] fn block_import_works() { - with_externalities(&mut new_test_ext(1), || { + set_and_run_with_externalities(&mut new_test_ext(1), || { Executive::execute_block(Block { header: Header { parent_hash: [69u8; 32].into(), @@ -463,7 +463,7 @@ mod tests { #[test] #[should_panic] fn block_import_of_bad_state_root_fails() { - with_externalities(&mut new_test_ext(1), || { + set_and_run_with_externalities(&mut new_test_ext(1), || { Executive::execute_block(Block { header: Header { parent_hash: [69u8; 32].into(), @@ -480,7 +480,7 @@ mod tests { #[test] #[should_panic] fn block_import_of_bad_extrinsic_root_fails() { - with_externalities(&mut new_test_ext(1), || { + set_and_run_with_externalities(&mut new_test_ext(1), || { Executive::execute_block(Block { header: Header { parent_hash: [69u8; 32].into(), @@ -499,7 +499,7 @@ mod tests { let mut t = new_test_ext(1); // bad nonce check! let xt = sr_primitives::testing::TestXt(sign_extra(1, 30, 0), Call::Balances(BalancesCall::transfer(33, 69))); - with_externalities(&mut t, || { + set_and_run_with_externalities(&mut t, || { Executive::initialize_block(&Header::new( 1, H256::default(), @@ -521,7 +521,7 @@ mod tests { let encoded_len = encoded.len() as Weight; let limit = AvailableBlockRatio::get() * MaximumBlockWeight::get(); let num_to_exhaust_block = limit / encoded_len; - with_externalities(&mut t, || { + set_and_run_with_externalities(&mut t, || { Executive::initialize_block(&Header::new( 1, H256::default(), @@ -557,7 +557,7 @@ mod tests { let x2 = sr_primitives::testing::TestXt(sign_extra(1, 2, 0), Call::Balances(BalancesCall::transfer(33, 0))); let len = xt.clone().encode().len() as u32; let mut t = new_test_ext(1); - with_externalities(&mut t, || { + set_and_run_with_externalities(&mut t, || { assert_eq!(>::all_extrinsics_weight(), 0); assert_eq!(>::all_extrinsics_weight(), 0); @@ -581,7 +581,7 @@ mod tests { let xt = sr_primitives::testing::TestXt(None, Call::Balances(BalancesCall::set_balance(33, 69, 69))); let mut t = new_test_ext(1); - with_externalities(&mut t, || { + set_and_run_with_externalities(&mut t, || { assert_eq!(Executive::validate_transaction(xt.clone()), Ok(Default::default())); assert_eq!( Executive::apply_extrinsic(xt), @@ -599,7 +599,7 @@ mod tests { let id: LockIdentifier = *b"0 "; let execute_with_lock = |lock: WithdrawReasons| { let mut t = new_test_ext(1); - with_externalities(&mut t, || { + set_and_run_with_externalities(&mut t, || { as LockableCurrency>::set_lock( id, &1, diff --git a/srml/finality-tracker/src/lib.rs b/srml/finality-tracker/src/lib.rs index 1bf9754b0a..f00762fcdf 100644 --- a/srml/finality-tracker/src/lib.rs +++ b/srml/finality-tracker/src/lib.rs @@ -247,11 +247,12 @@ impl ProvideInherent for Module { mod tests { use super::*; - use runtime_io::{with_externalities, TestExternalities}; + use runtime_io::TestExternalities; use primitives::H256; - use sr_primitives::traits::{BlakeTwo256, IdentityLookup, OnFinalize, Header as HeaderT}; - use sr_primitives::testing::Header; - use sr_primitives::Perbill; + use sr_primitives::{ + set_and_run_with_externalities, testing::Header, Perbill, + traits::{BlakeTwo256, IdentityLookup, OnFinalize, Header as HeaderT}, + }; use support::{assert_ok, impl_outer_origin, parameter_types}; use srml_system as system; use std::cell::RefCell; @@ -321,7 +322,7 @@ mod tests { #[test] fn median_works() { let t = system::GenesisConfig::default().build_storage::().unwrap(); - with_externalities(&mut TestExternalities::new(t), || { + set_and_run_with_externalities(&mut TestExternalities::new(t), || { FinalityTracker::update_hint(Some(500)); assert_eq!(FinalityTracker::median(), 250); assert!(NOTIFICATIONS.with(|n| n.borrow().is_empty())); @@ -331,7 +332,7 @@ mod tests { #[test] fn notifies_when_stalled() { let t = system::GenesisConfig::default().build_storage::().unwrap(); - with_externalities(&mut TestExternalities::new(t), || { + set_and_run_with_externalities(&mut TestExternalities::new(t), || { let mut parent_hash = System::parent_hash(); for i in 2..106 { System::initialize(&i, &parent_hash, &Default::default(), &Default::default()); @@ -350,7 +351,7 @@ mod tests { #[test] fn recent_notifications_prevent_stalling() { let t = system::GenesisConfig::default().build_storage::().unwrap(); - with_externalities(&mut TestExternalities::new(t), || { + set_and_run_with_externalities(&mut TestExternalities::new(t), || { let mut parent_hash = System::parent_hash(); for i in 2..106 { System::initialize(&i, &parent_hash, &Default::default(), &Default::default()); diff --git a/srml/generic-asset/src/mock.rs b/srml/generic-asset/src/mock.rs index 7e47de0b36..c0f9f154b8 100644 --- a/srml/generic-asset/src/mock.rs +++ b/srml/generic-asset/src/mock.rs @@ -25,7 +25,7 @@ use sr_primitives::{ testing::Header, traits::{BlakeTwo256, IdentityLookup}, }; -use primitives::{Blake2Hasher, H256}; +use primitives::H256; use support::{parameter_types, impl_outer_event, impl_outer_origin}; use super::*; @@ -118,7 +118,7 @@ impl ExtBuilder { } // builds genesis config - pub fn build(self) -> runtime_io::TestExternalities { + pub fn build(self) -> runtime_io::TestExternalities { let mut t = system::GenesisConfig::default().build_storage::().unwrap(); GenesisConfig:: { @@ -137,7 +137,7 @@ impl ExtBuilder { // This function basically just builds a genesis storage key/value store according to // our desired mockup. -pub fn new_test_ext() -> runtime_io::TestExternalities { +pub fn new_test_ext() -> runtime_io::TestExternalities { system::GenesisConfig::default() .build_storage::() .unwrap() diff --git a/srml/generic-asset/src/tests.rs b/srml/generic-asset/src/tests.rs index 685e553c1c..90e5775828 100644 --- a/srml/generic-asset/src/tests.rs +++ b/srml/generic-asset/src/tests.rs @@ -22,14 +22,14 @@ use super::*; use crate::mock::{new_test_ext, ExtBuilder, GenericAsset, Origin, System, Test, TestEvent}; -use runtime_io::with_externalities; +use sr_primitives::set_and_run_with_externalities; use support::{assert_noop, assert_ok}; #[test] fn issuing_asset_units_to_issuer_should_work() { let balance = 100; - with_externalities(&mut ExtBuilder::default().free_balance((16000, 1, 100)).build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().free_balance((16000, 1, 100)).build(), || { let default_permission = PermissionLatest { update: Owner::Address(1), mint: Owner::Address(1), @@ -51,7 +51,7 @@ fn issuing_asset_units_to_issuer_should_work() { #[test] fn issuing_with_next_asset_id_overflow_should_not_work() { - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default().free_balance((16000, 1, 100000)).build(), || { NextAssetId::::put(u32::max_value()); @@ -79,7 +79,7 @@ fn issuing_with_next_asset_id_overflow_should_not_work() { fn querying_total_supply_should_work() { let asset_id = 1000; - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default().free_balance((16000, 1, 100000)).build(), || { let default_permission = PermissionLatest { @@ -127,7 +127,7 @@ fn querying_total_supply_should_work() { fn transferring_amount_should_work() { let asset_id = 1000; let free_balance = 100; - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default().free_balance((16000, 1, 100000)).build(), || { let default_permission = PermissionLatest { @@ -168,7 +168,7 @@ fn transferring_amount_should_work() { #[test] fn transferring_amount_should_fail_when_transferring_more_than_free_balance() { let asset_id = 1000; - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default().free_balance((16000, 1, 100000)).build(), || { let default_permission = PermissionLatest { @@ -195,7 +195,7 @@ fn transferring_amount_should_fail_when_transferring_more_than_free_balance() { fn transferring_less_than_one_unit_should_not_work() { let asset_id = 1000; - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default().free_balance((16000, 1, 100000)).build(), || { let default_permission = PermissionLatest { @@ -233,7 +233,7 @@ fn self_transfer_should_fail() { let asset_id = 1000; let balance = 100; - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default().free_balance((16000, 1, 100000)).build(), || { let default_permission = PermissionLatest { @@ -259,7 +259,7 @@ fn self_transfer_should_fail() { #[test] fn transferring_more_units_than_total_supply_should_not_work() { let asset_id = 1000; - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default().free_balance((16000, 1, 100000)).build(), || { let default_permission = PermissionLatest { @@ -286,7 +286,7 @@ fn transferring_more_units_than_total_supply_should_not_work() { // Ensures it uses fake money for staking asset id. #[test] fn staking_asset_id_should_return_0() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { assert_eq!(GenericAsset::staking_asset_id(), 16000); }); } @@ -294,7 +294,7 @@ fn staking_asset_id_should_return_0() { // Ensures it uses fake money for spending asset id. #[test] fn spending_asset_id_should_return_10() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { assert_eq!(GenericAsset::spending_asset_id(), 16001); }); } @@ -305,7 +305,7 @@ fn spending_asset_id_should_return_10() { // -Â total_balance should return 0 #[test] fn total_balance_should_be_zero() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { assert_eq!(GenericAsset::total_balance(&0, &0), 0); }); } @@ -323,7 +323,7 @@ fn total_balance_should_be_equal_to_account_balance() { mint: Owner::Address(1), burn: Owner::Address(1), }; - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default().free_balance((16000, 1, 100000)).build(), || { assert_ok!(GenericAsset::create( @@ -348,7 +348,7 @@ fn total_balance_should_be_equal_to_account_balance() { // -Â free_balance should return 50. #[test] fn free_balance_should_only_return_account_free_balance() { - with_externalities(&mut ExtBuilder::default().free_balance((1, 0, 50)).build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().free_balance((1, 0, 50)).build(), || { GenericAsset::set_reserved_balance(&1, &0, 70); assert_eq!(GenericAsset::free_balance(&1, &0), 50); }); @@ -363,7 +363,7 @@ fn free_balance_should_only_return_account_free_balance() { // -Â total_balance should equals to account balance + free balance. #[test] fn total_balance_should_be_equal_to_sum_of_account_balance_and_free_balance() { - with_externalities(&mut ExtBuilder::default().free_balance((1, 0, 50)).build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().free_balance((1, 0, 50)).build(), || { GenericAsset::set_reserved_balance(&1, &0, 70); assert_eq!(GenericAsset::total_balance(&1, &0), 120); }); @@ -378,7 +378,7 @@ fn total_balance_should_be_equal_to_sum_of_account_balance_and_free_balance() { // - reserved_balance should return 70. #[test] fn reserved_balance_should_only_return_account_reserved_balance() { - with_externalities(&mut ExtBuilder::default().free_balance((1, 0, 50)).build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().free_balance((1, 0, 50)).build(), || { GenericAsset::set_reserved_balance(&1, &0, 70); assert_eq!(GenericAsset::reserved_balance(&1, &0), 70); }); @@ -394,7 +394,7 @@ fn reserved_balance_should_only_return_account_reserved_balance() { // - reserved_balance = amount #[test] fn set_reserved_balance_should_add_balance_as_reserved() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { GenericAsset::set_reserved_balance(&1, &0, 50); assert_eq!(GenericAsset::reserved_balance(&1, &0), 50); }); @@ -410,7 +410,7 @@ fn set_reserved_balance_should_add_balance_as_reserved() { // - New free_balance should replace older free_balance. #[test] fn set_free_balance_should_add_amount_as_free_balance() { - with_externalities(&mut ExtBuilder::default().free_balance((1, 0, 100)).build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().free_balance((1, 0, 100)).build(), || { GenericAsset::set_free_balance(&1, &0, 50); assert_eq!(GenericAsset::free_balance(&1, &0), 50); }); @@ -429,7 +429,7 @@ fn set_free_balance_should_add_amount_as_free_balance() { // - new reserved_balance = original free balance + reserved amount #[test] fn reserve_should_moves_amount_from_balance_to_reserved_balance() { - with_externalities(&mut ExtBuilder::default().free_balance((1, 0, 100)).build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().free_balance((1, 0, 100)).build(), || { assert_ok!(GenericAsset::reserve(&1, &0, 70)); assert_eq!(GenericAsset::free_balance(&1, &0), 30); assert_eq!(GenericAsset::reserved_balance(&1, &0), 70); @@ -448,7 +448,7 @@ fn reserve_should_moves_amount_from_balance_to_reserved_balance() { // - Should throw an error. #[test] fn reserve_should_not_moves_amount_from_balance_to_reserved_balance() { - with_externalities(&mut ExtBuilder::default().free_balance((1, 0, 100)).build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().free_balance((1, 0, 100)).build(), || { assert_noop!(GenericAsset::reserve(&1, &0, 120), "not enough free funds"); assert_eq!(GenericAsset::free_balance(&1, &0), 100); assert_eq!(GenericAsset::reserved_balance(&1, &0), 0); @@ -466,7 +466,7 @@ fn reserve_should_not_moves_amount_from_balance_to_reserved_balance() { // - unreserved should return 20. #[test] fn unreserve_should_return_substratced_value_from_unreserved_amount_by_actual_acount_balance() { - with_externalities(&mut ExtBuilder::default().free_balance((1, 0, 100)).build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().free_balance((1, 0, 100)).build(), || { GenericAsset::set_reserved_balance(&1, &0, 100); assert_eq!(GenericAsset::unreserve(&1, &0, 120), 20); }); @@ -483,7 +483,7 @@ fn unreserve_should_return_substratced_value_from_unreserved_amount_by_actual_ac // - unreserved should return None. #[test] fn unreserve_should_return_none() { - with_externalities(&mut ExtBuilder::default().free_balance((1, 0, 100)).build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().free_balance((1, 0, 100)).build(), || { GenericAsset::set_reserved_balance(&1, &0, 100); assert_eq!(GenericAsset::unreserve(&1, &0, 50), 0); }); @@ -500,7 +500,7 @@ fn unreserve_should_return_none() { // - free_balance should be 200. #[test] fn unreserve_should_increase_free_balance_by_reserved_balance() { - with_externalities(&mut ExtBuilder::default().free_balance((1, 0, 100)).build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().free_balance((1, 0, 100)).build(), || { GenericAsset::set_reserved_balance(&1, &0, 100); GenericAsset::unreserve(&1, &0, 120); assert_eq!(GenericAsset::free_balance(&1, &0), 200); @@ -518,7 +518,7 @@ fn unreserve_should_increase_free_balance_by_reserved_balance() { // - reserved_balance should be 0. #[test] fn unreserve_should_deduct_reserved_balance_by_reserved_amount() { - with_externalities(&mut ExtBuilder::default().free_balance((1, 0, 100)).build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().free_balance((1, 0, 100)).build(), || { GenericAsset::set_free_balance(&1, &0, 100); GenericAsset::unreserve(&1, &0, 120); assert_eq!(GenericAsset::reserved_balance(&1, &0), 0); @@ -536,7 +536,7 @@ fn unreserve_should_deduct_reserved_balance_by_reserved_amount() { // - slash should return None. #[test] fn slash_should_return_slash_reserved_amount() { - with_externalities(&mut ExtBuilder::default().free_balance((1, 0, 100)).build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().free_balance((1, 0, 100)).build(), || { GenericAsset::set_reserved_balance(&1, &0, 100); assert_eq!(GenericAsset::slash(&1, &0, 70), None); }); @@ -550,7 +550,7 @@ fn slash_should_return_slash_reserved_amount() { // - Should return slashed_reserved - reserved_balance. #[test] fn slash_reserved_should_deducts_up_to_amount_from_reserved_balance() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { GenericAsset::set_reserved_balance(&1, &0, 100); assert_eq!(GenericAsset::slash_reserved(&1, &0, 150), Some(50)); }); @@ -564,7 +564,7 @@ fn slash_reserved_should_deducts_up_to_amount_from_reserved_balance() { // - Should return None. #[test] fn slash_reserved_should_return_none() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { GenericAsset::set_reserved_balance(&1, &0, 100); assert_eq!(GenericAsset::slash_reserved(&1, &0, 100), None); }); @@ -579,7 +579,7 @@ fn slash_reserved_should_return_none() { // - Should not return None. #[test] fn repatriate_reserved_return_amount_substracted_by_slash_amount() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { GenericAsset::set_reserved_balance(&1, &0, 100); assert_eq!(GenericAsset::repatriate_reserved(&1, &0, &1, 130), 30); }); @@ -594,7 +594,7 @@ fn repatriate_reserved_return_amount_substracted_by_slash_amount() { // - Should return None. #[test] fn repatriate_reserved_return_none() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { GenericAsset::set_reserved_balance(&1, &0, 100); assert_eq!(GenericAsset::repatriate_reserved(&1, &0, &1, 90), 0); }); @@ -608,7 +608,7 @@ fn repatriate_reserved_return_none() { // - Should create a new reserved asset. #[test] fn create_reserved_should_create_a_default_account_with_the_balance_given() { - with_externalities(&mut ExtBuilder::default().next_asset_id(10).build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().next_asset_id(10).build(), || { let default_permission = PermissionLatest { update: Owner::Address(1), mint: Owner::Address(1), @@ -643,7 +643,7 @@ fn create_reserved_should_create_a_default_account_with_the_balance_given() { // - Should throw a permission error #[test] fn mint_should_throw_permission_error() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { let origin = 1; let asset_id = 4; let to_account = 2; @@ -666,7 +666,7 @@ fn mint_should_throw_permission_error() { // - Should not change `origins` free_balance. #[test] fn mint_should_increase_asset() { - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default().free_balance((16000, 1, 100000)).build(), || { let origin = 1; @@ -707,7 +707,7 @@ fn mint_should_increase_asset() { // - Should throw a permission error. #[test] fn burn_should_throw_permission_error() { - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default().free_balance((16000, 1, 100000)).build(), || { let origin = 1; @@ -733,7 +733,7 @@ fn burn_should_throw_permission_error() { // - Should not change `origin`'s free_balance. #[test] fn burn_should_burn_an_asset() { - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default().free_balance((16000, 1, 100000)).build(), || { let origin = 1; @@ -779,7 +779,7 @@ fn burn_should_burn_an_asset() { // - The account origin should have burn, mint and update permissions. #[test] fn check_permission_should_return_correct_permission() { - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default().free_balance((16000, 1, 100000)).build(), || { let origin = 1; @@ -825,7 +825,7 @@ fn check_permission_should_return_correct_permission() { // - The account origin should not have burn, mint and update permissions. #[test] fn check_permission_should_return_false_for_no_permission() { - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default().free_balance((16000, 1, 100000)).build(), || { let origin = 1; @@ -871,7 +871,7 @@ fn check_permission_should_return_false_for_no_permission() { // - The account origin should have update and mint permissions. #[test] fn update_permission_should_change_permission() { - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default().free_balance((16000, 1, 100000)).build(), || { let origin = 1; @@ -923,7 +923,7 @@ fn update_permission_should_change_permission() { // - Should throw an error stating "Origin does not have enough permission to update permissions." #[test] fn update_permission_should_throw_error_when_lack_of_permissions() { - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default().free_balance((16000, 1, 100000)).build(), || { let origin = 1; @@ -974,7 +974,7 @@ fn update_permission_should_throw_error_when_lack_of_permissions() { // - Permissions must have burn, mint and updatePermission for the given asset_id. #[test] fn create_asset_works_with_given_asset_id_and_from_account() { - with_externalities(&mut ExtBuilder::default().next_asset_id(10).build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().next_asset_id(10).build(), || { let origin = 1; let from_account: Option<::AccountId> = Some(1); @@ -1011,7 +1011,7 @@ fn create_asset_works_with_given_asset_id_and_from_account() { // - `create_asset` should not work. #[test] fn create_asset_with_non_reserved_asset_id_should_not_work() { - with_externalities(&mut ExtBuilder::default().next_asset_id(10).build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().next_asset_id(10).build(), || { let origin = 1; let from_account: Option<::AccountId> = Some(1); @@ -1045,7 +1045,7 @@ fn create_asset_with_non_reserved_asset_id_should_not_work() { // - `create_asset` should not work. #[test] fn create_asset_with_a_taken_asset_id_should_not_work() { - with_externalities(&mut ExtBuilder::default().next_asset_id(10).build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().next_asset_id(10).build(), || { let origin = 1; let from_account: Option<::AccountId> = Some(1); @@ -1090,7 +1090,7 @@ fn create_asset_with_a_taken_asset_id_should_not_work() { // - Should create a reserved token. #[test] fn create_asset_should_create_a_reserved_asset_when_from_account_is_none() { - with_externalities(&mut ExtBuilder::default().next_asset_id(10).build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().next_asset_id(10).build(), || { let origin = 1; let from_account: Option<::AccountId> = None; @@ -1133,7 +1133,7 @@ fn create_asset_should_create_a_reserved_asset_when_from_account_is_none() { // - Should not create a `reserved_asset`. #[test] fn create_asset_should_create_a_user_asset() { - with_externalities(&mut ExtBuilder::default().next_asset_id(10).build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().next_asset_id(10).build(), || { let origin = 1; let from_account: Option<::AccountId> = None; @@ -1180,7 +1180,7 @@ fn update_permission_should_raise_event() { burn: Owner::Address(origin), }; - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default() .next_asset_id(asset_id) .free_balance((staking_asset_id, origin, initial_balance)) @@ -1223,7 +1223,7 @@ fn mint_should_raise_event() { let to = 2; let amount = 100; - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default() .next_asset_id(asset_id) .free_balance((staking_asset_id, origin, initial_balance)) @@ -1262,7 +1262,7 @@ fn burn_should_raise_event() { }; let amount = 100; - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default() .next_asset_id(asset_id) .free_balance((staking_asset_id, origin, initial_balance)) diff --git a/srml/grandpa/src/mock.rs b/srml/grandpa/src/mock.rs index af2fedf42f..8d585e4b46 100644 --- a/srml/grandpa/src/mock.rs +++ b/srml/grandpa/src/mock.rs @@ -21,7 +21,7 @@ use sr_primitives::{Perbill, DigestItem, traits::IdentityLookup, testing::{Header, UintAuthorityId}}; use runtime_io; use support::{impl_outer_origin, impl_outer_event, parameter_types}; -use primitives::{H256, Blake2Hasher}; +use primitives::H256; use codec::{Encode, Decode}; use crate::{AuthorityId, GenesisConfig, Trait, Module, ConsensusLog}; use substrate_finality_grandpa_primitives::GRANDPA_ENGINE_ID; @@ -82,7 +82,7 @@ pub fn to_authorities(vec: Vec<(u64, u64)>) -> Vec<(AuthorityId, u64)> { .collect() } -pub fn new_test_ext(authorities: Vec<(u64, u64)>) -> runtime_io::TestExternalities { +pub fn new_test_ext(authorities: Vec<(u64, u64)>) -> runtime_io::TestExternalities { let mut t = system::GenesisConfig::default().build_storage::().unwrap(); GenesisConfig { authorities: to_authorities(authorities), diff --git a/srml/grandpa/src/tests.rs b/srml/grandpa/src/tests.rs index 41229a5136..aec75d274c 100644 --- a/srml/grandpa/src/tests.rs +++ b/srml/grandpa/src/tests.rs @@ -18,9 +18,7 @@ #![cfg(test)] -use sr_primitives::testing::Digest; -use sr_primitives::traits::{Header, OnFinalize}; -use runtime_io::with_externalities; +use sr_primitives::{set_and_run_with_externalities, testing::Digest, traits::{Header, OnFinalize}}; use crate::mock::*; use system::{EventRecord, Phase}; use codec::{Decode, Encode}; @@ -29,7 +27,7 @@ use super::*; #[test] fn authorities_change_logged() { - with_externalities(&mut new_test_ext(vec![(1, 1), (2, 1), (3, 1)]), || { + set_and_run_with_externalities(&mut new_test_ext(vec![(1, 1), (2, 1), (3, 1)]), || { System::initialize(&1, &Default::default(), &Default::default(), &Default::default()); Grandpa::schedule_change(to_authorities(vec![(4, 1), (5, 1), (6, 1)]), 0, None).unwrap(); @@ -57,7 +55,7 @@ fn authorities_change_logged() { #[test] fn authorities_change_logged_after_delay() { - with_externalities(&mut new_test_ext(vec![(1, 1), (2, 1), (3, 1)]), || { + set_and_run_with_externalities(&mut new_test_ext(vec![(1, 1), (2, 1), (3, 1)]), || { System::initialize(&1, &Default::default(), &Default::default(), &Default::default()); Grandpa::schedule_change(to_authorities(vec![(4, 1), (5, 1), (6, 1)]), 1, None).unwrap(); Grandpa::on_finalize(1); @@ -90,7 +88,7 @@ fn authorities_change_logged_after_delay() { #[test] fn cannot_schedule_change_when_one_pending() { - with_externalities(&mut new_test_ext(vec![(1, 1), (2, 1), (3, 1)]), || { + set_and_run_with_externalities(&mut new_test_ext(vec![(1, 1), (2, 1), (3, 1)]), || { System::initialize(&1, &Default::default(), &Default::default(), &Default::default()); Grandpa::schedule_change(to_authorities(vec![(4, 1), (5, 1), (6, 1)]), 1, None).unwrap(); assert!(>::exists()); @@ -133,7 +131,7 @@ fn new_decodes_from_old() { #[test] fn dispatch_forced_change() { - with_externalities(&mut new_test_ext(vec![(1, 1), (2, 1), (3, 1)]), || { + set_and_run_with_externalities(&mut new_test_ext(vec![(1, 1), (2, 1), (3, 1)]), || { System::initialize(&1, &Default::default(), &Default::default(), &Default::default()); Grandpa::schedule_change( to_authorities(vec![(4, 1), (5, 1), (6, 1)]), @@ -205,7 +203,7 @@ fn dispatch_forced_change() { #[test] fn schedule_pause_only_when_live() { - with_externalities(&mut new_test_ext(vec![(1, 1), (2, 1), (3, 1)]), || { + set_and_run_with_externalities(&mut new_test_ext(vec![(1, 1), (2, 1), (3, 1)]), || { // we schedule a pause at block 1 with delay of 1 System::initialize(&1, &Default::default(), &Default::default(), &Default::default()); Grandpa::schedule_pause(1).unwrap(); @@ -240,7 +238,7 @@ fn schedule_pause_only_when_live() { #[test] fn schedule_resume_only_when_paused() { - with_externalities(&mut new_test_ext(vec![(1, 1), (2, 1), (3, 1)]), || { + set_and_run_with_externalities(&mut new_test_ext(vec![(1, 1), (2, 1), (3, 1)]), || { System::initialize(&1, &Default::default(), &Default::default(), &Default::default()); // the set is currently live, resuming it is an error diff --git a/srml/im-online/src/mock.rs b/srml/im-online/src/mock.rs index a7b669ddb8..c2869136dc 100644 --- a/srml/im-online/src/mock.rs +++ b/srml/im-online/src/mock.rs @@ -25,7 +25,7 @@ use sr_primitives::Perbill; use sr_staking_primitives::{SessionIndex, offence::ReportOffence}; use sr_primitives::testing::{Header, UintAuthorityId, TestXt}; use sr_primitives::traits::{IdentityLookup, BlakeTwo256, ConvertInto}; -use primitives::{H256, Blake2Hasher}; +use primitives::H256; use support::{impl_outer_origin, impl_outer_dispatch, parameter_types}; use {runtime_io, system}; @@ -85,7 +85,7 @@ impl ReportOffence for OffenceHandler { } } -pub fn new_test_ext() -> runtime_io::TestExternalities { +pub fn new_test_ext() -> runtime_io::TestExternalities { let t = system::GenesisConfig::default().build_storage::().unwrap(); t.into() } diff --git a/srml/im-online/src/tests.rs b/srml/im-online/src/tests.rs index c6405c34fa..d57b9f59cb 100644 --- a/srml/im-online/src/tests.rs +++ b/srml/im-online/src/tests.rs @@ -21,10 +21,9 @@ use super::*; use crate::mock::*; use offchain::testing::TestOffchainExt; -use primitives::offchain::OpaquePeerId; -use runtime_io::with_externalities; +use primitives::offchain::{OpaquePeerId, OffchainExt}; use support::{dispatch, assert_noop}; -use sr_primitives::testing::UintAuthorityId; +use sr_primitives::{set_and_run_with_externalities, testing::UintAuthorityId}; #[test] @@ -49,7 +48,7 @@ fn test_unresponsiveness_slash_fraction() { #[test] fn should_report_offline_validators() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { // given let block = 1; System::set_block_number(block); @@ -125,7 +124,7 @@ fn heartbeat( #[test] fn should_mark_online_validator_when_heartbeat_is_received() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { advance_session(); // given VALIDATORS.with(|l| *l.borrow_mut() = Some(vec![1, 2, 3, 4, 5, 6])); @@ -160,7 +159,7 @@ fn should_mark_online_validator_when_heartbeat_is_received() { #[test] fn late_heartbeat_should_fail() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { advance_session(); // given VALIDATORS.with(|l| *l.borrow_mut() = Some(vec![1, 2, 4, 4, 5, 6])); @@ -181,9 +180,9 @@ fn late_heartbeat_should_fail() { fn should_generate_heartbeats() { let mut ext = new_test_ext(); let (offchain, state) = TestOffchainExt::new(); - ext.set_offchain_externalities(offchain); + ext.register_extension(OffchainExt::new(offchain)); - with_externalities(&mut ext, || { + set_and_run_with_externalities(&mut ext, || { // given let block = 1; System::set_block_number(block); @@ -219,7 +218,7 @@ fn should_generate_heartbeats() { #[test] fn should_cleanup_received_heartbeats_on_session_end() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { advance_session(); VALIDATORS.with(|l| *l.borrow_mut() = Some(vec![1, 2, 3])); diff --git a/srml/indices/src/mock.rs b/srml/indices/src/mock.rs index 65a0193b5a..59d84279a9 100644 --- a/srml/indices/src/mock.rs +++ b/srml/indices/src/mock.rs @@ -22,7 +22,7 @@ use std::collections::HashSet; use ref_thread_local::{ref_thread_local, RefThreadLocal}; use sr_primitives::testing::Header; use sr_primitives::Perbill; -use primitives::{H256, Blake2Hasher}; +use primitives::H256; use support::{impl_outer_origin, parameter_types}; use {runtime_io, system}; use crate::{GenesisConfig, Module, Trait, IsDeadAccount, OnNewAccount, ResolveHint}; @@ -96,7 +96,7 @@ impl Trait for Runtime { type Event = (); } -pub fn new_test_ext() -> runtime_io::TestExternalities { +pub fn new_test_ext() -> runtime_io::TestExternalities { { let mut h = ALIVE.borrow_mut(); h.clear(); diff --git a/srml/indices/src/tests.rs b/srml/indices/src/tests.rs index 7b60e30527..4b8f1822b4 100644 --- a/srml/indices/src/tests.rs +++ b/srml/indices/src/tests.rs @@ -20,11 +20,11 @@ use super::*; use crate::mock::{Indices, new_test_ext, make_account, kill_account, TestIsDeadAccount}; -use runtime_io::with_externalities; +use sr_primitives::set_and_run_with_externalities; #[test] fn indexing_lookup_should_work() { - with_externalities( + set_and_run_with_externalities( &mut new_test_ext(), || { assert_eq!(Indices::lookup_index(0), Some(1)); @@ -38,7 +38,7 @@ fn indexing_lookup_should_work() { #[test] fn default_indexing_on_new_accounts_should_work() { - with_externalities( + set_and_run_with_externalities( &mut new_test_ext(), || { assert_eq!(Indices::lookup_index(4), None); @@ -50,7 +50,7 @@ fn default_indexing_on_new_accounts_should_work() { #[test] fn reclaim_indexing_on_new_accounts_should_work() { - with_externalities( + set_and_run_with_externalities( &mut new_test_ext(), || { assert_eq!(Indices::lookup_index(1), Some(2)); @@ -66,7 +66,7 @@ fn reclaim_indexing_on_new_accounts_should_work() { #[test] fn alive_account_should_prevent_reclaim() { - with_externalities( + set_and_run_with_externalities( &mut new_test_ext(), || { assert!(!TestIsDeadAccount::is_dead_account(&2)); diff --git a/srml/membership/src/lib.rs b/srml/membership/src/lib.rs index 87e9268bd9..1a6ca82986 100644 --- a/srml/membership/src/lib.rs +++ b/srml/membership/src/lib.rs @@ -193,12 +193,12 @@ mod tests { use std::cell::RefCell; use support::{assert_ok, assert_noop, impl_outer_origin, parameter_types}; - use runtime_io::with_externalities; - use primitives::{H256, Blake2Hasher}; + use primitives::H256; // The testing primitives are very useful for avoiding having to work with signatures // or public keys. `u64` is used as the `AccountId` and no `Signature`s are requried. use sr_primitives::{ - Perbill, traits::{BlakeTwo256, IdentityLookup}, testing::Header + Perbill, traits::{BlakeTwo256, IdentityLookup}, testing::Header, + set_and_run_with_externalities, }; use system::EnsureSignedBy; @@ -281,7 +281,7 @@ mod tests { // This function basically just builds a genesis storage key/value store according to // our desired mockup. - fn new_test_ext() -> runtime_io::TestExternalities { + fn new_test_ext() -> runtime_io::TestExternalities { let mut t = system::GenesisConfig::default().build_storage::().unwrap(); // We use default for brevity, but you can configure as desired if needed. GenesisConfig::{ @@ -293,7 +293,7 @@ mod tests { #[test] fn query_membership_works() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { assert_eq!(Membership::members(), vec![10, 20, 30]); assert_eq!(MEMBERS.with(|m| m.borrow().clone()), vec![10, 20, 30]); }); @@ -301,7 +301,7 @@ mod tests { #[test] fn add_member_works() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { assert_noop!(Membership::add_member(Origin::signed(5), 15), "bad origin"); assert_noop!(Membership::add_member(Origin::signed(1), 10), "already a member"); assert_ok!(Membership::add_member(Origin::signed(1), 15)); @@ -312,7 +312,7 @@ mod tests { #[test] fn remove_member_works() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { assert_noop!(Membership::remove_member(Origin::signed(5), 20), "bad origin"); assert_noop!(Membership::remove_member(Origin::signed(2), 15), "not a member"); assert_ok!(Membership::remove_member(Origin::signed(2), 20)); @@ -323,7 +323,7 @@ mod tests { #[test] fn swap_member_works() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { assert_noop!(Membership::swap_member(Origin::signed(5), 10, 25), "bad origin"); assert_noop!(Membership::swap_member(Origin::signed(3), 15, 25), "not a member"); assert_noop!(Membership::swap_member(Origin::signed(3), 10, 30), "already a member"); @@ -337,7 +337,7 @@ mod tests { #[test] fn reset_members_works() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { assert_noop!(Membership::reset_members(Origin::signed(1), vec![20, 40, 30]), "bad origin"); assert_ok!(Membership::reset_members(Origin::signed(4), vec![20, 40, 30])); assert_eq!(Membership::members(), vec![20, 30, 40]); diff --git a/srml/offences/src/mock.rs b/srml/offences/src/mock.rs index e7280c34e9..01891ce32b 100644 --- a/srml/offences/src/mock.rs +++ b/srml/offences/src/mock.rs @@ -28,7 +28,7 @@ use sr_staking_primitives::{ }; use sr_primitives::testing::Header; use sr_primitives::traits::{IdentityLookup, BlakeTwo256}; -use substrate_primitives::{H256, Blake2Hasher}; +use substrate_primitives::H256; use support::{impl_outer_origin, impl_outer_event, parameter_types, StorageMap, StorageDoubleMap}; use {runtime_io, system}; @@ -103,7 +103,7 @@ impl_outer_event! { } } -pub fn new_test_ext() -> runtime_io::TestExternalities { +pub fn new_test_ext() -> runtime_io::TestExternalities { let t = system::GenesisConfig::default().build_storage::().unwrap(); t.into() } diff --git a/srml/offences/src/tests.rs b/srml/offences/src/tests.rs index 17f933b8e8..7604533ba5 100644 --- a/srml/offences/src/tests.rs +++ b/srml/offences/src/tests.rs @@ -24,11 +24,11 @@ use crate::mock::{ offence_reports, }; use system::{EventRecord, Phase}; -use runtime_io::with_externalities; +use sr_primitives::set_and_run_with_externalities; #[test] fn should_report_an_authority_and_trigger_on_offence() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { // given let time_slot = 42; assert_eq!(offence_reports(KIND, time_slot), vec![]); @@ -51,7 +51,7 @@ fn should_report_an_authority_and_trigger_on_offence() { #[test] fn should_calculate_the_fraction_correctly() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { // given let time_slot = 42; assert_eq!(offence_reports(KIND, time_slot), vec![]); @@ -83,7 +83,7 @@ fn should_calculate_the_fraction_correctly() { #[test] fn should_not_report_the_same_authority_twice_in_the_same_slot() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { // given let time_slot = 42; assert_eq!(offence_reports(KIND, time_slot), vec![]); @@ -113,7 +113,7 @@ fn should_not_report_the_same_authority_twice_in_the_same_slot() { #[test] fn should_report_in_different_time_slot() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { // given let time_slot = 42; assert_eq!(offence_reports(KIND, time_slot), vec![]); @@ -143,7 +143,7 @@ fn should_report_in_different_time_slot() { #[test] fn should_deposit_event() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { // given let time_slot = 42; assert_eq!(offence_reports(KIND, time_slot), vec![]); @@ -171,7 +171,7 @@ fn should_deposit_event() { #[test] fn doesnt_deposit_event_for_dups() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { // given let time_slot = 42; assert_eq!(offence_reports(KIND, time_slot), vec![]); @@ -208,7 +208,7 @@ fn doesnt_deposit_event_for_dups() { fn should_properly_count_offences() { // We report two different authorities for the same issue. Ultimately, the 1st authority // should have `count` equal 2 and the count of the 2nd one should be equal to 1. - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { // given let time_slot = 42; assert_eq!(offence_reports(KIND, time_slot), vec![]); diff --git a/srml/randomness-collective-flip/src/lib.rs b/srml/randomness-collective-flip/src/lib.rs index 39dcf15ab4..e5110c5d21 100644 --- a/srml/randomness-collective-flip/src/lib.rs +++ b/srml/randomness-collective-flip/src/lib.rs @@ -161,10 +161,12 @@ impl Module { #[cfg(test)] mod tests { use super::*; - use primitives::{H256, Blake2Hasher}; - use sr_primitives::{Perbill, traits::{BlakeTwo256, OnInitialize, Header as _, IdentityLookup}, testing::Header}; + use primitives::H256; + use sr_primitives::{ + Perbill, traits::{BlakeTwo256, OnInitialize, Header as _, IdentityLookup}, testing::Header, + set_and_run_with_externalities, + }; use support::{impl_outer_origin, parameter_types}; - use runtime_io::with_externalities; #[derive(Clone, PartialEq, Eq)] pub struct Test; @@ -202,7 +204,7 @@ mod tests { type System = system::Module; type Randomness = Module; - fn new_test_ext() -> runtime_io::TestExternalities { + fn new_test_ext() -> runtime_io::TestExternalities { let t = system::GenesisConfig::default().build_storage::().unwrap(); t.into() } @@ -229,7 +231,7 @@ mod tests { #[test] fn test_random_material_parital() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { let genesis_hash = System::parent_hash(); setup_blocks(38); @@ -243,7 +245,7 @@ mod tests { #[test] fn test_random_material_filled() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { let genesis_hash = System::parent_hash(); setup_blocks(81); @@ -258,7 +260,7 @@ mod tests { #[test] fn test_random_material_filled_twice() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { let genesis_hash = System::parent_hash(); setup_blocks(162); @@ -273,7 +275,7 @@ mod tests { #[test] fn test_random() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { setup_blocks(162); assert_eq!(System::block_number(), 162); diff --git a/srml/scored-pool/src/mock.rs b/srml/scored-pool/src/mock.rs index fd14abd617..92a16bf25d 100644 --- a/srml/scored-pool/src/mock.rs +++ b/srml/scored-pool/src/mock.rs @@ -20,7 +20,7 @@ use super::*; use std::cell::RefCell; use support::{impl_outer_origin, parameter_types}; -use primitives::{H256, Blake2Hasher}; +use primitives::H256; // The testing primitives are very useful for avoiding having to work with signatures // or public keys. `u64` is used as the `AccountId` and no `Signature`s are requried. use sr_primitives::{ @@ -132,7 +132,7 @@ impl Trait for Test { // This function basically just builds a genesis storage key/value store according to // our desired mockup. -pub fn new_test_ext() -> runtime_io::TestExternalities { +pub fn new_test_ext() -> runtime_io::TestExternalities { let mut t = system::GenesisConfig::default().build_storage::().unwrap(); // We use default for brevity, but you can configure as desired if needed. balances::GenesisConfig:: { diff --git a/srml/scored-pool/src/tests.rs b/srml/scored-pool/src/tests.rs index 740e707ce0..cd3efb0ceb 100644 --- a/srml/scored-pool/src/tests.rs +++ b/srml/scored-pool/src/tests.rs @@ -20,8 +20,7 @@ use super::*; use mock::*; use support::{assert_ok, assert_noop}; -use runtime_io::with_externalities; -use sr_primitives::traits::OnInitialize; +use sr_primitives::{set_and_run_with_externalities, traits::OnInitialize}; type ScoredPool = Module; type System = system::Module; @@ -32,7 +31,7 @@ const INDEX_ERR: &str = "index does not match requested account"; #[test] fn query_membership_works() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { assert_eq!(ScoredPool::members(), vec![20, 40]); assert_eq!(Balances::reserved_balance(&31), CandidateDeposit::get()); assert_eq!(Balances::reserved_balance(&40), CandidateDeposit::get()); @@ -42,7 +41,7 @@ fn query_membership_works() { #[test] fn submit_candidacy_must_not_work() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { assert_noop!( ScoredPool::submit_candidacy(Origin::signed(99)), "balance too low to submit candidacy" @@ -56,7 +55,7 @@ fn submit_candidacy_must_not_work() { #[test] fn submit_candidacy_works() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { // given let who = 15; @@ -71,7 +70,7 @@ fn submit_candidacy_works() { #[test] fn scoring_works() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { // given let who = 15; let score = 99; @@ -89,7 +88,7 @@ fn scoring_works() { #[test] fn scoring_same_element_with_same_score_works() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { // given let who = 31; let index = find_in_pool(who).expect("entity must be in pool") as u32; @@ -109,7 +108,7 @@ fn scoring_same_element_with_same_score_works() { #[test] fn kicking_works_only_for_authorized() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { let who = 40; let index = find_in_pool(who).expect("entity must be in pool") as u32; assert_noop!(ScoredPool::kick(Origin::signed(99), who, index), "bad origin"); @@ -118,7 +117,7 @@ fn kicking_works_only_for_authorized() { #[test] fn kicking_works() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { // given let who = 40; assert_eq!(Balances::reserved_balance(&who), CandidateDeposit::get()); @@ -138,7 +137,7 @@ fn kicking_works() { #[test] fn unscored_entities_must_not_be_used_for_filling_members() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { // given // we submit a candidacy, score will be `None` assert_ok!(ScoredPool::submit_candidacy(Origin::signed(15))); @@ -163,7 +162,7 @@ fn unscored_entities_must_not_be_used_for_filling_members() { #[test] fn refreshing_works() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { // given let who = 15; assert_ok!(ScoredPool::submit_candidacy(Origin::signed(who))); @@ -181,7 +180,7 @@ fn refreshing_works() { #[test] fn refreshing_happens_every_period() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { // given System::set_block_number(1); assert_ok!(ScoredPool::submit_candidacy(Origin::signed(15))); @@ -201,7 +200,7 @@ fn refreshing_happens_every_period() { #[test] fn withdraw_candidacy_must_only_work_for_members() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { let who = 77; let index = 0; assert_noop!( ScoredPool::withdraw_candidacy(Origin::signed(who), index), INDEX_ERR); @@ -210,7 +209,7 @@ fn withdraw_candidacy_must_only_work_for_members() { #[test] fn oob_index_should_abort() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { let who = 40; let oob_index = ScoredPool::pool().len() as u32; assert_noop!(ScoredPool::withdraw_candidacy(Origin::signed(who), oob_index), OOB_ERR); @@ -221,7 +220,7 @@ fn oob_index_should_abort() { #[test] fn index_mismatches_should_abort() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { let who = 40; let index = 3; assert_noop!(ScoredPool::withdraw_candidacy(Origin::signed(who), index), INDEX_ERR); @@ -232,7 +231,7 @@ fn index_mismatches_should_abort() { #[test] fn withdraw_unscored_candidacy_must_work() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { // given let who = 5; @@ -247,7 +246,7 @@ fn withdraw_unscored_candidacy_must_work() { #[test] fn withdraw_scored_candidacy_must_work() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { // given let who = 40; assert_eq!(Balances::reserved_balance(&who), CandidateDeposit::get()); @@ -265,7 +264,7 @@ fn withdraw_scored_candidacy_must_work() { #[test] fn candidacy_resubmitting_works() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { // given let who = 15; diff --git a/srml/session/src/historical.rs b/srml/session/src/historical.rs index 24821a0393..af9447eb7e 100644 --- a/srml/session/src/historical.rs +++ b/srml/session/src/historical.rs @@ -312,9 +312,10 @@ impl> support::traits::KeyOwnerProofSystem<(KeyTypeId, #[cfg(test)] mod tests { use super::*; - use runtime_io::with_externalities; - use primitives::{Blake2Hasher, crypto::key_types::DUMMY}; - use sr_primitives::{traits::OnInitialize, testing::UintAuthorityId}; + use primitives::crypto::key_types::DUMMY; + use sr_primitives::{ + traits::OnInitialize, testing::UintAuthorityId, set_and_run_with_externalities, + }; use crate::mock::{ NEXT_VALIDATORS, force_new_session, set_next_validators, Test, System, Session, @@ -323,7 +324,7 @@ mod tests { type Historical = Module; - fn new_test_ext() -> runtime_io::TestExternalities { + fn new_test_ext() -> runtime_io::TestExternalities { let mut t = system::GenesisConfig::default().build_storage::().unwrap(); crate::GenesisConfig:: { keys: NEXT_VALIDATORS.with(|l| @@ -335,7 +336,7 @@ mod tests { #[test] fn generated_proof_is_good() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { set_next_validators(vec![1, 2]); force_new_session(); @@ -376,7 +377,7 @@ mod tests { #[test] fn prune_up_to_works() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { for i in 1..101u64 { set_next_validators(vec![i]); force_new_session(); diff --git a/srml/session/src/lib.rs b/srml/session/src/lib.rs index 208be4664a..df311f5081 100644 --- a/srml/session/src/lib.rs +++ b/srml/session/src/lib.rs @@ -680,11 +680,9 @@ impl> FindAuthor mod tests { use super::*; use support::assert_ok; - use runtime_io::with_externalities; - use primitives::{Blake2Hasher, crypto::key_types::DUMMY}; + use primitives::crypto::key_types::DUMMY; use sr_primitives::{ - traits::OnInitialize, - testing::UintAuthorityId, + traits::OnInitialize, set_and_run_with_externalities, testing::UintAuthorityId, }; use mock::{ NEXT_VALIDATORS, SESSION_CHANGED, TEST_SESSION_CHANGED, authorities, force_new_session, @@ -692,7 +690,7 @@ mod tests { reset_before_session_end_called, before_session_end_called, }; - fn new_test_ext() -> runtime_io::TestExternalities { + fn new_test_ext() -> runtime_io::TestExternalities { let mut t = system::GenesisConfig::default().build_storage::().unwrap(); GenesisConfig:: { keys: NEXT_VALIDATORS.with(|l| @@ -710,7 +708,7 @@ mod tests { #[test] fn simple_setup_should_work() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { assert_eq!(authorities(), vec![UintAuthorityId(1), UintAuthorityId(2), UintAuthorityId(3)]); assert_eq!(Session::validators(), vec![1, 2, 3]); }); @@ -718,7 +716,7 @@ mod tests { #[test] fn put_get_keys() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { Session::put_keys(&10, &UintAuthorityId(10).into()); assert_eq!(Session::load_keys(&10), Some(UintAuthorityId(10).into())); }) @@ -727,7 +725,7 @@ mod tests { #[test] fn keys_cleared_on_kill() { let mut ext = new_test_ext(); - with_externalities(&mut ext, || { + set_and_run_with_externalities(&mut ext, || { assert_eq!(Session::validators(), vec![1, 2, 3]); assert_eq!(Session::load_keys(&1), Some(UintAuthorityId(1).into())); @@ -744,7 +742,7 @@ mod tests { fn authorities_should_track_validators() { reset_before_session_end_called(); - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { set_next_validators(vec![1, 2]); force_new_session(); initialize_block(1); @@ -795,7 +793,7 @@ mod tests { #[test] fn should_work_with_early_exit() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { set_session_length(10); initialize_block(1); @@ -818,7 +816,7 @@ mod tests { #[test] fn session_change_should_work() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { // Block 1: No change initialize_block(1); assert_eq!(authorities(), vec![UintAuthorityId(1), UintAuthorityId(2), UintAuthorityId(3)]); @@ -848,7 +846,7 @@ mod tests { #[test] fn duplicates_are_not_allowed() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { System::set_block_number(1); Session::on_initialize(1); assert!(Session::set_keys(Origin::signed(4), UintAuthorityId(1).into(), vec![]).is_err()); @@ -863,7 +861,7 @@ mod tests { fn session_changed_flag_works() { reset_before_session_end_called(); - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { TEST_SESSION_CHANGED.with(|l| *l.borrow_mut() = true); force_new_session(); @@ -952,7 +950,7 @@ mod tests { #[test] fn session_keys_generate_output_works_as_set_keys_input() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { let new_keys = mock::MockSessionKeys::generate(None); assert_ok!( Session::set_keys( @@ -966,7 +964,7 @@ mod tests { #[test] fn return_true_if_more_than_third_is_disabled() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { set_next_validators(vec![1, 2, 3, 4, 5, 6, 7]); force_new_session(); initialize_block(1); diff --git a/srml/staking/src/mock.rs b/srml/staking/src/mock.rs index d8d3656142..9055d7db87 100644 --- a/srml/staking/src/mock.rs +++ b/srml/staking/src/mock.rs @@ -22,7 +22,7 @@ use sr_primitives::curve::PiecewiseLinear; use sr_primitives::traits::{IdentityLookup, Convert, OpaqueKeys, OnInitialize, SaturatedConversion}; use sr_primitives::testing::{Header, UintAuthorityId}; use sr_staking_primitives::SessionIndex; -use primitives::{H256, Blake2Hasher}; +use primitives::H256; use runtime_io; use support::{assert_ok, impl_outer_origin, parameter_types, StorageLinkedMap}; use support::traits::{Currency, Get, FindAuthor}; @@ -274,7 +274,7 @@ impl ExtBuilder { pub fn set_associated_consts(&self) { EXISTENTIAL_DEPOSIT.with(|v| *v.borrow_mut() = self.existential_deposit); } - pub fn build(self) -> runtime_io::TestExternalities { + pub fn build(self) -> runtime_io::TestExternalities { self.set_associated_consts(); let mut storage = system::GenesisConfig::default().build_storage::().unwrap(); let balance_factor = if self.existential_deposit > 0 { @@ -341,7 +341,7 @@ impl ExtBuilder { }.assimilate_storage(&mut storage); let mut ext = storage.into(); - runtime_io::with_externalities(&mut ext, || { + sr_primitives::set_and_run_with_externalities(&mut ext, || { let validators = Session::validators(); SESSION.with(|x| *x.borrow_mut() = (validators.clone(), HashSet::new()) diff --git a/srml/staking/src/tests.rs b/srml/staking/src/tests.rs index 6b51fb9b3f..48218f9eb7 100644 --- a/srml/staking/src/tests.rs +++ b/srml/staking/src/tests.rs @@ -18,16 +18,14 @@ use super::*; use mock::*; -use runtime_io::with_externalities; -use sr_primitives::{assert_eq_error_rate, traits::OnInitialize}; +use sr_primitives::{assert_eq_error_rate, traits::OnInitialize, set_and_run_with_externalities}; use sr_staking_primitives::offence::{OffenceDetails, OnOffenceHandler}; -use support::{assert_ok, assert_noop, assert_eq_uvec}; -use support::traits::{Currency, ReservableCurrency}; +use support::{assert_ok, assert_noop, assert_eq_uvec, traits::{Currency, ReservableCurrency}}; #[test] fn basic_setup_works() { // Verifies initial conditions of mock - with_externalities(&mut ExtBuilder::default() + set_and_run_with_externalities(&mut ExtBuilder::default() .build(), || { // Account 11 is stashed and locked, and account 10 is the controller @@ -109,7 +107,7 @@ fn basic_setup_works() { #[test] fn change_controller_works() { - with_externalities(&mut ExtBuilder::default().build(), + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { assert_eq!(Staking::bonded(&11), Some(10)); @@ -136,7 +134,7 @@ fn rewards_should_work() { // * rewards get recorded per session // * rewards get paid per Era // * Check that nominators are also rewarded - with_externalities(&mut ExtBuilder::default() + set_and_run_with_externalities(&mut ExtBuilder::default() .nominate(false) .build(), || { @@ -217,7 +215,7 @@ fn multi_era_reward_should_work() { // Should check that: // The value of current_session_reward is set at the end of each era, based on // slot_stake and session_reward. - with_externalities(&mut ExtBuilder::default() + set_and_run_with_externalities(&mut ExtBuilder::default() .nominate(false) .build(), || { @@ -260,7 +258,7 @@ fn staking_should_work() { // * new validators can be added to the default set // * new ones will be chosen per era // * either one can unlock the stash and back-down from being a validator via `chill`ing. - with_externalities(&mut ExtBuilder::default() + set_and_run_with_externalities(&mut ExtBuilder::default() .nominate(false) .fair(false) // to give 20 more staked value .build(), @@ -322,7 +320,7 @@ fn staking_should_work() { #[test] fn less_than_needed_candidates_works() { - with_externalities(&mut ExtBuilder::default() + set_and_run_with_externalities(&mut ExtBuilder::default() .minimum_validator_count(1) .validator_count(4) .nominate(false) @@ -349,7 +347,7 @@ fn less_than_needed_candidates_works() { #[test] fn no_candidate_emergency_condition() { - with_externalities(&mut ExtBuilder::default() + set_and_run_with_externalities(&mut ExtBuilder::default() .minimum_validator_count(10) .validator_count(15) .num_validators(4) @@ -415,7 +413,7 @@ fn nominating_and_rewards_should_work() { // 10 with stake 400.0 20 with stake 600.0 30 with stake 0 // 4 has load 0.0005555555555555556 and supported // 10 with stake 600.0 20 with stake 400.0 40 with stake 0.0 - with_externalities(&mut ExtBuilder::default() + set_and_run_with_externalities(&mut ExtBuilder::default() .nominate(false) .validator_pool(true) .build(), @@ -599,7 +597,7 @@ fn nominators_also_get_slashed() { // 10 - is the controller of 11 // 11 - is the stash. // 2 - is the nominator of 20, 10 - with_externalities(&mut ExtBuilder::default().nominate(false).build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().nominate(false).build(), || { assert_eq!(Staking::validator_count(), 2); // Set payee to controller @@ -659,7 +657,7 @@ fn double_staking_should_fail() { // * an account already bonded as stash cannot be be stashed again. // * an account already bonded as stash cannot nominate. // * an account already bonded as controller can nominate. - with_externalities(&mut ExtBuilder::default() + set_and_run_with_externalities(&mut ExtBuilder::default() .build(), || { let arbitrary_value = 5; @@ -684,7 +682,7 @@ fn double_staking_should_fail() { fn double_controlling_should_fail() { // should test (in the same order): // * an account already bonded as controller CANNOT be reused as the controller of another account. - with_externalities(&mut ExtBuilder::default() + set_and_run_with_externalities(&mut ExtBuilder::default() .build(), || { let arbitrary_value = 5; @@ -703,7 +701,7 @@ fn double_controlling_should_fail() { #[test] fn session_and_eras_work() { - with_externalities(&mut ExtBuilder::default() + set_and_run_with_externalities(&mut ExtBuilder::default() .build(), || { assert_eq!(Staking::current_era(), 0); @@ -747,7 +745,7 @@ fn session_and_eras_work() { #[test] fn forcing_new_era_works() { - with_externalities(&mut ExtBuilder::default().build(),|| { + set_and_run_with_externalities(&mut ExtBuilder::default().build(),|| { // normal flow of session. assert_eq!(Staking::current_era(), 0); start_session(0); @@ -786,7 +784,7 @@ fn forcing_new_era_works() { #[test] fn cannot_transfer_staked_balance() { // Tests that a stash account cannot transfer funds - with_externalities(&mut ExtBuilder::default().nominate(false).build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().nominate(false).build(), || { // Confirm account 11 is stashed assert_eq!(Staking::bonded(&11), Some(10)); // Confirm account 11 has some free balance @@ -811,7 +809,7 @@ fn cannot_transfer_staked_balance_2() { // Tests that a stash account cannot transfer funds // Same test as above but with 20, and more accurate. // 21 has 2000 free balance but 1000 at stake - with_externalities(&mut ExtBuilder::default() + set_and_run_with_externalities(&mut ExtBuilder::default() .nominate(false) .fair(true) .build(), @@ -834,7 +832,7 @@ fn cannot_transfer_staked_balance_2() { #[test] fn cannot_reserve_staked_balance() { // Checks that a bonded account cannot reserve balance from free balance - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { // Confirm account 11 is stashed assert_eq!(Staking::bonded(&11), Some(10)); // Confirm account 11 has some free balance @@ -854,7 +852,7 @@ fn cannot_reserve_staked_balance() { #[test] fn reward_destination_works() { // Rewards go to the correct destination as determined in Payee - with_externalities(&mut ExtBuilder::default().nominate(false).build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().nominate(false).build(), || { // Check that account 11 is a validator assert!(Staking::current_elected().contains(&11)); // Check the balance of the validator account @@ -946,7 +944,7 @@ fn validator_payment_prefs_work() { // Test that validator preferences are correctly honored // Note: unstake threshold is being directly tested in slashing tests. // This test will focus on validator payment. - with_externalities(&mut ExtBuilder::default() + set_and_run_with_externalities(&mut ExtBuilder::default() .build(), || { // Initial config @@ -998,7 +996,7 @@ fn bond_extra_works() { // Tests that extra `free_balance` in the stash can be added to stake // NOTE: this tests only verifies `StakingLedger` for correct updates // See `bond_extra_and_withdraw_unbonded_works` for more details and updates on `Exposure`. - with_externalities(&mut ExtBuilder::default().build(), + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { // Check that account 10 is a validator assert!(>::exists(11)); @@ -1044,7 +1042,7 @@ fn bond_extra_and_withdraw_unbonded_works() { // * It can add extra funds to the bonded account. // * it can unbond a portion of its funds from the stash account. // * Once the unbonding period is done, it can actually take the funds out of the stash. - with_externalities(&mut ExtBuilder::default() + set_and_run_with_externalities(&mut ExtBuilder::default() .nominate(false) .build(), || { @@ -1131,7 +1129,7 @@ fn bond_extra_and_withdraw_unbonded_works() { #[test] fn too_many_unbond_calls_should_not_work() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { // locked at era 0 until 3 for _ in 0..MAX_UNLOCKING_CHUNKS-1 { assert_ok!(Staking::unbond(Origin::signed(10), 1)); @@ -1160,7 +1158,7 @@ fn too_many_unbond_calls_should_not_work() { fn slot_stake_is_least_staked_validator_and_exposure_defines_maximum_punishment() { // Test that slot_stake is determined by the least staked validator // Test that slot_stake is the maximum punishment that can happen to a validator - with_externalities(&mut ExtBuilder::default() + set_and_run_with_externalities(&mut ExtBuilder::default() .nominate(false) .fair(false) .build(), @@ -1213,7 +1211,7 @@ fn slot_stake_is_least_staked_validator_and_exposure_defines_maximum_punishment( fn on_free_balance_zero_stash_removes_validator() { // Tests that validator storage items are cleaned up when stash is empty // Tests that storage items are untouched when controller is empty - with_externalities(&mut ExtBuilder::default() + set_and_run_with_externalities(&mut ExtBuilder::default() .existential_deposit(10) .build(), || { @@ -1266,7 +1264,7 @@ fn on_free_balance_zero_stash_removes_validator() { fn on_free_balance_zero_stash_removes_nominator() { // Tests that nominator storage items are cleaned up when stash is empty // Tests that storage items are untouched when controller is empty - with_externalities(&mut ExtBuilder::default() + set_and_run_with_externalities(&mut ExtBuilder::default() .existential_deposit(10) .build(), || { @@ -1322,7 +1320,7 @@ fn on_free_balance_zero_stash_removes_nominator() { #[test] fn switching_roles() { // Test that it should be possible to switch between roles (nominator, validator, idle) with minimal overhead. - with_externalities(&mut ExtBuilder::default() + set_and_run_with_externalities(&mut ExtBuilder::default() .nominate(false) .build(), || { @@ -1391,7 +1389,7 @@ fn switching_roles() { #[test] fn wrong_vote_is_null() { - with_externalities(&mut ExtBuilder::default() + set_and_run_with_externalities(&mut ExtBuilder::default() .nominate(false) .validator_pool(true) .build(), @@ -1419,7 +1417,7 @@ fn wrong_vote_is_null() { fn bond_with_no_staked_value() { // Behavior when someone bonds with no staked value. // Particularly when she votes and the candidate is elected. - with_externalities(&mut ExtBuilder::default() + set_and_run_with_externalities(&mut ExtBuilder::default() .validator_count(3) .existential_deposit(5) .nominate(false) @@ -1467,7 +1465,7 @@ fn bond_with_no_staked_value() { fn bond_with_little_staked_value_bounded_by_slot_stake() { // Behavior when someone bonds with little staked value. // Particularly when she votes and the candidate is elected. - with_externalities(&mut ExtBuilder::default() + set_and_run_with_externalities(&mut ExtBuilder::default() .validator_count(3) .nominate(false) .minimum_validator_count(1) @@ -1517,7 +1515,7 @@ fn bond_with_little_staked_value_bounded_by_slot_stake() { #[cfg(feature = "equalize")] #[test] fn phragmen_linear_worse_case_equalize() { - with_externalities(&mut ExtBuilder::default() + set_and_run_with_externalities(&mut ExtBuilder::default() .nominate(false) .validator_pool(true) .fair(true) @@ -1562,7 +1560,7 @@ fn phragmen_linear_worse_case_equalize() { #[test] fn new_era_elects_correct_number_of_validators() { - with_externalities(&mut ExtBuilder::default() + set_and_run_with_externalities(&mut ExtBuilder::default() .nominate(true) .validator_pool(true) .fair(true) @@ -1583,7 +1581,7 @@ fn new_era_elects_correct_number_of_validators() { #[test] fn phragmen_should_not_overflow_validators() { - with_externalities(&mut ExtBuilder::default() + set_and_run_with_externalities(&mut ExtBuilder::default() .nominate(false) .build(), || { @@ -1609,7 +1607,7 @@ fn phragmen_should_not_overflow_validators() { #[test] fn phragmen_should_not_overflow_nominators() { - with_externalities(&mut ExtBuilder::default() + set_and_run_with_externalities(&mut ExtBuilder::default() .nominate(false) .build(), || { @@ -1634,7 +1632,7 @@ fn phragmen_should_not_overflow_nominators() { #[test] fn phragmen_should_not_overflow_ultimate() { - with_externalities(&mut ExtBuilder::default() + set_and_run_with_externalities(&mut ExtBuilder::default() .nominate(false) .build(), || { @@ -1656,7 +1654,7 @@ fn phragmen_should_not_overflow_ultimate() { #[test] fn reward_validator_slashing_validator_doesnt_overflow() { - with_externalities(&mut ExtBuilder::default() + set_and_run_with_externalities(&mut ExtBuilder::default() .build(), || { let stake = u32::max_value() as u64 * 2; @@ -1689,7 +1687,7 @@ fn reward_validator_slashing_validator_doesnt_overflow() { #[test] fn reward_from_authorship_event_handler_works() { - with_externalities(&mut ExtBuilder::default() + set_and_run_with_externalities(&mut ExtBuilder::default() .build(), || { use authorship::EventHandler; @@ -1716,7 +1714,7 @@ fn reward_from_authorship_event_handler_works() { #[test] fn add_reward_points_fns_works() { - with_externalities(&mut ExtBuilder::default() + set_and_run_with_externalities(&mut ExtBuilder::default() .build(), || { let validators = >::current_elected(); @@ -1744,7 +1742,7 @@ fn add_reward_points_fns_works() { #[test] fn unbonded_balance_is_not_slashable() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { // total amount staked is slashable. assert_eq!(Staking::slashable_balance_of(&11), 1000); @@ -1759,7 +1757,7 @@ fn unbonded_balance_is_not_slashable() { fn era_is_always_same_length() { // This ensures that the sessions is always of the same length if there is no forcing no // session changes. - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { start_era(1); assert_eq!(Staking::current_era_start_session_index(), SessionsPerEra::get()); @@ -1779,7 +1777,7 @@ fn era_is_always_same_length() { #[test] fn offence_forces_new_era() { - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { Staking::on_offence( &[OffenceDetails { offender: ( @@ -1799,7 +1797,7 @@ fn offence_forces_new_era() { fn slashing_performed_according_exposure() { // This test checks that slashing is performed according the exposure (or more precisely, // historical exposure), not the current balance. - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { assert_eq!(Staking::stakers(&11).own, 1000); // Handle an offence with a historical exposure. @@ -1827,7 +1825,7 @@ fn slashing_performed_according_exposure() { fn reporters_receive_their_slice() { // This test verifies that the reporters of the offence receive their slice from the slashed // amount. - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { // The reporters' reward is calculated from the total exposure. #[cfg(feature = "equalize")] let initial_balance = 1250; @@ -1857,7 +1855,7 @@ fn reporters_receive_their_slice() { #[test] fn invulnerables_are_not_slashed() { // For invulnerable validators no slashing is performed. - with_externalities( + set_and_run_with_externalities( &mut ExtBuilder::default().invulnerables(vec![11]).build(), || { #[cfg(feature = "equalize")] @@ -1894,7 +1892,7 @@ fn invulnerables_are_not_slashed() { #[test] fn dont_slash_if_fraction_is_zero() { // Don't slash if the fraction is zero. - with_externalities(&mut ExtBuilder::default().build(), || { + set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { assert_eq!(Balances::free_balance(&11), 1000); Staking::on_offence( diff --git a/srml/support/src/lib.rs b/srml/support/src/lib.rs index b88d86761c..675e5b6ea8 100644 --- a/srml/support/src/lib.rs +++ b/srml/support/src/lib.rs @@ -236,13 +236,12 @@ pub use serde::{Serialize, Deserialize}; mod tests { use super::*; use codec::{Codec, EncodeLike}; - use runtime_io::with_externalities; - use primitives::Blake2Hasher; - pub use srml_metadata::{ + use sr_primitives::set_and_run_with_externalities; + use srml_metadata::{ DecodeDifferent, StorageEntryMetadata, StorageMetadata, StorageEntryType, - StorageEntryModifier, DefaultByte, DefaultByteGetter, StorageHasher + StorageEntryModifier, DefaultByteGetter, StorageHasher, }; - pub use rstd::marker::PhantomData; + use rstd::marker::PhantomData; pub trait Trait { type BlockNumber: Codec + EncodeLike + Default; @@ -281,7 +280,7 @@ mod tests { type Origin = u32; } - fn new_test_ext() -> runtime_io::TestExternalities { + fn new_test_ext() -> runtime_io::TestExternalities { GenesisConfig::default().build_storage().unwrap().into() } @@ -289,7 +288,7 @@ mod tests { #[test] fn linked_map_issue_3318() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { OptionLinkedMap::insert(1, 1); assert_eq!(OptionLinkedMap::get(1), Some(1)); OptionLinkedMap::insert(1, 2); @@ -299,7 +298,7 @@ mod tests { #[test] fn linked_map_swap_works() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { OptionLinkedMap::insert(0, 0); OptionLinkedMap::insert(1, 1); OptionLinkedMap::insert(2, 2); @@ -328,7 +327,7 @@ mod tests { #[test] fn linked_map_basic_insert_remove_should_work() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { // initialized during genesis assert_eq!(Map::get(&15u32), 42u64); @@ -354,7 +353,7 @@ mod tests { #[test] fn linked_map_enumeration_and_head_should_work() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { assert_eq!(Map::head(), Some(15)); assert_eq!(Map::enumerate().collect::>(), vec![(15, 42)]); // insert / remove @@ -406,7 +405,7 @@ mod tests { #[test] fn double_map_basic_insert_remove_remove_prefix_should_work() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { type DoubleMap = DataDM; // initialized during genesis assert_eq!(DoubleMap::get(&15u32, &16u32), 42u64); @@ -446,7 +445,7 @@ mod tests { #[test] fn double_map_append_should_work() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { type DoubleMap = AppendableDM; let key1 = 17u32; diff --git a/srml/support/src/storage/storage_items.rs b/srml/support/src/storage/storage_items.rs index 24a7f3984a..4f8f194795 100644 --- a/srml/support/src/storage/storage_items.rs +++ b/srml/support/src/storage/storage_items.rs @@ -758,8 +758,8 @@ mod test3 { #[cfg(test)] #[allow(dead_code)] mod test_append_and_len { - use crate::storage::{StorageValue}; - use runtime_io::{with_externalities, TestExternalities}; + use runtime_io::TestExternalities; + use sr_primitives::set_and_run_with_externalities; use codec::{Encode, Decode}; pub trait Trait { @@ -801,7 +801,7 @@ mod test_append_and_len { #[test] fn default_for_option() { - with_externalities(&mut TestExternalities::default(), || { + set_and_run_with_externalities(&mut TestExternalities::default(), || { assert_eq!(OptionVec::get(), None); assert_eq!(JustVec::get(), vec![]); }); @@ -809,7 +809,7 @@ mod test_append_and_len { #[test] fn append_works() { - with_externalities(&mut TestExternalities::default(), || { + set_and_run_with_externalities(&mut TestExternalities::default(), || { let _ = MapVec::append(1, [1, 2, 3].iter()); let _ = MapVec::append(1, [4, 5].iter()); assert_eq!(MapVec::get(1), vec![1, 2, 3, 4, 5]); @@ -822,7 +822,7 @@ mod test_append_and_len { #[test] fn append_works_for_default() { - with_externalities(&mut TestExternalities::default(), || { + set_and_run_with_externalities(&mut TestExternalities::default(), || { assert_eq!(JustVecWithDefault::get(), vec![6, 9]); let _ = JustVecWithDefault::append([1].iter()); assert_eq!(JustVecWithDefault::get(), vec![6, 9, 1]); @@ -839,7 +839,7 @@ mod test_append_and_len { #[test] fn append_or_put_works() { - with_externalities(&mut TestExternalities::default(), || { + set_and_run_with_externalities(&mut TestExternalities::default(), || { let _ = MapVec::append_or_insert(1, &[1, 2, 3][..]); let _ = MapVec::append_or_insert(1, &[4, 5][..]); assert_eq!(MapVec::get(1), vec![1, 2, 3, 4, 5]); @@ -856,7 +856,7 @@ mod test_append_and_len { #[test] fn len_works() { - with_externalities(&mut TestExternalities::default(), || { + set_and_run_with_externalities(&mut TestExternalities::default(), || { JustVec::put(&vec![1, 2, 3, 4]); OptionVec::put(&vec![1, 2, 3, 4, 5]); MapVec::insert(1, &vec![1, 2, 3, 4, 5, 6]); @@ -871,7 +871,7 @@ mod test_append_and_len { #[test] fn len_works_for_default() { - with_externalities(&mut TestExternalities::default(), || { + set_and_run_with_externalities(&mut TestExternalities::default(), || { // vec assert_eq!(JustVec::get(), vec![]); assert_eq!(JustVec::decode_len(), Ok(0)); diff --git a/srml/support/test/Cargo.toml b/srml/support/test/Cargo.toml index bb1b3749e9..f40fef9ead 100644 --- a/srml/support/test/Cargo.toml +++ b/srml/support/test/Cargo.toml @@ -10,6 +10,7 @@ codec = { package = "parity-scale-codec", version = "1.0.0", default-features = runtime-io ={ package = "sr-io", path = "../../../core/sr-io", default-features = false } support = { package = "srml-support", version = "2", path = "../", default-features = false } inherents = { package = "substrate-inherents", path = "../../../core/inherents", default-features = false } +sr-primitives = { package = "sr-primitives", path = "../../../core/sr-primitives", default-features = false } primitives = { package = "substrate-primitives", path = "../../../core/primitives", default-features = false } trybuild = "1.0.14" pretty_assertions = "0.6.1" @@ -23,4 +24,5 @@ std = [ "support/std", "inherents/std", "primitives/std", + "sr-primitives/std", ] diff --git a/srml/support/test/tests/instance.rs b/srml/support/test/tests/instance.rs index da4e73e710..c7a2d25eed 100644 --- a/srml/support/test/tests/instance.rs +++ b/srml/support/test/tests/instance.rs @@ -15,20 +15,22 @@ // along with Substrate. If not, see . #![recursion_limit="128"] -use runtime_io::with_externalities; +use sr_primitives::{ + generic, BuildStorage, traits::{BlakeTwo256, Block as _, Verify}, + set_and_run_with_externalities, +}; use support::{ Parameter, traits::Get, parameter_types, - sr_primitives::{generic, BuildStorage, traits::{BlakeTwo256, Block as _, Verify}}, metadata::{ DecodeDifferent, StorageMetadata, StorageEntryModifier, StorageEntryType, DefaultByteGetter, - StorageEntryMetadata, StorageHasher + StorageEntryMetadata, StorageHasher, }, StorageValue, StorageMap, StorageLinkedMap, StorageDoubleMap, }; use inherents::{ ProvideInherent, InherentData, InherentIdentifier, RuntimeString, MakeFatalError }; -use primitives::{H256, sr25519, Blake2Hasher}; +use primitives::{H256, sr25519}; mod system; @@ -275,7 +277,7 @@ pub type Header = generic::Header; pub type Block = generic::Block; pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; -fn new_test_ext() -> runtime_io::TestExternalities { +fn new_test_ext() -> runtime_io::TestExternalities { GenesisConfig{ module1_Instance1: Some(module1::GenesisConfig { value: 3, @@ -329,7 +331,7 @@ fn storage_instance_independance() { #[test] fn storage_with_instance_basic_operation() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { type Value = module2::Value; type Map = module2::Map; type LinkedMap = module2::LinkedMap; diff --git a/srml/system/benches/bench.rs b/srml/system/benches/bench.rs index b24e52f457..89e9af9525 100644 --- a/srml/system/benches/bench.rs +++ b/srml/system/benches/bench.rs @@ -17,9 +17,10 @@ use criterion::{Criterion, criterion_group, criterion_main, black_box}; use srml_system as system; use support::{decl_module, decl_event, impl_outer_origin, impl_outer_event}; -use runtime_io::with_externalities; -use primitives::{H256, Blake2Hasher}; -use sr_primitives::{Perbill, traits::{BlakeTwo256, IdentityLookup}, testing::Header}; +use primitives::H256; +use sr_primitives::{ + set_and_run_with_externalities, Perbill, traits::{BlakeTwo256, IdentityLookup}, testing::Header, +}; mod module { use super::*; @@ -82,13 +83,13 @@ impl module::Trait for Runtime { type Event = Event; } -fn new_test_ext() -> runtime_io::TestExternalities { +fn new_test_ext() -> runtime_io::TestExternalities { system::GenesisConfig::default().build_storage::().unwrap().into() } fn deposit_events(n: usize) { let mut t = new_test_ext(); - with_externalities(&mut t, || { + set_and_run_with_externalities(&mut t, || { for _ in 0..n { module::Module::::deposit_event( module::Event::Complex(vec![1, 2, 3], 2, 3, 899) diff --git a/srml/system/src/lib.rs b/srml/system/src/lib.rs index 79782d5af4..065b23bda1 100644 --- a/srml/system/src/lib.rs +++ b/srml/system/src/lib.rs @@ -120,7 +120,7 @@ use codec::{Encode, Decode}; use runtime_io::TestExternalities; #[cfg(any(feature = "std", test))] -use primitives::{ChangesTrieConfiguration, Blake2Hasher}; +use primitives::ChangesTrieConfiguration; pub mod offchain; @@ -695,7 +695,7 @@ impl Module { /// Get the basic externalities for this module, useful for tests. #[cfg(any(feature = "std", test))] - pub fn externalities() -> TestExternalities { + pub fn externalities() -> TestExternalities { TestExternalities::new((map![ >::hashed_key_for(T::BlockNumber::zero()) => [69u8; 32].encode(), >::hashed_key().to_vec() => T::BlockNumber::one().encode(), @@ -1090,9 +1090,11 @@ impl Lookup for ChainContext { #[cfg(test)] mod tests { use super::*; - use runtime_io::with_externalities; use primitives::H256; - use sr_primitives::{traits::{BlakeTwo256, IdentityLookup}, testing::Header, DispatchError}; + use sr_primitives::{ + traits::{BlakeTwo256, IdentityLookup}, testing::Header, DispatchError, + set_and_run_with_externalities, + }; use support::{impl_outer_origin, parameter_types}; impl_outer_origin! { @@ -1141,7 +1143,7 @@ mod tests { const CALL: &::Call = &(); - fn new_test_ext() -> runtime_io::TestExternalities { + fn new_test_ext() -> runtime_io::TestExternalities { GenesisConfig::default().build_storage::().unwrap().into() } @@ -1162,7 +1164,7 @@ mod tests { #[test] fn deposit_event_should_work() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { System::initialize(&1, &[0u8; 32].into(), &[0u8; 32].into(), &Default::default()); System::note_finished_extrinsics(); System::deposit_event(1u16); @@ -1199,7 +1201,7 @@ mod tests { #[test] fn deposit_event_topics() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { const BLOCK_NUMBER: u64 = 1; System::initialize(&BLOCK_NUMBER, &[0u8; 32].into(), &[0u8; 32].into(), &Default::default()); @@ -1259,7 +1261,7 @@ mod tests { #[test] fn prunes_block_hash_mappings() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { // simulate import of 15 blocks for n in 1..=15 { System::initialize( @@ -1292,7 +1294,7 @@ mod tests { #[test] fn signed_ext_check_nonce_works() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { >::insert(1, 1); let info = DispatchInfo::default(); let len = 0_usize; @@ -1310,7 +1312,7 @@ mod tests { #[test] fn signed_ext_check_weight_works_normal_tx() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { let normal_limit = normal_weight_limit(); let small = DispatchInfo { weight: 100, ..Default::default() }; let medium = DispatchInfo { @@ -1337,7 +1339,7 @@ mod tests { #[test] fn signed_ext_check_weight_fee_works() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { let free = DispatchInfo { weight: 0, ..Default::default() }; let len = 0_usize; @@ -1350,7 +1352,7 @@ mod tests { #[test] fn signed_ext_check_weight_max_works() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { let max = DispatchInfo { weight: Weight::max_value(), ..Default::default() }; let len = 0_usize; let normal_limit = normal_weight_limit(); @@ -1364,7 +1366,7 @@ mod tests { #[test] fn signed_ext_check_weight_works_operational_tx() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { let normal = DispatchInfo { weight: 100, ..Default::default() }; let op = DispatchInfo { weight: 100, class: DispatchClass::Operational }; let len = 0_usize; @@ -1387,7 +1389,7 @@ mod tests { #[test] fn signed_ext_check_weight_priority_works() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { let normal = DispatchInfo { weight: 100, class: DispatchClass::Normal }; let op = DispatchInfo { weight: 100, class: DispatchClass::Operational }; let len = 0_usize; @@ -1408,7 +1410,7 @@ mod tests { #[test] fn signed_ext_check_weight_block_size_works() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { let normal = DispatchInfo::default(); let normal_limit = normal_weight_limit() as usize; let reset_check_weight = |tx, s, f| { @@ -1432,7 +1434,7 @@ mod tests { #[test] fn signed_ext_check_era_should_work() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { // future assert_eq!( CheckEra::::from(Era::mortal(4, 2)).additional_signed().err().unwrap(), @@ -1448,7 +1450,7 @@ mod tests { #[test] fn signed_ext_check_era_should_change_longevity() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { let normal = DispatchInfo { weight: 100, class: DispatchClass::Normal }; let len = 0_usize; let ext = ( diff --git a/srml/timestamp/src/lib.rs b/srml/timestamp/src/lib.rs index 4af0de8bd1..8ed3aa8dc0 100644 --- a/srml/timestamp/src/lib.rs +++ b/srml/timestamp/src/lib.rs @@ -322,9 +322,12 @@ mod tests { use super::*; use support::{impl_outer_origin, assert_ok, parameter_types}; - use runtime_io::{with_externalities, TestExternalities}; + use runtime_io::TestExternalities; use primitives::H256; - use sr_primitives::{Perbill, traits::{BlakeTwo256, IdentityLookup}, testing::Header}; + use sr_primitives::{ + Perbill, traits::{BlakeTwo256, IdentityLookup}, testing::Header, + set_and_run_with_externalities, + }; impl_outer_origin! { pub enum Origin for Test {} @@ -369,7 +372,7 @@ mod tests { #[test] fn timestamp_works() { let t = system::GenesisConfig::default().build_storage::().unwrap(); - with_externalities(&mut TestExternalities::new(t), || { + set_and_run_with_externalities(&mut TestExternalities::new(t), || { Timestamp::set_timestamp(42); assert_ok!(Timestamp::dispatch(Call::set(69), Origin::NONE)); assert_eq!(Timestamp::now(), 69); @@ -380,7 +383,7 @@ mod tests { #[should_panic(expected = "Timestamp must be updated only once in the block")] fn double_timestamp_should_fail() { let t = system::GenesisConfig::default().build_storage::().unwrap(); - with_externalities(&mut TestExternalities::new(t), || { + set_and_run_with_externalities(&mut TestExternalities::new(t), || { Timestamp::set_timestamp(42); assert_ok!(Timestamp::dispatch(Call::set(69), Origin::NONE)); let _ = Timestamp::dispatch(Call::set(70), Origin::NONE); @@ -391,7 +394,7 @@ mod tests { #[should_panic(expected = "Timestamp must increment by at least between sequential blocks")] fn block_period_minimum_enforced() { let t = system::GenesisConfig::default().build_storage::().unwrap(); - with_externalities(&mut TestExternalities::new(t), || { + set_and_run_with_externalities(&mut TestExternalities::new(t), || { Timestamp::set_timestamp(42); let _ = Timestamp::dispatch(Call::set(46), Origin::NONE); }); diff --git a/srml/treasury/src/lib.rs b/srml/treasury/src/lib.rs index db8b0f34c9..8ccc260fa7 100644 --- a/srml/treasury/src/lib.rs +++ b/srml/treasury/src/lib.rs @@ -355,13 +355,11 @@ impl OnDilution> for Module { mod tests { use super::*; - use runtime_io::with_externalities; use support::{assert_noop, assert_ok, impl_outer_origin, parameter_types}; - use primitives::{H256, Blake2Hasher}; + use primitives::H256; use sr_primitives::{ - traits::{BlakeTwo256, OnFinalize, IdentityLookup}, - testing::Header, - assert_eq_error_rate, + traits::{BlakeTwo256, OnFinalize, IdentityLookup}, set_and_run_with_externalities, + testing::Header, assert_eq_error_rate, }; impl_outer_origin! { @@ -437,7 +435,7 @@ mod tests { type Balances = balances::Module; type Treasury = Module; - fn new_test_ext() -> runtime_io::TestExternalities { + fn new_test_ext() -> runtime_io::TestExternalities { let mut t = system::GenesisConfig::default().build_storage::().unwrap(); balances::GenesisConfig::{ balances: vec![(0, 100), (1, 99), (2, 1)], @@ -448,7 +446,7 @@ mod tests { #[test] fn genesis_config_works() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { assert_eq!(Treasury::pot(), 0); assert_eq!(Treasury::proposal_count(), 0); }); @@ -456,7 +454,7 @@ mod tests { #[test] fn minting_works() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { // Check that accumulate works when we have Some value in Dummy already. Treasury::on_dilution(100, 100); assert_eq!(Treasury::pot(), 100); @@ -467,7 +465,7 @@ mod tests { fn minting_works_2() { let tests = [(1, 10), (1, 20), (40, 130), (2, 66), (2, 67), (2, 100), (2, 101), (2, 134)]; for &(minted, portion) in &tests { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { let init_total_issuance = Balances::total_issuance(); Treasury::on_dilution(minted, portion); @@ -491,7 +489,7 @@ mod tests { #[test] fn spend_proposal_takes_min_deposit() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { assert_ok!(Treasury::propose_spend(Origin::signed(0), 1, 3)); assert_eq!(Balances::free_balance(&0), 99); assert_eq!(Balances::reserved_balance(&0), 1); @@ -500,7 +498,7 @@ mod tests { #[test] fn spend_proposal_takes_proportional_deposit() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { assert_ok!(Treasury::propose_spend(Origin::signed(0), 100, 3)); assert_eq!(Balances::free_balance(&0), 95); assert_eq!(Balances::reserved_balance(&0), 5); @@ -509,14 +507,14 @@ mod tests { #[test] fn spend_proposal_fails_when_proposer_poor() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { assert_noop!(Treasury::propose_spend(Origin::signed(2), 100, 3), "Proposer's balance too low"); }); } #[test] fn accepted_spend_proposal_ignored_outside_spend_period() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { Treasury::on_dilution(100, 100); assert_ok!(Treasury::propose_spend(Origin::signed(0), 100, 3)); @@ -530,7 +528,7 @@ mod tests { #[test] fn unused_pot_should_diminish() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { let init_total_issuance = Balances::total_issuance(); Treasury::on_dilution(100, 100); assert_eq!(Balances::total_issuance(), init_total_issuance + 100); @@ -543,7 +541,7 @@ mod tests { #[test] fn rejected_spend_proposal_ignored_on_spend_period() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { Treasury::on_dilution(100, 100); assert_ok!(Treasury::propose_spend(Origin::signed(0), 100, 3)); @@ -557,7 +555,7 @@ mod tests { #[test] fn reject_already_rejected_spend_proposal_fails() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { Treasury::on_dilution(100, 100); assert_ok!(Treasury::propose_spend(Origin::signed(0), 100, 3)); @@ -568,21 +566,21 @@ mod tests { #[test] fn reject_non_existant_spend_proposal_fails() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { assert_noop!(Treasury::reject_proposal(Origin::ROOT, 0), "No proposal at that index"); }); } #[test] fn accept_non_existant_spend_proposal_fails() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { assert_noop!(Treasury::approve_proposal(Origin::ROOT, 0), "No proposal at that index"); }); } #[test] fn accept_already_rejected_spend_proposal_fails() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { Treasury::on_dilution(100, 100); assert_ok!(Treasury::propose_spend(Origin::signed(0), 100, 3)); @@ -593,7 +591,7 @@ mod tests { #[test] fn accepted_spend_proposal_enacted_on_spend_period() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { Treasury::on_dilution(100, 100); assert_eq!(Treasury::pot(), 100); @@ -608,7 +606,7 @@ mod tests { #[test] fn pot_underflow_should_not_diminish() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { Treasury::on_dilution(100, 100); assert_ok!(Treasury::propose_spend(Origin::signed(0), 150, 3)); diff --git a/srml/utility/src/lib.rs b/srml/utility/src/lib.rs index c0b1954da9..a9009a3a7e 100644 --- a/srml/utility/src/lib.rs +++ b/srml/utility/src/lib.rs @@ -64,10 +64,10 @@ mod tests { use super::*; use support::{assert_ok, assert_noop, impl_outer_origin, parameter_types, impl_outer_dispatch}; - use runtime_io::with_externalities; - use primitives::{H256, Blake2Hasher}; + use primitives::H256; use sr_primitives::{ - Perbill, traits::{BlakeTwo256, IdentityLookup}, testing::Header + Perbill, traits::{BlakeTwo256, IdentityLookup}, testing::Header, + set_and_run_with_externalities, }; impl_outer_origin! { @@ -139,7 +139,7 @@ mod tests { type Balances = balances::Module; type Utility = Module; - fn new_test_ext() -> runtime_io::TestExternalities { + fn new_test_ext() -> runtime_io::TestExternalities { let mut t = system::GenesisConfig::default().build_storage::().unwrap(); balances::GenesisConfig:: { balances: vec![(1, 10), (2, 0)], @@ -150,7 +150,7 @@ mod tests { #[test] fn batch_works() { - with_externalities(&mut new_test_ext(), || { + set_and_run_with_externalities(&mut new_test_ext(), || { assert_eq!(Balances::free_balance(1), 10); assert_eq!(Balances::free_balance(2), 0); assert_noop!(Utility::batch(Origin::signed(1), vec![ -- GitLab From e44bd4415de36b661a3e17f7f98aaf466d270f79 Mon Sep 17 00:00:00 2001 From: Demi Obenour <48690212+DemiMarie-parity@users.noreply.github.com> Date: Wed, 9 Oct 2019 12:29:28 -0400 Subject: [PATCH 028/167] Bump dependencies (#3787) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update dependencies, respecting semver * Bump dependencies * Don’t patch tiny-bip39 dependency --- Cargo.lock | 78 +++++++++++++++----------- core/authority-discovery/Cargo.toml | 2 +- core/chain-spec/Cargo.toml | 2 +- core/cli/Cargo.toml | 4 +- core/client/Cargo.toml | 2 +- core/client/db/Cargo.toml | 2 +- core/consensus/aura/Cargo.toml | 2 +- core/consensus/babe/Cargo.toml | 2 +- core/finality-grandpa/Cargo.toml | 4 +- core/keystore/Cargo.toml | 2 +- core/network/Cargo.toml | 4 +- core/offchain/Cargo.toml | 2 +- core/peerset/Cargo.toml | 2 +- core/rpc-servers/Cargo.toml | 2 +- core/rpc/Cargo.toml | 2 +- core/rpc/api/Cargo.toml | 2 +- core/serializer/Cargo.toml | 2 +- core/service/Cargo.toml | 2 +- core/service/test/Cargo.toml | 2 +- core/sr-primitives/Cargo.toml | 2 +- core/state-db/Cargo.toml | 2 +- core/transaction-pool/graph/Cargo.toml | 2 +- node/rpc-client/Cargo.toml | 2 +- node/rpc/Cargo.toml | 2 +- srml/utility/Cargo.toml | 2 +- 25 files changed, 72 insertions(+), 60 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a1f3ba2983..8a1ead4978 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -104,10 +104,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "arrayvec" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -240,7 +240,7 @@ name = "blake2-rfc" version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "constant_time_eq 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -341,7 +341,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -569,7 +569,7 @@ name = "crossbeam-epoch" version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -787,6 +787,18 @@ dependencies = [ "termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "env_logger" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", + "humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "environmental" version = "1.0.2" @@ -1055,7 +1067,7 @@ name = "generic-array" version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", "typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1313,7 +1325,7 @@ dependencies = [ "http 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", "http-body 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1405,11 +1417,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "iovec" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1785,7 +1796,7 @@ name = "libp2p-kad" version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2209,7 +2220,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2235,7 +2246,7 @@ name = "mio-uds" version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2418,7 +2429,7 @@ dependencies = [ name = "node-rpc" version = "2.0.0" dependencies = [ - "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "futures-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core-client 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2442,7 +2453,7 @@ dependencies = [ name = "node-rpc-client" version = "2.0.0" dependencies = [ - "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.12.35 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core-client 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2590,7 +2601,7 @@ dependencies = [ [[package]] name = "nodrop" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -2767,7 +2778,7 @@ name = "parity-scale-codec" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "bitvec 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", "byte-slice-cast 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec-derive 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4669,7 +4680,7 @@ dependencies = [ "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", "derive_more 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "exit-future 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4701,7 +4712,7 @@ name = "substrate-client" version = "2.0.0" dependencies = [ "derive_more 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "futures-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4734,7 +4745,7 @@ dependencies = [ name = "substrate-client-db" version = "2.0.0" dependencies = [ - "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "hash-db 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", "kvdb 0.1.0 (git+https://github.com/paritytech/parity-common?rev=b0317f649ab2c665b7987b8475878fc4d2e1f81d)", "kvdb-memorydb 0.1.0 (git+https://github.com/paritytech/parity-common?rev=b0317f649ab2c665b7987b8475878fc4d2e1f81d)", @@ -4761,7 +4772,7 @@ name = "substrate-consensus-aura" version = "2.0.0" dependencies = [ "derive_more 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "futures-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", "futures-timer 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4806,7 +4817,7 @@ dependencies = [ name = "substrate-consensus-babe" version = "2.0.0" dependencies = [ - "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "fork-tree 2.0.0", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "futures-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", @@ -5004,7 +5015,7 @@ dependencies = [ name = "substrate-finality-grandpa" version = "2.0.0" dependencies = [ - "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "finality-grandpa 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "fork-tree 2.0.0", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", @@ -5099,7 +5110,7 @@ dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "derive_more 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "erased-serde 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "fork-tree 2.0.0", @@ -5145,7 +5156,7 @@ name = "substrate-offchain" version = "2.0.0" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "futures-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", @@ -5402,7 +5413,7 @@ dependencies = [ name = "substrate-service-test" version = "2.0.0" dependencies = [ - "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "futures-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", @@ -5431,7 +5442,7 @@ dependencies = [ name = "substrate-state-db" version = "2.0.0" dependencies = [ - "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -5547,7 +5558,7 @@ version = "2.0.0" dependencies = [ "assert_matches 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "derive_more 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "futures-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -5888,7 +5899,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "rustls 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "webpki 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -5910,7 +5921,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-reactor 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -5974,7 +5985,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", @@ -6598,7 +6609,7 @@ dependencies = [ "checksum app_dirs 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e73a24bad9bd6a94d6395382a6c69fe071708ae4409f763c5475e14ee896313d" "checksum arc-swap 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "bc4662175ead9cd84451d5c35070517777949a2ed84551764129cedb88384841" "checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee" -"checksum arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b8d73f9beda665eaa98ab9e4f7442bd4e7de6652587de55b2525e52e29c1b0ba" +"checksum arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" "checksum asn1_der 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bea40e881533b1fe23afca9cd1c1ca022219a10fce604099ecfc96bfa26eaf1a" "checksum asn1_der_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9e7f92edafad155aff997fa5b727c6429b91e996b5a5d62a2b0adbae1306b5fe" "checksum assert_matches 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7deb0a829ca7bcfaf5da70b073a8d128619259a7be8216a355e23f00763059e5" @@ -6677,6 +6688,7 @@ dependencies = [ "checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" "checksum elastic-array 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "073be79b6538296faf81c631872676600616073817dd9a440c477ad09b408983" "checksum env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3" +"checksum env_logger 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "39ecdb7dd54465526f0a56d666e3b2dd5f3a218665a030b6e4ad9e70fa95d8fa" "checksum environmental 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "34f8467a0284de039e6bd0e25c14519538462ba5beb548bb1f03e645097837a8" "checksum erased-serde 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3beee4bc16478a1b26f2e80ad819a52d24745e292f521a63c16eea5f74b7eb60" "checksum error-chain 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3ab49e9dcb602294bc42f9a7dfc9bc6e936fca4418ea300dbfb84fe16de0b7d9" @@ -6746,7 +6758,7 @@ dependencies = [ "checksum indexmap 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a61202fbe46c4a951e9404a720a0180bcf3212c750d735cb5c4ba4dc551299f3" "checksum integer-sqrt 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ea155abb3ba6f382a75f1418988c05fe82959ed9ce727de427f9cfd425b0c903" "checksum interleaved-ordered 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "141340095b15ed7491bd3d4ced9d20cebfb826174b6bb03386381f62b01e3d77" -"checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" +"checksum iovec 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c9636900aa73ffed13cdbb199f17cd955670bb300927c8d25b517dfa136b6567" "checksum ipnet 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e61c2da0d0f700c77d2d313dbf4f93e41d235fa12c6681fee06621036df4c2af" "checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358" "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" @@ -6823,7 +6835,7 @@ dependencies = [ "checksum native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4b2df1a4c22fd44a62147fd8f13dd0f95c9d8ca7b2610299b2a2f9cf8964274e" "checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" "checksum nix 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6c722bee1037d430d0f8e687bbdbf222f27cc6e4e68d5caf630857bb2b6dbdce" -"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" +"checksum nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" "checksum nohash-hasher 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4e657a6ec97f9a3ba46f6f7034ea6db9fcd5b71d25ef1074b7bc03da49be0e8e" "checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6" "checksum num-bigint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f9c3f34cdd24f334cb265d9bf8bfa8a241920d026916785747a92f0e55541a1a" diff --git a/core/authority-discovery/Cargo.toml b/core/authority-discovery/Cargo.toml index a74549eb45..7283e07f89 100644 --- a/core/authority-discovery/Cargo.toml +++ b/core/authority-discovery/Cargo.toml @@ -20,7 +20,7 @@ log = "0.4.8" network = { package = "substrate-network", path = "../../core/network" } primitives = { package = "substrate-primitives", path = "../primitives" } prost = "0.5.0" -serde_json = "1.0.40" +serde_json = "1.0.41" sr-primitives = { path = "../../core/sr-primitives" } tokio-timer = "0.2.11" diff --git a/core/chain-spec/Cargo.toml b/core/chain-spec/Cargo.toml index bff5999ef4..1a3c56affb 100644 --- a/core/chain-spec/Cargo.toml +++ b/core/chain-spec/Cargo.toml @@ -10,7 +10,7 @@ impl-trait-for-tuples = "0.1.2" network = { package = "substrate-network", path = "../../core/network" } primitives = { package = "substrate-primitives", path = "../primitives" } serde = { version = "1.0.101", features = ["derive"] } -serde_json = "1.0.40" +serde_json = "1.0.41" sr-primitives = { path = "../../core/sr-primitives" } tel = { package = "substrate-telemetry", path = "../../core/telemetry" } diff --git a/core/cli/Cargo.toml b/core/cli/Cargo.toml index e3b33746d5..b1cb1d57ca 100644 --- a/core/cli/Cargo.toml +++ b/core/cli/Cargo.toml @@ -8,7 +8,7 @@ edition = "2018" [dependencies] clap = "~2.32.0" derive_more = "0.15.0" -env_logger = "0.6.2" +env_logger = "0.7.0" log = "0.4.8" atty = "0.2.13" regex = "1.3.1" @@ -21,7 +21,7 @@ futures = "0.1.29" futures03 = { package = "futures-preview", version = "=0.3.0-alpha.19", features = ["compat"] } fdlimit = "0.1.1" exit-future = "0.1.4" -serde_json = "1.0.40" +serde_json = "1.0.41" panic-handler = { package = "substrate-panic-handler", path = "../../core/panic-handler" } client = { package = "substrate-client", path = "../../core/client" } header-metadata = { package = "substrate-header-metadata", path = "../../core/client/header-metadata" } diff --git a/core/client/Cargo.toml b/core/client/Cargo.toml index 8852988cb1..5a0afd2d6f 100644 --- a/core/client/Cargo.toml +++ b/core/client/Cargo.toml @@ -30,7 +30,7 @@ sr-api-macros = { path = "../sr-api-macros" } header-metadata = { package = "substrate-header-metadata", path = "header-metadata", optional = true } [dev-dependencies] -env_logger = "0.6.2" +env_logger = "0.7.0" tempfile = "3.1.0" test-client = { package = "substrate-test-runtime-client", path = "../test-runtime/client" } kvdb-memorydb = { git = "https://github.com/paritytech/parity-common", rev="b0317f649ab2c665b7987b8475878fc4d2e1f81d" } diff --git a/core/client/db/Cargo.toml b/core/client/db/Cargo.toml index 891255cb77..7d88c39d7f 100644 --- a/core/client/db/Cargo.toml +++ b/core/client/db/Cargo.toml @@ -27,7 +27,7 @@ header_metadata = { package = "substrate-header-metadata", path = "../header-met [dev-dependencies] substrate-keyring = { path = "../../keyring" } test-client = { package = "substrate-test-runtime-client", path = "../../test-runtime/client" } -env_logger = "0.6.2" +env_logger = "0.7.0" [features] default = [] diff --git a/core/consensus/aura/Cargo.toml b/core/consensus/aura/Cargo.toml index b63987ecb7..a09d510950 100644 --- a/core/consensus/aura/Cargo.toml +++ b/core/consensus/aura/Cargo.toml @@ -35,5 +35,5 @@ network = { package = "substrate-network", path = "../../network", features = [" service = { package = "substrate-service", path = "../../service" } test-client = { package = "substrate-test-runtime-client", path = "../../test-runtime/client" } tokio = "0.1.22" -env_logger = "0.6.2" +env_logger = "0.7.0" tempfile = "3.1.0" diff --git a/core/consensus/babe/Cargo.toml b/core/consensus/babe/Cargo.toml index e225c2503a..b1c2c31f7d 100644 --- a/core/consensus/babe/Cargo.toml +++ b/core/consensus/babe/Cargo.toml @@ -44,7 +44,7 @@ network = { package = "substrate-network", path = "../../network", features = [" service = { package = "substrate-service", path = "../../service" } test-client = { package = "substrate-test-runtime-client", path = "../../test-runtime/client" } tokio = "0.1.22" -env_logger = "0.6.2" +env_logger = "0.7.0" tempfile = "3.1.0" [features] diff --git a/core/finality-grandpa/Cargo.toml b/core/finality-grandpa/Cargo.toml index 0a42ff4531..84178c8a78 100644 --- a/core/finality-grandpa/Cargo.toml +++ b/core/finality-grandpa/Cargo.toml @@ -19,7 +19,7 @@ consensus_common = { package = "substrate-consensus-common", path = "../consensu primitives = { package = "substrate-primitives", path = "../primitives" } substrate-telemetry = { path = "../telemetry" } keystore = { package = "substrate-keystore", path = "../keystore" } -serde_json = "1.0.40" +serde_json = "1.0.41" client = { package = "substrate-client", path = "../client" } header-metadata = { package = "substrate-header-metadata", path = "../client/header-metadata" } inherents = { package = "substrate-inherents", path = "../../core/inherents" } @@ -34,6 +34,6 @@ network = { package = "substrate-network", path = "../network", features = ["tes keyring = { package = "substrate-keyring", path = "../keyring" } test-client = { package = "substrate-test-runtime-client", path = "../test-runtime/client"} babe_primitives = { package = "substrate-consensus-babe-primitives", path = "../consensus/babe/primitives" } -env_logger = "0.6.2" +env_logger = "0.7.0" tokio = "0.1.22" tempfile = "3.1.0" diff --git a/core/keystore/Cargo.toml b/core/keystore/Cargo.toml index ff5696ab37..cc491337cf 100644 --- a/core/keystore/Cargo.toml +++ b/core/keystore/Cargo.toml @@ -10,7 +10,7 @@ primitives = { package = "substrate-primitives", path = "../primitives" } app-crypto = { package = "substrate-application-crypto", path = "../application-crypto" } hex = "0.3.2" rand = "0.7.2" -serde_json = "1.0.40" +serde_json = "1.0.41" subtle = "2.1.1" parking_lot = "0.9.0" diff --git a/core/network/Cargo.toml b/core/network/Cargo.toml index 453fbbeee3..016ddb8010 100644 --- a/core/network/Cargo.toml +++ b/core/network/Cargo.toml @@ -32,7 +32,7 @@ primitives = { package = "substrate-primitives", path = "../../core/primitives" codec = { package = "parity-scale-codec", version = "1.0.0", features = ["derive"] } peerset = { package = "substrate-peerset", path = "../../core/peerset" } serde = { version = "1.0.101", features = ["derive"] } -serde_json = "1.0.40" +serde_json = "1.0.41" slog = { version = "2.5.2", features = ["nested-values"] } slog_derive = "0.1.1" smallvec = "0.6.10" @@ -48,7 +48,7 @@ zeroize = "0.10.1" babe-primitives = { package = "substrate-consensus-babe-primitives", path = "../consensus/babe/primitives" } [dev-dependencies] -env_logger = "0.6.2" +env_logger = "0.7.0" keyring = { package = "substrate-keyring", path = "../../core/keyring" } quickcheck = "0.9.0" rand = "0.7.2" diff --git a/core/offchain/Cargo.toml b/core/offchain/Cargo.toml index 8f342ee602..ca9b27eee2 100644 --- a/core/offchain/Cargo.toml +++ b/core/offchain/Cargo.toml @@ -27,7 +27,7 @@ network = { package = "substrate-network", path = "../../core/network" } keystore = { package = "substrate-keystore", path = "../keystore" } [dev-dependencies] -env_logger = "0.6.2" +env_logger = "0.7.0" client-db = { package = "substrate-client-db", path = "../../core/client/db/", default-features = true } test-client = { package = "substrate-test-runtime-client", path = "../../core/test-runtime/client" } tokio = "0.1.22" diff --git a/core/peerset/Cargo.toml b/core/peerset/Cargo.toml index b11e59c770..96b721b41c 100644 --- a/core/peerset/Cargo.toml +++ b/core/peerset/Cargo.toml @@ -13,7 +13,7 @@ libp2p = { version = "0.12.0", default-features = false } linked-hash-map = "0.5.2" log = "0.4.8" lru-cache = "0.1.2" -serde_json = "1.0.40" +serde_json = "1.0.41" [dev-dependencies] rand = "0.7.2" diff --git a/core/rpc-servers/Cargo.toml b/core/rpc-servers/Cargo.toml index 27601d8cc1..80e16bc5ae 100644 --- a/core/rpc-servers/Cargo.toml +++ b/core/rpc-servers/Cargo.toml @@ -9,7 +9,7 @@ jsonrpc-core = "13.2.0" pubsub = { package = "jsonrpc-pubsub", version = "13.2.0" } log = "0.4.8" serde = "1.0.101" -serde_json = "1.0" +serde_json = "1.0.41" sr-primitives = { path = "../sr-primitives" } [target.'cfg(not(target_os = "unknown"))'.dependencies] diff --git a/core/rpc/Cargo.toml b/core/rpc/Cargo.toml index e6f0db1c9c..85998feb1b 100644 --- a/core/rpc/Cargo.toml +++ b/core/rpc/Cargo.toml @@ -14,7 +14,7 @@ log = "0.4.8" primitives = { package = "substrate-primitives", path = "../primitives" } rpc = { package = "jsonrpc-core", version = "13.0.0" } runtime_version = { package = "sr-version", path = "../sr-version" } -serde_json = "1.0.40" +serde_json = "1.0.41" session = { package = "substrate-session", path = "../session" } sr-primitives = { path = "../sr-primitives" } rpc-primitives = { package = "substrate-rpc-primitives", path = "primitives" } diff --git a/core/rpc/api/Cargo.toml b/core/rpc/api/Cargo.toml index b2614dbced..bccafc2a85 100644 --- a/core/rpc/api/Cargo.toml +++ b/core/rpc/api/Cargo.toml @@ -17,6 +17,6 @@ parking_lot = "0.9.0" primitives = { package = "substrate-primitives", path = "../../primitives" } runtime_version = { package = "sr-version", path = "../../sr-version" } serde = { version = "1.0.101", features = ["derive"] } -serde_json = "1.0.40" +serde_json = "1.0.41" txpool = { package = "substrate-transaction-graph", path = "../../transaction-pool/graph" } rpc-primitives = { package = "substrate-rpc-primitives", path = "../../rpc/primitives" } diff --git a/core/serializer/Cargo.toml b/core/serializer/Cargo.toml index b6dfa3f470..4e0e706e2f 100644 --- a/core/serializer/Cargo.toml +++ b/core/serializer/Cargo.toml @@ -6,4 +6,4 @@ edition = "2018" [dependencies] serde = "1.0.101" -serde_json = "1.0.40" +serde_json = "1.0.41" diff --git a/core/service/Cargo.toml b/core/service/Cargo.toml index 5d8abee116..5f5f132233 100644 --- a/core/service/Cargo.toml +++ b/core/service/Cargo.toml @@ -16,7 +16,7 @@ tokio-executor = "0.1.8" tokio-timer = "0.2.11" exit-future = "0.1.4" serde = "1.0.101" -serde_json = "1.0.40" +serde_json = "1.0.41" sysinfo = "0.9.5" target_info = "0.1.0" keystore = { package = "substrate-keystore", path = "../../core/keystore" } diff --git a/core/service/test/Cargo.toml b/core/service/test/Cargo.toml index b4651da7a7..872d63415f 100644 --- a/core/service/test/Cargo.toml +++ b/core/service/test/Cargo.toml @@ -9,7 +9,7 @@ tempdir = "0.3.7" tokio = "0.1.22" futures = "0.1.29" log = "0.4.8" -env_logger = "0.6.2" +env_logger = "0.7.0" fdlimit = "0.1.1" futures03 = { package = "futures-preview", version = "=0.3.0-alpha.19", features = ["compat"] } service = { package = "substrate-service", path = "../../../core/service" } diff --git a/core/sr-primitives/Cargo.toml b/core/sr-primitives/Cargo.toml index ab81df2b53..1074e509a6 100644 --- a/core/sr-primitives/Cargo.toml +++ b/core/sr-primitives/Cargo.toml @@ -20,7 +20,7 @@ externalities = { package = "substrate-externalities", path = "../externalities" impl-trait-for-tuples = "0.1.2" [dev-dependencies] -serde_json = "1.0.40" +serde_json = "1.0.41" primitive-types = "0.5.1" rand = "0.7.2" substrate-offchain = { path = "../offchain" } diff --git a/core/state-db/Cargo.toml b/core/state-db/Cargo.toml index 86298ae909..d271a0e179 100644 --- a/core/state-db/Cargo.toml +++ b/core/state-db/Cargo.toml @@ -11,4 +11,4 @@ primitives = { package = "substrate-primitives", path = "../../core/primitives" codec = { package = "parity-scale-codec", version = "1.0.0", features = ["derive"] } [dev-dependencies] -env_logger = "0.6.2" +env_logger = "0.7.0" diff --git a/core/transaction-pool/graph/Cargo.toml b/core/transaction-pool/graph/Cargo.toml index d99291476e..fa0d6f14b6 100644 --- a/core/transaction-pool/graph/Cargo.toml +++ b/core/transaction-pool/graph/Cargo.toml @@ -15,6 +15,6 @@ sr-primitives = { path = "../../sr-primitives" } [dev-dependencies] assert_matches = "1.3.0" -env_logger = "0.6.2" +env_logger = "0.7.0" codec = { package = "parity-scale-codec", version = "1.0.0" } test_runtime = { package = "substrate-test-runtime", path = "../../test-runtime" } diff --git a/node/rpc-client/Cargo.toml b/node/rpc-client/Cargo.toml index 7dca144886..e377f89359 100644 --- a/node/rpc-client/Cargo.toml +++ b/node/rpc-client/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] edition = "2018" [dependencies] -env_logger = "0.6.2" +env_logger = "0.7.0" futures = "0.1.29" hyper = "0.12.35" jsonrpc-core-client = { version = "13.1.0", features = ["http", "ws"] } diff --git a/node/rpc/Cargo.toml b/node/rpc/Cargo.toml index 6bec6adb6f..6985d94e54 100644 --- a/node/rpc/Cargo.toml +++ b/node/rpc/Cargo.toml @@ -23,5 +23,5 @@ transaction_pool = { package = "substrate-transaction-pool", path = "../../core/ [dev-dependencies] node-testing = { path = "../testing" } node-runtime = { path = "../runtime" } -env_logger = "0.6.2" +env_logger = "0.7.0" futures03 = { package = "futures-preview", version = "=0.3.0-alpha.19" } diff --git a/srml/utility/Cargo.toml b/srml/utility/Cargo.toml index d46ed62a55..5e92bcf88a 100644 --- a/srml/utility/Cargo.toml +++ b/srml/utility/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] edition = "2018" [dependencies] -serde = { version = "1.0", optional = true } +serde = { version = "1.0.101", optional = true } codec = { package = "parity-scale-codec", version = "1.0.0", default-features = false } support = { package = "srml-support", path = "../support", default-features = false } system = { package = "srml-system", path = "../system", default-features = false } -- GitLab From 66042f1cc737f4eb5ca8d05db9d981c3e4bd3693 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Thu, 10 Oct 2019 09:52:08 +0200 Subject: [PATCH 029/167] Multi-limb arithmetic for runtime (#3743) * First working version of all operations. * New and improved version of everything. * Minor cleanup. * Fix build * Finalize nignum * Some final works on refactors and tests. * fix build * Some review comments * Bench, better try into and nits * mutify the API * rename to big_uint * unmutify. * Remove resize * Apply suggestions from code review * Update core/sr-primitives/src/sr_arithmetic.rs Co-Authored-By: thiolliere * BEtter proof * Fix panic doc. * Bump. --- core/phragmen/src/lib.rs | 12 +- core/sr-primitives/Cargo.toml | 1 + core/sr-primitives/src/lib.rs | 10 +- core/sr-primitives/src/sr_arithmetic.rs | 1199 +++++++++++++++++++---- node/runtime/src/lib.rs | 4 +- 5 files changed, 1015 insertions(+), 211 deletions(-) diff --git a/core/phragmen/src/lib.rs b/core/phragmen/src/lib.rs index 5295d0f422..e15a857b5f 100644 --- a/core/phragmen/src/lib.rs +++ b/core/phragmen/src/lib.rs @@ -34,8 +34,8 @@ #![cfg_attr(not(feature = "std"), no_std)] use rstd::{prelude::*, collections::btree_map::BTreeMap}; -use sr_primitives::{helpers_128bit::multiply_by_rational_best_effort, Perbill, Rational128}; -use sr_primitives::traits::{Zero, Convert, Member, SimpleArithmetic, Saturating}; +use sr_primitives::{helpers_128bit::multiply_by_rational, Perbill, Rational128}; +use sr_primitives::traits::{Zero, Convert, Member, SimpleArithmetic, Saturating, Bounded}; mod mock; mod tests; @@ -253,11 +253,11 @@ pub fn elect( for e in &n.edges { let c = &mut candidates[e.candidate_index]; if !c.elected && !c.approval_stake.is_zero() { - let temp_n = multiply_by_rational_best_effort( + let temp_n = multiply_by_rational( n.load.n(), n.budget, c.approval_stake, - ); + ).unwrap_or(Bounded::max_value()); let temp_d = n.load.d(); let temp = Rational128::from(temp_n, temp_d); c.score = c.score.lazy_saturating_add(temp); @@ -303,11 +303,11 @@ pub fn elect( if e.load.d() == n.load.d() { // return e.load / n.load. let desired_scale: u128 = Perbill::accuracy().into(); - multiply_by_rational_best_effort( + multiply_by_rational( desired_scale, e.load.n(), n.load.n(), - ) + ).unwrap_or(Bounded::max_value()) } else { // defensive only. Both edge and nominator loads are built from // scores, hence MUST have the same denominator. diff --git a/core/sr-primitives/Cargo.toml b/core/sr-primitives/Cargo.toml index 1074e509a6..2ffe8a010d 100644 --- a/core/sr-primitives/Cargo.toml +++ b/core/sr-primitives/Cargo.toml @@ -26,6 +26,7 @@ rand = "0.7.2" substrate-offchain = { path = "../offchain" } [features] +bench = [] default = ["std"] std = [ "num-traits/std", diff --git a/core/sr-primitives/src/lib.rs b/core/sr-primitives/src/lib.rs index 36d785f9a6..3c75bae849 100644 --- a/core/sr-primitives/src/lib.rs +++ b/core/sr-primitives/src/lib.rs @@ -19,6 +19,10 @@ #![warn(missing_docs)] #![cfg_attr(not(feature = "std"), no_std)] +// to allow benchmarking +#![cfg_attr(feature = "bench", feature(test))] +#[cfg(feature = "bench")] extern crate test; + #[doc(hidden)] pub use codec; #[cfg(feature = "std")] @@ -59,13 +63,15 @@ pub use generic::{DigestItem, Digest}; pub use primitives::{TypeId, crypto::{key_types, KeyTypeId, CryptoType}}; pub use app_crypto::RuntimeAppPublic; -/// Re-export arithmetic stuff. +/// Re-export top-level arithmetic stuff. pub use sr_arithmetic::{ Perquintill, Perbill, Permill, Percent, Rational128, Fixed64 }; -/// Re-export 128 bit helpers from sr_arithmetic +/// Re-export 128 bit helpers. pub use sr_arithmetic::helpers_128bit; +/// Re-export big_uint stiff. +pub use sr_arithmetic::biguint; #[cfg(feature = "std")] pub use externalities::set_and_run_with_externalities; diff --git a/core/sr-primitives/src/sr_arithmetic.rs b/core/sr-primitives/src/sr_arithmetic.rs index 20a7f51c1f..043a383a33 100644 --- a/core/sr-primitives/src/sr_arithmetic.rs +++ b/core/sr-primitives/src/sr_arithmetic.rs @@ -20,9 +20,8 @@ use crate::serde::{Serialize, Deserialize}; use rstd::{ - ops, prelude::*, - convert::{TryInto, TryFrom}, - cmp::Ordering, + ops, cmp::Ordering, prelude::*, + convert::{TryFrom, TryInto}, }; use codec::{Encode, Decode}; use crate::traits::{ @@ -669,16 +668,930 @@ impl CheckedAdd for Fixed64 { } } +/// Infinite precision unsigned integer for substrate runtime. +pub mod biguint { + use super::Zero; + use rstd::{cmp::Ordering, ops, prelude::*, cell::RefCell, convert::TryFrom}; + + // A sensible value for this would be half of the dword size of the host machine. Since the + // runtime is compiled to 32bit webassembly, using 32 and 64 for single and double respectively + // should yield the most performance. TODO #3745 we could benchmark this and verify. + /// Representation of a single limb. + pub type Single = u32; + /// Representation of two limbs. + pub type Double = u64; + /// Difference in the number of bits of [`Single`] and [`Double`]. + const SHIFT: usize = 32; + /// short form of _Base_. Analogous to the value 10 in base-10 decimal numbers. + const B: Double = Single::max_value() as Double + 1; + + /// Splits a [`Double`] limb number into a tuple of two [`Single`] limb numbers. + pub fn split(a: Double) -> (Single, Single) { + let al = a as Single; + let ah = (a >> SHIFT) as Single; + (ah, al) + } + + /// Assumed as a given primitive. + /// + /// Multiplication of two singles, which at most yields 1 double. + pub fn mul_single(a: Single, b: Single) -> Double { + let a: Double = a.into(); + let b: Double = b.into(); + let r = a * b; + r + } + + /// Assumed as a given primitive. + /// + /// Addition of two singles, which at most takes a single limb of result and a carry, + /// returned as a tuple respectively. + pub fn add_single(a: Single, b: Single) -> (Single, Single) { + let a: Double = a.into(); + let b: Double = b.into(); + let q = a + b; + let (carry, r) = split(q); + (r, carry) + } + + /// Assumed as a given primitive. + /// + /// Division of double by a single limb. Always returns a double limb of quotient and a single + /// limb of remainder. + fn div_single(a: Double, b: Single) -> (Double, Single) { + let b: Double = b.into(); + let q = a / b; + let r = a % b; + // both conversions are trivially safe. + (q, r as Single) + } + + /// Simple wrapper around an infinitely large integer, represented as limbs of [`Single`]. + #[derive(Clone, Default)] + pub struct BigUint { + /// digits (limbs) of this number (sorted as msb -> lsd). + pub(crate) digits: Vec, + } + + impl BigUint { + /// Create a new instance with `size` limbs. This prevents any number with zero limbs to be + /// created. + /// + /// The behavior of the type is undefined with zero limbs. + pub fn with_capacity(size: usize) -> Self { + Self { digits: vec![0; size.max(1)] } + } + + /// Raw constructor from custom limbs. If `limbs` is empty, `Zero::zero()` implementation is + /// used. + pub fn from_limbs(limbs: &[Single]) -> Self { + if limbs.len() > 0 { + Self { digits: limbs.to_vec() } + } else { + Zero::zero() + } + } + + /// Number of limbs. + pub fn len(&self) -> usize { self.digits.len() } + + /// A naive getter for limb at `index`. Note that the order is lsb -> msb. + /// + /// #### Panics + /// + /// This panics if index is out of range. + pub fn get(&self, index: usize) -> Single { + self.digits[self.len() - 1 - index] + } + + /// A naive getter for limb at `index`. Note that the order is lsb -> msb. + pub fn checked_get(&self, index: usize) -> Option { + if let Some(i) = self.len().checked_sub(1) { + if let Some(j) = i.checked_sub(index) { + return self.digits.get(j).cloned(); + } + } + return None; + } + + /// A naive setter for limb at `index`. Note that the order is lsb -> msb. + /// + /// #### Panics + /// + /// This panics if index is out of range. + pub fn set(&mut self, index: usize, value: Single) { + let len = self.digits.len(); + self.digits[len - 1 - index] = value; + } + + /// returns the least significant limb of the number. + /// + /// #### Panics + /// + /// While the constructor of the type prevents this, this can panic if `self` has no digits. + pub fn lsb(&self) -> Single { + self.digits[self.len() - 1] + } + + /// returns the most significant limb of the number. + /// + /// #### Panics + /// + /// While the constructor of the type prevents this, this can panic if `self` has no digits. + pub fn msb(&self) -> Single { + self.digits[0] + } + + /// Strips zeros from the left side of `self`, if any. + pub fn lstrip(&mut self) { + // by definition, a big-int number should never have leading zero limbs. This function + // has the ability to cause this. There is nothing to do if the number already has 1 + // limb only. call it a day and return. + if self.len().is_zero() { return; } + let mut index = 0; + for elem in self.digits.iter() { + if *elem != 0 { break } else { index += 1 } + } + if index > 0 { + self.digits = self.digits[index..].to_vec() + } + } + + /// Zero-pad `self` from left to reach `size` limbs. Will not make any difference if `self` + /// is already bigger than `size` limbs. + pub fn lpad(&mut self, size: usize) { + let n = self.len(); + if n >= size { return; } + let pad = size - n; + let mut new_digits = (0..pad).map(|_| 0).collect::>(); + new_digits.extend(self.digits.iter()); + self.digits = new_digits; + } + + /// Adds `self` with `other`. self and other do not have to have any particular size. Given + /// that the `n = max{size(self), size(other)}`, it will produce a number with `n + 1` + /// limbs. + /// + /// This function does not strip the output and returns the original allocated `n + 1` + /// limbs. The caller may strip the output if desired. + /// + /// Taken from "The Art of Computer Programming" by D.E. Knuth, vol 2, chapter 4. + pub fn add(self, other: &Self) -> Self { + let n = self.len().max(other.len()); + let mut k: Double = 0; + let mut w = Self::with_capacity(n + 1); + + for j in 0..n { + let u = Double::from(self.checked_get(j).unwrap_or(0)); + let v = Double::from(other.checked_get(j).unwrap_or(0)); + let s = u + v + k; + w.set(j, (s % B) as Single); + k = s / B; + } + // k is always 0 or 1. + w.set(n, k as Single); + w + } + + /// Subtracts `other` from `self`. self and other do not have to have any particular size. + /// Given that the `n = max{size(self), size(other)}`, it will produce a number of size `n`. + /// + /// If `other` is bigger than `self`, `Err(B - borrow)` is returned. + /// + /// Taken from "The Art of Computer Programming" by D.E. Knuth, vol 2, chapter 4. + pub fn sub(self, other: &Self) -> Result { + let n = self.len().max(other.len()); + let mut k = 0; + let mut w = Self::with_capacity(n); + for j in 0..n { + let s = { + let u = Double::from(self.checked_get(j).unwrap_or(0)); + let v = Double::from(other.checked_get(j).unwrap_or(0)); + let mut needs_borrow = false; + let mut t = 0; + + if let Some(v) = u.checked_sub(v) { + if let Some(v2) = v.checked_sub(k) { + t = v2 % B; + k = 0; + } else { + needs_borrow = true; + } + } else { + needs_borrow = true; + } + if needs_borrow { + t = u + B - v - k; + k = 1; + } + t + }; + // PROOF: t either comes from `v2 % B`, or from `u + B - v - k`. The former is + // trivial. The latter will not overflow this branch will only happen if the sum of + // `u - v - k` part has been negative, hence `u + B - v - k < b`. + w.set(j, s as Single); + } + + if k.is_zero() { + Ok(w) + } else { + Err(w) + } + } + + /// Multiplies n-limb number `self` with m-limb number `other`. + /// + /// The resulting number will always have `n + m` limbs. + /// + /// This function does not strip the output and returns the original allocated `n + m` + /// limbs. The caller may strip the output if desired. + /// + /// Taken from "The Art of Computer Programming" by D.E. Knuth, vol 2, chapter 4. + pub fn mul(self, other: &Self) -> Self { + let n = self.len(); + let m = other.len(); + let mut w = Self::with_capacity(m + n); + + for j in 0..n { + if self.get(j) == 0 { + // Note: `with_capacity` allocates with 0. Explicitly set j + m to zero if + // otherwise. + continue; + } + + let mut k = 0; + for i in 0..m { + // PROOF: (B−1) × (B−1) + (B−1) + (B−1) = B^2 −1 < B^2. addition is safe. + let t = + mul_single(self.get(j), other.get(i)) + + Double::from(w.get(i + j)) + + Double::from(k); + w.set(i + j, (t % B) as Single); + // PROOF: (B^2 - 1) / B < B. conversion is safe. + k = (t / B) as Single; + } + w.set(j + m, k); + } + w + } + + /// Divides `self` by a single limb `other`. This can be used in cases where the original + /// division cannot work due to the divisor (`other`) being just one limb. + /// + /// Invariant: `other` cannot be zero. + pub fn div_unit(self, mut other: Single) -> Self { + other = other.max(1); + let n = self.len(); + let mut out = Self::with_capacity(n); + let mut r: Single = 0; + // PROOF: (B-1) * B + (B-1) still fits in double + let with_r = |x: Double, r: Single| { r as Double * B + x }; + for d in (0..=n-1).rev() { + let (q, rr) = div_single(with_r(self.get(d).into(), r), other) ; + out.set(d, q as Single); + r = rr; + } + out + } + + /// Divides an `n + m` limb self by a `n` limb `other`. The result is a `m + 1` limb + /// quotient and a `n` limb remainder, if enabled by passing `true` in `rem` argument, both + /// in the form of an option's `Ok`. + /// + /// - requires `other` to be stripped and have no leading zeros. + /// - requires `self` to be stripped and have no leading zeros. + /// - requires `other` to have at least two limbs. + /// - requires `self` to have a greater length compared to `other`. + /// + /// All arguments are examined without being stripped for the above conditions. If any of + /// the above fails, `None` is returned.` + /// + /// Taken from "The Art of Computer Programming" by D.E. Knuth, vol 2, chapter 4. + pub fn div(self, other: &Self, rem: bool) -> Option<(Self, Self)> { + if other.len() <= 1 + || other.msb() == 0 + || self.msb() == 0 + || self.len() <= other.len() + { + return None + } + let n = other.len(); + let m = self.len() - n; + + let mut q = Self::with_capacity(m + 1); + let mut r = Self::with_capacity(n); + + debug_assert!(other.msb() != 0); + + // PROOF: 0 <= normalizer_bits < SHIFT 0 <= normalizer < B. all conversions are + // safe. + let normalizer_bits = other.msb().leading_zeros() as Single; + let normalizer = (2 as Single).pow(normalizer_bits as u32) as Single; + + // step D1. + let mut self_norm = self.mul(&Self::from(normalizer)); + let mut other_norm = other.clone().mul(&Self::from(normalizer)); + + // defensive only; the mul implementation should always create this. + self_norm.lpad(n + m + 1); + other_norm.lstrip(); + + // step D2. + for j in (0..=m).rev() { + // step D3.0 Find an estimate of q[j], named qhat. + let (qhat, rhat) = { + // PROOF: this always fits into `Double`. In the context of Single = u8, and + // Double = u16, think of 255 * 256 + 255 which is just u16::max_value(). + let dividend = + Double::from(self_norm.get(j + n)) + * B + + Double::from(self_norm.get(j + n - 1)); + let divisor = other_norm.get(n - 1); + div_single(dividend, divisor.into()) + }; + + // D3.1 test qhat + // replace qhat and rhat with RefCells. This helps share state with the closure + let qhat = RefCell::new(qhat); + let rhat = RefCell::new(rhat as Double); + + let test = || { + // decrease qhat if it is bigger than the base (B) + let qhat_local = *qhat.borrow(); + let rhat_local = *rhat.borrow(); + let predicate_1 = qhat_local >= B; + let predicate_2 = { + let lhs = qhat_local * other_norm.get(n - 2) as Double; + let rhs = B * rhat_local + self_norm.get(j + n - 2) as Double; + lhs > rhs + }; + if predicate_1 || predicate_2 { + *qhat.borrow_mut() -= 1; + *rhat.borrow_mut() += other_norm.get(n - 1) as Double; + true + } else { + false + } + }; + + test(); + while (*rhat.borrow() as Double) < B { + if !test() { break; } + } + + let qhat = qhat.into_inner(); + // we don't need rhat anymore. just let it go out of scope when it does. + + // step D4 + let lhs = Self { digits: (j..=j+n).rev().map(|d| self_norm.get(d)).collect() }; + let rhs = other_norm.clone().mul(&Self::from(qhat)); + + let maybe_sub = lhs.sub(&rhs); + let mut negative = false; + let sub = match maybe_sub { + Ok(t) => t, + Err(t) => { negative = true; t } + }; + (j..=j+n).for_each(|d| { self_norm.set(d, sub.get(d - j)); }); + + // step D5 + // PROOF: the `test()` specifically decreases qhat until it is below `B`. conversion + // is safe. + q.set(j, qhat as Single); + + // step D6: add back if negative happened. + if negative { + q.set(j, q.get(j) - 1); + let u = Self { digits: (j..=j+n).rev().map(|d| self_norm.get(d)).collect() }; + let r = other_norm.clone().add(&u); + (j..=j+n).rev().for_each(|d| { self_norm.set(d, r.get(d - j)); }) + } + } + + // if requested, calculate remainder. + if rem { + // undo the normalization. + if normalizer_bits > 0 { + let s = SHIFT as u32; + let nb = normalizer_bits; + for d in 0..n-1 { + let v = self_norm.get(d) >> nb + | self_norm.get(d + 1).overflowing_shl(s - nb).0; + r.set(d, v); + } + r.set(n - 1, self_norm.get(n - 1) >> normalizer_bits); + } else { + r = self_norm; + } + } + + Some((q, r)) + } + } + + #[cfg(feature = "std")] + impl rstd::fmt::Debug for BigUint { + fn fmt(&self, f: &mut rstd::fmt::Formatter<'_>) -> rstd::fmt::Result { + write!( + f, + "BigUint {{ {:?} ({:?})}}", + self.digits, + u128::try_from(self.clone()).unwrap_or_else(|_| 0), + ) + } + } + + impl PartialEq for BigUint { + fn eq(&self, other: &Self) -> bool { + // sadly, we have to reallocate here as strip mutably uses self. + let mut lhs = self.clone(); + let mut rhs = other.clone(); + lhs.lstrip(); + rhs.lstrip(); + lhs.digits.eq(&rhs.digits) + } + } + + impl Eq for BigUint {} + + impl Ord for BigUint { + fn cmp(&self, other: &Self) -> Ordering { + let lhs_first = self.digits.iter().position(|&e| e != 0); + let rhs_first = other.digits.iter().position(|&e| e != 0); + + match (lhs_first, rhs_first) { + // edge cases that should not happen. This basically means that one or both were + // zero. + (None, None) => Ordering::Equal, + (Some(_), None) => Ordering::Greater, + (None, Some(_)) => Ordering::Less, + (Some(lhs_idx), Some(rhs_idx)) => { + let lhs = &self.digits[lhs_idx..]; + let rhs = &other.digits[rhs_idx..]; + let len_cmp = lhs.len().cmp(&rhs.len()); + match len_cmp { + Ordering::Equal => lhs.cmp(rhs), + _ => len_cmp, + } + } + } + } + } + + impl PartialOrd for BigUint { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } + } + + impl ops::Add for BigUint { + type Output = Self; + fn add(self, rhs: Self) -> Self::Output { + self.add(&rhs) + } + } + + impl ops::Sub for BigUint { + type Output = Self; + fn sub(self, rhs: Self) -> Self::Output { + self.sub(&rhs).unwrap_or_else(|e| e) + } + } + + impl ops::Mul for BigUint { + type Output = Self; + fn mul(self, rhs: Self) -> Self::Output { + self.mul(&rhs) + } + } + + impl Zero for BigUint { + fn zero() -> Self { + Self { digits: vec![Zero::zero()] } + } + + fn is_zero(&self) -> bool { + self.digits.iter().all(|d| d.is_zero()) + } + } + + macro_rules! impl_try_from_number_for { + ($([$type:ty, $len:expr]),+) => { + $( + impl TryFrom for $type { + type Error = &'static str; + fn try_from(mut value: BigUint) -> Result<$type, Self::Error> { + value.lstrip(); + let error_message = concat!("cannot fit a number into ", stringify!($type)); + if value.len() * SHIFT > $len { + Err(error_message) + } else { + let mut acc: $type = Zero::zero(); + for (i, d) in value.digits.iter().rev().cloned().enumerate() { + let d: $type = d.into(); + acc += d << (SHIFT * i); + } + Ok(acc) + } + } + } + )* + }; + } + // can only be implemented for sizes bigger than two limb. + impl_try_from_number_for!([u128, 128], [u64, 64]); + + macro_rules! impl_from_for_smaller_than_word { + ($($type:ty),+) => { + $(impl From<$type> for BigUint { + fn from(a: $type) -> Self { + Self { digits: vec! [a.into()] } + } + })* + } + } + impl_from_for_smaller_than_word!(u8, u16, Single); + + impl From for BigUint { + fn from(a: Double) -> Self { + let (ah, al) = split(a); + Self { digits: vec![ah, al] } + } + } + + #[cfg(test)] + pub mod tests_biguint { + use super::*; + use rand::Rng; + #[cfg(feature = "bench")] + use test::Bencher; + + // TODO move into a proper fuzzer #3745 + const FUZZ_COUNT: usize = 100_000; + + pub fn random_big_uint(size: usize) -> BigUint { + let mut rng = rand::thread_rng(); + let digits = (0..size).map(|_| rng.gen_range(0, Single::max_value())).collect(); + BigUint { digits } + } + + fn run_with_data_set( + count: usize, + limbs_ub_1: usize, + limbs_ub_2: usize, + exact: bool, + assertion: F, + ) where + F: Fn(BigUint, BigUint) -> () + { + let mut rng = rand::thread_rng(); + for _ in 0..count { + let digits_len_1 = if exact { limbs_ub_1 } else { rng.gen_range(1, limbs_ub_1) }; + let digits_len_2 = if exact { limbs_ub_2 } else { rng.gen_range(1, limbs_ub_2) }; + + let u = random_big_uint(digits_len_1); + let v = random_big_uint(digits_len_2); + assertion(u, v); + } + } + + fn with_limbs(n: usize) -> BigUint { + BigUint { digits: vec![1; n] } + } + + #[test] + fn split_works() { + let a = SHIFT / 2; + let b = SHIFT * 3 / 2; + let num: Double = 1 << a | 1 << b; + // example when `Single = u8` + // assert_eq!(num, 0b_0001_0000_0001_0000) + assert_eq!(split(num), (1 << a, 1 << a)); + } + + #[test] + fn strip_works() { + let mut a = BigUint::from_limbs(&[0, 1, 0]); + a.lstrip(); + assert_eq!(a, BigUint { digits: vec![1, 0] }); + + let mut a = BigUint::from_limbs(&[0, 0, 1]); + a.lstrip(); + assert_eq!(a, BigUint { digits: vec![1] }); + + let mut a = BigUint::from_limbs(&[0, 0]); + a.lstrip(); + assert_eq!(a, BigUint { digits: vec![0] }); + + let mut a = BigUint::from_limbs(&[0, 0, 0]); + a.lstrip(); + assert_eq!(a, BigUint { digits: vec![0] }); + } + + #[test] + fn lpad_works() { + let mut a = BigUint::from_limbs(&[0, 1, 0]); + a.lpad(2); + assert_eq!(a.digits, vec![0, 1, 0]); + + let mut a = BigUint::from_limbs(&[0, 1, 0]); + a.lpad(3); + assert_eq!(a.digits, vec![0, 1, 0]); + + let mut a = BigUint::from_limbs(&[0, 1, 0]); + a.lpad(4); + assert_eq!(a.digits, vec![0, 0, 1, 0]); + } + + #[test] + fn equality_works() { + assert_eq!( + BigUint { digits: vec![1, 2, 3] } == BigUint { digits: vec![1, 2, 3] }, + true, + ); + assert_eq!( + BigUint { digits: vec![3, 2, 3] } == BigUint { digits: vec![1, 2, 3] }, + false, + ); + assert_eq!( + BigUint { digits: vec![0, 1, 2, 3] } == BigUint { digits: vec![1, 2, 3] }, + true, + ); + } + + #[test] + fn ordering_works() { + assert!(BigUint { digits: vec![0] } < BigUint { digits: vec![1] }); + assert!(BigUint { digits: vec![0] } == BigUint { digits: vec![0] }); + assert!(BigUint { digits: vec![] } == BigUint { digits: vec![0] }); + assert!(BigUint { digits: vec![] } == BigUint { digits: vec![] }); + assert!(BigUint { digits: vec![] } < BigUint { digits: vec![1] }); + + assert!(BigUint { digits: vec![1, 2, 3] } == BigUint { digits: vec![1, 2, 3] }); + assert!(BigUint { digits: vec![0, 1, 2, 3] } == BigUint { digits: vec![1, 2, 3] }); + + assert!(BigUint { digits: vec![1, 2, 4] } > BigUint { digits: vec![1, 2, 3] }); + assert!(BigUint { digits: vec![0, 1, 2, 4] } > BigUint { digits: vec![1, 2, 3] }); + assert!(BigUint { digits: vec![1, 2, 1, 0] } > BigUint { digits: vec![1, 2, 3] }); + + assert!(BigUint { digits: vec![0, 1, 2, 1] } < BigUint { digits: vec![1, 2, 3] }); + } + + #[test] + fn basic_random_ord_eq_works() { + type S = u128; + run_with_data_set(FUZZ_COUNT, 4, 4, false, |u, v| { + let ue = S::try_from(u.clone()).unwrap(); + let ve = S::try_from(v.clone()).unwrap(); + assert_eq!(u.cmp(&v), ue.cmp(&ve)); + assert_eq!(u.eq(&v), ue.eq(&ve)); + }) + } + + #[test] + fn can_try_build_numbers_from_types() { + use rstd::convert::TryFrom; + assert_eq!(u64::try_from(with_limbs(1)).unwrap(), 1); + assert_eq!(u64::try_from(with_limbs(2)).unwrap(), u32::max_value() as u64 + 2); + assert_eq!( + u64::try_from(with_limbs(3)).unwrap_err(), + "cannot fit a number into u64", + ); + assert_eq!( + u128::try_from(with_limbs(3)).unwrap(), + u32::max_value() as u128 + u64::max_value() as u128 + 3 + ); + } + + #[test] + fn zero_works() { + assert_eq!(BigUint::zero(), BigUint { digits: vec![0] }); + assert_eq!(BigUint { digits: vec![0, 1, 0] }.is_zero(), false); + assert_eq!(BigUint { digits: vec![0, 0, 0] }.is_zero(), true); + + let a = BigUint::zero(); + let b = BigUint::zero(); + let c = a * b; + assert_eq!(c.digits, vec![0, 0]); + } + + #[test] + fn basic_random_add_works() { + type S = u128; + run_with_data_set(FUZZ_COUNT, 3, 3, false, |u, v| { + let expected = S::try_from(u.clone()).unwrap() + S::try_from(v.clone()).unwrap(); + let t = u.clone().add(&v); + assert_eq!( + S::try_from(t.clone()).unwrap(), expected, + "{:?} + {:?} ===> {:?} != {:?}", u, v, t, expected, + ); + }) + } + + #[test] + fn sub_negative_works() { + assert_eq!( + BigUint::from(10 as Single).sub(&BigUint::from(5 as Single)).unwrap(), + BigUint::from(5 as Single) + ); + assert_eq!( + BigUint::from(10 as Single).sub(&BigUint::from(10 as Single)).unwrap(), + BigUint::from(0 as Single) + ); + assert_eq!( + BigUint::from(10 as Single).sub(&BigUint::from(13 as Single)).unwrap_err(), + BigUint::from((B - 3) as Single), + ); + } + + #[test] + fn basic_random_sub_works() { + type S = u128; + run_with_data_set(FUZZ_COUNT, 4, 4, false, |u, v| { + let expected = S::try_from(u.clone()).unwrap() + .checked_sub(S::try_from(v.clone()).unwrap()); + let t = u.clone().sub(&v); + if expected.is_none() { + assert!(t.is_err()) + } else { + let t = t.unwrap(); + let expected = expected.unwrap(); + assert_eq!( + S::try_from(t.clone()).unwrap(), expected, + "{:?} - {:?} ===> {:?} != {:?}", u, v, t, expected, + ); + } + }) + } + + #[test] + fn basic_random_mul_works() { + type S = u128; + run_with_data_set(FUZZ_COUNT, 2, 2, false, |u, v| { + let expected = S::try_from(u.clone()).unwrap() * S::try_from(v.clone()).unwrap(); + let t = u.clone().mul(&v); + assert_eq!( + S::try_from(t.clone()).unwrap(), expected, + "{:?} * {:?} ===> {:?} != {:?}", u, v, t, expected, + ); + }) + } + + #[test] + fn mul_always_appends_one_digit() { + let a = BigUint::from(10 as Single); + let b = BigUint::from(4 as Single); + assert_eq!(a.len(), 1); + assert_eq!(b.len(), 1); + + let n = a.mul(&b); + + assert_eq!(n.len(), 2); + assert_eq!(n.digits, vec![0, 40]); + } + + #[test] + fn div_conditions_work() { + let a = BigUint { digits: vec![2] }; + let b = BigUint { digits: vec![1, 2] }; + let c = BigUint { digits: vec![1, 1, 2] }; + let d = BigUint { digits: vec![0, 2] }; + let e = BigUint { digits: vec![0, 1, 1, 2] }; + + assert!(a.clone().div(&b, true).is_none()); + assert!(c.clone().div(&a, true).is_none()); + assert!(c.clone().div(&d, true).is_none()); + assert!(e.clone().div(&a, true).is_none()); + + assert!(c.clone().div(&b, true).is_some()); + } + + #[test] + fn div_unit_works() { + let a = BigUint { digits: vec![100] }; + let b = BigUint { digits: vec![1, 100] }; + + assert_eq!(a.clone().div_unit(1), a); + assert_eq!(a.clone().div_unit(0), a); + assert_eq!(a.clone().div_unit(2), BigUint::from(50 as Single)); + assert_eq!(a.clone().div_unit(7), BigUint::from(14 as Single)); + + assert_eq!(b.clone().div_unit(1), b); + assert_eq!(b.clone().div_unit(0), b); + assert_eq!(b.clone().div_unit(2), BigUint::from(((B + 100) / 2) as Single)); + assert_eq!(b.clone().div_unit(7), BigUint::from(((B + 100) / 7) as Single)); + + } + + #[test] + fn basic_random_div_works() { + type S = u128; + run_with_data_set(FUZZ_COUNT, 4, 4, false, |u, v| { + let ue = S::try_from(u.clone()).unwrap(); + let ve = S::try_from(v.clone()).unwrap(); + let (q, r) = (ue / ve, ue % ve); + if let Some((qq, rr)) = u.clone().div(&v, true) { + assert_eq!( + S::try_from(qq.clone()).unwrap(), q, + "{:?} / {:?} ===> {:?} != {:?}", u, v, qq, q, + ); + assert_eq!( + S::try_from(rr.clone()).unwrap(), r, + "{:?} % {:?} ===> {:?} != {:?}", u, v, rr, r, + ); + } else if v.len() == 1 { + let qq = u.clone().div_unit(ve as Single); + assert_eq!( + S::try_from(qq.clone()).unwrap(), q, + "[single] {:?} / {:?} ===> {:?} != {:?}", u, v, qq, q, + ); + } else { + if v.msb() == 0 || v.msb() == 0 || u.len() <= v.len() {} // nada + else { panic!("div returned none for an unexpected reason"); } + } + }) + } + + #[cfg(feature = "bench")] + #[bench] + fn bench_addition_2_digit(bencher: &mut Bencher) { + let a = random_big_uint(2); + let b = random_big_uint(2); + bencher.iter(|| { + let _ = a.clone().add(&b); + }); + } + + #[cfg(feature = "bench")] + #[bench] + fn bench_addition_4_digit(bencher: &mut Bencher) { + let a = random_big_uint(4); + let b = random_big_uint(4); + bencher.iter(|| { + let _ = a.clone().add(&b); + }); + } + + #[cfg(feature = "bench")] + #[bench] + fn bench_subtraction_2_digit(bencher: &mut Bencher) { + let a = random_big_uint(2); + let b = random_big_uint(2); + bencher.iter(|| { + let _ = a.clone().sub(&b); + }); + } + + #[cfg(feature = "bench")] + #[bench] + fn bench_subtraction_4_digit(bencher: &mut Bencher) { + let a = random_big_uint(4); + let b = random_big_uint(4); + bencher.iter(|| { + let _ = a.clone().sub(&b); + }); + } + + #[cfg(feature = "bench")] + #[bench] + fn bench_multiplication_2_digit(bencher: &mut Bencher) { + let a = random_big_uint(2); + let b = random_big_uint(2); + bencher.iter(|| { + let _ = a.clone().mul(&b); + }); + } + + #[cfg(feature = "bench")] + #[bench] + fn bench_multiplication_4_digit(bencher: &mut Bencher) { + let a = random_big_uint(4); + let b = random_big_uint(4); + bencher.iter(|| { + let _ = a.clone().mul(&b); + }); + } + + #[cfg(feature = "bench")] + #[bench] + fn bench_division_4_digit(bencher: &mut Bencher) { + let a = random_big_uint(4); + let b = random_big_uint(2); + bencher.iter(|| { + let _ = a.clone().div(&b, true); + }); + } + } +} + /// Some helper functions to work with 128bit numbers. Note that the functionality provided here is /// only sensible to use with 128bit numbers because for smaller sizes, you can always rely on /// assumptions of a bigger type (u128) being available, or simply create a per-thing and use the /// multiplication implementation provided there. pub mod helpers_128bit { - use super::Perquintill; + use crate::biguint; use crate::traits::Zero; - use rstd::cmp::{min, max}; - - const ERROR: &'static str = "can not accurately multiply by rational in this type"; + use rstd::{cmp::{min, max}, convert::TryInto}; /// Helper gcd function used in Rational128 implementation. pub fn gcd(a: u128, b: u128) -> u128 { @@ -695,18 +1608,31 @@ pub mod helpers_128bit { } } + /// split a u128 into two u64 limbs + pub fn split(a: u128) -> (u64, u64) { + let al = a as u64; + let ah = (a >> 64) as u64; + (ah, al) + } + + /// Convert a u128 to a u32 based biguint. + pub fn to_big_uint(x: u128) -> biguint::BigUint { + let (xh, xl) = split(x); + let (xhh, xhl) = biguint::split(xh); + let (xlh, xll) = biguint::split(xl); + let mut n = biguint::BigUint::from_limbs(&[xhh, xhl, xlh, xll]); + n.lstrip(); + n + } + /// Safely and accurately compute `a * b / c`. The approach is: /// - Simply try `a * b / c`. - /// - Else, swap the operations (divide first) if `a > c` (division is possible) and `b <= c` - /// (overflow cannot happen) - /// - At any point, given an overflow or accuracy loss, return an Error. + /// - Else, convert them both into big numbers and re-try. `Err` is returned if the result + /// cannot be safely casted back to u128. /// /// Invariant: c must be greater than or equal to 1. - /// This might not return Ok even if `b < c`. pub fn multiply_by_rational(a: u128, b: u128, c: u128) -> Result { if a.is_zero() || b.is_zero() { return Ok(Zero::zero()); } - - // invariant: C cannot be zero. let c = c.max(1); // a and b are interchangeable by definition in this function. It always helps to assume the @@ -719,69 +1645,31 @@ pub mod helpers_128bit { if let Some(x) = a.checked_mul(b) { // This is the safest way to go. Try it. Ok(x / c) - } else if a > c { - // if it can be safely swapped and it is a fraction, then swap. - let q = a / c; - let r = a % c; - let r_additional = multiply_by_rational(r, b, c)?; - - let q_part = q.checked_mul(b) - .ok_or(ERROR)?; - let result = q_part.checked_add(r_additional) - .ok_or(ERROR)?; - Ok(result) } else { - Err(ERROR) - } - } - - /// Performs [`multiply_by_rational`]. In case of failure, if `b < c` it tries to approximate - /// the ratio into a perquintillion and return a lossy result. Otherwise, a best effort approach - /// of shifting both b and c is performed until multiply_by_rational can work. - /// - /// This function can very well be lossy and as the name suggests, perform a best effort in the - /// scope of u128 numbers. In case `b > c` and overflow happens, `a` is returned. - /// - /// c must be greater than or equal to 1. - pub fn multiply_by_rational_best_effort(a: u128, b: u128, c: u128) -> u128 { - if a.is_zero() || b.is_zero() { return Zero::zero(); } - let c = c.max(1); - - // unwrap the loop once. This favours performance over readability. - multiply_by_rational(a, b, c).unwrap_or_else(|_| { - if b <= c { - let per_thing = Perquintill::from_rational_approximation(b, c); - per_thing * a + let a_num = to_big_uint(a); + let b_num = to_big_uint(b); + let c_num = to_big_uint(c); + + let mut ab = a_num * b_num; + ab.lstrip(); + let mut q = if c_num.len() == 1 { + // PROOF: if `c_num.len() == 1` then `c` fits in one limb. + ab.div_unit(c as biguint::Single) } else { - let mut shift = 1; - let mut shifted_b = b.checked_shr(shift).unwrap_or(0); - let mut shifted_c = c.checked_shr(shift).unwrap_or(0); - - loop { - if shifted_b.is_zero() || shifted_c.is_zero() { - break a - } - match multiply_by_rational(a, shifted_b, shifted_c) { - Ok(r) => break r, - Err(_) => { - shift = shift + 1; - // by the time we reach here, b >= 1 && c >= 1. Before panic, they have - // to be zero which is prevented to happen by the break. - shifted_b = b.checked_shr(shift) - .expect( - "b >= 1 && c >= 1; break prevents them from ever being zero; \ - panic can only happen after either is zero; qed" - ); - shifted_c = c.checked_shr(shift) - .expect( - "b >= 1 && c >= 1; break prevents them from ever being zero; \ - panic can only happen after either is zero; qed" - ); - } - } - } - } - }) + // PROOF: both `ab` and `c` cannot have leading zero limbs; if length of `c` is 1, + // the previous branch would handle. Also, if ab for sure has a bigger size than + // c, because `a.checked_mul(b)` has failed, hence ab must be at least one limb + // bigger than c. In this case, returning zero is defensive-only and div should + // always return Some. + let (mut q, r) = ab.div(&c_num, true).unwrap_or((Zero::zero(), Zero::zero())); + let r: u128 = r.try_into() + .expect("reminder of div by c is always less than c; qed"); + if r > (c / 2) { q = q.add(&to_big_uint(1)); } + q + }; + q.lstrip(); + q.try_into().map_err(|_| "result cannot fit in u128") + } } } @@ -829,13 +1717,7 @@ impl Rational128 { if den == self.1 { Ok(self) } else { - if den > self.1 { - let n = helpers_128bit::multiply_by_rational(self.0, den, self.1)?; - Ok(Self(n, den)) - } else { - let div = self.1 / den; - Ok(Self(self.0 / div.max(1), den)) - } + helpers_128bit::multiply_by_rational(self.0, den, self.1).map(|n| Self(n, den)) } } @@ -872,9 +1754,9 @@ impl Rational128 { /// /// Overflow might happen during any of the steps. Error is returned in such cases. pub fn checked_add(self, other: Self) -> Result { - let lcm = self.lcm(&other)?; - let self_scaled = self.to_den(lcm)?; - let other_scaled = other.to_den(lcm)?; + let lcm = self.lcm(&other).map_err(|_| "failed to scale to denominator")?; + let self_scaled = self.to_den(lcm).map_err(|_| "failed to scale to denominator")?; + let other_scaled = other.to_den(lcm).map_err(|_| "failed to scale to denominator")?; let n = self_scaled.0.checked_add(other_scaled.0) .ok_or("overflow while adding numerators")?; Ok(Self(n, self_scaled.1)) @@ -884,9 +1766,9 @@ impl Rational128 { /// /// Overflow might happen during any of the steps. None is returned in such cases. pub fn checked_sub(self, other: Self) -> Result { - let lcm = self.lcm(&other)?; - let self_scaled = self.to_den(lcm)?; - let other_scaled = other.to_den(lcm)?; + let lcm = self.lcm(&other).map_err(|_| "failed to scale to denominator")?; + let self_scaled = self.to_den(lcm).map_err(|_| "failed to scale to denominator")?; + let other_scaled = other.to_den(lcm).map_err(|_| "failed to scale to denominator")?; let n = self_scaled.0.checked_sub(other_scaled.0) .ok_or("overflow while subtracting numerators")?; @@ -900,7 +1782,6 @@ impl PartialOrd for Rational128 { } } -/// Note that this implementation can very well be lossy. TODO #3670 impl Ord for Rational128 { fn cmp(&self, other: &Self) -> Ordering { // handle some edge cases. @@ -911,49 +1792,31 @@ impl Ord for Rational128 { } else if other.1.is_zero() { Ordering::Less } else { - // general lossy case - let saturated_lcm = helpers_128bit::multiply_by_rational_best_effort( - self.1, - other.1, - helpers_128bit::gcd(self.1, other.1) - ); - let self_scaled = self.to_den(saturated_lcm) - .unwrap_or(Self(Bounded::max_value(), self.1)); - let other_scaled = other.to_den(saturated_lcm) - .unwrap_or(Self(Bounded::max_value(), other.1)); - self_scaled.n().cmp(&other_scaled.n()) + // Don't even compute gcd. + let self_n = helpers_128bit::to_big_uint(self.0) * helpers_128bit::to_big_uint(other.1); + let other_n = helpers_128bit::to_big_uint(other.0) * helpers_128bit::to_big_uint(self.1); + self_n.cmp(&other_n) } } } -/// Note that this implementation can very well be lossy. TODO #3670 impl PartialEq for Rational128 { fn eq(&self, other: &Self) -> bool { // handle some edge cases. if self.1 == other.1 { self.0.eq(&other.0) } else { - // general lossy case - let saturated_lcm = helpers_128bit::multiply_by_rational_best_effort( - self.1, - other.1, - helpers_128bit::gcd(self.1, other.1) - ); - let self_scaled = self.to_den(saturated_lcm) - .unwrap_or(Self(Bounded::max_value(), self.1)); - let other_scaled = other.to_den(saturated_lcm) - .unwrap_or(Self(Bounded::max_value(), other.1)); - self_scaled.n().eq(&other_scaled.n()) + let self_n = helpers_128bit::to_big_uint(self.0) * helpers_128bit::to_big_uint(other.1); + let other_n = helpers_128bit::to_big_uint(other.0) * helpers_128bit::to_big_uint(self.1); + self_n.eq(&other_n) } } } - #[cfg(test)] mod test_rational128 { use super::*; use super::helpers_128bit::*; - use crate::assert_eq_error_rate; use rand::Rng; const MAX128: u128 = u128::max_value(); @@ -1004,7 +1867,7 @@ mod test_rational128 { assert_eq!(r(4, 10).to_den(5), Ok(r(2, 5))); // up and down with large numbers - assert_eq!(r(MAX128 - 10, MAX128).to_den(10), Ok(r(9, 10))); + assert_eq!(r(MAX128 - 10, MAX128).to_den(10), Ok(r(10, 10))); assert_eq!(r(MAX128 / 2, MAX128).to_den(10), Ok(r(5, 10))); // large to perbill. This is very well needed for phragmen. @@ -1033,7 +1896,7 @@ mod test_rational128 { // large numbers assert_eq!( r(1_000_000_000, MAX128).lcm(&r(7_000_000_000, MAX128-1)), - Err("can not accurately multiply by rational in this type"), + Err("result cannot fit in u128"), ); assert_eq!( r(1_000_000_000, MAX64).lcm(&r(7_000_000_000, MAX64-1)), @@ -1052,7 +1915,7 @@ mod test_rational128 { // errors assert_eq!( r(1, MAX128).checked_add(r(1, MAX128-1)), - Err("can not accurately multiply by rational in this type"), + Err("failed to scale to denominator"), ); assert_eq!( r(7, MAX128).checked_add(r(MAX128, MAX128)), @@ -1073,7 +1936,7 @@ mod test_rational128 { // errors assert_eq!( r(2, MAX128).checked_sub(r(1, MAX128-1)), - Err("can not accurately multiply by rational in this type"), + Err("failed to scale to denominator"), ); assert_eq!( r(7, MAX128).checked_sub(r(MAX128, MAX128)), @@ -1105,7 +1968,6 @@ mod test_rational128 { assert_eq!(multiply_by_rational(7, 20, 30).unwrap(), 7 * 2 / 3); assert_eq!(multiply_by_rational(20, 7, 30).unwrap(), 7 * 2 / 3); - // computed with swap assert_eq!( // MAX128 % 3 == 0 multiply_by_rational(MAX128, 2, 3).unwrap(), @@ -1136,7 +1998,6 @@ mod test_rational128 { 2 * MAX64 - 3, ); - assert_eq!( multiply_by_rational(MAX64 + 100, MAX64_2, MAX64_2 / 2).unwrap(), (MAX64 + 100) * 2, @@ -1146,9 +2007,14 @@ mod test_rational128 { (MAX64 + 100) * 2, ); - // fails to compute. have to use the greedy, lossy version here - assert!(multiply_by_rational(2u128.pow(66) - 1, 2u128.pow(65) - 1, 2u128.pow(65)).is_err()); - assert!(multiply_by_rational(1_000_000_000, MAX128 / 8, MAX128 / 2).is_err()); + assert_eq!( + multiply_by_rational(2u128.pow(66) - 1, 2u128.pow(65) - 1, 2u128.pow(65)).unwrap(), + 73786976294838206461, + ); + assert_eq!( + multiply_by_rational(1_000_000_000, MAX128 / 8, MAX128 / 2).unwrap(), + 250000000, + ); } #[test] @@ -1163,40 +2029,6 @@ mod test_rational128 { ); } - #[test] - fn multiply_by_rational_best_effort_works() { - assert_eq_error_rate!( - multiply_by_rational_best_effort(MAX64 + 100, MAX64_2, MAX64_2 / 2), - (MAX64 + 100) * 2, - 10, - ); - assert_eq_error_rate!( - multiply_by_rational_best_effort(MAX64 + 100, MAX64_2 * 100, MAX64_2 * 100 / 2), - (MAX64 + 100) * 2, - 10, - ); - assert_eq_error_rate!( - multiply_by_rational_best_effort(2u128.pow(66) - 1, 2u128.pow(65) - 1, 2u128.pow(65)), - mul_div(2u128.pow(66) - 1, 2u128.pow(65) - 1, 2u128.pow(65)), - 10, - ); - assert_eq_error_rate!( - multiply_by_rational_best_effort(1_000_000_000, MAX128 / 8, MAX128 / 2), - 1_000_000_000 / 4, - 10, - ); - - assert_eq!( - multiply_by_rational_best_effort(MAX128, MAX128 - 1, MAX128), - MAX128, - ); - - assert_eq!( - multiply_by_rational_best_effort(MAX64, MAX128 / 2, MAX128), - MAX64 / 2, - ); - } - fn do_fuzz_multiply_by_rational( iters: usize, bits: u32, @@ -1242,42 +2074,8 @@ mod test_rational128 { ); } - #[test] - fn fuzz_multiply_by_rational_best_effort_32() { - let f = |a, b, c| multiply_by_rational_best_effort(a, b, c); - println!("\nInvariant: b < c"); - do_fuzz_multiply_by_rational(1_000_000, 32, 0, false, true, f); - println!("every possibility"); - do_fuzz_multiply_by_rational(1_000_000, 32, 0, false, false, f); - } - - #[test] - fn fuzz_multiply_by_rational_best_effort_64() { - let f = |a, b, c| multiply_by_rational_best_effort(a, b, c); - println!("\nInvariant: b < c"); - do_fuzz_multiply_by_rational(1_000_000, 64, 0, false, true, f); - println!("every possibility"); - do_fuzz_multiply_by_rational(1_000_000, 64, 0, false, false, f); - } - - #[test] - fn fuzz_multiply_by_rational_best_effort_96() { - let f = |a, b, c| multiply_by_rational_best_effort(a, b, c); - // println!("\nInvariant: b < c"); - // do_fuzz_multiply_by_rational(1_000_000, 96, 0, false, true, f); - println!("every possibility"); - // do_fuzz_multiply_by_rational(1_000_000, 96, 0, false, false, f); - do_fuzz_multiply_by_rational(10, 96, 0, true, false, f); - } - - #[test] - fn fuzz_multiply_by_rational_best_effort_128() { - let f = |a, b, c| multiply_by_rational_best_effort(a, b, c); - println!("\nInvariant: b < c"); - do_fuzz_multiply_by_rational(1_000_000, 127, 0, false, true, f); - println!("every possibility"); - do_fuzz_multiply_by_rational(1_000_000, 127, 0, false, false, f); - } + // TODO $# move into a proper fuzzer #3745 + const FUZZ_COUNT: usize = 100_000; #[test] fn fuzz_multiply_by_rational_32() { @@ -1286,40 +2084,39 @@ mod test_rational128 { // returning `Err` is fine. let f = |a, b, c| multiply_by_rational(a, b, c).unwrap_or(mul_div(a, b, c)); println!("\nInvariant: b < c"); - do_fuzz_multiply_by_rational(1_000_000, 32, 0, false, true, f); + do_fuzz_multiply_by_rational(FUZZ_COUNT, 32, 0, false, true, f); println!("every possibility"); - do_fuzz_multiply_by_rational(1_000_000, 32, 0, false, false, f); + do_fuzz_multiply_by_rational(FUZZ_COUNT, 32, 0, false, false, f); } #[test] fn fuzz_multiply_by_rational_64() { let f = |a, b, c| multiply_by_rational(a, b, c).unwrap_or(mul_div(a, b, c)); println!("\nInvariant: b < c"); - do_fuzz_multiply_by_rational(1_000_000, 64, 0, false, true, f); + do_fuzz_multiply_by_rational(FUZZ_COUNT, 64, 0, false, true, f); println!("every possibility"); - do_fuzz_multiply_by_rational(1_000_000, 64, 0, false, false, f); + do_fuzz_multiply_by_rational(FUZZ_COUNT, 64, 0, false, false, f); } #[test] fn fuzz_multiply_by_rational_96() { let f = |a, b, c| multiply_by_rational(a, b, c).unwrap_or(mul_div(a, b, c)); println!("\nInvariant: b < c"); - do_fuzz_multiply_by_rational(1_000_000, 96, 0, false, true, f); + do_fuzz_multiply_by_rational(FUZZ_COUNT, 96, 0, false, true, f); println!("every possibility"); - do_fuzz_multiply_by_rational(1_000_000, 96, 0, false, false, f); + do_fuzz_multiply_by_rational(FUZZ_COUNT, 96, 0, false, false, f); } #[test] fn fuzz_multiply_by_rational_128() { let f = |a, b, c| multiply_by_rational(a, b, c).unwrap_or(mul_div(a, b, c)); println!("\nInvariant: b < c"); - do_fuzz_multiply_by_rational(1_000_000, 127, 0, false, true, f); + do_fuzz_multiply_by_rational(FUZZ_COUNT, 127, 0, false, true, f); println!("every possibility"); - do_fuzz_multiply_by_rational(1_000_000, 127, 0, false, false, f); + do_fuzz_multiply_by_rational(FUZZ_COUNT, 127, 0, false, false, f); } } - #[cfg(test)] mod tests_fixed64 { use super::*; diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index ebe7b134e0..c132e2d430 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -84,8 +84,8 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // and set impl_version to equal spec_version. If only runtime // implementation changes and behavior does not, then leave spec_version as // is and increment impl_version. - spec_version: 173, - impl_version: 173, + spec_version: 174, + impl_version: 174, apis: RUNTIME_API_VERSIONS, }; -- GitLab From f922df62fa7db34f8731514133f0b120259cabbc Mon Sep 17 00:00:00 2001 From: Xiliang Chen Date: Thu, 10 Oct 2019 23:41:42 +1300 Subject: [PATCH 030/167] Decouple randomness-collective-flip (#3792) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Abstract Randomness trait * bump version * fix doc test * simpify code a bit * Apply suggestions from code review Co-Authored-By: Bastian Köcher Co-Authored-By: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * fix tests --- node-template/runtime/src/lib.rs | 2 +- node/runtime/src/lib.rs | 5 +-- srml/contracts/Cargo.toml | 4 +-- srml/contracts/src/exec.rs | 4 +-- srml/contracts/src/lib.rs | 5 +-- srml/contracts/src/tests.rs | 2 ++ srml/randomness-collective-flip/src/lib.rs | 37 ++++++++-------------- srml/support/src/traits.rs | 20 ++++++++++++ 8 files changed, 46 insertions(+), 33 deletions(-) diff --git a/node-template/runtime/src/lib.rs b/node-template/runtime/src/lib.rs index ba328c6e37..0e9b8050f0 100644 --- a/node-template/runtime/src/lib.rs +++ b/node-template/runtime/src/lib.rs @@ -33,7 +33,7 @@ pub use sr_primitives::BuildStorage; pub use timestamp::Call as TimestampCall; pub use balances::Call as BalancesCall; pub use sr_primitives::{Permill, Perbill}; -pub use support::{StorageValue, construct_runtime, parameter_types}; +pub use support::{StorageValue, construct_runtime, parameter_types, traits::Randomness}; /// An index to a block. pub type BlockNumber = u32; diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index c132e2d430..6ecce4c481 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -22,7 +22,7 @@ use rstd::prelude::*; use support::{ - construct_runtime, parameter_types, traits::{SplitTwoWays, Currency} + construct_runtime, parameter_types, traits::{SplitTwoWays, Currency, Randomness} }; use primitives::u32_trait::{_1, _2, _3, _4}; use node_primitives::{ @@ -85,7 +85,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // implementation changes and behavior does not, then leave spec_version as // is and increment impl_version. spec_version: 174, - impl_version: 174, + impl_version: 175, apis: RUNTIME_API_VERSIONS, }; @@ -398,6 +398,7 @@ parameter_types! { impl contracts::Trait for Runtime { type Currency = Balances; type Time = Timestamp; + type Randomness = RandomnessCollectiveFlip; type Call = Call; type Event = Event; type DetermineContractAddress = contracts::SimpleAddressDeterminator; diff --git a/srml/contracts/Cargo.toml b/srml/contracts/Cargo.toml index aad45df860..365566cfb5 100644 --- a/srml/contracts/Cargo.toml +++ b/srml/contracts/Cargo.toml @@ -17,8 +17,6 @@ rstd = { package = "sr-std", path = "../../core/sr-std", default-features = fals sandbox = { package = "sr-sandbox", path = "../../core/sr-sandbox", default-features = false } support = { package = "srml-support", path = "../support", default-features = false } system = { package = "srml-system", path = "../system", default-features = false } -randomness-collective-flip = { package = "srml-randomness-collective-flip", path = "../randomness-collective-flip", default-features = false } -timestamp = { package = "srml-timestamp", path = "../timestamp", default-features = false } [dev-dependencies] wabt = "0.9.2" @@ -27,6 +25,7 @@ hex-literal = "0.2.1" balances = { package = "srml-balances", path = "../balances" } hex = "0.3.2" timestamp = { package = "srml-timestamp", path = "../timestamp" } +randomness-collective-flip = { package = "srml-randomness-collective-flip", path = "../randomness-collective-flip" } [features] default = ["std"] @@ -35,7 +34,6 @@ std = [ "codec/std", "primitives/std", "sr-primitives/std", - "randomness-collective-flip/std", "runtime-io/std", "rstd/std", "sandbox/std", diff --git a/srml/contracts/src/exec.rs b/srml/contracts/src/exec.rs index 0cb0ee2679..a2dd3c1f3d 100644 --- a/srml/contracts/src/exec.rs +++ b/srml/contracts/src/exec.rs @@ -22,7 +22,7 @@ use crate::rent; use rstd::prelude::*; use sr_primitives::traits::{Bounded, CheckedAdd, CheckedSub, Zero}; -use support::traits::{WithdrawReason, Currency, Time}; +use support::traits::{WithdrawReason, Currency, Time, Randomness}; pub type AccountIdOf = ::AccountId; pub type CallOf = ::Call; @@ -753,7 +753,7 @@ where } fn random(&self, subject: &[u8]) -> SeedOf { - randomness_collective_flip::Module::::random(subject) + T::Randomness::random(subject) } fn now(&self) -> &MomentOf { diff --git a/srml/contracts/src/lib.rs b/srml/contracts/src/lib.rs index 918d0838c4..678fc65d76 100644 --- a/srml/contracts/src/lib.rs +++ b/srml/contracts/src/lib.rs @@ -122,9 +122,9 @@ use sr_primitives::{ use support::dispatch::{Result, Dispatchable}; use support::{ Parameter, decl_module, decl_event, decl_storage, storage::child, - parameter_types, + parameter_types, IsSubType }; -use support::{traits::{OnFreeBalanceZero, OnUnbalanced, Currency, Get, Time}, IsSubType}; +use support::traits::{OnFreeBalanceZero, OnUnbalanced, Currency, Get, Time, Randomness}; use system::{ensure_signed, RawOrigin, ensure_root}; use primitives::storage::well_known_keys::CHILD_STORAGE_KEY_PREFIX; @@ -335,6 +335,7 @@ parameter_types! { pub trait Trait: system::Trait { type Currency: Currency; type Time: Time; + type Randomness: Randomness; /// The outer call dispatch type. type Call: Parameter + Dispatchable::Origin> + IsSubType, Self>; diff --git a/srml/contracts/src/tests.rs b/srml/contracts/src/tests.rs index a92d11e4d4..9d02419b17 100644 --- a/srml/contracts/src/tests.rs +++ b/srml/contracts/src/tests.rs @@ -159,6 +159,7 @@ parameter_types! { impl Trait for Test { type Currency = Balances; type Time = Timestamp; + type Randomness = Randomness; type Call = Call; type DetermineContractAddress = DummyContractAddressFor; type Event = MetaEvent; @@ -187,6 +188,7 @@ type Balances = balances::Module; type Timestamp = timestamp::Module; type Contract = Module; type System = system::Module; +type Randomness = randomness_collective_flip::Module; pub struct DummyContractAddressFor; impl ContractAddressFor for DummyContractAddressFor { diff --git a/srml/randomness-collective-flip/src/lib.rs b/srml/randomness-collective-flip/src/lib.rs index e5110c5d21..4ad0095fdf 100644 --- a/srml/randomness-collective-flip/src/lib.rs +++ b/srml/randomness-collective-flip/src/lib.rs @@ -35,7 +35,7 @@ //! ### Example - Get random seed for the current block //! //! ``` -//! use support::{decl_module, dispatch::Result}; +//! use support::{decl_module, dispatch::Result, traits::Randomness}; //! //! pub trait Trait: system::Trait {} //! @@ -54,7 +54,7 @@ use rstd::{prelude::*, convert::TryInto}; use sr_primitives::traits::Hash; -use support::{decl_module, decl_storage}; +use support::{decl_module, decl_storage, traits::Randomness}; use safe_mix::TripletMix; use codec::Encode; use system::Trait; @@ -91,16 +91,7 @@ decl_storage! { } } -impl Module { - /// Get the basic random seed. - /// - /// In general you won't want to use this, but rather `Self::random` which allows you to give a - /// subject for the random result and whose value will be independently low-influence random - /// from any other such seeds. - pub fn random_seed() -> T::Hash { - Self::random(&[][..]) - } - +impl Randomness for Module { /// Get a low-influence "random" value. /// /// Being a deterministic block chain, real randomness is difficult to come by. This gives you @@ -138,7 +129,7 @@ impl Module { /// WARNING: Hashing the result of this function will remove any low-influence properties it has /// and mean that all bits of the resulting value are entirely manipulatable by the author of /// the parent block, who can determine the value of `parent_hash`. - pub fn random(subject: &[u8]) -> T::Hash { + fn random(subject: &[u8]) -> T::Hash { let block_number = >::block_number(); let index = block_number_to_index::(block_number); @@ -166,7 +157,7 @@ mod tests { Perbill, traits::{BlakeTwo256, OnInitialize, Header as _, IdentityLookup}, testing::Header, set_and_run_with_externalities, }; - use support::{impl_outer_origin, parameter_types}; + use support::{impl_outer_origin, parameter_types, traits::Randomness}; #[derive(Clone, PartialEq, Eq)] pub struct Test; @@ -202,7 +193,7 @@ mod tests { } type System = system::Module; - type Randomness = Module; + type CollectiveFlip = Module; fn new_test_ext() -> runtime_io::TestExternalities { let t = system::GenesisConfig::default().build_storage::().unwrap(); @@ -221,7 +212,7 @@ mod tests { for i in 1 .. (blocks + 1) { System::initialize(&i, &parent_hash, &Default::default(), &Default::default()); - Randomness::on_initialize(i); + CollectiveFlip::on_initialize(i); let header = System::finalize(); parent_hash = header.hash(); @@ -236,7 +227,7 @@ mod tests { setup_blocks(38); - let random_material = Randomness::random_material(); + let random_material = CollectiveFlip::random_material(); assert_eq!(random_material.len(), 38); assert_eq!(random_material[0], genesis_hash); @@ -250,7 +241,7 @@ mod tests { setup_blocks(81); - let random_material = Randomness::random_material(); + let random_material = CollectiveFlip::random_material(); assert_eq!(random_material.len(), 81); assert_ne!(random_material[0], random_material[1]); @@ -265,7 +256,7 @@ mod tests { setup_blocks(162); - let random_material = Randomness::random_material(); + let random_material = CollectiveFlip::random_material(); assert_eq!(random_material.len(), 81); assert_ne!(random_material[0], random_material[1]); @@ -279,13 +270,13 @@ mod tests { setup_blocks(162); assert_eq!(System::block_number(), 162); - assert_eq!(Randomness::random_seed(), Randomness::random_seed()); - assert_ne!(Randomness::random(b"random_1"), Randomness::random(b"random_2")); + assert_eq!(CollectiveFlip::random_seed(), CollectiveFlip::random_seed()); + assert_ne!(CollectiveFlip::random(b"random_1"), CollectiveFlip::random(b"random_2")); - let random = Randomness::random_seed(); + let random = CollectiveFlip::random_seed(); assert_ne!(random, H256::zero()); - assert!(!Randomness::random_material().contains(&random)); + assert!(!CollectiveFlip::random_material().contains(&random)); }); } } diff --git a/srml/support/src/traits.rs b/srml/support/src/traits.rs index 88e6159365..694e6ec4b0 100644 --- a/srml/support/src/traits.rs +++ b/srml/support/src/traits.rs @@ -717,3 +717,23 @@ pub trait InitializeMembers { impl InitializeMembers for () { fn initialize_members(_: &[T]) {} } + +// A trait that is able to provide randomness. +pub trait Randomness { + /// Get a "random" value + /// + /// Being a deterministic blockchain, real randomness is difficult to come by. This gives you + /// something that approximates it. `subject` is a context identifier and allows you to get a + /// different result to other callers of this function; use it like + /// `random(&b"my context"[..])`. + fn random(subject: &[u8]) -> Output; + + /// Get the basic random seed. + /// + /// In general you won't want to use this, but rather `Self::random` which allows you to give a + /// subject for the random result and whose value will be independently low-influence random + /// from any other such seeds. + fn random_seed() -> Output { + Self::random(&[][..]) + } +} -- GitLab From 7adfd837565f870882cb9726e546dc9df6804885 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Thu, 10 Oct 2019 15:01:30 +0200 Subject: [PATCH 031/167] Add `execute_with` to `TestExternalities` (#3793) This function executes the given closure in a context where the test externalities are set. This makes the srml tests easier to write, as the test externalities need to be created anyway. --- Cargo.lock | 1 - core/sr-primitives/Cargo.toml | 2 - core/sr-primitives/src/lib.rs | 3 - core/sr-primitives/src/offchain/http.rs | 5 +- core/state-machine/src/testing.rs | 7 + core/test-runtime/src/system.rs | 25 +- node-template/runtime/src/template.rs | 5 +- node/executor/src/lib.rs | 24 +- srml/assets/src/lib.rs | 21 +- srml/aura/src/tests.rs | 3 +- srml/authority-discovery/src/lib.rs | 8 +- srml/authorship/src/lib.rs | 9 +- srml/babe/src/tests.rs | 12 +- srml/balances/src/tests.rs | 374 ++--- srml/collective/src/lib.rs | 44 +- srml/contracts/src/exec.rs | 409 +++-- srml/contracts/src/tests.rs | 1727 ++++++++++---------- srml/democracy/src/lib.rs | 73 +- srml/elections-phragmen/src/lib.rs | 78 +- srml/elections/src/mock.rs | 5 +- srml/elections/src/tests.rs | 271 +-- srml/example/src/lib.rs | 8 +- srml/executive/src/lib.rs | 19 +- srml/finality-tracker/src/lib.rs | 8 +- srml/generic-asset/src/tests.rs | 803 +++++---- srml/grandpa/src/tests.rs | 14 +- srml/im-online/src/tests.rs | 13 +- srml/indices/src/tests.rs | 65 +- srml/membership/src/lib.rs | 15 +- srml/offences/src/tests.rs | 15 +- srml/randomness-collective-flip/src/lib.rs | 9 +- srml/scored-pool/src/tests.rs | 34 +- srml/session/src/historical.rs | 8 +- srml/session/src/lib.rs | 25 +- srml/staking/src/mock.rs | 4 +- srml/staking/src/tests.rs | 1012 ++++++------ srml/support/src/lib.rs | 17 +- srml/support/src/storage/storage_items.rs | 13 +- srml/support/test/tests/instance.rs | 7 +- srml/system/benches/bench.rs | 6 +- srml/system/src/lib.rs | 36 +- srml/timestamp/src/lib.rs | 11 +- srml/treasury/src/lib.rs | 33 +- srml/utility/src/lib.rs | 7 +- 44 files changed, 2506 insertions(+), 2782 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8a1ead4978..6e7dea9d1d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3841,7 +3841,6 @@ dependencies = [ "sr-io 2.0.0", "sr-std 2.0.0", "substrate-application-crypto 2.0.0", - "substrate-externalities 2.0.0", "substrate-offchain 2.0.0", "substrate-primitives 2.0.0", ] diff --git a/core/sr-primitives/Cargo.toml b/core/sr-primitives/Cargo.toml index 2ffe8a010d..ac6e8685e2 100644 --- a/core/sr-primitives/Cargo.toml +++ b/core/sr-primitives/Cargo.toml @@ -16,7 +16,6 @@ runtime_io = { package = "sr-io", path = "../sr-io", default-features = false } log = { version = "0.4.8", optional = true } paste = "0.1.6" rand = { version = "0.7.2", optional = true } -externalities = { package = "substrate-externalities", path = "../externalities", optional = true } impl-trait-for-tuples = "0.1.2" [dev-dependencies] @@ -38,5 +37,4 @@ std = [ "primitives/std", "app-crypto/std", "rand", - "externalities", ] diff --git a/core/sr-primitives/src/lib.rs b/core/sr-primitives/src/lib.rs index 3c75bae849..7032560d0f 100644 --- a/core/sr-primitives/src/lib.rs +++ b/core/sr-primitives/src/lib.rs @@ -73,9 +73,6 @@ pub use sr_arithmetic::helpers_128bit; /// Re-export big_uint stiff. pub use sr_arithmetic::biguint; -#[cfg(feature = "std")] -pub use externalities::set_and_run_with_externalities; - /// An abstraction over justification for a block's validity under a consensus algorithm. /// /// Essentially a finality proof. The exact formulation will vary between consensus diff --git a/core/sr-primitives/src/offchain/http.rs b/core/sr-primitives/src/offchain/http.rs index 2d84f175d1..b68cf28365 100644 --- a/core/sr-primitives/src/offchain/http.rs +++ b/core/sr-primitives/src/offchain/http.rs @@ -512,7 +512,6 @@ impl<'a> HeadersIterator<'a> { #[cfg(test)] mod tests { use super::*; - use crate::set_and_run_with_externalities; use runtime_io::TestExternalities; use substrate_offchain::testing; use primitives::offchain::OffchainExt; @@ -523,7 +522,7 @@ mod tests { let mut t = TestExternalities::default(); t.register_extension(OffchainExt::new(offchain)); - set_and_run_with_externalities(&mut t, || { + t.execute_with(|| { let request: Request = Request::get("http://localhost:1234"); let pending = request .add_header("X-Auth", "hunter2") @@ -564,7 +563,7 @@ mod tests { let mut t = TestExternalities::default(); t.register_extension(OffchainExt::new(offchain)); - set_and_run_with_externalities(&mut t, || { + t.execute_with(|| { let pending = Request::default() .method(Method::Post) .url("http://localhost:1234") diff --git a/core/state-machine/src/testing.rs b/core/state-machine/src/testing.rs index ea63eac021..ca89921ff0 100644 --- a/core/state-machine/src/testing.rs +++ b/core/state-machine/src/testing.rs @@ -113,6 +113,13 @@ impl, N: ChangesTrieBlockNumber> TestExternalities { self.backend.update(top.chain(children).collect()) } + + /// Execute the given closure while `self` is set as externalities. + /// + /// Returns the result of the given closure. + pub fn execute_with(&mut self, execute: impl FnOnce() -> R) -> R { + externalities::set_and_run_with_externalities(self, execute) + } } impl, N: ChangesTrieBlockNumber> std::fmt::Debug for TestExternalities { diff --git a/core/test-runtime/src/system.rs b/core/test-runtime/src/system.rs index 81bca2fad3..f3359aa1ba 100644 --- a/core/test-runtime/src/system.rs +++ b/core/test-runtime/src/system.rs @@ -321,7 +321,6 @@ mod tests { use runtime_io::TestExternalities; use substrate_test_runtime_client::{AccountKeyring, Sr25519Keyring}; - use sr_primitives::set_and_run_with_externalities; use crate::{Header, Transfer, WASM_BINARY}; use primitives::{NeverNativeValue, map, traits::CodeExecutor}; use substrate_executor::{NativeExecutor, WasmExecutionMethod, native_executor_instance}; @@ -371,18 +370,14 @@ mod tests { extrinsics: vec![], }; - set_and_run_with_externalities(&mut new_test_ext(), || polish_block(&mut b)); + new_test_ext().execute_with(|| polish_block(&mut b)); block_executor(b, &mut new_test_ext()); } #[test] fn block_import_works_native() { - block_import_works(|b, ext| { - set_and_run_with_externalities(ext, || { - execute_block(b); - }); - }); + block_import_works(|b, ext| ext.execute_with(|| execute_block(b))); } #[test] @@ -420,7 +415,7 @@ mod tests { }; let mut dummy_ext = new_test_ext(); - set_and_run_with_externalities(&mut dummy_ext, || polish_block(&mut b1)); + dummy_ext.execute_with(|| polish_block(&mut b1)); let mut b2 = Block { header: Header { @@ -446,26 +441,26 @@ mod tests { ], }; - set_and_run_with_externalities(&mut dummy_ext, || polish_block(&mut b2)); + dummy_ext.execute_with(|| polish_block(&mut b2)); drop(dummy_ext); let mut t = new_test_ext(); - set_and_run_with_externalities(&mut t, || { + t.execute_with(|| { assert_eq!(balance_of(AccountKeyring::Alice.into()), 111); assert_eq!(balance_of(AccountKeyring::Bob.into()), 0); }); block_executor(b1, &mut t); - set_and_run_with_externalities(&mut t, || { + t.execute_with(|| { assert_eq!(balance_of(AccountKeyring::Alice.into()), 42); assert_eq!(balance_of(AccountKeyring::Bob.into()), 69); }); block_executor(b2, &mut t); - set_and_run_with_externalities(&mut t, || { + t.execute_with(|| { assert_eq!(balance_of(AccountKeyring::Alice.into()), 0); assert_eq!(balance_of(AccountKeyring::Bob.into()), 42); assert_eq!(balance_of(AccountKeyring::Charlie.into()), 69); @@ -474,11 +469,7 @@ mod tests { #[test] fn block_import_with_transaction_works_native() { - block_import_with_transaction_works(|b, ext| { - set_and_run_with_externalities(ext, || { - execute_block(b); - }); - }); + block_import_with_transaction_works(|b, ext| ext.execute_with(|| execute_block(b))); } #[test] diff --git a/node-template/runtime/src/template.rs b/node-template/runtime/src/template.rs index 0266890dd8..eb4398787d 100644 --- a/node-template/runtime/src/template.rs +++ b/node-template/runtime/src/template.rs @@ -72,8 +72,7 @@ mod tests { use primitives::H256; use support::{impl_outer_origin, assert_ok, parameter_types}; use sr_primitives::{ - set_and_run_with_externalities, traits::{BlakeTwo256, IdentityLookup}, testing::Header, - weights::Weight, Perbill, + traits::{BlakeTwo256, IdentityLookup}, testing::Header, weights::Weight, Perbill, }; impl_outer_origin! { @@ -122,7 +121,7 @@ mod tests { #[test] fn it_works_for_default_value() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { // Just a dummy test for the dummy funtion `do_something` // calling the `do_something` function with a value 42 assert_ok!(TemplateModule::do_something(Origin::signed(1), 42)); diff --git a/node/executor/src/lib.rs b/node/executor/src/lib.rs index 40c1e08f9b..2c2ad479f5 100644 --- a/node/executor/src/lib.rs +++ b/node/executor/src/lib.rs @@ -226,7 +226,7 @@ mod tests { ).0; assert!(r.is_ok()); - sr_primitives::set_and_run_with_externalities(&mut t, || { + t.execute_with(|| { assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - transfer_fee(&xt())); assert_eq!(Balances::total_balance(&bob()), 69 * DOLLARS); }); @@ -262,7 +262,7 @@ mod tests { ).0; assert!(r.is_ok()); - sr_primitives::set_and_run_with_externalities(&mut t, || { + t.execute_with(|| { assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - transfer_fee(&xt())); assert_eq!(Balances::total_balance(&bob()), 69 * DOLLARS); }); @@ -433,7 +433,7 @@ mod tests { None, ).0.unwrap(); - sr_primitives::set_and_run_with_externalities(&mut t, || { + t.execute_with(|| { assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - transfer_fee(&xt())); assert_eq!(Balances::total_balance(&bob()), 169 * DOLLARS); let events = vec![ @@ -468,7 +468,7 @@ mod tests { None, ).0.unwrap(); - sr_primitives::set_and_run_with_externalities(&mut t, || { + t.execute_with(|| { // NOTE: fees differ slightly in tests that execute more than one block due to the // weight update. Hence, using `assert_eq_error_rate`. assert_eq_error_rate!( @@ -540,7 +540,7 @@ mod tests { None, ).0.unwrap(); - sr_primitives::set_and_run_with_externalities(&mut t, || { + t.execute_with(|| { assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - transfer_fee(&xt())); assert_eq!(Balances::total_balance(&bob()), 169 * DOLLARS); }); @@ -553,7 +553,7 @@ mod tests { None, ).0.unwrap(); - sr_primitives::set_and_run_with_externalities(&mut t, || { + t.execute_with(|| { assert_eq_error_rate!( Balances::total_balance(&alice()), 32 * DOLLARS - 2 * transfer_fee(&xt()), @@ -715,7 +715,7 @@ mod tests { None, ).0.unwrap(); - sr_primitives::set_and_run_with_externalities(&mut t, || { + t.execute_with(|| { // Verify that the contract constructor worked well and code of TRANSFER contract is actually deployed. assert_eq!( &contracts::ContractInfoOf::::get(addr) @@ -836,7 +836,7 @@ mod tests { .expect("Extrinsic could be applied") .expect("Extrinsic did not fail"); - sr_primitives::set_and_run_with_externalities(&mut t, || { + t.execute_with(|| { assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - 1 * transfer_fee(&xt())); assert_eq!(Balances::total_balance(&bob()), 69 * DOLLARS); }); @@ -895,7 +895,7 @@ mod tests { let mut prev_multiplier = WeightMultiplier::default(); - sr_primitives::set_and_run_with_externalities(&mut t, || { + t.execute_with(|| { assert_eq!(System::next_weight_multiplier(), prev_multiplier); }); @@ -947,7 +947,7 @@ mod tests { ).0.unwrap(); // weight multiplier is increased for next block. - sr_primitives::set_and_run_with_externalities(&mut t, || { + t.execute_with(|| { let fm = System::next_weight_multiplier(); println!("After a big block: {:?} -> {:?}", prev_multiplier, fm); assert!(fm > prev_multiplier); @@ -964,7 +964,7 @@ mod tests { ).0.unwrap(); // weight multiplier is increased for next block. - sr_primitives::set_and_run_with_externalities(&mut t, || { + t.execute_with(|| { let fm = System::next_weight_multiplier(); println!("After a small block: {:?} -> {:?}", prev_multiplier, fm); assert!(fm < prev_multiplier); @@ -1018,7 +1018,7 @@ mod tests { ).0; assert!(r.is_ok()); - sr_primitives::set_and_run_with_externalities(&mut t, || { + t.execute_with(|| { assert_eq!(Balances::total_balance(&bob()), (10 + 69) * DOLLARS); // Components deducted from alice's balances: // - Weight fee diff --git a/srml/assets/src/lib.rs b/srml/assets/src/lib.rs index e7f258483f..de95caf88f 100644 --- a/srml/assets/src/lib.rs +++ b/srml/assets/src/lib.rs @@ -244,10 +244,7 @@ mod tests { use primitives::H256; // The testing primitives are very useful for avoiding having to work with signatures // or public keys. `u64` is used as the `AccountId` and no `Signature`s are required. - use sr_primitives::{ - Perbill, traits::{BlakeTwo256, IdentityLookup}, testing::Header, - set_and_run_with_externalities, - }; + use sr_primitives::{Perbill, traits::{BlakeTwo256, IdentityLookup}, testing::Header}; impl_outer_origin! { pub enum Origin for Test {} @@ -297,7 +294,7 @@ mod tests { #[test] fn issuing_asset_units_to_issuer_should_work() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { assert_ok!(Assets::issue(Origin::signed(1), 100)); assert_eq!(Assets::balance(0, 1), 100); }); @@ -305,7 +302,7 @@ mod tests { #[test] fn querying_total_supply_should_work() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { assert_ok!(Assets::issue(Origin::signed(1), 100)); assert_eq!(Assets::balance(0, 1), 100); assert_ok!(Assets::transfer(Origin::signed(1), 0, 2, 50)); @@ -322,7 +319,7 @@ mod tests { #[test] fn transferring_amount_above_available_balance_should_work() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { assert_ok!(Assets::issue(Origin::signed(1), 100)); assert_eq!(Assets::balance(0, 1), 100); assert_ok!(Assets::transfer(Origin::signed(1), 0, 2, 50)); @@ -333,7 +330,7 @@ mod tests { #[test] fn transferring_amount_less_than_available_balance_should_not_work() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { assert_ok!(Assets::issue(Origin::signed(1), 100)); assert_eq!(Assets::balance(0, 1), 100); assert_ok!(Assets::transfer(Origin::signed(1), 0, 2, 50)); @@ -347,7 +344,7 @@ mod tests { #[test] fn transferring_less_than_one_unit_should_not_work() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { assert_ok!(Assets::issue(Origin::signed(1), 100)); assert_eq!(Assets::balance(0, 1), 100); assert_noop!(Assets::transfer(Origin::signed(1), 0, 2, 0), "transfer amount should be non-zero"); @@ -356,7 +353,7 @@ mod tests { #[test] fn transferring_more_units_than_total_supply_should_not_work() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { assert_ok!(Assets::issue(Origin::signed(1), 100)); assert_eq!(Assets::balance(0, 1), 100); assert_noop!(Assets::transfer(Origin::signed(1), 0, 2, 101), "origin account balance must be greater than or equal to the transfer amount"); @@ -365,7 +362,7 @@ mod tests { #[test] fn destroying_asset_balance_with_positive_balance_should_work() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { assert_ok!(Assets::issue(Origin::signed(1), 100)); assert_eq!(Assets::balance(0, 1), 100); assert_ok!(Assets::destroy(Origin::signed(1), 0)); @@ -374,7 +371,7 @@ mod tests { #[test] fn destroying_asset_balance_with_zero_balance_should_not_work() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { assert_ok!(Assets::issue(Origin::signed(1), 100)); assert_eq!(Assets::balance(0, 2), 0); assert_noop!(Assets::destroy(Origin::signed(2), 0), "origin balance should be non-zero"); diff --git a/srml/aura/src/tests.rs b/srml/aura/src/tests.rs index 0537fc8b64..a90ec3a861 100644 --- a/srml/aura/src/tests.rs +++ b/srml/aura/src/tests.rs @@ -18,12 +18,11 @@ #![cfg(test)] -use sr_primitives::set_and_run_with_externalities; use crate::mock::{Aura, new_test_ext}; #[test] fn initial_values() { - set_and_run_with_externalities(&mut new_test_ext(vec![0, 1, 2, 3]), || { + new_test_ext(vec![0, 1, 2, 3]).execute_with(|| { assert_eq!(Aura::last(), 0u64); assert_eq!(Aura::authorities().len(), 4); }); diff --git a/srml/authority-discovery/src/lib.rs b/srml/authority-discovery/src/lib.rs index 38d587ba05..177e11c4c0 100644 --- a/srml/authority-discovery/src/lib.rs +++ b/srml/authority-discovery/src/lib.rs @@ -139,7 +139,7 @@ mod tests { use runtime_io::TestExternalities; use sr_primitives::{ testing::{Header, UintAuthorityId}, traits::{ConvertInto, IdentityLookup, OpaqueKeys}, - Perbill, set_and_run_with_externalities, + Perbill, }; use support::{impl_outer_origin, parameter_types}; @@ -263,7 +263,7 @@ mod tests { let mut externalities = TestExternalities::new(t); externalities.register_extension(KeystoreExt(key_store)); - set_and_run_with_externalities(&mut externalities, || { + externalities.execute_with(|| { assert_eq!( authority_id, AuthorityDiscovery::authority_id().expect("Retrieving public key.") @@ -300,7 +300,7 @@ mod tests { let mut externalities = TestExternalities::new(t); externalities.register_extension(KeystoreExt(key_store)); - set_and_run_with_externalities(&mut externalities, || { + externalities.execute_with(|| { assert_eq!(None, AuthorityDiscovery::authority_id()); }); } @@ -337,7 +337,7 @@ mod tests { let mut externalities = TestExternalities::new(t); externalities.register_extension(KeystoreExt(key_store)); - set_and_run_with_externalities(&mut externalities, || { + externalities.execute_with(|| { let payload = String::from("test payload").into_bytes(); let (sig, authority_id) = AuthorityDiscovery::sign(&payload).expect("signature"); diff --git a/srml/authorship/src/lib.rs b/srml/authorship/src/lib.rs index 0033e53221..dcd1985664 100644 --- a/srml/authorship/src/lib.rs +++ b/srml/authorship/src/lib.rs @@ -414,8 +414,7 @@ mod tests { use super::*; use primitives::H256; use sr_primitives::{ - set_and_run_with_externalities, traits::{BlakeTwo256, IdentityLookup}, testing::Header, - generic::DigestItem, Perbill, + traits::{BlakeTwo256, IdentityLookup}, testing::Header, generic::DigestItem, Perbill, }; use support::{parameter_types, impl_outer_origin, ConsensusEngineId}; @@ -542,7 +541,7 @@ mod tests { #[test] fn prune_old_uncles_works() { use UncleEntryItem::*; - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { let hash = Default::default(); let author = Default::default(); let uncles = vec![ @@ -561,7 +560,7 @@ mod tests { #[test] fn rejects_bad_uncles() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { let author_a = 69; struct CanonChain { @@ -674,7 +673,7 @@ mod tests { #[test] fn sets_author_lazily() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { let author = 42; let mut header = seal_header( create_header(1, Default::default(), [1; 32].into()), diff --git a/srml/babe/src/tests.rs b/srml/babe/src/tests.rs index 0a165b3854..f860375de4 100644 --- a/srml/babe/src/tests.rs +++ b/srml/babe/src/tests.rs @@ -18,9 +18,7 @@ use super::*; use mock::{new_test_ext, Babe, Test}; -use sr_primitives::{ - set_and_run_with_externalities, traits::OnFinalize, testing::{Digest, DigestItem}, -}; +use sr_primitives::{traits::OnFinalize, testing::{Digest, DigestItem}}; use session::ShouldEndSession; const EMPTY_RANDOMNESS: [u8; 32] = [ @@ -54,14 +52,14 @@ fn empty_randomness_is_correct() { #[test] fn initial_values() { - set_and_run_with_externalities(&mut new_test_ext(vec![0, 1, 2, 3]), || { + new_test_ext(vec![0, 1, 2, 3]).execute_with(|| { assert_eq!(Babe::authorities().len(), 4) }) } #[test] fn check_module() { - set_and_run_with_externalities(&mut new_test_ext(vec![0, 1, 2, 3]), || { + new_test_ext(vec![0, 1, 2, 3]).execute_with(|| { assert!(!Babe::should_end_session(0), "Genesis does not change sessions"); assert!(!Babe::should_end_session(200000), "BABE does not include the block number in epoch calculations"); @@ -72,7 +70,7 @@ type System = system::Module; #[test] fn first_block_epoch_zero_start() { - set_and_run_with_externalities(&mut new_test_ext(vec![0, 1, 2, 3]), || { + new_test_ext(vec![0, 1, 2, 3]).execute_with(|| { let genesis_slot = 100; let first_vrf = [1; 32]; let pre_digest = make_pre_digest( @@ -120,7 +118,7 @@ fn first_block_epoch_zero_start() { #[test] fn authority_index() { - set_and_run_with_externalities(&mut new_test_ext(vec![0, 1, 2, 3]), || { + new_test_ext(vec![0, 1, 2, 3]).execute_with(|| { assert_eq!( Babe::find_author((&[(BABE_ENGINE_ID, &[][..])]).into_iter().cloned()), None, "Trivially invalid authorities are ignored") diff --git a/srml/balances/src/tests.rs b/srml/balances/src/tests.rs index b4745c2253..3e7cb9a133 100644 --- a/srml/balances/src/tests.rs +++ b/srml/balances/src/tests.rs @@ -20,7 +20,6 @@ use super::*; use mock::{Balances, ExtBuilder, Runtime, System, info_from_weight, CALL}; -use sr_primitives::set_and_run_with_externalities; use support::{ assert_noop, assert_ok, assert_err, traits::{LockableCurrency, LockIdentifier, WithdrawReason, WithdrawReasons, @@ -34,7 +33,7 @@ const ID_3: LockIdentifier = *b"3 "; #[test] fn basic_locking_should_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().existential_deposit(1).monied(true).build(), || { + ExtBuilder::default().existential_deposit(1).monied(true).build().execute_with(|| { assert_eq!(Balances::free_balance(&1), 10); Balances::set_lock(ID_1, &1, 9, u64::max_value(), WithdrawReasons::all()); assert_noop!( @@ -46,7 +45,7 @@ fn basic_locking_should_work() { #[test] fn partial_locking_should_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().existential_deposit(1).monied(true).build(), || { + ExtBuilder::default().existential_deposit(1).monied(true).build().execute_with(|| { Balances::set_lock(ID_1, &1, 5, u64::max_value(), WithdrawReasons::all()); assert_ok!(>::transfer(&1, &2, 1)); }); @@ -54,7 +53,7 @@ fn partial_locking_should_work() { #[test] fn lock_removal_should_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().existential_deposit(1).monied(true).build(), || { + ExtBuilder::default().existential_deposit(1).monied(true).build().execute_with(|| { Balances::set_lock(ID_1, &1, u64::max_value(), u64::max_value(), WithdrawReasons::all()); Balances::remove_lock(ID_1, &1); assert_ok!(>::transfer(&1, &2, 1)); @@ -63,7 +62,7 @@ fn lock_removal_should_work() { #[test] fn lock_replacement_should_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().existential_deposit(1).monied(true).build(), || { + ExtBuilder::default().existential_deposit(1).monied(true).build().execute_with(|| { Balances::set_lock(ID_1, &1, u64::max_value(), u64::max_value(), WithdrawReasons::all()); Balances::set_lock(ID_1, &1, 5, u64::max_value(), WithdrawReasons::all()); assert_ok!(>::transfer(&1, &2, 1)); @@ -72,7 +71,7 @@ fn lock_replacement_should_work() { #[test] fn double_locking_should_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().existential_deposit(1).monied(true).build(), || { + ExtBuilder::default().existential_deposit(1).monied(true).build().execute_with(|| { Balances::set_lock(ID_1, &1, 5, u64::max_value(), WithdrawReasons::all()); Balances::set_lock(ID_2, &1, 5, u64::max_value(), WithdrawReasons::all()); assert_ok!(>::transfer(&1, &2, 1)); @@ -81,7 +80,7 @@ fn double_locking_should_work() { #[test] fn combination_locking_should_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().existential_deposit(1).monied(true).build(), || { + ExtBuilder::default().existential_deposit(1).monied(true).build().execute_with(|| { Balances::set_lock(ID_1, &1, u64::max_value(), 0, WithdrawReasons::none()); Balances::set_lock(ID_2, &1, 0, u64::max_value(), WithdrawReasons::none()); Balances::set_lock(ID_3, &1, 0, 0, WithdrawReasons::all()); @@ -91,7 +90,7 @@ fn combination_locking_should_work() { #[test] fn lock_value_extension_should_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().existential_deposit(1).monied(true).build(), || { + ExtBuilder::default().existential_deposit(1).monied(true).build().execute_with(|| { Balances::set_lock(ID_1, &1, 5, u64::max_value(), WithdrawReasons::all()); assert_noop!( >::transfer(&1, &2, 6), @@ -112,12 +111,12 @@ fn lock_value_extension_should_work() { #[test] fn lock_reasons_should_work() { - set_and_run_with_externalities( - &mut ExtBuilder::default() - .existential_deposit(1) - .monied(true).transaction_fees(0, 1, 0) - .build(), - || { + ExtBuilder::default() + .existential_deposit(1) + .monied(true) + .transaction_fees(0, 1, 0) + .build() + .execute_with(|| { Balances::set_lock(ID_1, &1, 10, u64::max_value(), WithdrawReason::Transfer.into()); assert_noop!( >::transfer(&1, &2, 1), @@ -157,13 +156,12 @@ fn lock_reasons_should_work() { info_from_weight(1), 0, ).is_err()); - } - ); + }); } #[test] fn lock_block_number_should_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().existential_deposit(1).monied(true).build(), || { + ExtBuilder::default().existential_deposit(1).monied(true).build().execute_with(|| { Balances::set_lock(ID_1, &1, 10, 2, WithdrawReasons::all()); assert_noop!( >::transfer(&1, &2, 1), @@ -177,7 +175,7 @@ fn lock_block_number_should_work() { #[test] fn lock_block_number_extension_should_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().existential_deposit(1).monied(true).build(), || { + ExtBuilder::default().existential_deposit(1).monied(true).build().execute_with(|| { Balances::set_lock(ID_1, &1, 10, 2, WithdrawReasons::all()); assert_noop!( >::transfer(&1, &2, 6), @@ -199,7 +197,7 @@ fn lock_block_number_extension_should_work() { #[test] fn lock_reasons_extension_should_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().existential_deposit(1).monied(true).build(), || { + ExtBuilder::default().existential_deposit(1).monied(true).build().execute_with(|| { Balances::set_lock(ID_1, &1, 10, 10, WithdrawReason::Transfer.into()); assert_noop!( >::transfer(&1, &2, 6), @@ -220,14 +218,12 @@ fn lock_reasons_extension_should_work() { #[test] fn default_indexing_on_new_accounts_should_not_work2() { - set_and_run_with_externalities( - &mut ExtBuilder::default() - .existential_deposit(10) - .creation_fee(50) - .monied(true) - .build(), - || { - + ExtBuilder::default() + .existential_deposit(10) + .creation_fee(50) + .monied(true) + .build() + .execute_with(|| { assert_eq!(Balances::is_dead_account(&5), true); // account 5 should not exist // ext_deposit is 10, value is 9, not satisfies for ext_deposit assert_noop!( @@ -236,18 +232,16 @@ fn default_indexing_on_new_accounts_should_not_work2() { ); assert_eq!(Balances::is_dead_account(&5), true); // account 5 should not exist assert_eq!(Balances::free_balance(&1), 100); - }, - ); + }); } #[test] fn reserved_balance_should_prevent_reclaim_count() { - set_and_run_with_externalities( - &mut ExtBuilder::default() - .existential_deposit(256 * 1) - .monied(true) - .build(), - || { + ExtBuilder::default() + .existential_deposit(256 * 1) + .monied(true) + .build() + .execute_with(|| { System::inc_account_nonce(&2); assert_eq!(Balances::is_dead_account(&2), false); assert_eq!(Balances::is_dead_account(&5), true); @@ -274,14 +268,13 @@ fn reserved_balance_should_prevent_reclaim_count() { assert_ok!(Balances::transfer(Some(4).into(), 6, 256 * 1 + 0x69)); assert_eq!(Balances::total_balance(&6), 256 * 1 + 0x69); assert_eq!(Balances::is_dead_account(&6), false); - }, - ); + }); } #[test] fn reward_should_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().monied(true).build(), || { + ExtBuilder::default().monied(true).build().execute_with(|| { assert_eq!(Balances::total_balance(&1), 10); assert_ok!(Balances::deposit_into_existing(&1, 10).map(drop)); assert_eq!(Balances::total_balance(&1), 20); @@ -291,12 +284,11 @@ fn reward_should_work() { #[test] fn dust_account_removal_should_work() { - set_and_run_with_externalities( - &mut ExtBuilder::default() - .existential_deposit(100) - .monied(true) - .build(), - || { + ExtBuilder::default() + .existential_deposit(100) + .monied(true) + .build() + .execute_with(|| { System::inc_account_nonce(&2); assert_eq!(System::account_nonce(&2), 1); assert_eq!(Balances::total_balance(&2), 2000); @@ -305,19 +297,17 @@ fn dust_account_removal_should_work() { assert_eq!(Balances::total_balance(&2), 0); assert_eq!(Balances::total_balance(&5), 1901); assert_eq!(System::account_nonce(&2), 0); - }, - ); + }); } #[test] fn dust_account_removal_should_work2() { - set_and_run_with_externalities( - &mut ExtBuilder::default() - .existential_deposit(100) - .creation_fee(50) - .monied(true) - .build(), - || { + ExtBuilder::default() + .existential_deposit(100) + .creation_fee(50) + .monied(true) + .build() + .execute_with(|| { System::inc_account_nonce(&2); assert_eq!(System::account_nonce(&2), 1); assert_eq!(Balances::total_balance(&2), 2000); @@ -326,13 +316,12 @@ fn dust_account_removal_should_work2() { assert_eq!(Balances::total_balance(&2), 0); assert_eq!(Balances::total_balance(&5), 1851); assert_eq!(System::account_nonce(&2), 0); - }, - ); + }); } #[test] fn balance_works() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { let _ = Balances::deposit_creating(&1, 42); assert_eq!(Balances::free_balance(&1), 42); assert_eq!(Balances::reserved_balance(&1), 0); @@ -345,7 +334,7 @@ fn balance_works() { #[test] fn balance_transfer_works() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { let _ = Balances::deposit_creating(&1, 111); assert_ok!(Balances::transfer(Some(1).into(), 2, 69)); assert_eq!(Balances::total_balance(&1), 42); @@ -355,7 +344,7 @@ fn balance_transfer_works() { #[test] fn force_transfer_works() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { let _ = Balances::deposit_creating(&1, 111); assert_noop!( Balances::force_transfer(Some(2).into(), 1, 2, 69), @@ -369,7 +358,7 @@ fn force_transfer_works() { #[test] fn reserving_balance_should_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { let _ = Balances::deposit_creating(&1, 111); assert_eq!(Balances::total_balance(&1), 111); @@ -386,7 +375,7 @@ fn reserving_balance_should_work() { #[test] fn balance_transfer_when_reserved_should_not_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { let _ = Balances::deposit_creating(&1, 111); assert_ok!(Balances::reserve(&1, 69)); assert_noop!( @@ -398,7 +387,7 @@ fn balance_transfer_when_reserved_should_not_work() { #[test] fn deducting_balance_should_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { let _ = Balances::deposit_creating(&1, 111); assert_ok!(Balances::reserve(&1, 69)); assert_eq!(Balances::free_balance(&1), 42); @@ -407,7 +396,7 @@ fn deducting_balance_should_work() { #[test] fn refunding_balance_should_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { let _ = Balances::deposit_creating(&1, 42); Balances::set_reserved_balance(&1, 69); Balances::unreserve(&1, 69); @@ -418,7 +407,7 @@ fn refunding_balance_should_work() { #[test] fn slashing_balance_should_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { let _ = Balances::deposit_creating(&1, 111); assert_ok!(Balances::reserve(&1, 69)); assert!(Balances::slash(&1, 69).1.is_zero()); @@ -430,7 +419,7 @@ fn slashing_balance_should_work() { #[test] fn slashing_incomplete_balance_should_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { let _ = Balances::deposit_creating(&1, 42); assert_ok!(Balances::reserve(&1, 21)); assert_eq!(Balances::slash(&1, 69).1, 27); @@ -442,7 +431,7 @@ fn slashing_incomplete_balance_should_work() { #[test] fn unreserving_balance_should_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { let _ = Balances::deposit_creating(&1, 111); assert_ok!(Balances::reserve(&1, 111)); Balances::unreserve(&1, 42); @@ -453,7 +442,7 @@ fn unreserving_balance_should_work() { #[test] fn slashing_reserved_balance_should_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { let _ = Balances::deposit_creating(&1, 111); assert_ok!(Balances::reserve(&1, 111)); assert_eq!(Balances::slash_reserved(&1, 42).1, 0); @@ -465,7 +454,7 @@ fn slashing_reserved_balance_should_work() { #[test] fn slashing_incomplete_reserved_balance_should_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { let _ = Balances::deposit_creating(&1, 111); assert_ok!(Balances::reserve(&1, 42)); assert_eq!(Balances::slash_reserved(&1, 69).1, 27); @@ -477,7 +466,7 @@ fn slashing_incomplete_reserved_balance_should_work() { #[test] fn transferring_reserved_balance_should_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { let _ = Balances::deposit_creating(&1, 110); let _ = Balances::deposit_creating(&2, 1); assert_ok!(Balances::reserve(&1, 110)); @@ -491,7 +480,7 @@ fn transferring_reserved_balance_should_work() { #[test] fn transferring_reserved_balance_to_nonexistent_should_fail() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { let _ = Balances::deposit_creating(&1, 111); assert_ok!(Balances::reserve(&1, 111)); assert_noop!(Balances::repatriate_reserved(&1, &2, 42), "beneficiary account must pre-exist"); @@ -500,7 +489,7 @@ fn transferring_reserved_balance_to_nonexistent_should_fail() { #[test] fn transferring_incomplete_reserved_balance_should_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { let _ = Balances::deposit_creating(&1, 110); let _ = Balances::deposit_creating(&2, 1); assert_ok!(Balances::reserve(&1, 41)); @@ -514,7 +503,7 @@ fn transferring_incomplete_reserved_balance_should_work() { #[test] fn transferring_too_high_value_should_not_panic() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { >::insert(1, u64::max_value()); >::insert(2, 1); @@ -530,89 +519,76 @@ fn transferring_too_high_value_should_not_panic() { #[test] fn account_create_on_free_too_low_with_other() { - set_and_run_with_externalities( - &mut ExtBuilder::default().existential_deposit(100).build(), - || { - let _ = Balances::deposit_creating(&1, 100); - assert_eq!(>::get(), 100); + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = Balances::deposit_creating(&1, 100); + assert_eq!(>::get(), 100); - // No-op. - let _ = Balances::deposit_creating(&2, 50); - assert_eq!(Balances::free_balance(&2), 0); - assert_eq!(>::get(), 100); - } - ) + // No-op. + let _ = Balances::deposit_creating(&2, 50); + assert_eq!(Balances::free_balance(&2), 0); + assert_eq!(>::get(), 100); + }) } #[test] fn account_create_on_free_too_low() { - set_and_run_with_externalities( - &mut ExtBuilder::default().existential_deposit(100).build(), - || { - // No-op. - let _ = Balances::deposit_creating(&2, 50); - assert_eq!(Balances::free_balance(&2), 0); - assert_eq!(>::get(), 0); - } - ) + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + // No-op. + let _ = Balances::deposit_creating(&2, 50); + assert_eq!(Balances::free_balance(&2), 0); + assert_eq!(>::get(), 0); + }) } #[test] fn account_removal_on_free_too_low() { - set_and_run_with_externalities( - &mut ExtBuilder::default().existential_deposit(100).build(), - || { - assert_eq!(>::get(), 0); + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + assert_eq!(>::get(), 0); - // Setup two accounts with free balance above the existential threshold. - let _ = Balances::deposit_creating(&1, 110); - let _ = Balances::deposit_creating(&2, 110); + // Setup two accounts with free balance above the existential threshold. + let _ = Balances::deposit_creating(&1, 110); + let _ = Balances::deposit_creating(&2, 110); - assert_eq!(Balances::free_balance(&1), 110); - assert_eq!(Balances::free_balance(&2), 110); - assert_eq!(>::get(), 220); + assert_eq!(Balances::free_balance(&1), 110); + assert_eq!(Balances::free_balance(&2), 110); + assert_eq!(>::get(), 220); - // Transfer funds from account 1 of such amount that after this transfer - // the balance of account 1 will be below the existential threshold. - // This should lead to the removal of all balance of this account. - assert_ok!(Balances::transfer(Some(1).into(), 2, 20)); + // Transfer funds from account 1 of such amount that after this transfer + // the balance of account 1 will be below the existential threshold. + // This should lead to the removal of all balance of this account. + assert_ok!(Balances::transfer(Some(1).into(), 2, 20)); - // Verify free balance removal of account 1. - assert_eq!(Balances::free_balance(&1), 0); - assert_eq!(Balances::free_balance(&2), 130); + // Verify free balance removal of account 1. + assert_eq!(Balances::free_balance(&1), 0); + assert_eq!(Balances::free_balance(&2), 130); - // Verify that TotalIssuance tracks balance removal when free balance is too low. - assert_eq!(>::get(), 130); - }, - ); + // Verify that TotalIssuance tracks balance removal when free balance is too low. + assert_eq!(>::get(), 130); + }); } #[test] fn transfer_overflow_isnt_exploitable() { - set_and_run_with_externalities( - &mut ExtBuilder::default().creation_fee(50).build(), - || { - // Craft a value that will overflow if summed with `creation_fee`. - let evil_value = u64::max_value() - 49; - - assert_err!( - Balances::transfer(Some(1).into(), 5, evil_value), - "got overflow after adding a fee to value", - ); - } - ); + ExtBuilder::default().creation_fee(50).build().execute_with(|| { + // Craft a value that will overflow if summed with `creation_fee`. + let evil_value = u64::max_value() - 49; + + assert_err!( + Balances::transfer(Some(1).into(), 5, evil_value), + "got overflow after adding a fee to value", + ); + }); } #[test] fn check_vesting_status() { - set_and_run_with_externalities( - &mut ExtBuilder::default() - .existential_deposit(256) - .monied(true) - .vesting(true) - .build(), - || { + ExtBuilder::default() + .existential_deposit(256) + .monied(true) + .vesting(true) + .build() + .execute_with(|| { assert_eq!(System::block_number(), 1); let user1_free_balance = Balances::free_balance(&1); let user2_free_balance = Balances::free_balance(&2); @@ -663,19 +639,17 @@ fn check_vesting_status() { assert_eq!(Balances::vesting_balance(&2), 0); // Account 2 has fully vested by block 30 assert_eq!(Balances::vesting_balance(&12), 0); // Account 2 has fully vested by block 30 - } - ); + }); } #[test] fn unvested_balance_should_not_transfer() { - set_and_run_with_externalities( - &mut ExtBuilder::default() - .existential_deposit(10) - .monied(true) - .vesting(true) - .build(), - || { + ExtBuilder::default() + .existential_deposit(10) + .monied(true) + .vesting(true) + .build() + .execute_with(|| { assert_eq!(System::block_number(), 1); let user1_free_balance = Balances::free_balance(&1); assert_eq!(user1_free_balance, 100); // Account 1 has free balance @@ -685,38 +659,34 @@ fn unvested_balance_should_not_transfer() { Balances::transfer(Some(1).into(), 2, 56), "vesting balance too high to send value", ); // Account 1 cannot send more than vested amount - } - ); + }); } #[test] fn vested_balance_should_transfer() { - set_and_run_with_externalities( - &mut ExtBuilder::default() - .existential_deposit(10) - .monied(true) - .vesting(true) - .build(), - || { + ExtBuilder::default() + .existential_deposit(10) + .monied(true) + .vesting(true) + .build() + .execute_with(|| { assert_eq!(System::block_number(), 1); let user1_free_balance = Balances::free_balance(&1); assert_eq!(user1_free_balance, 100); // Account 1 has free balance // Account 1 has only 5 units vested at block 1 (plus 50 unvested) assert_eq!(Balances::vesting_balance(&1), 45); assert_ok!(Balances::transfer(Some(1).into(), 2, 55)); - } - ); + }); } #[test] fn extra_balance_should_transfer() { - set_and_run_with_externalities( - &mut ExtBuilder::default() - .existential_deposit(10) - .monied(true) - .vesting(true) - .build(), - || { + ExtBuilder::default() + .existential_deposit(10) + .monied(true) + .vesting(true) + .build() + .execute_with(|| { assert_eq!(System::block_number(), 1); assert_ok!(Balances::transfer(Some(3).into(), 1, 100)); assert_ok!(Balances::transfer(Some(3).into(), 2, 100)); @@ -734,19 +704,17 @@ fn extra_balance_should_transfer() { // Account 2 has no units vested at block 1, but gained 100 assert_eq!(Balances::vesting_balance(&2), 200); assert_ok!(Balances::transfer(Some(2).into(), 3, 100)); // Account 2 can send extra units gained - } - ); + }); } #[test] fn liquid_funds_should_transfer_with_delayed_vesting() { - set_and_run_with_externalities( - &mut ExtBuilder::default() - .existential_deposit(256) - .monied(true) - .vesting(true) - .build(), - || { + ExtBuilder::default() + .existential_deposit(256) + .monied(true) + .vesting(true) + .build() + .execute_with(|| { assert_eq!(System::block_number(), 1); let user12_free_balance = Balances::free_balance(&12); @@ -764,62 +732,64 @@ fn liquid_funds_should_transfer_with_delayed_vesting() { // Account 12 can still send liquid funds assert_ok!(Balances::transfer(Some(12).into(), 3, 256 * 5)); - } - ); + }); } #[test] fn signed_extension_take_fees_work() { - set_and_run_with_externalities( - &mut ExtBuilder::default() - .existential_deposit(10) - .transaction_fees(10, 1, 5) - .monied(true) - .build(), - || { + ExtBuilder::default() + .existential_deposit(10) + .transaction_fees(10, 1, 5) + .monied(true) + .build() + .execute_with(|| { let len = 10; - assert!(TakeFees::::from(0).pre_dispatch(&1, CALL, info_from_weight(5), len).is_ok()); + assert!( + TakeFees::::from(0) + .pre_dispatch(&1, CALL, info_from_weight(5), len) + .is_ok() + ); assert_eq!(Balances::free_balance(&1), 100 - 20 - 25); - assert!(TakeFees::::from(5 /* tipped */).pre_dispatch(&1, CALL, info_from_weight(3), len).is_ok()); + assert!( + TakeFees::::from(5 /* tipped */) + .pre_dispatch(&1, CALL, info_from_weight(3), len) + .is_ok() + ); assert_eq!(Balances::free_balance(&1), 100 - 20 - 25 - 20 - 5 - 15); - } - ); + }); } #[test] fn signed_extension_take_fees_is_bounded() { - set_and_run_with_externalities( - &mut ExtBuilder::default() - .existential_deposit(1000) - .transaction_fees(0, 0, 1) - .monied(true) - .build(), - || { + ExtBuilder::default() + .existential_deposit(1000) + .transaction_fees(0, 0, 1) + .monied(true) + .build() + .execute_with(|| { use sr_primitives::weights::Weight; // maximum weight possible - assert!(TakeFees::::from(0).pre_dispatch(&1, CALL, info_from_weight(Weight::max_value()), 10).is_ok()); + assert!( + TakeFees::::from(0) + .pre_dispatch(&1, CALL, info_from_weight(Weight::max_value()), 10) + .is_ok() + ); // fee will be proportional to what is the actual maximum weight in the runtime. assert_eq!( Balances::free_balance(&1), (10000 - ::MaximumBlockWeight::get()) as u64 ); - } - ); + }); } #[test] fn burn_must_work() { - set_and_run_with_externalities( - &mut ExtBuilder::default() - .monied(true) - .build(), - || { - let init_total_issuance = Balances::total_issuance(); - let imbalance = Balances::burn(10); - assert_eq!(Balances::total_issuance(), init_total_issuance - 10); - drop(imbalance); - assert_eq!(Balances::total_issuance(), init_total_issuance); - } - ); + ExtBuilder::default().monied(true).build().execute_with(|| { + let init_total_issuance = Balances::total_issuance(); + let imbalance = Balances::burn(10); + assert_eq!(Balances::total_issuance(), init_total_issuance - 10); + drop(imbalance); + assert_eq!(Balances::total_issuance(), init_total_issuance); + }); } diff --git a/srml/collective/src/lib.rs b/srml/collective/src/lib.rs index 7ae352266a..2de6243dd6 100644 --- a/srml/collective/src/lib.rs +++ b/srml/collective/src/lib.rs @@ -384,8 +384,8 @@ mod tests { use hex_literal::hex; use primitives::H256; use sr_primitives::{ - set_and_run_with_externalities, Perbill, - traits::{BlakeTwo256, IdentityLookup, Block as BlockT}, testing::Header, BuildStorage, + Perbill, traits::{BlakeTwo256, IdentityLookup, Block as BlockT}, testing::Header, + BuildStorage, }; use crate as collective; @@ -451,7 +451,7 @@ mod tests { #[test] fn motions_basic_environment_works() { - set_and_run_with_externalities(&mut make_ext(), || { + make_ext().execute_with(|| { System::set_block_number(1); assert_eq!(Collective::members(), vec![1, 2, 3]); assert_eq!(Collective::proposals(), Vec::::new()); @@ -464,7 +464,7 @@ mod tests { #[test] fn removal_of_old_voters_votes_works() { - set_and_run_with_externalities(&mut make_ext(), || { + make_ext().execute_with(|| { System::set_block_number(1); let proposal = make_proposal(42); let hash = BlakeTwo256::hash_of(&proposal); @@ -498,7 +498,7 @@ mod tests { #[test] fn removal_of_old_voters_votes_works_with_set_members() { - set_and_run_with_externalities(&mut make_ext(), || { + make_ext().execute_with(|| { System::set_block_number(1); let proposal = make_proposal(42); let hash = BlakeTwo256::hash_of(&proposal); @@ -532,7 +532,7 @@ mod tests { #[test] fn propose_works() { - set_and_run_with_externalities(&mut make_ext(), || { + make_ext().execute_with(|| { System::set_block_number(1); let proposal = make_proposal(42); let hash = proposal.blake2_256().into(); @@ -561,7 +561,7 @@ mod tests { #[test] fn motions_ignoring_non_collective_proposals_works() { - set_and_run_with_externalities(&mut make_ext(), || { + make_ext().execute_with(|| { System::set_block_number(1); let proposal = make_proposal(42); assert_noop!( @@ -573,29 +573,35 @@ mod tests { #[test] fn motions_ignoring_non_collective_votes_works() { - set_and_run_with_externalities(&mut make_ext(), || { + make_ext().execute_with(|| { System::set_block_number(1); let proposal = make_proposal(42); let hash: H256 = proposal.blake2_256().into(); assert_ok!(Collective::propose(Origin::signed(1), 3, Box::new(proposal.clone()))); - assert_noop!(Collective::vote(Origin::signed(42), hash.clone(), 0, true), "voter not a member"); + assert_noop!( + Collective::vote(Origin::signed(42), hash.clone(), 0, true), + "voter not a member", + ); }); } #[test] fn motions_ignoring_bad_index_collective_vote_works() { - set_and_run_with_externalities(&mut make_ext(), || { + make_ext().execute_with(|| { System::set_block_number(3); let proposal = make_proposal(42); let hash: H256 = proposal.blake2_256().into(); assert_ok!(Collective::propose(Origin::signed(1), 3, Box::new(proposal.clone()))); - assert_noop!(Collective::vote(Origin::signed(2), hash.clone(), 1, true), "mismatched index"); + assert_noop!( + Collective::vote(Origin::signed(2), hash.clone(), 1, true), + "mismatched index", + ); }); } #[test] fn motions_revoting_works() { - set_and_run_with_externalities(&mut make_ext(), || { + make_ext().execute_with(|| { System::set_block_number(1); let proposal = make_proposal(42); let hash: H256 = proposal.blake2_256().into(); @@ -604,13 +610,19 @@ mod tests { Collective::voting(&hash), Some(Votes { index: 0, threshold: 2, ayes: vec![1], nays: vec![] }) ); - assert_noop!(Collective::vote(Origin::signed(1), hash.clone(), 0, true), "duplicate vote ignored"); + assert_noop!( + Collective::vote(Origin::signed(1), hash.clone(), 0, true), + "duplicate vote ignored", + ); assert_ok!(Collective::vote(Origin::signed(1), hash.clone(), 0, false)); assert_eq!( Collective::voting(&hash), Some(Votes { index: 0, threshold: 2, ayes: vec![], nays: vec![1] }) ); - assert_noop!(Collective::vote(Origin::signed(1), hash.clone(), 0, false), "duplicate vote ignored"); + assert_noop!( + Collective::vote(Origin::signed(1), hash.clone(), 0, false), + "duplicate vote ignored", + ); assert_eq!(System::events(), vec![ EventRecord { @@ -640,7 +652,7 @@ mod tests { #[test] fn motions_disapproval_works() { - set_and_run_with_externalities(&mut make_ext(), || { + make_ext().execute_with(|| { System::set_block_number(1); let proposal = make_proposal(42); let hash: H256 = proposal.blake2_256().into(); @@ -683,7 +695,7 @@ mod tests { #[test] fn motions_approval_works() { - set_and_run_with_externalities(&mut make_ext(), || { + make_ext().execute_with(|| { System::set_block_number(1); let proposal = make_proposal(42); let hash: H256 = proposal.blake2_256().into(); diff --git a/srml/contracts/src/exec.rs b/srml/contracts/src/exec.rs index a2dd3c1f3d..f85797378f 100644 --- a/srml/contracts/src/exec.rs +++ b/srml/contracts/src/exec.rs @@ -807,7 +807,6 @@ mod tests { account_db::AccountDb, gas::GasMeter, tests::{ExtBuilder, Test}, exec::{ExecReturnValue, ExecError, STATUS_SUCCESS}, CodeHash, Config, }; - use sr_primitives::set_and_run_with_externalities; use std::{cell::RefCell, rc::Rc, collections::HashMap, marker::PhantomData}; use assert_matches::assert_matches; @@ -933,7 +932,7 @@ mod tests { exec_success() }); - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { let cfg = Config::preload(); let mut ctx = ExecutionContext::top_level(ALICE, &cfg, &vm, &loader); ctx.overlay.instantiate_contract(&BOB, exec_ch).unwrap(); @@ -953,7 +952,7 @@ mod tests { let dest = BOB; // This test verifies that base fee for call is taken. - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { let vm = MockVm::new(); let loader = MockLoader::empty(); let cfg = Config::preload(); @@ -971,7 +970,7 @@ mod tests { }); // This test verifies that base fee for instantiation is taken. - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { let mut loader = MockLoader::empty(); let code = loader.insert(|_| exec_success()); @@ -1001,7 +1000,7 @@ mod tests { let vm = MockVm::new(); let loader = MockLoader::empty(); - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { let cfg = Config::preload(); let mut ctx = ExecutionContext::top_level(origin, &cfg, &vm, &loader); ctx.overlay.set_balance(&origin, 100); @@ -1033,7 +1032,7 @@ mod tests { |_| Ok(ExecReturnValue { status: 1, data: Vec::new() }) ); - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { let cfg = Config::preload(); let mut ctx = ExecutionContext::top_level(origin, &cfg, &vm, &loader); ctx.overlay.instantiate_contract(&BOB, return_ch).unwrap(); @@ -1061,93 +1060,84 @@ mod tests { // This test sends 50 units of currency to a non-existent account. // This should lead to creation of a new account thus // a fee should be charged. - set_and_run_with_externalities( - &mut ExtBuilder::default().existential_deposit(15).build(), - || { - let vm = MockVm::new(); - let loader = MockLoader::empty(); - let cfg = Config::preload(); - let mut ctx = ExecutionContext::top_level(origin, &cfg, &vm, &loader); - ctx.overlay.set_balance(&origin, 100); - ctx.overlay.set_balance(&dest, 0); - - let mut gas_meter = GasMeter::::with_limit(1000, 1); - - let result = ctx.call(dest, 50, &mut gas_meter, vec![]); - assert_matches!(result, Ok(_)); - - let mut toks = gas_meter.tokens().iter(); - match_tokens!( - toks, - ExecFeeToken::Call, - TransferFeeToken { - kind: TransferFeeKind::AccountCreate, - gas_price: 1u64 - }, - ); - }, - ); + ExtBuilder::default().existential_deposit(15).build().execute_with(|| { + let vm = MockVm::new(); + let loader = MockLoader::empty(); + let cfg = Config::preload(); + let mut ctx = ExecutionContext::top_level(origin, &cfg, &vm, &loader); + ctx.overlay.set_balance(&origin, 100); + ctx.overlay.set_balance(&dest, 0); + + let mut gas_meter = GasMeter::::with_limit(1000, 1); + + let result = ctx.call(dest, 50, &mut gas_meter, vec![]); + assert_matches!(result, Ok(_)); + + let mut toks = gas_meter.tokens().iter(); + match_tokens!( + toks, + ExecFeeToken::Call, + TransferFeeToken { + kind: TransferFeeKind::AccountCreate, + gas_price: 1u64 + }, + ); + }); // This one is similar to the previous one but transfer to an existing account. // In this test we expect that a regular transfer fee is charged. - set_and_run_with_externalities( - &mut ExtBuilder::default().existential_deposit(15).build(), - || { - let vm = MockVm::new(); - let loader = MockLoader::empty(); - let cfg = Config::preload(); - let mut ctx = ExecutionContext::top_level(origin, &cfg, &vm, &loader); - ctx.overlay.set_balance(&origin, 100); - ctx.overlay.set_balance(&dest, 15); - - let mut gas_meter = GasMeter::::with_limit(1000, 1); - - let result = ctx.call(dest, 50, &mut gas_meter, vec![]); - assert_matches!(result, Ok(_)); - - let mut toks = gas_meter.tokens().iter(); - match_tokens!( - toks, - ExecFeeToken::Call, - TransferFeeToken { - kind: TransferFeeKind::Transfer, - gas_price: 1u64 - }, - ); - }, - ); + ExtBuilder::default().existential_deposit(15).build().execute_with(|| { + let vm = MockVm::new(); + let loader = MockLoader::empty(); + let cfg = Config::preload(); + let mut ctx = ExecutionContext::top_level(origin, &cfg, &vm, &loader); + ctx.overlay.set_balance(&origin, 100); + ctx.overlay.set_balance(&dest, 15); + + let mut gas_meter = GasMeter::::with_limit(1000, 1); + + let result = ctx.call(dest, 50, &mut gas_meter, vec![]); + assert_matches!(result, Ok(_)); + + let mut toks = gas_meter.tokens().iter(); + match_tokens!( + toks, + ExecFeeToken::Call, + TransferFeeToken { + kind: TransferFeeKind::Transfer, + gas_price: 1u64 + }, + ); + }); // This test sends 50 units of currency as an endownment to a newly // instantiated contract. - set_and_run_with_externalities( - &mut ExtBuilder::default().existential_deposit(15).build(), - || { - let mut loader = MockLoader::empty(); - let code = loader.insert(|_| exec_success()); - - let vm = MockVm::new(); - let cfg = Config::preload(); - let mut ctx = ExecutionContext::top_level(origin, &cfg, &vm, &loader); - - ctx.overlay.set_balance(&origin, 100); - ctx.overlay.set_balance(&dest, 15); - - let mut gas_meter = GasMeter::::with_limit(1000, 1); - - let result = ctx.instantiate(50, &mut gas_meter, &code, vec![]); - assert_matches!(result, Ok(_)); - - let mut toks = gas_meter.tokens().iter(); - match_tokens!( - toks, - ExecFeeToken::Instantiate, - TransferFeeToken { - kind: TransferFeeKind::ContractInstantiate, - gas_price: 1u64 - }, - ); - }, - ); + ExtBuilder::default().existential_deposit(15).build().execute_with(|| { + let mut loader = MockLoader::empty(); + let code = loader.insert(|_| exec_success()); + + let vm = MockVm::new(); + let cfg = Config::preload(); + let mut ctx = ExecutionContext::top_level(origin, &cfg, &vm, &loader); + + ctx.overlay.set_balance(&origin, 100); + ctx.overlay.set_balance(&dest, 15); + + let mut gas_meter = GasMeter::::with_limit(1000, 1); + + let result = ctx.instantiate(50, &mut gas_meter, &code, vec![]); + assert_matches!(result, Ok(_)); + + let mut toks = gas_meter.tokens().iter(); + match_tokens!( + toks, + ExecFeeToken::Instantiate, + TransferFeeToken { + kind: TransferFeeKind::ContractInstantiate, + gas_price: 1u64 + }, + ); + }); } #[test] @@ -1160,7 +1150,7 @@ mod tests { let vm = MockVm::new(); let loader = MockLoader::empty(); - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { let cfg = Config::preload(); let mut ctx = ExecutionContext::top_level(origin, &cfg, &vm, &loader); ctx.overlay.set_balance(&origin, 0); @@ -1194,7 +1184,7 @@ mod tests { |_| Ok(ExecReturnValue { status: STATUS_SUCCESS, data: vec![1, 2, 3, 4] }) ); - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { let cfg = Config::preload(); let mut ctx = ExecutionContext::top_level(origin, &cfg, &vm, &loader); ctx.overlay.instantiate_contract(&BOB, return_ch).unwrap(); @@ -1225,7 +1215,7 @@ mod tests { |_| Ok(ExecReturnValue { status: 1, data: vec![1, 2, 3, 4] }) ); - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { let cfg = Config::preload(); let mut ctx = ExecutionContext::top_level(origin, &cfg, &vm, &loader); ctx.overlay.instantiate_contract(&BOB, return_ch).unwrap(); @@ -1253,7 +1243,7 @@ mod tests { }); // This one tests passing the input data into a contract via call. - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { let cfg = Config::preload(); let mut ctx = ExecutionContext::top_level(ALICE, &cfg, &vm, &loader); ctx.overlay.instantiate_contract(&BOB, input_data_ch).unwrap(); @@ -1278,7 +1268,7 @@ mod tests { }); // This one tests passing the input data into a contract via instantiate. - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { let cfg = Config::preload(); let mut ctx = ExecutionContext::top_level(ALICE, &cfg, &vm, &loader); @@ -1322,7 +1312,7 @@ mod tests { exec_success() }); - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { let cfg = Config::preload(); let mut ctx = ExecutionContext::top_level(ALICE, &cfg, &vm, &loader); ctx.overlay.instantiate_contract(&BOB, recurse_ch).unwrap(); @@ -1366,7 +1356,7 @@ mod tests { exec_success() }); - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { let cfg = Config::preload(); let mut ctx = ExecutionContext::top_level(origin, &cfg, &vm, &loader); @@ -1408,7 +1398,7 @@ mod tests { exec_success() }); - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { let cfg = Config::preload(); let mut ctx = ExecutionContext::top_level(ALICE, &cfg, &vm, &loader); ctx.overlay.instantiate_contract(&BOB, bob_ch).unwrap(); @@ -1432,23 +1422,20 @@ mod tests { let mut loader = MockLoader::empty(); let dummy_ch = loader.insert(|_| exec_success()); - set_and_run_with_externalities( - &mut ExtBuilder::default().existential_deposit(15).build(), - || { - let cfg = Config::preload(); - let mut ctx = ExecutionContext::top_level(ALICE, &cfg, &vm, &loader); + ExtBuilder::default().existential_deposit(15).build().execute_with(|| { + let cfg = Config::preload(); + let mut ctx = ExecutionContext::top_level(ALICE, &cfg, &vm, &loader); - assert_matches!( - ctx.instantiate( - 0, // <- zero endowment - &mut GasMeter::::with_limit(10000, 1), - &dummy_ch, - vec![], - ), - Err(_) - ); - } - ); + assert_matches!( + ctx.instantiate( + 0, // <- zero endowment + &mut GasMeter::::with_limit(10000, 1), + &dummy_ch, + vec![], + ), + Err(_) + ); + }); } #[test] @@ -1460,38 +1447,35 @@ mod tests { |_| Ok(ExecReturnValue { status: STATUS_SUCCESS, data: vec![80, 65, 83, 83] }) ); - set_and_run_with_externalities( - &mut ExtBuilder::default().existential_deposit(15).build(), - || { - let cfg = Config::preload(); - let mut ctx = ExecutionContext::top_level(ALICE, &cfg, &vm, &loader); - ctx.overlay.set_balance(&ALICE, 1000); - - let instantiated_contract_address = assert_matches!( - ctx.instantiate( - 100, - &mut GasMeter::::with_limit(10000, 1), - &dummy_ch, - vec![], - ), - Ok((address, ref output)) if output.data == vec![80, 65, 83, 83] => address - ); + ExtBuilder::default().existential_deposit(15).build().execute_with(|| { + let cfg = Config::preload(); + let mut ctx = ExecutionContext::top_level(ALICE, &cfg, &vm, &loader); + ctx.overlay.set_balance(&ALICE, 1000); - // Check that the newly created account has the expected code hash and - // there are instantiation event. - assert_eq!(ctx.overlay.get_code_hash(&instantiated_contract_address).unwrap(), dummy_ch); - assert_eq!(&ctx.events(), &[ - DeferredAction::DepositEvent { - event: RawEvent::Transfer(ALICE, instantiated_contract_address, 100), - topics: Vec::new(), - }, - DeferredAction::DepositEvent { - event: RawEvent::Instantiated(ALICE, instantiated_contract_address), - topics: Vec::new(), - } - ]); - } - ); + let instantiated_contract_address = assert_matches!( + ctx.instantiate( + 100, + &mut GasMeter::::with_limit(10000, 1), + &dummy_ch, + vec![], + ), + Ok((address, ref output)) if output.data == vec![80, 65, 83, 83] => address + ); + + // Check that the newly created account has the expected code hash and + // there are instantiation event. + assert_eq!(ctx.overlay.get_code_hash(&instantiated_contract_address).unwrap(), dummy_ch); + assert_eq!(&ctx.events(), &[ + DeferredAction::DepositEvent { + event: RawEvent::Transfer(ALICE, instantiated_contract_address, 100), + topics: Vec::new(), + }, + DeferredAction::DepositEvent { + event: RawEvent::Instantiated(ALICE, instantiated_contract_address), + topics: Vec::new(), + } + ]); + }); } #[test] @@ -1503,28 +1487,25 @@ mod tests { |_| Ok(ExecReturnValue { status: 1, data: vec![70, 65, 73, 76] }) ); - set_and_run_with_externalities( - &mut ExtBuilder::default().existential_deposit(15).build(), - || { - let cfg = Config::preload(); - let mut ctx = ExecutionContext::top_level(ALICE, &cfg, &vm, &loader); - ctx.overlay.set_balance(&ALICE, 1000); - - let instantiated_contract_address = assert_matches!( - ctx.instantiate( - 100, - &mut GasMeter::::with_limit(10000, 1), - &dummy_ch, - vec![], - ), - Ok((address, ref output)) if output.data == vec![70, 65, 73, 76] => address - ); + ExtBuilder::default().existential_deposit(15).build().execute_with(|| { + let cfg = Config::preload(); + let mut ctx = ExecutionContext::top_level(ALICE, &cfg, &vm, &loader); + ctx.overlay.set_balance(&ALICE, 1000); - // Check that the account has not been created. - assert!(ctx.overlay.get_code_hash(&instantiated_contract_address).is_none()); - assert!(ctx.events().is_empty()); - } - ); + let instantiated_contract_address = assert_matches!( + ctx.instantiate( + 100, + &mut GasMeter::::with_limit(10000, 1), + &dummy_ch, + vec![], + ), + Ok((address, ref output)) if output.data == vec![70, 65, 73, 76] => address + ); + + // Check that the account has not been created. + assert!(ctx.overlay.get_code_hash(&instantiated_contract_address).is_none()); + assert!(ctx.events().is_empty()); + }); } #[test] @@ -1551,40 +1532,37 @@ mod tests { } }); - set_and_run_with_externalities( - &mut ExtBuilder::default().existential_deposit(15).build(), - || { - let cfg = Config::preload(); - let mut ctx = ExecutionContext::top_level(ALICE, &cfg, &vm, &loader); - ctx.overlay.set_balance(&ALICE, 1000); - ctx.overlay.instantiate_contract(&BOB, instantiator_ch).unwrap(); + ExtBuilder::default().existential_deposit(15).build().execute_with(|| { + let cfg = Config::preload(); + let mut ctx = ExecutionContext::top_level(ALICE, &cfg, &vm, &loader); + ctx.overlay.set_balance(&ALICE, 1000); + ctx.overlay.instantiate_contract(&BOB, instantiator_ch).unwrap(); - assert_matches!( - ctx.call(BOB, 20, &mut GasMeter::::with_limit(1000, 1), vec![]), - Ok(_) - ); + assert_matches!( + ctx.call(BOB, 20, &mut GasMeter::::with_limit(1000, 1), vec![]), + Ok(_) + ); - let instantiated_contract_address = instantiated_contract_address.borrow().as_ref().unwrap().clone(); - - // Check that the newly created account has the expected code hash and - // there are instantiation event. - assert_eq!(ctx.overlay.get_code_hash(&instantiated_contract_address).unwrap(), dummy_ch); - assert_eq!(&ctx.events(), &[ - DeferredAction::DepositEvent { - event: RawEvent::Transfer(ALICE, BOB, 20), - topics: Vec::new(), - }, - DeferredAction::DepositEvent { - event: RawEvent::Transfer(BOB, instantiated_contract_address, 15), - topics: Vec::new(), - }, - DeferredAction::DepositEvent { - event: RawEvent::Instantiated(BOB, instantiated_contract_address), - topics: Vec::new(), - }, - ]); - } - ); + let instantiated_contract_address = instantiated_contract_address.borrow().as_ref().unwrap().clone(); + + // Check that the newly created account has the expected code hash and + // there are instantiation event. + assert_eq!(ctx.overlay.get_code_hash(&instantiated_contract_address).unwrap(), dummy_ch); + assert_eq!(&ctx.events(), &[ + DeferredAction::DepositEvent { + event: RawEvent::Transfer(ALICE, BOB, 20), + topics: Vec::new(), + }, + DeferredAction::DepositEvent { + event: RawEvent::Transfer(BOB, instantiated_contract_address, 15), + topics: Vec::new(), + }, + DeferredAction::DepositEvent { + event: RawEvent::Instantiated(BOB, instantiated_contract_address), + topics: Vec::new(), + }, + ]); + }); } #[test] @@ -1613,29 +1591,26 @@ mod tests { } }); - set_and_run_with_externalities( - &mut ExtBuilder::default().existential_deposit(15).build(), - || { - let cfg = Config::preload(); - let mut ctx = ExecutionContext::top_level(ALICE, &cfg, &vm, &loader); - ctx.overlay.set_balance(&ALICE, 1000); - ctx.overlay.instantiate_contract(&BOB, instantiator_ch).unwrap(); + ExtBuilder::default().existential_deposit(15).build().execute_with(|| { + let cfg = Config::preload(); + let mut ctx = ExecutionContext::top_level(ALICE, &cfg, &vm, &loader); + ctx.overlay.set_balance(&ALICE, 1000); + ctx.overlay.instantiate_contract(&BOB, instantiator_ch).unwrap(); - assert_matches!( - ctx.call(BOB, 20, &mut GasMeter::::with_limit(1000, 1), vec![]), - Ok(_) - ); + assert_matches!( + ctx.call(BOB, 20, &mut GasMeter::::with_limit(1000, 1), vec![]), + Ok(_) + ); - // The contract wasn't instantiated so we don't expect to see an instantiation - // event here. - assert_eq!(&ctx.events(), &[ - DeferredAction::DepositEvent { - event: RawEvent::Transfer(ALICE, BOB, 20), - topics: Vec::new(), - }, - ]); - } - ); + // The contract wasn't instantiated so we don't expect to see an instantiation + // event here. + assert_eq!(&ctx.events(), &[ + DeferredAction::DepositEvent { + event: RawEvent::Transfer(ALICE, BOB, 20), + topics: Vec::new(), + }, + ]); + }); } #[test] @@ -1649,7 +1624,7 @@ mod tests { exec_success() }); - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { let cfg = Config::preload(); let mut ctx = ExecutionContext::top_level(ALICE, &cfg, &vm, &loader); diff --git a/srml/contracts/src/tests.rs b/srml/contracts/src/tests.rs index 9d02419b17..d6de2ce3bd 100644 --- a/srml/contracts/src/tests.rs +++ b/srml/contracts/src/tests.rs @@ -30,7 +30,7 @@ use codec::{Decode, Encode, KeyedVec}; use sr_primitives::{ Perbill, BuildStorage, transaction_validity::{InvalidTransaction, ValidTransaction}, traits::{BlakeTwo256, Hash, IdentityLookup, SignedExtension}, - weights::{DispatchInfo, DispatchClass}, set_and_run_with_externalities, + weights::{DispatchInfo, DispatchClass}, testing::{Digest, DigestItem, Header, UintAuthorityId, H256}, }; use support::{ @@ -306,7 +306,7 @@ fn compile_module(wabt_module: &str) // Then we check that the all unused gas is refunded. #[test] fn refunds_unused_gas() { - set_and_run_with_externalities(&mut ExtBuilder::default().gas_price(2).build(), || { + ExtBuilder::default().gas_price(2).build().execute_with(|| { Balances::deposit_creating(&ALICE, 100_000_000); assert_ok!(Contract::call(Origin::signed(ALICE), BOB, 0, 100_000, Vec::new())); @@ -318,70 +318,67 @@ fn refunds_unused_gas() { #[test] fn account_removal_removes_storage() { - set_and_run_with_externalities( - &mut ExtBuilder::default().existential_deposit(100).build(), - || { - let trie_id1 = ::TrieIdGenerator::trie_id(&1); - let trie_id2 = ::TrieIdGenerator::trie_id(&2); - let key1 = &[1; 32]; - let key2 = &[2; 32]; - - // Set up two accounts with free balance above the existential threshold. - { - Balances::deposit_creating(&1, 110); - ContractInfoOf::::insert(1, &ContractInfo::Alive(RawAliveContractInfo { - trie_id: trie_id1.clone(), - storage_size: ::StorageSizeOffset::get(), - deduct_block: System::block_number(), - code_hash: H256::repeat_byte(1), - rent_allowance: 40, - last_write: None, - })); - - let mut overlay = OverlayAccountDb::::new(&DirectAccountDb); - overlay.set_storage(&1, key1.clone(), Some(b"1".to_vec())); - overlay.set_storage(&1, key2.clone(), Some(b"2".to_vec())); - DirectAccountDb.commit(overlay.into_change_set()); - - Balances::deposit_creating(&2, 110); - ContractInfoOf::::insert(2, &ContractInfo::Alive(RawAliveContractInfo { - trie_id: trie_id2.clone(), - storage_size: ::StorageSizeOffset::get(), - deduct_block: System::block_number(), - code_hash: H256::repeat_byte(2), - rent_allowance: 40, - last_write: None, - })); - - let mut overlay = OverlayAccountDb::::new(&DirectAccountDb); - overlay.set_storage(&2, key1.clone(), Some(b"3".to_vec())); - overlay.set_storage(&2, key2.clone(), Some(b"4".to_vec())); - DirectAccountDb.commit(overlay.into_change_set()); - } + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let trie_id1 = ::TrieIdGenerator::trie_id(&1); + let trie_id2 = ::TrieIdGenerator::trie_id(&2); + let key1 = &[1; 32]; + let key2 = &[2; 32]; + + // Set up two accounts with free balance above the existential threshold. + { + Balances::deposit_creating(&1, 110); + ContractInfoOf::::insert(1, &ContractInfo::Alive(RawAliveContractInfo { + trie_id: trie_id1.clone(), + storage_size: ::StorageSizeOffset::get(), + deduct_block: System::block_number(), + code_hash: H256::repeat_byte(1), + rent_allowance: 40, + last_write: None, + })); + + let mut overlay = OverlayAccountDb::::new(&DirectAccountDb); + overlay.set_storage(&1, key1.clone(), Some(b"1".to_vec())); + overlay.set_storage(&1, key2.clone(), Some(b"2".to_vec())); + DirectAccountDb.commit(overlay.into_change_set()); + + Balances::deposit_creating(&2, 110); + ContractInfoOf::::insert(2, &ContractInfo::Alive(RawAliveContractInfo { + trie_id: trie_id2.clone(), + storage_size: ::StorageSizeOffset::get(), + deduct_block: System::block_number(), + code_hash: H256::repeat_byte(2), + rent_allowance: 40, + last_write: None, + })); + + let mut overlay = OverlayAccountDb::::new(&DirectAccountDb); + overlay.set_storage(&2, key1.clone(), Some(b"3".to_vec())); + overlay.set_storage(&2, key2.clone(), Some(b"4".to_vec())); + DirectAccountDb.commit(overlay.into_change_set()); + } - // Transfer funds from account 1 of such amount that after this transfer - // the balance of account 1 will be below the existential threshold. - // - // This should lead to the removal of all storage associated with this account. - assert_ok!(Balances::transfer(Origin::signed(1), 2, 20)); - - // Verify that all entries from account 1 is removed, while - // entries from account 2 is in place. - { - assert!(>::get_storage(&DirectAccountDb, &1, Some(&trie_id1), key1).is_none()); - assert!(>::get_storage(&DirectAccountDb, &1, Some(&trie_id1), key2).is_none()); - - assert_eq!( - >::get_storage(&DirectAccountDb, &2, Some(&trie_id2), key1), - Some(b"3".to_vec()) - ); - assert_eq!( - >::get_storage(&DirectAccountDb, &2, Some(&trie_id2), key2), - Some(b"4".to_vec()) - ); - } - }, - ); + // Transfer funds from account 1 of such amount that after this transfer + // the balance of account 1 will be below the existential threshold. + // + // This should lead to the removal of all storage associated with this account. + assert_ok!(Balances::transfer(Origin::signed(1), 2, 20)); + + // Verify that all entries from account 1 is removed, while + // entries from account 2 is in place. + { + assert!(>::get_storage(&DirectAccountDb, &1, Some(&trie_id1), key1).is_none()); + assert!(>::get_storage(&DirectAccountDb, &1, Some(&trie_id1), key2).is_none()); + + assert_eq!( + >::get_storage(&DirectAccountDb, &2, Some(&trie_id2), key1), + Some(b"3".to_vec()) + ); + assert_eq!( + >::get_storage(&DirectAccountDb, &2, Some(&trie_id2), key2), + Some(b"4".to_vec()) + ); + } + }); } const CODE_RETURN_FROM_START_FN: &str = r#" @@ -418,61 +415,58 @@ const CODE_RETURN_FROM_START_FN: &str = r#" fn instantiate_and_call_and_deposit_event() { let (wasm, code_hash) = compile_module::(CODE_RETURN_FROM_START_FN).unwrap(); - set_and_run_with_externalities( - &mut ExtBuilder::default().existential_deposit(100).build(), - || { - Balances::deposit_creating(&ALICE, 1_000_000); - - assert_ok!(Contract::put_code(Origin::signed(ALICE), 100_000, wasm)); - - // Check at the end to get hash on error easily - let creation = Contract::instantiate( - Origin::signed(ALICE), - 100, - 100_000, - code_hash.into(), - vec![], - ); + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + Balances::deposit_creating(&ALICE, 1_000_000); + + assert_ok!(Contract::put_code(Origin::signed(ALICE), 100_000, wasm)); + + // Check at the end to get hash on error easily + let creation = Contract::instantiate( + Origin::signed(ALICE), + 100, + 100_000, + code_hash.into(), + vec![], + ); + + assert_eq!(System::events(), vec![ + EventRecord { + phase: Phase::ApplyExtrinsic(0), + event: MetaEvent::balances(balances::RawEvent::NewAccount(1, 1_000_000)), + topics: vec![], + }, + EventRecord { + phase: Phase::ApplyExtrinsic(0), + event: MetaEvent::contract(RawEvent::CodeStored(code_hash.into())), + topics: vec![], + }, + EventRecord { + phase: Phase::ApplyExtrinsic(0), + event: MetaEvent::balances( + balances::RawEvent::NewAccount(BOB, 100) + ), + topics: vec![], + }, + EventRecord { + phase: Phase::ApplyExtrinsic(0), + event: MetaEvent::contract(RawEvent::Transfer(ALICE, BOB, 100)), + topics: vec![], + }, + EventRecord { + phase: Phase::ApplyExtrinsic(0), + event: MetaEvent::contract(RawEvent::Contract(BOB, vec![1, 2, 3, 4])), + topics: vec![], + }, + EventRecord { + phase: Phase::ApplyExtrinsic(0), + event: MetaEvent::contract(RawEvent::Instantiated(ALICE, BOB)), + topics: vec![], + } + ]); - assert_eq!(System::events(), vec![ - EventRecord { - phase: Phase::ApplyExtrinsic(0), - event: MetaEvent::balances(balances::RawEvent::NewAccount(1, 1_000_000)), - topics: vec![], - }, - EventRecord { - phase: Phase::ApplyExtrinsic(0), - event: MetaEvent::contract(RawEvent::CodeStored(code_hash.into())), - topics: vec![], - }, - EventRecord { - phase: Phase::ApplyExtrinsic(0), - event: MetaEvent::balances( - balances::RawEvent::NewAccount(BOB, 100) - ), - topics: vec![], - }, - EventRecord { - phase: Phase::ApplyExtrinsic(0), - event: MetaEvent::contract(RawEvent::Transfer(ALICE, BOB, 100)), - topics: vec![], - }, - EventRecord { - phase: Phase::ApplyExtrinsic(0), - event: MetaEvent::contract(RawEvent::Contract(BOB, vec![1, 2, 3, 4])), - topics: vec![], - }, - EventRecord { - phase: Phase::ApplyExtrinsic(0), - event: MetaEvent::contract(RawEvent::Instantiated(ALICE, BOB)), - topics: vec![], - } - ]); - - assert_ok!(creation); - assert!(ContractInfoOf::::exists(BOB)); - }, - ); + assert_ok!(creation); + assert!(ContractInfoOf::::exists(BOB)); + }); } const CODE_DISPATCH_CALL: &str = r#" @@ -501,98 +495,95 @@ fn dispatch_call() { let (wasm, code_hash) = compile_module::(CODE_DISPATCH_CALL).unwrap(); - set_and_run_with_externalities( - &mut ExtBuilder::default().existential_deposit(50).build(), - || { - Balances::deposit_creating(&ALICE, 1_000_000); - - assert_ok!(Contract::put_code(Origin::signed(ALICE), 100_000, wasm)); - - // Let's keep this assert even though it's redundant. If you ever need to update the - // wasm source this test will fail and will show you the actual hash. - assert_eq!(System::events(), vec![ - EventRecord { - phase: Phase::ApplyExtrinsic(0), - event: MetaEvent::balances(balances::RawEvent::NewAccount(1, 1_000_000)), - topics: vec![], - }, - EventRecord { - phase: Phase::ApplyExtrinsic(0), - event: MetaEvent::contract(RawEvent::CodeStored(code_hash.into())), - topics: vec![], - }, - ]); - - assert_ok!(Contract::instantiate( - Origin::signed(ALICE), - 100, - 100_000, - code_hash.into(), - vec![], - )); + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + Balances::deposit_creating(&ALICE, 1_000_000); - assert_ok!(Contract::call( - Origin::signed(ALICE), - BOB, // newly created account - 0, - 100_000, - vec![], - )); - - assert_eq!(System::events(), vec![ - EventRecord { - phase: Phase::ApplyExtrinsic(0), - event: MetaEvent::balances(balances::RawEvent::NewAccount(1, 1_000_000)), - topics: vec![], - }, - EventRecord { - phase: Phase::ApplyExtrinsic(0), - event: MetaEvent::contract(RawEvent::CodeStored(code_hash.into())), - topics: vec![], - }, - EventRecord { - phase: Phase::ApplyExtrinsic(0), - event: MetaEvent::balances( - balances::RawEvent::NewAccount(BOB, 100) - ), - topics: vec![], - }, - EventRecord { - phase: Phase::ApplyExtrinsic(0), - event: MetaEvent::contract(RawEvent::Transfer(ALICE, BOB, 100)), - topics: vec![], - }, - EventRecord { - phase: Phase::ApplyExtrinsic(0), - event: MetaEvent::contract(RawEvent::Instantiated(ALICE, BOB)), - topics: vec![], - }, - - // Dispatching the call. - EventRecord { - phase: Phase::ApplyExtrinsic(0), - event: MetaEvent::balances( - balances::RawEvent::NewAccount(CHARLIE, 50) - ), - topics: vec![], - }, - EventRecord { - phase: Phase::ApplyExtrinsic(0), - event: MetaEvent::balances( - balances::RawEvent::Transfer(BOB, CHARLIE, 50, 0) - ), - topics: vec![], - }, - - // Event emited as a result of dispatch. - EventRecord { - phase: Phase::ApplyExtrinsic(0), - event: MetaEvent::contract(RawEvent::Dispatched(BOB, true)), - topics: vec![], - } - ]); - }, - ); + assert_ok!(Contract::put_code(Origin::signed(ALICE), 100_000, wasm)); + + // Let's keep this assert even though it's redundant. If you ever need to update the + // wasm source this test will fail and will show you the actual hash. + assert_eq!(System::events(), vec![ + EventRecord { + phase: Phase::ApplyExtrinsic(0), + event: MetaEvent::balances(balances::RawEvent::NewAccount(1, 1_000_000)), + topics: vec![], + }, + EventRecord { + phase: Phase::ApplyExtrinsic(0), + event: MetaEvent::contract(RawEvent::CodeStored(code_hash.into())), + topics: vec![], + }, + ]); + + assert_ok!(Contract::instantiate( + Origin::signed(ALICE), + 100, + 100_000, + code_hash.into(), + vec![], + )); + + assert_ok!(Contract::call( + Origin::signed(ALICE), + BOB, // newly created account + 0, + 100_000, + vec![], + )); + + assert_eq!(System::events(), vec![ + EventRecord { + phase: Phase::ApplyExtrinsic(0), + event: MetaEvent::balances(balances::RawEvent::NewAccount(1, 1_000_000)), + topics: vec![], + }, + EventRecord { + phase: Phase::ApplyExtrinsic(0), + event: MetaEvent::contract(RawEvent::CodeStored(code_hash.into())), + topics: vec![], + }, + EventRecord { + phase: Phase::ApplyExtrinsic(0), + event: MetaEvent::balances( + balances::RawEvent::NewAccount(BOB, 100) + ), + topics: vec![], + }, + EventRecord { + phase: Phase::ApplyExtrinsic(0), + event: MetaEvent::contract(RawEvent::Transfer(ALICE, BOB, 100)), + topics: vec![], + }, + EventRecord { + phase: Phase::ApplyExtrinsic(0), + event: MetaEvent::contract(RawEvent::Instantiated(ALICE, BOB)), + topics: vec![], + }, + + // Dispatching the call. + EventRecord { + phase: Phase::ApplyExtrinsic(0), + event: MetaEvent::balances( + balances::RawEvent::NewAccount(CHARLIE, 50) + ), + topics: vec![], + }, + EventRecord { + phase: Phase::ApplyExtrinsic(0), + event: MetaEvent::balances( + balances::RawEvent::Transfer(BOB, CHARLIE, 50, 0) + ), + topics: vec![], + }, + + // Event emited as a result of dispatch. + EventRecord { + phase: Phase::ApplyExtrinsic(0), + event: MetaEvent::contract(RawEvent::Dispatched(BOB, true)), + topics: vec![], + } + ]); + }); } const CODE_DISPATCH_CALL_THEN_TRAP: &str = r#" @@ -622,80 +613,77 @@ fn dispatch_call_not_dispatched_after_top_level_transaction_failure() { let (wasm, code_hash) = compile_module::(CODE_DISPATCH_CALL_THEN_TRAP).unwrap(); - set_and_run_with_externalities( - &mut ExtBuilder::default().existential_deposit(50).build(), - || { - Balances::deposit_creating(&ALICE, 1_000_000); - - assert_ok!(Contract::put_code(Origin::signed(ALICE), 100_000, wasm)); - - // Let's keep this assert even though it's redundant. If you ever need to update the - // wasm source this test will fail and will show you the actual hash. - assert_eq!(System::events(), vec![ - EventRecord { - phase: Phase::ApplyExtrinsic(0), - event: MetaEvent::balances(balances::RawEvent::NewAccount(1, 1_000_000)), - topics: vec![], - }, - EventRecord { - phase: Phase::ApplyExtrinsic(0), - event: MetaEvent::contract(RawEvent::CodeStored(code_hash.into())), - topics: vec![], - }, - ]); - - assert_ok!(Contract::instantiate( + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + Balances::deposit_creating(&ALICE, 1_000_000); + + assert_ok!(Contract::put_code(Origin::signed(ALICE), 100_000, wasm)); + + // Let's keep this assert even though it's redundant. If you ever need to update the + // wasm source this test will fail and will show you the actual hash. + assert_eq!(System::events(), vec![ + EventRecord { + phase: Phase::ApplyExtrinsic(0), + event: MetaEvent::balances(balances::RawEvent::NewAccount(1, 1_000_000)), + topics: vec![], + }, + EventRecord { + phase: Phase::ApplyExtrinsic(0), + event: MetaEvent::contract(RawEvent::CodeStored(code_hash.into())), + topics: vec![], + }, + ]); + + assert_ok!(Contract::instantiate( + Origin::signed(ALICE), + 100, + 100_000, + code_hash.into(), + vec![], + )); + + // Call the newly instantiated contract. The contract is expected to dispatch a call + // and then trap. + assert_err!( + Contract::call( Origin::signed(ALICE), - 100, + BOB, // newly created account + 0, 100_000, - code_hash.into(), vec![], - )); - - // Call the newly instantiated contract. The contract is expected to dispatch a call - // and then trap. - assert_err!( - Contract::call( - Origin::signed(ALICE), - BOB, // newly created account - 0, - 100_000, - vec![], + ), + "during execution" + ); + assert_eq!(System::events(), vec![ + EventRecord { + phase: Phase::ApplyExtrinsic(0), + event: MetaEvent::balances(balances::RawEvent::NewAccount(1, 1_000_000)), + topics: vec![], + }, + EventRecord { + phase: Phase::ApplyExtrinsic(0), + event: MetaEvent::contract(RawEvent::CodeStored(code_hash.into())), + topics: vec![], + }, + EventRecord { + phase: Phase::ApplyExtrinsic(0), + event: MetaEvent::balances( + balances::RawEvent::NewAccount(BOB, 100) ), - "during execution" - ); - assert_eq!(System::events(), vec![ - EventRecord { - phase: Phase::ApplyExtrinsic(0), - event: MetaEvent::balances(balances::RawEvent::NewAccount(1, 1_000_000)), - topics: vec![], - }, - EventRecord { - phase: Phase::ApplyExtrinsic(0), - event: MetaEvent::contract(RawEvent::CodeStored(code_hash.into())), - topics: vec![], - }, - EventRecord { - phase: Phase::ApplyExtrinsic(0), - event: MetaEvent::balances( - balances::RawEvent::NewAccount(BOB, 100) - ), - topics: vec![], - }, - EventRecord { - phase: Phase::ApplyExtrinsic(0), - event: MetaEvent::contract(RawEvent::Transfer(ALICE, BOB, 100)), - topics: vec![], - }, - EventRecord { - phase: Phase::ApplyExtrinsic(0), - event: MetaEvent::contract(RawEvent::Instantiated(ALICE, BOB)), - topics: vec![], - }, - // ABSENCE of events which would be caused by dispatched Balances::transfer call - ]); - }, - ); + topics: vec![], + }, + EventRecord { + phase: Phase::ApplyExtrinsic(0), + event: MetaEvent::contract(RawEvent::Transfer(ALICE, BOB, 100)), + topics: vec![], + }, + EventRecord { + phase: Phase::ApplyExtrinsic(0), + event: MetaEvent::contract(RawEvent::Instantiated(ALICE, BOB)), + topics: vec![], + }, + // ABSENCE of events which would be caused by dispatched Balances::transfer call + ]); + }); } const CODE_SET_RENT: &str = r#" @@ -825,28 +813,25 @@ fn test_set_rent_code_and_hash() { let (wasm, code_hash) = compile_module::(CODE_SET_RENT).unwrap(); - set_and_run_with_externalities( - &mut ExtBuilder::default().existential_deposit(50).build(), - || { - Balances::deposit_creating(&ALICE, 1_000_000); - assert_ok!(Contract::put_code(Origin::signed(ALICE), 100_000, wasm)); - - // If you ever need to update the wasm source this test will fail - // and will show you the actual hash. - assert_eq!(System::events(), vec![ - EventRecord { - phase: Phase::ApplyExtrinsic(0), - event: MetaEvent::balances(balances::RawEvent::NewAccount(1, 1_000_000)), - topics: vec![], - }, - EventRecord { - phase: Phase::ApplyExtrinsic(0), - event: MetaEvent::contract(RawEvent::CodeStored(code_hash.into())), - topics: vec![], - }, - ]); - } - ); + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + Balances::deposit_creating(&ALICE, 1_000_000); + assert_ok!(Contract::put_code(Origin::signed(ALICE), 100_000, wasm)); + + // If you ever need to update the wasm source this test will fail + // and will show you the actual hash. + assert_eq!(System::events(), vec![ + EventRecord { + phase: Phase::ApplyExtrinsic(0), + event: MetaEvent::balances(balances::RawEvent::NewAccount(1, 1_000_000)), + topics: vec![], + }, + EventRecord { + phase: Phase::ApplyExtrinsic(0), + event: MetaEvent::contract(RawEvent::CodeStored(code_hash.into())), + topics: vec![], + }, + ]); + }); } #[test] @@ -854,92 +839,86 @@ fn storage_size() { let (wasm, code_hash) = compile_module::(CODE_SET_RENT).unwrap(); // Storage size - set_and_run_with_externalities( - &mut ExtBuilder::default().existential_deposit(50).build(), - || { - // Create - Balances::deposit_creating(&ALICE, 1_000_000); - assert_ok!(Contract::put_code(Origin::signed(ALICE), 100_000, wasm)); - assert_ok!(Contract::instantiate( - Origin::signed(ALICE), - 30_000, - 100_000, code_hash.into(), - ::Balance::from(1_000u32).encode() // rent allowance - )); - let bob_contract = ContractInfoOf::::get(BOB).unwrap().get_alive().unwrap(); - assert_eq!(bob_contract.storage_size, ::StorageSizeOffset::get() + 4); - - assert_ok!(Contract::call(Origin::signed(ALICE), BOB, 0, 100_000, call::set_storage_4_byte())); - let bob_contract = ContractInfoOf::::get(BOB).unwrap().get_alive().unwrap(); - assert_eq!(bob_contract.storage_size, ::StorageSizeOffset::get() + 4 + 4); - - assert_ok!(Contract::call(Origin::signed(ALICE), BOB, 0, 100_000, call::remove_storage_4_byte())); - let bob_contract = ContractInfoOf::::get(BOB).unwrap().get_alive().unwrap(); - assert_eq!(bob_contract.storage_size, ::StorageSizeOffset::get() + 4); - } - ); + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + // Create + Balances::deposit_creating(&ALICE, 1_000_000); + assert_ok!(Contract::put_code(Origin::signed(ALICE), 100_000, wasm)); + assert_ok!(Contract::instantiate( + Origin::signed(ALICE), + 30_000, + 100_000, code_hash.into(), + ::Balance::from(1_000u32).encode() // rent allowance + )); + let bob_contract = ContractInfoOf::::get(BOB).unwrap().get_alive().unwrap(); + assert_eq!(bob_contract.storage_size, ::StorageSizeOffset::get() + 4); + + assert_ok!(Contract::call(Origin::signed(ALICE), BOB, 0, 100_000, call::set_storage_4_byte())); + let bob_contract = ContractInfoOf::::get(BOB).unwrap().get_alive().unwrap(); + assert_eq!(bob_contract.storage_size, ::StorageSizeOffset::get() + 4 + 4); + + assert_ok!(Contract::call(Origin::signed(ALICE), BOB, 0, 100_000, call::remove_storage_4_byte())); + let bob_contract = ContractInfoOf::::get(BOB).unwrap().get_alive().unwrap(); + assert_eq!(bob_contract.storage_size, ::StorageSizeOffset::get() + 4); + }); } #[test] fn deduct_blocks() { let (wasm, code_hash) = compile_module::(CODE_SET_RENT).unwrap(); - set_and_run_with_externalities( - &mut ExtBuilder::default().existential_deposit(50).build(), - || { - // Create - Balances::deposit_creating(&ALICE, 1_000_000); - assert_ok!(Contract::put_code(Origin::signed(ALICE), 100_000, wasm)); - assert_ok!(Contract::instantiate( - Origin::signed(ALICE), - 30_000, - 100_000, code_hash.into(), - ::Balance::from(1_000u32).encode() // rent allowance - )); - - // Check creation - let bob_contract = ContractInfoOf::::get(BOB).unwrap().get_alive().unwrap(); - assert_eq!(bob_contract.rent_allowance, 1_000); - - // Advance 4 blocks - System::initialize(&5, &[0u8; 32].into(), &[0u8; 32].into(), &Default::default()); - - // Trigger rent through call - assert_ok!(Contract::call(Origin::signed(ALICE), BOB, 0, 100_000, call::null())); - - // Check result - let rent = (8 + 4 - 3) // storage size = size_offset + deploy_set_storage - deposit_offset - * 4 // rent byte price - * 4; // blocks to rent - let bob_contract = ContractInfoOf::::get(BOB).unwrap().get_alive().unwrap(); - assert_eq!(bob_contract.rent_allowance, 1_000 - rent); - assert_eq!(bob_contract.deduct_block, 5); - assert_eq!(Balances::free_balance(BOB), 30_000 - rent); - - // Advance 7 blocks more - System::initialize(&12, &[0u8; 32].into(), &[0u8; 32].into(), &Default::default()); - - // Trigger rent through call - assert_ok!(Contract::call(Origin::signed(ALICE), BOB, 0, 100_000, call::null())); - - // Check result - let rent_2 = (8 + 4 - 2) // storage size = size_offset + deploy_set_storage - deposit_offset - * 4 // rent byte price - * 7; // blocks to rent - let bob_contract = ContractInfoOf::::get(BOB).unwrap().get_alive().unwrap(); - assert_eq!(bob_contract.rent_allowance, 1_000 - rent - rent_2); - assert_eq!(bob_contract.deduct_block, 12); - assert_eq!(Balances::free_balance(BOB), 30_000 - rent - rent_2); - - // Second call on same block should have no effect on rent - assert_ok!(Contract::call(Origin::signed(ALICE), BOB, 0, 100_000, call::null())); - - let bob_contract = ContractInfoOf::::get(BOB).unwrap().get_alive().unwrap(); - assert_eq!(bob_contract.rent_allowance, 1_000 - rent - rent_2); - assert_eq!(bob_contract.deduct_block, 12); - assert_eq!(Balances::free_balance(BOB), 30_000 - rent - rent_2); - } - ); + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + // Create + Balances::deposit_creating(&ALICE, 1_000_000); + assert_ok!(Contract::put_code(Origin::signed(ALICE), 100_000, wasm)); + assert_ok!(Contract::instantiate( + Origin::signed(ALICE), + 30_000, + 100_000, code_hash.into(), + ::Balance::from(1_000u32).encode() // rent allowance + )); + + // Check creation + let bob_contract = ContractInfoOf::::get(BOB).unwrap().get_alive().unwrap(); + assert_eq!(bob_contract.rent_allowance, 1_000); + + // Advance 4 blocks + System::initialize(&5, &[0u8; 32].into(), &[0u8; 32].into(), &Default::default()); + + // Trigger rent through call + assert_ok!(Contract::call(Origin::signed(ALICE), BOB, 0, 100_000, call::null())); + + // Check result + let rent = (8 + 4 - 3) // storage size = size_offset + deploy_set_storage - deposit_offset + * 4 // rent byte price + * 4; // blocks to rent + let bob_contract = ContractInfoOf::::get(BOB).unwrap().get_alive().unwrap(); + assert_eq!(bob_contract.rent_allowance, 1_000 - rent); + assert_eq!(bob_contract.deduct_block, 5); + assert_eq!(Balances::free_balance(BOB), 30_000 - rent); + + // Advance 7 blocks more + System::initialize(&12, &[0u8; 32].into(), &[0u8; 32].into(), &Default::default()); + + // Trigger rent through call + assert_ok!(Contract::call(Origin::signed(ALICE), BOB, 0, 100_000, call::null())); + + // Check result + let rent_2 = (8 + 4 - 2) // storage size = size_offset + deploy_set_storage - deposit_offset + * 4 // rent byte price + * 7; // blocks to rent + let bob_contract = ContractInfoOf::::get(BOB).unwrap().get_alive().unwrap(); + assert_eq!(bob_contract.rent_allowance, 1_000 - rent - rent_2); + assert_eq!(bob_contract.deduct_block, 12); + assert_eq!(Balances::free_balance(BOB), 30_000 - rent - rent_2); + + // Second call on same block should have no effect on rent + assert_ok!(Contract::call(Origin::signed(ALICE), BOB, 0, 100_000, call::null())); + + let bob_contract = ContractInfoOf::::get(BOB).unwrap().get_alive().unwrap(); + assert_eq!(bob_contract.rent_allowance, 1_000 - rent - rent_2); + assert_eq!(bob_contract.deduct_block, 12); + assert_eq!(Balances::free_balance(BOB), 30_000 - rent - rent_2); + }); } #[test] @@ -981,32 +960,29 @@ fn claim_surcharge_malus() { fn claim_surcharge(blocks: u64, trigger_call: impl Fn() -> bool, removes: bool) { let (wasm, code_hash) = compile_module::(CODE_SET_RENT).unwrap(); - set_and_run_with_externalities( - &mut ExtBuilder::default().existential_deposit(50).build(), - || { - // Create - Balances::deposit_creating(&ALICE, 1_000_000); - assert_ok!(Contract::put_code(Origin::signed(ALICE), 100_000, wasm)); - assert_ok!(Contract::instantiate( - Origin::signed(ALICE), - 100, - 100_000, code_hash.into(), - ::Balance::from(1_000u32).encode() // rent allowance - )); + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + // Create + Balances::deposit_creating(&ALICE, 1_000_000); + assert_ok!(Contract::put_code(Origin::signed(ALICE), 100_000, wasm)); + assert_ok!(Contract::instantiate( + Origin::signed(ALICE), + 100, + 100_000, code_hash.into(), + ::Balance::from(1_000u32).encode() // rent allowance + )); - // Advance blocks - System::initialize(&blocks, &[0u8; 32].into(), &[0u8; 32].into(), &Default::default()); + // Advance blocks + System::initialize(&blocks, &[0u8; 32].into(), &[0u8; 32].into(), &Default::default()); - // Trigger rent through call - assert!(trigger_call()); + // Trigger rent through call + assert!(trigger_call()); - if removes { - assert!(ContractInfoOf::::get(BOB).unwrap().get_tombstone().is_some()); - } else { - assert!(ContractInfoOf::::get(BOB).unwrap().get_alive().is_some()); - } + if removes { + assert!(ContractInfoOf::::get(BOB).unwrap().get_tombstone().is_some()); + } else { + assert!(ContractInfoOf::::get(BOB).unwrap().get_alive().is_some()); } - ); + }); } /// Test for all kind of removals for the given trigger: @@ -1017,123 +993,114 @@ fn removals(trigger_call: impl Fn() -> bool) { let (wasm, code_hash) = compile_module::(CODE_SET_RENT).unwrap(); // Balance reached and superior to subsistence threshold - set_and_run_with_externalities( - &mut ExtBuilder::default().existential_deposit(50).build(), - || { - // Create - Balances::deposit_creating(&ALICE, 1_000_000); - assert_ok!(Contract::put_code(Origin::signed(ALICE), 100_000, wasm.clone())); - assert_ok!(Contract::instantiate( - Origin::signed(ALICE), - 100, - 100_000, code_hash.into(), - ::Balance::from(1_000u32).encode() // rent allowance - )); - - let subsistence_threshold = 50 /*existential_deposit*/ + 16 /*tombstone_deposit*/; - - // Trigger rent must have no effect - assert!(trigger_call()); - assert_eq!(ContractInfoOf::::get(BOB).unwrap().get_alive().unwrap().rent_allowance, 1_000); - assert_eq!(Balances::free_balance(&BOB), 100); - - // Advance blocks - System::initialize(&10, &[0u8; 32].into(), &[0u8; 32].into(), &Default::default()); - - // Trigger rent through call - assert!(trigger_call()); - assert!(ContractInfoOf::::get(BOB).unwrap().get_tombstone().is_some()); - assert_eq!(Balances::free_balance(&BOB), subsistence_threshold); - - // Advance blocks - System::initialize(&20, &[0u8; 32].into(), &[0u8; 32].into(), &Default::default()); - - // Trigger rent must have no effect - assert!(trigger_call()); - assert!(ContractInfoOf::::get(BOB).unwrap().get_tombstone().is_some()); - assert_eq!(Balances::free_balance(&BOB), subsistence_threshold); - } - ); + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + // Create + Balances::deposit_creating(&ALICE, 1_000_000); + assert_ok!(Contract::put_code(Origin::signed(ALICE), 100_000, wasm.clone())); + assert_ok!(Contract::instantiate( + Origin::signed(ALICE), + 100, + 100_000, code_hash.into(), + ::Balance::from(1_000u32).encode() // rent allowance + )); + + let subsistence_threshold = 50 /*existential_deposit*/ + 16 /*tombstone_deposit*/; + + // Trigger rent must have no effect + assert!(trigger_call()); + assert_eq!(ContractInfoOf::::get(BOB).unwrap().get_alive().unwrap().rent_allowance, 1_000); + assert_eq!(Balances::free_balance(&BOB), 100); + + // Advance blocks + System::initialize(&10, &[0u8; 32].into(), &[0u8; 32].into(), &Default::default()); + + // Trigger rent through call + assert!(trigger_call()); + assert!(ContractInfoOf::::get(BOB).unwrap().get_tombstone().is_some()); + assert_eq!(Balances::free_balance(&BOB), subsistence_threshold); + + // Advance blocks + System::initialize(&20, &[0u8; 32].into(), &[0u8; 32].into(), &Default::default()); + + // Trigger rent must have no effect + assert!(trigger_call()); + assert!(ContractInfoOf::::get(BOB).unwrap().get_tombstone().is_some()); + assert_eq!(Balances::free_balance(&BOB), subsistence_threshold); + }); // Allowance exceeded - set_and_run_with_externalities( - &mut ExtBuilder::default().existential_deposit(50).build(), - || { - // Create - Balances::deposit_creating(&ALICE, 1_000_000); - assert_ok!(Contract::put_code(Origin::signed(ALICE), 100_000, wasm.clone())); - assert_ok!(Contract::instantiate( - Origin::signed(ALICE), - 1_000, - 100_000, code_hash.into(), - ::Balance::from(100u32).encode() // rent allowance - )); - - // Trigger rent must have no effect - assert!(trigger_call()); - assert_eq!(ContractInfoOf::::get(BOB).unwrap().get_alive().unwrap().rent_allowance, 100); - assert_eq!(Balances::free_balance(&BOB), 1_000); - - // Advance blocks - System::initialize(&10, &[0u8; 32].into(), &[0u8; 32].into(), &Default::default()); - - // Trigger rent through call - assert!(trigger_call()); - assert!(ContractInfoOf::::get(BOB).unwrap().get_tombstone().is_some()); - // Balance should be initial balance - initial rent_allowance - assert_eq!(Balances::free_balance(&BOB), 900); - - // Advance blocks - System::initialize(&20, &[0u8; 32].into(), &[0u8; 32].into(), &Default::default()); - - // Trigger rent must have no effect - assert!(trigger_call()); - assert!(ContractInfoOf::::get(BOB).unwrap().get_tombstone().is_some()); - assert_eq!(Balances::free_balance(&BOB), 900); - } - ); + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + // Create + Balances::deposit_creating(&ALICE, 1_000_000); + assert_ok!(Contract::put_code(Origin::signed(ALICE), 100_000, wasm.clone())); + assert_ok!(Contract::instantiate( + Origin::signed(ALICE), + 1_000, + 100_000, code_hash.into(), + ::Balance::from(100u32).encode() // rent allowance + )); + + // Trigger rent must have no effect + assert!(trigger_call()); + assert_eq!(ContractInfoOf::::get(BOB).unwrap().get_alive().unwrap().rent_allowance, 100); + assert_eq!(Balances::free_balance(&BOB), 1_000); + + // Advance blocks + System::initialize(&10, &[0u8; 32].into(), &[0u8; 32].into(), &Default::default()); + + // Trigger rent through call + assert!(trigger_call()); + assert!(ContractInfoOf::::get(BOB).unwrap().get_tombstone().is_some()); + // Balance should be initial balance - initial rent_allowance + assert_eq!(Balances::free_balance(&BOB), 900); + + // Advance blocks + System::initialize(&20, &[0u8; 32].into(), &[0u8; 32].into(), &Default::default()); + + // Trigger rent must have no effect + assert!(trigger_call()); + assert!(ContractInfoOf::::get(BOB).unwrap().get_tombstone().is_some()); + assert_eq!(Balances::free_balance(&BOB), 900); + }); // Balance reached and inferior to subsistence threshold - set_and_run_with_externalities( - &mut ExtBuilder::default().existential_deposit(50).build(), - || { - // Create - Balances::deposit_creating(&ALICE, 1_000_000); - assert_ok!(Contract::put_code(Origin::signed(ALICE), 100_000, wasm.clone())); - assert_ok!(Contract::instantiate( - Origin::signed(ALICE), - 50+Balances::minimum_balance(), - 100_000, code_hash.into(), - ::Balance::from(1_000u32).encode() // rent allowance - )); - - // Trigger rent must have no effect - assert!(trigger_call()); - assert_eq!(ContractInfoOf::::get(BOB).unwrap().get_alive().unwrap().rent_allowance, 1_000); - assert_eq!(Balances::free_balance(&BOB), 50 + Balances::minimum_balance()); - - // Transfer funds - assert_ok!(Contract::call(Origin::signed(ALICE), BOB, 0, 100_000, call::transfer())); - assert_eq!(ContractInfoOf::::get(BOB).unwrap().get_alive().unwrap().rent_allowance, 1_000); - assert_eq!(Balances::free_balance(&BOB), Balances::minimum_balance()); - - // Advance blocks - System::initialize(&10, &[0u8; 32].into(), &[0u8; 32].into(), &Default::default()); - - // Trigger rent through call - assert!(trigger_call()); - assert!(ContractInfoOf::::get(BOB).is_none()); - assert_eq!(Balances::free_balance(&BOB), Balances::minimum_balance()); - - // Advance blocks - System::initialize(&20, &[0u8; 32].into(), &[0u8; 32].into(), &Default::default()); - - // Trigger rent must have no effect - assert!(trigger_call()); - assert!(ContractInfoOf::::get(BOB).is_none()); - assert_eq!(Balances::free_balance(&BOB), Balances::minimum_balance()); - } - ); + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + // Create + Balances::deposit_creating(&ALICE, 1_000_000); + assert_ok!(Contract::put_code(Origin::signed(ALICE), 100_000, wasm.clone())); + assert_ok!(Contract::instantiate( + Origin::signed(ALICE), + 50+Balances::minimum_balance(), + 100_000, code_hash.into(), + ::Balance::from(1_000u32).encode() // rent allowance + )); + + // Trigger rent must have no effect + assert!(trigger_call()); + assert_eq!(ContractInfoOf::::get(BOB).unwrap().get_alive().unwrap().rent_allowance, 1_000); + assert_eq!(Balances::free_balance(&BOB), 50 + Balances::minimum_balance()); + + // Transfer funds + assert_ok!(Contract::call(Origin::signed(ALICE), BOB, 0, 100_000, call::transfer())); + assert_eq!(ContractInfoOf::::get(BOB).unwrap().get_alive().unwrap().rent_allowance, 1_000); + assert_eq!(Balances::free_balance(&BOB), Balances::minimum_balance()); + + // Advance blocks + System::initialize(&10, &[0u8; 32].into(), &[0u8; 32].into(), &Default::default()); + + // Trigger rent through call + assert!(trigger_call()); + assert!(ContractInfoOf::::get(BOB).is_none()); + assert_eq!(Balances::free_balance(&BOB), Balances::minimum_balance()); + + // Advance blocks + System::initialize(&20, &[0u8; 32].into(), &[0u8; 32].into(), &Default::default()); + + // Trigger rent must have no effect + assert!(trigger_call()); + assert!(ContractInfoOf::::get(BOB).is_none()); + assert_eq!(Balances::free_balance(&BOB), Balances::minimum_balance()); + }); } #[test] @@ -1141,38 +1108,35 @@ fn call_removed_contract() { let (wasm, code_hash) = compile_module::(CODE_SET_RENT).unwrap(); // Balance reached and superior to subsistence threshold - set_and_run_with_externalities( - &mut ExtBuilder::default().existential_deposit(50).build(), - || { - // Create - Balances::deposit_creating(&ALICE, 1_000_000); - assert_ok!(Contract::put_code(Origin::signed(ALICE), 100_000, wasm.clone())); - assert_ok!(Contract::instantiate( - Origin::signed(ALICE), - 100, - 100_000, code_hash.into(), - ::Balance::from(1_000u32).encode() // rent allowance - )); - - // Calling contract should succeed. - assert_ok!(Contract::call(Origin::signed(ALICE), BOB, 0, 100_000, call::null())); - - // Advance blocks - System::initialize(&10, &[0u8; 32].into(), &[0u8; 32].into(), &Default::default()); - - // Calling contract should remove contract and fail. - assert_err!( - Contract::call(Origin::signed(ALICE), BOB, 0, 100_000, call::null()), - "contract has been evicted" - ); - - // Subsequent contract calls should also fail. - assert_err!( - Contract::call(Origin::signed(ALICE), BOB, 0, 100_000, call::null()), - "contract has been evicted" - ); - } - ) + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + // Create + Balances::deposit_creating(&ALICE, 1_000_000); + assert_ok!(Contract::put_code(Origin::signed(ALICE), 100_000, wasm.clone())); + assert_ok!(Contract::instantiate( + Origin::signed(ALICE), + 100, + 100_000, code_hash.into(), + ::Balance::from(1_000u32).encode() // rent allowance + )); + + // Calling contract should succeed. + assert_ok!(Contract::call(Origin::signed(ALICE), BOB, 0, 100_000, call::null())); + + // Advance blocks + System::initialize(&10, &[0u8; 32].into(), &[0u8; 32].into(), &Default::default()); + + // Calling contract should remove contract and fail. + assert_err!( + Contract::call(Origin::signed(ALICE), BOB, 0, 100_000, call::null()), + "contract has been evicted" + ); + + // Subsequent contract calls should also fail. + assert_err!( + Contract::call(Origin::signed(ALICE), BOB, 0, 100_000, call::null()), + "contract has been evicted" + ); + }) } const CODE_CHECK_DEFAULT_RENT_ALLOWANCE: &str = r#" @@ -1229,35 +1193,32 @@ const CODE_CHECK_DEFAULT_RENT_ALLOWANCE: &str = r#" fn default_rent_allowance_on_instantiate() { let (wasm, code_hash) = compile_module::(CODE_CHECK_DEFAULT_RENT_ALLOWANCE).unwrap(); - set_and_run_with_externalities( - &mut ExtBuilder::default().existential_deposit(50).build(), - || { - // Create - Balances::deposit_creating(&ALICE, 1_000_000); - assert_ok!(Contract::put_code(Origin::signed(ALICE), 100_000, wasm)); - assert_ok!(Contract::instantiate( - Origin::signed(ALICE), - 30_000, - 100_000, - code_hash.into(), - vec![], - )); - - // Check creation - let bob_contract = ContractInfoOf::::get(BOB).unwrap().get_alive().unwrap(); - assert_eq!(bob_contract.rent_allowance, >::max_value()); - - // Advance blocks - System::initialize(&5, &[0u8; 32].into(), &[0u8; 32].into(), &Default::default()); - - // Trigger rent through call - assert_ok!(Contract::call(Origin::signed(ALICE), BOB, 0, 100_000, call::null())); - - // Check contract is still alive - let bob_contract = ContractInfoOf::::get(BOB).unwrap().get_alive(); - assert!(bob_contract.is_some()) - } - ); + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + // Create + Balances::deposit_creating(&ALICE, 1_000_000); + assert_ok!(Contract::put_code(Origin::signed(ALICE), 100_000, wasm)); + assert_ok!(Contract::instantiate( + Origin::signed(ALICE), + 30_000, + 100_000, + code_hash.into(), + vec![], + )); + + // Check creation + let bob_contract = ContractInfoOf::::get(BOB).unwrap().get_alive().unwrap(); + assert_eq!(bob_contract.rent_allowance, >::max_value()); + + // Advance blocks + System::initialize(&5, &[0u8; 32].into(), &[0u8; 32].into(), &Default::default()); + + // Trigger rent through call + assert_ok!(Contract::call(Origin::signed(ALICE), BOB, 0, 100_000, call::null())); + + // Check contract is still alive + let bob_contract = ContractInfoOf::::get(BOB).unwrap().get_alive(); + assert!(bob_contract.is_some()) + }); } const CODE_RESTORATION: &str = r#" @@ -1346,122 +1307,119 @@ fn restoration(test_different_storage: bool, test_restore_to_with_dirty_storage: let (restoration_wasm, restoration_code_hash) = compile_module::(CODE_RESTORATION).unwrap(); - set_and_run_with_externalities( - &mut ExtBuilder::default().existential_deposit(50).build(), - || { - Balances::deposit_creating(&ALICE, 1_000_000); - assert_ok!(Contract::put_code(Origin::signed(ALICE), 100_000, restoration_wasm)); - assert_ok!(Contract::put_code(Origin::signed(ALICE), 100_000, set_rent_wasm)); - - // If you ever need to update the wasm source this test will fail - // and will show you the actual hash. - assert_eq!(System::events(), vec![ - EventRecord { - phase: Phase::ApplyExtrinsic(0), - event: MetaEvent::balances(balances::RawEvent::NewAccount(1, 1_000_000)), - topics: vec![], - }, - EventRecord { - phase: Phase::ApplyExtrinsic(0), - event: MetaEvent::contract(RawEvent::CodeStored(restoration_code_hash.into())), - topics: vec![], - }, - EventRecord { - phase: Phase::ApplyExtrinsic(0), - event: MetaEvent::contract(RawEvent::CodeStored(set_rent_code_hash.into())), - topics: vec![], - }, - ]); - - // Create an account with address `BOB` with code `CODE_SET_RENT`. - // The input parameter sets the rent allowance to 0. - assert_ok!(Contract::instantiate( + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + Balances::deposit_creating(&ALICE, 1_000_000); + assert_ok!(Contract::put_code(Origin::signed(ALICE), 100_000, restoration_wasm)); + assert_ok!(Contract::put_code(Origin::signed(ALICE), 100_000, set_rent_wasm)); + + // If you ever need to update the wasm source this test will fail + // and will show you the actual hash. + assert_eq!(System::events(), vec![ + EventRecord { + phase: Phase::ApplyExtrinsic(0), + event: MetaEvent::balances(balances::RawEvent::NewAccount(1, 1_000_000)), + topics: vec![], + }, + EventRecord { + phase: Phase::ApplyExtrinsic(0), + event: MetaEvent::contract(RawEvent::CodeStored(restoration_code_hash.into())), + topics: vec![], + }, + EventRecord { + phase: Phase::ApplyExtrinsic(0), + event: MetaEvent::contract(RawEvent::CodeStored(set_rent_code_hash.into())), + topics: vec![], + }, + ]); + + // Create an account with address `BOB` with code `CODE_SET_RENT`. + // The input parameter sets the rent allowance to 0. + assert_ok!(Contract::instantiate( + Origin::signed(ALICE), + 30_000, + 100_000, + set_rent_code_hash.into(), + ::Balance::from(0u32).encode() + )); + + // Check if `BOB` was created successfully and that the rent allowance is + // set to 0. + let bob_contract = ContractInfoOf::::get(BOB).unwrap().get_alive().unwrap(); + assert_eq!(bob_contract.rent_allowance, 0); + + if test_different_storage { + assert_ok!(Contract::call( Origin::signed(ALICE), - 30_000, - 100_000, - set_rent_code_hash.into(), - ::Balance::from(0u32).encode() - )); - - // Check if `BOB` was created successfully and that the rent allowance is - // set to 0. - let bob_contract = ContractInfoOf::::get(BOB).unwrap().get_alive().unwrap(); - assert_eq!(bob_contract.rent_allowance, 0); - - if test_different_storage { - assert_ok!(Contract::call( - Origin::signed(ALICE), - BOB, 0, 100_000, - call::set_storage_4_byte()) - ); - } - - // Advance 4 blocks, to the 5th. - System::initialize(&5, &[0u8; 32].into(), &[0u8; 32].into(), &Default::default()); - - // Call `BOB`, which makes it pay rent. Since the rent allowance is set to 0 - // we expect that it will get removed leaving tombstone. - assert_err!( - Contract::call(Origin::signed(ALICE), BOB, 0, 100_000, call::null()), - "contract has been evicted" + BOB, 0, 100_000, + call::set_storage_4_byte()) ); - assert!(ContractInfoOf::::get(BOB).unwrap().get_tombstone().is_some()); - - /// Create another account with the address `DJANGO` with `CODE_RESTORATION`. - /// - /// Note that we can't use `ALICE` for creating `DJANGO` so we create yet another - /// account `CHARLIE` and create `DJANGO` with it. - Balances::deposit_creating(&CHARLIE, 1_000_000); - assert_ok!(Contract::instantiate( - Origin::signed(CHARLIE), - 30_000, - 100_000, - restoration_code_hash.into(), - ::Balance::from(0u32).encode() - )); - - // Before performing a call to `DJANGO` save its original trie id. - let django_trie_id = ContractInfoOf::::get(DJANGO).unwrap() - .get_alive().unwrap().trie_id; + } - if !test_restore_to_with_dirty_storage { - // Advance 1 block, to the 6th. - System::initialize(&6, &[0u8; 32].into(), &[0u8; 32].into(), &Default::default()); - } + // Advance 4 blocks, to the 5th. + System::initialize(&5, &[0u8; 32].into(), &[0u8; 32].into(), &Default::default()); + + // Call `BOB`, which makes it pay rent. Since the rent allowance is set to 0 + // we expect that it will get removed leaving tombstone. + assert_err!( + Contract::call(Origin::signed(ALICE), BOB, 0, 100_000, call::null()), + "contract has been evicted" + ); + assert!(ContractInfoOf::::get(BOB).unwrap().get_tombstone().is_some()); + + /// Create another account with the address `DJANGO` with `CODE_RESTORATION`. + /// + /// Note that we can't use `ALICE` for creating `DJANGO` so we create yet another + /// account `CHARLIE` and create `DJANGO` with it. + Balances::deposit_creating(&CHARLIE, 1_000_000); + assert_ok!(Contract::instantiate( + Origin::signed(CHARLIE), + 30_000, + 100_000, + restoration_code_hash.into(), + ::Balance::from(0u32).encode() + )); + + // Before performing a call to `DJANGO` save its original trie id. + let django_trie_id = ContractInfoOf::::get(DJANGO).unwrap() + .get_alive().unwrap().trie_id; + + if !test_restore_to_with_dirty_storage { + // Advance 1 block, to the 6th. + System::initialize(&6, &[0u8; 32].into(), &[0u8; 32].into(), &Default::default()); + } - // Perform a call to `DJANGO`. This should either perform restoration successfully or - // fail depending on the test parameters. - assert_ok!(Contract::call( - Origin::signed(ALICE), - DJANGO, - 0, - 100_000, - vec![], - )); - - if test_different_storage || test_restore_to_with_dirty_storage { - // Parametrization of the test imply restoration failure. Check that `DJANGO` aka - // restoration contract is still in place and also that `BOB` doesn't exist. - assert!(ContractInfoOf::::get(BOB).unwrap().get_tombstone().is_some()); - let django_contract = ContractInfoOf::::get(DJANGO).unwrap() - .get_alive().unwrap(); - assert_eq!(django_contract.storage_size, 16); - assert_eq!(django_contract.trie_id, django_trie_id); - assert_eq!(django_contract.deduct_block, System::block_number()); - } else { - // Here we expect that the restoration is succeeded. Check that the restoration - // contract `DJANGO` ceased to exist and that `BOB` returned back. - println!("{:?}", ContractInfoOf::::get(BOB)); - let bob_contract = ContractInfoOf::::get(BOB).unwrap() - .get_alive().unwrap(); - assert_eq!(bob_contract.rent_allowance, 50); - assert_eq!(bob_contract.storage_size, 12); - assert_eq!(bob_contract.trie_id, django_trie_id); - assert_eq!(bob_contract.deduct_block, System::block_number()); - assert!(ContractInfoOf::::get(DJANGO).is_none()); - } + // Perform a call to `DJANGO`. This should either perform restoration successfully or + // fail depending on the test parameters. + assert_ok!(Contract::call( + Origin::signed(ALICE), + DJANGO, + 0, + 100_000, + vec![], + )); + + if test_different_storage || test_restore_to_with_dirty_storage { + // Parametrization of the test imply restoration failure. Check that `DJANGO` aka + // restoration contract is still in place and also that `BOB` doesn't exist. + assert!(ContractInfoOf::::get(BOB).unwrap().get_tombstone().is_some()); + let django_contract = ContractInfoOf::::get(DJANGO).unwrap() + .get_alive().unwrap(); + assert_eq!(django_contract.storage_size, 16); + assert_eq!(django_contract.trie_id, django_trie_id); + assert_eq!(django_contract.deduct_block, System::block_number()); + } else { + // Here we expect that the restoration is succeeded. Check that the restoration + // contract `DJANGO` ceased to exist and that `BOB` returned back. + println!("{:?}", ContractInfoOf::::get(BOB)); + let bob_contract = ContractInfoOf::::get(BOB).unwrap() + .get_alive().unwrap(); + assert_eq!(bob_contract.rent_allowance, 50); + assert_eq!(bob_contract.storage_size, 12); + assert_eq!(bob_contract.trie_id, django_trie_id); + assert_eq!(bob_contract.deduct_block, System::block_number()); + assert!(ContractInfoOf::::get(DJANGO).is_none()); } - ); + }); } const CODE_STORAGE_SIZE: &str = r#" @@ -1532,46 +1490,43 @@ const CODE_STORAGE_SIZE: &str = r#" fn storage_max_value_limit() { let (wasm, code_hash) = compile_module::(CODE_STORAGE_SIZE).unwrap(); - set_and_run_with_externalities( - &mut ExtBuilder::default().existential_deposit(50).build(), - || { - // Create - Balances::deposit_creating(&ALICE, 1_000_000); - assert_ok!(Contract::put_code(Origin::signed(ALICE), 100_000, wasm)); - assert_ok!(Contract::instantiate( - Origin::signed(ALICE), - 30_000, - 100_000, - code_hash.into(), - vec![], - )); - - // Check creation - let bob_contract = ContractInfoOf::::get(BOB).unwrap().get_alive().unwrap(); - assert_eq!(bob_contract.rent_allowance, >::max_value()); - - // Call contract with allowed storage value. - assert_ok!(Contract::call( + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + // Create + Balances::deposit_creating(&ALICE, 1_000_000); + assert_ok!(Contract::put_code(Origin::signed(ALICE), 100_000, wasm)); + assert_ok!(Contract::instantiate( + Origin::signed(ALICE), + 30_000, + 100_000, + code_hash.into(), + vec![], + )); + + // Check creation + let bob_contract = ContractInfoOf::::get(BOB).unwrap().get_alive().unwrap(); + assert_eq!(bob_contract.rent_allowance, >::max_value()); + + // Call contract with allowed storage value. + assert_ok!(Contract::call( + Origin::signed(ALICE), + BOB, + 0, + 100_000, + Encode::encode(&self::MaxValueSize::get()), + )); + + // Call contract with too large a storage value. + assert_err!( + Contract::call( Origin::signed(ALICE), BOB, 0, 100_000, - Encode::encode(&self::MaxValueSize::get()), - )); - - // Call contract with too large a storage value. - assert_err!( - Contract::call( - Origin::signed(ALICE), - BOB, - 0, - 100_000, - Encode::encode(&(self::MaxValueSize::get() + 1)), - ), - "during execution" - ); - } - ); + Encode::encode(&(self::MaxValueSize::get() + 1)), + ), + "during execution" + ); + }); } const CODE_RETURN_WITH_DATA: &str = r#" @@ -1899,33 +1854,30 @@ fn deploy_and_call_other_contract() { let (callee_wasm, callee_code_hash) = compile_module::(CODE_RETURN_WITH_DATA).unwrap(); let (caller_wasm, caller_code_hash) = compile_module::(CODE_CALLER_CONTRACT).unwrap(); - set_and_run_with_externalities( - &mut ExtBuilder::default().existential_deposit(50).build(), - || { - // Create - Balances::deposit_creating(&ALICE, 1_000_000); - assert_ok!(Contract::put_code(Origin::signed(ALICE), 100_000, callee_wasm)); - assert_ok!(Contract::put_code(Origin::signed(ALICE), 100_000, caller_wasm)); - - assert_ok!(Contract::instantiate( - Origin::signed(ALICE), - 100_000, - 100_000, - caller_code_hash.into(), - vec![], - )); - - // Call BOB contract, which attempts to instantiate and call the callee contract and - // makes various assertions on the results from those calls. - assert_ok!(Contract::call( - Origin::signed(ALICE), - BOB, - 0, - 200_000, - callee_code_hash.as_ref().to_vec(), - )); - } - ); + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + // Create + Balances::deposit_creating(&ALICE, 1_000_000); + assert_ok!(Contract::put_code(Origin::signed(ALICE), 100_000, callee_wasm)); + assert_ok!(Contract::put_code(Origin::signed(ALICE), 100_000, caller_wasm)); + + assert_ok!(Contract::instantiate( + Origin::signed(ALICE), + 100_000, + 100_000, + caller_code_hash.into(), + vec![], + )); + + // Call BOB contract, which attempts to instantiate and call the callee contract and + // makes various assertions on the results from those calls. + assert_ok!(Contract::call( + Origin::signed(ALICE), + BOB, + 0, + 200_000, + callee_code_hash.as_ref().to_vec(), + )); + }); } const CODE_SELF_DESTRUCT: &str = r#" @@ -2030,86 +1982,80 @@ const CODE_SELF_DESTRUCT: &str = r#" #[test] fn self_destruct_by_draining_balance() { let (wasm, code_hash) = compile_module::(CODE_SELF_DESTRUCT).unwrap(); - set_and_run_with_externalities( - &mut ExtBuilder::default().existential_deposit(50).build(), - || { - Balances::deposit_creating(&ALICE, 1_000_000); - assert_ok!(Contract::put_code(Origin::signed(ALICE), 100_000, wasm)); - - // Instantiate the BOB contract. - assert_ok!(Contract::instantiate( - Origin::signed(ALICE), - 100_000, - 100_000, - code_hash.into(), - vec![], - )); - - // Check that the BOB contract has been instantiated. - assert_matches!( - ContractInfoOf::::get(BOB), - Some(ContractInfo::Alive(_)) - ); - - // Call BOB with no input data, forcing it to self-destruct. - assert_ok!(Contract::call( - Origin::signed(ALICE), - BOB, - 0, - 100_000, - vec![], - )); - - // Check that BOB is now dead. - assert!(ContractInfoOf::::get(BOB).is_none()); - } - ); + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + Balances::deposit_creating(&ALICE, 1_000_000); + assert_ok!(Contract::put_code(Origin::signed(ALICE), 100_000, wasm)); + + // Instantiate the BOB contract. + assert_ok!(Contract::instantiate( + Origin::signed(ALICE), + 100_000, + 100_000, + code_hash.into(), + vec![], + )); + + // Check that the BOB contract has been instantiated. + assert_matches!( + ContractInfoOf::::get(BOB), + Some(ContractInfo::Alive(_)) + ); + + // Call BOB with no input data, forcing it to self-destruct. + assert_ok!(Contract::call( + Origin::signed(ALICE), + BOB, + 0, + 100_000, + vec![], + )); + + // Check that BOB is now dead. + assert!(ContractInfoOf::::get(BOB).is_none()); + }); } #[test] fn cannot_self_destruct_while_live() { let (wasm, code_hash) = compile_module::(CODE_SELF_DESTRUCT).unwrap(); - set_and_run_with_externalities( - &mut ExtBuilder::default().existential_deposit(50).build(), - || { - Balances::deposit_creating(&ALICE, 1_000_000); - assert_ok!(Contract::put_code(Origin::signed(ALICE), 100_000, wasm)); - - // Instantiate the BOB contract. - assert_ok!(Contract::instantiate( + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + Balances::deposit_creating(&ALICE, 1_000_000); + assert_ok!(Contract::put_code(Origin::signed(ALICE), 100_000, wasm)); + + // Instantiate the BOB contract. + assert_ok!(Contract::instantiate( + Origin::signed(ALICE), + 100_000, + 100_000, + code_hash.into(), + vec![], + )); + + // Check that the BOB contract has been instantiated. + assert_matches!( + ContractInfoOf::::get(BOB), + Some(ContractInfo::Alive(_)) + ); + + // Call BOB with input data, forcing it make a recursive call to itself to + // self-destruct, resulting in a trap. + assert_err!( + Contract::call( Origin::signed(ALICE), + BOB, + 0, 100_000, - 100_000, - code_hash.into(), - vec![], - )); - - // Check that the BOB contract has been instantiated. - assert_matches!( - ContractInfoOf::::get(BOB), - Some(ContractInfo::Alive(_)) - ); - - // Call BOB with input data, forcing it make a recursive call to itself to - // self-destruct, resulting in a trap. - assert_err!( - Contract::call( - Origin::signed(ALICE), - BOB, - 0, - 100_000, - vec![0], - ), - "during execution" - ); - - // Check that BOB is still alive. - assert_matches!( - ContractInfoOf::::get(BOB), - Some(ContractInfo::Alive(_)) - ); - } - ); + vec![0], + ), + "during execution" + ); + + // Check that BOB is still alive. + assert_matches!( + ContractInfoOf::::get(BOB), + Some(ContractInfo::Alive(_)) + ); + }); } const CODE_DESTROY_AND_TRANSFER: &str = r#" @@ -2271,43 +2217,40 @@ fn destroy_contract_and_transfer_funds() { let (callee_wasm, callee_code_hash) = compile_module::(CODE_SELF_DESTRUCT).unwrap(); let (caller_wasm, caller_code_hash) = compile_module::(CODE_DESTROY_AND_TRANSFER).unwrap(); - set_and_run_with_externalities( - &mut ExtBuilder::default().existential_deposit(50).build(), - || { - // Create - Balances::deposit_creating(&ALICE, 1_000_000); - assert_ok!(Contract::put_code(Origin::signed(ALICE), 100_000, callee_wasm)); - assert_ok!(Contract::put_code(Origin::signed(ALICE), 100_000, caller_wasm)); - - // This deploys the BOB contract, which in turn deploys the CHARLIE contract during - // construction. - assert_ok!(Contract::instantiate( - Origin::signed(ALICE), - 200_000, - 100_000, - caller_code_hash.into(), - callee_code_hash.as_ref().to_vec(), - )); - - // Check that the CHARLIE contract has been instantiated. - assert_matches!( - ContractInfoOf::::get(CHARLIE), - Some(ContractInfo::Alive(_)) - ); - - // Call BOB, which calls CHARLIE, forcing CHARLIE to self-destruct. - assert_ok!(Contract::call( - Origin::signed(ALICE), - BOB, - 0, - 100_000, - CHARLIE.encode(), - )); - - // Check that CHARLIE has moved on to the great beyond (ie. died). - assert!(ContractInfoOf::::get(CHARLIE).is_none()); - } - ); + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + // Create + Balances::deposit_creating(&ALICE, 1_000_000); + assert_ok!(Contract::put_code(Origin::signed(ALICE), 100_000, callee_wasm)); + assert_ok!(Contract::put_code(Origin::signed(ALICE), 100_000, caller_wasm)); + + // This deploys the BOB contract, which in turn deploys the CHARLIE contract during + // construction. + assert_ok!(Contract::instantiate( + Origin::signed(ALICE), + 200_000, + 100_000, + caller_code_hash.into(), + callee_code_hash.as_ref().to_vec(), + )); + + // Check that the CHARLIE contract has been instantiated. + assert_matches!( + ContractInfoOf::::get(CHARLIE), + Some(ContractInfo::Alive(_)) + ); + + // Call BOB, which calls CHARLIE, forcing CHARLIE to self-destruct. + assert_ok!(Contract::call( + Origin::signed(ALICE), + BOB, + 0, + 100_000, + CHARLIE.encode(), + )); + + // Check that CHARLIE has moved on to the great beyond (ie. died). + assert!(ContractInfoOf::::get(CHARLIE).is_none()); + }); } const CODE_SELF_DESTRUCTING_CONSTRUCTOR: &str = r#" @@ -2370,43 +2313,37 @@ const CODE_SELF_DESTRUCTING_CONSTRUCTOR: &str = r#" #[test] fn cannot_self_destruct_in_constructor() { let (wasm, code_hash) = compile_module::(CODE_SELF_DESTRUCTING_CONSTRUCTOR).unwrap(); - set_and_run_with_externalities( - &mut ExtBuilder::default().existential_deposit(50).build(), - || { - Balances::deposit_creating(&ALICE, 1_000_000); - assert_ok!(Contract::put_code(Origin::signed(ALICE), 100_000, wasm)); - - // Fail to instantiate the BOB contract since its final balance is below existential - // deposit. - assert_err!( - Contract::instantiate( - Origin::signed(ALICE), - 100_000, - 100_000, - code_hash.into(), - vec![], - ), - "insufficient remaining balance" - ); - } - ); + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + Balances::deposit_creating(&ALICE, 1_000_000); + assert_ok!(Contract::put_code(Origin::signed(ALICE), 100_000, wasm)); + + // Fail to instantiate the BOB contract since its final balance is below existential + // deposit. + assert_err!( + Contract::instantiate( + Origin::signed(ALICE), + 100_000, + 100_000, + code_hash.into(), + vec![], + ), + "insufficient remaining balance" + ); + }); } #[test] fn check_block_gas_limit_works() { - set_and_run_with_externalities( - &mut ExtBuilder::default().block_gas_limit(50).build(), - || { - let info = DispatchInfo { weight: 100, class: DispatchClass::Normal }; - let check = CheckBlockGasLimit::(Default::default()); - let call: Call = crate::Call::put_code(1000, vec![]).into(); + ExtBuilder::default().block_gas_limit(50).build().execute_with(|| { + let info = DispatchInfo { weight: 100, class: DispatchClass::Normal }; + let check = CheckBlockGasLimit::(Default::default()); + let call: Call = crate::Call::put_code(1000, vec![]).into(); - assert_eq!( - check.validate(&0, &call, info, 0), InvalidTransaction::ExhaustsResources.into(), - ); + assert_eq!( + check.validate(&0, &call, info, 0), InvalidTransaction::ExhaustsResources.into(), + ); - let call: Call = crate::Call::update_schedule(Default::default()).into(); - assert_eq!(check.validate(&0, &call, info, 0), Ok(Default::default())); - } - ); + let call: Call = crate::Call::update_schedule(Default::default()).into(); + assert_eq!(check.validate(&0, &call, info, 0), Ok(Default::default())); + }); } diff --git a/srml/democracy/src/lib.rs b/srml/democracy/src/lib.rs index 477e6818c9..2af301df1c 100644 --- a/srml/democracy/src/lib.rs +++ b/srml/democracy/src/lib.rs @@ -976,10 +976,7 @@ mod tests { traits::Contains }; use primitives::H256; - use sr_primitives::{ - set_and_run_with_externalities, traits::{BlakeTwo256, IdentityLookup, Bounded}, - testing::Header, Perbill, - }; + use sr_primitives::{traits::{BlakeTwo256, IdentityLookup, Bounded}, testing::Header, Perbill}; use balances::BalanceLock; use system::EnsureSignedBy; @@ -1101,7 +1098,7 @@ mod tests { #[test] fn params_should_work() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { assert_eq!(Democracy::referendum_count(), 0); assert_eq!(Balances::free_balance(&42), 0); assert_eq!(Balances::total_issuance(), 210); @@ -1133,7 +1130,7 @@ mod tests { #[test] fn external_and_public_interleaving_works() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { System::set_block_number(0); assert_ok!(Democracy::external_propose( Origin::signed(2), @@ -1246,7 +1243,7 @@ mod tests { #[test] fn emergency_cancel_should_work() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { System::set_block_number(0); let r = Democracy::inject_referendum( 2, @@ -1275,7 +1272,7 @@ mod tests { #[test] fn veto_external_works() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { System::set_block_number(0); assert_ok!(Democracy::external_propose( Origin::signed(2), @@ -1335,7 +1332,7 @@ mod tests { #[test] fn external_referendum_works() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { System::set_block_number(0); assert_noop!(Democracy::external_propose( Origin::signed(1), @@ -1364,7 +1361,7 @@ mod tests { #[test] fn external_majority_referendum_works() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { System::set_block_number(0); assert_noop!(Democracy::external_propose_majority( Origin::signed(1), @@ -1389,7 +1386,7 @@ mod tests { #[test] fn external_default_referendum_works() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { System::set_block_number(0); assert_noop!(Democracy::external_propose_default( Origin::signed(3), @@ -1414,7 +1411,7 @@ mod tests { #[test] fn fast_track_referendum_works() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { System::set_block_number(0); let h = BlakeTwo256::hash_of(&set_balance_proposal(2)); assert_noop!(Democracy::fast_track(Origin::signed(5), h, 3, 2), "no proposal made"); @@ -1438,7 +1435,7 @@ mod tests { #[test] fn fast_track_referendum_fails_when_no_simple_majority() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { System::set_block_number(0); let h = BlakeTwo256::hash_of(&set_balance_proposal(2)); assert_ok!(Democracy::external_propose( @@ -1454,7 +1451,7 @@ mod tests { #[test] fn locked_for_should_work() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { System::set_block_number(1); assert_ok!(propose_set_balance(1, 2, 2)); assert_ok!(propose_set_balance(1, 4, 4)); @@ -1467,7 +1464,7 @@ mod tests { #[test] fn single_proposal_should_work() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { System::set_block_number(0); assert_ok!(propose_set_balance(1, 2, 1)); assert!(Democracy::referendum_info(0).is_none()); @@ -1514,7 +1511,7 @@ mod tests { #[test] fn cancel_queued_should_work() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { System::set_block_number(0); assert_ok!(propose_set_balance(1, 2, 1)); @@ -1538,7 +1535,7 @@ mod tests { #[test] fn proxy_should_work() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { assert_eq!(Democracy::proxy(10), None); assert_ok!(Democracy::set_proxy(Origin::signed(1), 10)); assert_eq!(Democracy::proxy(10), Some(1)); @@ -1568,7 +1565,7 @@ mod tests { #[test] fn single_proposal_should_work_with_proxy() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { System::set_block_number(0); assert_ok!(propose_set_balance(1, 2, 1)); @@ -1588,7 +1585,7 @@ mod tests { #[test] fn single_proposal_should_work_with_delegation() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { System::set_block_number(0); assert_ok!(propose_set_balance(1, 2, 1)); @@ -1613,7 +1610,7 @@ mod tests { #[test] fn single_proposal_should_work_with_cyclic_delegation() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { System::set_block_number(0); assert_ok!(propose_set_balance(1, 2, 1)); @@ -1640,7 +1637,7 @@ mod tests { #[test] /// If transactor already voted, delegated vote is overwriten. fn single_proposal_should_work_with_vote_and_delegation() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { System::set_block_number(0); assert_ok!(propose_set_balance(1, 2, 1)); @@ -1666,7 +1663,7 @@ mod tests { #[test] fn single_proposal_should_work_with_undelegation() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { System::set_block_number(0); assert_ok!(propose_set_balance(1, 2, 1)); @@ -1695,7 +1692,7 @@ mod tests { #[test] /// If transactor voted, delegated vote is overwriten. fn single_proposal_should_work_with_delegation_and_vote() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { System::set_block_number(0); assert_ok!(propose_set_balance(1, 2, 1)); @@ -1726,7 +1723,7 @@ mod tests { #[test] fn deposit_for_proposals_should_be_taken() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { System::set_block_number(1); assert_ok!(propose_set_balance(1, 2, 5)); assert_ok!(Democracy::second(Origin::signed(2), 0)); @@ -1741,7 +1738,7 @@ mod tests { #[test] fn deposit_for_proposals_should_be_returned() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { System::set_block_number(1); assert_ok!(propose_set_balance(1, 2, 5)); assert_ok!(Democracy::second(Origin::signed(2), 0)); @@ -1757,7 +1754,7 @@ mod tests { #[test] fn proposal_with_deposit_below_minimum_should_not_work() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { System::set_block_number(1); assert_noop!(propose_set_balance(1, 2, 0), "value too low"); }); @@ -1765,7 +1762,7 @@ mod tests { #[test] fn poor_proposer_should_not_work() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { System::set_block_number(1); assert_noop!(propose_set_balance(1, 2, 11), "proposer\'s balance too low"); }); @@ -1773,7 +1770,7 @@ mod tests { #[test] fn poor_seconder_should_not_work() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { System::set_block_number(1); assert_ok!(propose_set_balance(2, 2, 11)); assert_noop!(Democracy::second(Origin::signed(1), 0), "seconder\'s balance too low"); @@ -1782,7 +1779,7 @@ mod tests { #[test] fn runners_up_should_come_after() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { System::set_block_number(0); assert_ok!(propose_set_balance(1, 2, 2)); assert_ok!(propose_set_balance(1, 4, 4)); @@ -1798,7 +1795,7 @@ mod tests { #[test] fn simple_passing_should_work() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { System::set_block_number(1); let r = Democracy::inject_referendum( 1, @@ -1821,7 +1818,7 @@ mod tests { #[test] fn cancel_referendum_should_work() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { System::set_block_number(1); let r = Democracy::inject_referendum( 1, @@ -1841,7 +1838,7 @@ mod tests { #[test] fn simple_failing_should_work() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { System::set_block_number(1); let r = Democracy::inject_referendum( 1, @@ -1864,7 +1861,7 @@ mod tests { #[test] fn controversial_voting_should_work() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { System::set_block_number(1); let r = Democracy::inject_referendum( 1, @@ -1890,7 +1887,7 @@ mod tests { #[test] fn delayed_enactment_should_work() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { System::set_block_number(1); let r = Democracy::inject_referendum( 1, @@ -1918,7 +1915,7 @@ mod tests { #[test] fn controversial_low_turnout_voting_should_work() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { System::set_block_number(1); let r = Democracy::inject_referendum( 1, @@ -1940,7 +1937,7 @@ mod tests { #[test] fn passing_low_turnout_voting_should_work() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { assert_eq!(Balances::free_balance(&42), 0); assert_eq!(Balances::total_issuance(), 210); @@ -1966,7 +1963,7 @@ mod tests { #[test] fn lock_voting_should_work() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { System::set_block_number(0); let r = Democracy::inject_referendum( 1, @@ -2026,7 +2023,7 @@ mod tests { #[test] fn lock_voting_should_work_with_delegation() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { System::set_block_number(1); let r = Democracy::inject_referendum( 1, diff --git a/srml/elections-phragmen/src/lib.rs b/srml/elections-phragmen/src/lib.rs index 1405536267..6ec79a537c 100644 --- a/srml/elections-phragmen/src/lib.rs +++ b/srml/elections-phragmen/src/lib.rs @@ -594,7 +594,7 @@ mod tests { use primitives::H256; use sr_primitives::{ Perbill, testing::Header, BuildStorage, - traits::{BlakeTwo256, IdentityLookup, Block as BlockT}, set_and_run_with_externalities + traits::{BlakeTwo256, IdentityLookup, Block as BlockT}, }; use crate as elections; @@ -770,7 +770,7 @@ mod tests { #[test] fn params_should_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { System::set_block_number(1); assert_eq!(Elections::desired_members(), 2); assert_eq!(Elections::term_duration(), 5); @@ -790,7 +790,7 @@ mod tests { #[test] fn simple_candidate_submission_should_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { assert_eq!(Elections::candidates(), Vec::::new()); assert!(Elections::is_candidate(&1).is_err()); assert!(Elections::is_candidate(&2).is_err()); @@ -817,7 +817,7 @@ mod tests { #[test] fn simple_candidate_submission_with_no_votes_should_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { assert_eq!(Elections::candidates(), Vec::::new()); assert_ok!(Elections::submit_candidacy(Origin::signed(1))); @@ -844,7 +844,7 @@ mod tests { #[test] fn dupe_candidate_submission_should_not_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { assert_eq!(Elections::candidates(), Vec::::new()); assert_ok!(Elections::submit_candidacy(Origin::signed(1))); assert_eq!(Elections::candidates(), vec![1]); @@ -858,7 +858,7 @@ mod tests { #[test] fn member_candidacy_submission_should_not_work() { // critically important to make sure that outgoing candidates and losers are not mixed up. - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { assert_ok!(Elections::submit_candidacy(Origin::signed(5))); assert_ok!(Elections::vote(Origin::signed(2), vec![5], 20)); @@ -878,7 +878,7 @@ mod tests { #[test] fn poor_candidate_submission_should_not_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { assert_eq!(Elections::candidates(), Vec::::new()); assert_noop!( Elections::submit_candidacy(Origin::signed(7)), @@ -889,7 +889,7 @@ mod tests { #[test] fn simple_voting_should_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { assert_eq!(Elections::candidates(), Vec::::new()); assert_eq!(balances(&2), (20, 0)); @@ -903,7 +903,7 @@ mod tests { #[test] fn can_vote_with_custom_stake() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { assert_eq!(Elections::candidates(), Vec::::new()); assert_eq!(balances(&2), (20, 0)); @@ -917,7 +917,7 @@ mod tests { #[test] fn can_update_votes_and_stake() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { assert_eq!(balances(&2), (20, 0)); assert_ok!(Elections::submit_candidacy(Origin::signed(5))); @@ -938,7 +938,7 @@ mod tests { #[test] fn cannot_vote_for_no_candidate() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { assert_noop!( Elections::vote(Origin::signed(2), vec![], 20), "cannot vote when no candidates or members exist" @@ -949,7 +949,7 @@ mod tests { #[test] fn can_vote_for_old_members_even_when_no_new_candidates() { // let allowed_votes = candidates_count as usize + Self::members().len() - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { assert_ok!(Elections::submit_candidacy(Origin::signed(5))); assert_ok!(Elections::submit_candidacy(Origin::signed(4))); @@ -967,7 +967,7 @@ mod tests { #[test] fn cannot_vote_for_more_than_candidates() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { assert_ok!(Elections::submit_candidacy(Origin::signed(5))); assert_ok!(Elections::submit_candidacy(Origin::signed(4))); @@ -980,7 +980,7 @@ mod tests { #[test] fn cannot_vote_for_less_than_ed() { - set_and_run_with_externalities(&mut ExtBuilder::default().voter_bond(8).build(), || { + ExtBuilder::default().voter_bond(8).build().execute_with(|| { assert_ok!(Elections::submit_candidacy(Origin::signed(5))); assert_ok!(Elections::submit_candidacy(Origin::signed(4))); @@ -993,7 +993,7 @@ mod tests { #[test] fn can_vote_for_more_than_total_balance_but_moot() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { assert_ok!(Elections::submit_candidacy(Origin::signed(5))); assert_ok!(Elections::submit_candidacy(Origin::signed(4))); @@ -1006,7 +1006,7 @@ mod tests { #[test] fn remove_voter_should_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().voter_bond(8).build(), || { + ExtBuilder::default().voter_bond(8).build().execute_with(|| { assert_ok!(Elections::submit_candidacy(Origin::signed(5))); assert_ok!(Elections::vote(Origin::signed(2), vec![5], 20)); @@ -1031,14 +1031,14 @@ mod tests { #[test] fn non_voter_remove_should_not_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { assert_noop!(Elections::remove_voter(Origin::signed(3)), "must be a voter"); }); } #[test] fn dupe_remove_should_fail() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { assert_ok!(Elections::submit_candidacy(Origin::signed(5))); assert_ok!(Elections::vote(Origin::signed(2), vec![5], 20)); @@ -1051,7 +1051,7 @@ mod tests { #[test] fn removed_voter_should_not_be_counted() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { assert_ok!(Elections::submit_candidacy(Origin::signed(5))); assert_ok!(Elections::submit_candidacy(Origin::signed(4))); assert_ok!(Elections::submit_candidacy(Origin::signed(3))); @@ -1071,7 +1071,7 @@ mod tests { #[test] fn reporter_must_be_voter() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { assert_noop!( Elections::report_defunct_voter(Origin::signed(1), 2), "reporter must be a voter", @@ -1081,7 +1081,7 @@ mod tests { #[test] fn can_detect_defunct_voter() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { assert_ok!(Elections::submit_candidacy(Origin::signed(5))); assert_ok!(Elections::submit_candidacy(Origin::signed(4))); @@ -1116,7 +1116,7 @@ mod tests { #[test] fn report_voter_should_work_and_earn_reward() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { assert_ok!(Elections::submit_candidacy(Origin::signed(5))); assert_ok!(Elections::submit_candidacy(Origin::signed(4))); @@ -1148,8 +1148,7 @@ mod tests { #[test] fn report_voter_should_slash_when_bad_report() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { assert_ok!(Elections::submit_candidacy(Origin::signed(5))); assert_ok!(Elections::submit_candidacy(Origin::signed(4))); @@ -1174,13 +1173,12 @@ mod tests { assert_eq!(balances(&4), (35, 5)); assert_eq!(balances(&5), (45, 3)); }); - }); } #[test] fn simple_voting_rounds_should_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { assert_ok!(Elections::submit_candidacy(Origin::signed(5))); assert_ok!(Elections::submit_candidacy(Origin::signed(4))); assert_ok!(Elections::submit_candidacy(Origin::signed(3))); @@ -1215,7 +1213,7 @@ mod tests { #[test] fn defunct_voter_will_be_counted() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { assert_ok!(Elections::submit_candidacy(Origin::signed(5))); // This guy's vote is pointless for this round. @@ -1243,7 +1241,7 @@ mod tests { #[test] fn only_desired_seats_are_chosen() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { assert_ok!(Elections::submit_candidacy(Origin::signed(5))); assert_ok!(Elections::submit_candidacy(Origin::signed(4))); assert_ok!(Elections::submit_candidacy(Origin::signed(3))); @@ -1264,7 +1262,7 @@ mod tests { #[test] fn phragmen_should_not_self_vote() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { assert_ok!(Elections::submit_candidacy(Origin::signed(5))); assert_ok!(Elections::submit_candidacy(Origin::signed(4))); @@ -1279,7 +1277,7 @@ mod tests { #[test] fn runners_up_should_be_kept() { - set_and_run_with_externalities(&mut ExtBuilder::default().desired_runners_up(2).build(), || { + ExtBuilder::default().desired_runners_up(2).build().execute_with(|| { assert_ok!(Elections::submit_candidacy(Origin::signed(5))); assert_ok!(Elections::submit_candidacy(Origin::signed(4))); assert_ok!(Elections::submit_candidacy(Origin::signed(3))); @@ -1306,7 +1304,7 @@ mod tests { #[test] fn runners_up_should_be_next_candidates() { - set_and_run_with_externalities(&mut ExtBuilder::default().desired_runners_up(2).build(), || { + ExtBuilder::default().desired_runners_up(2).build().execute_with(|| { assert_ok!(Elections::submit_candidacy(Origin::signed(5))); assert_ok!(Elections::submit_candidacy(Origin::signed(4))); assert_ok!(Elections::submit_candidacy(Origin::signed(3))); @@ -1333,7 +1331,7 @@ mod tests { #[test] fn runners_up_lose_bond_once_outgoing() { - set_and_run_with_externalities(&mut ExtBuilder::default().desired_runners_up(1).build(), || { + ExtBuilder::default().desired_runners_up(1).build().execute_with(|| { assert_ok!(Elections::submit_candidacy(Origin::signed(5))); assert_ok!(Elections::submit_candidacy(Origin::signed(4))); assert_ok!(Elections::submit_candidacy(Origin::signed(2))); @@ -1364,7 +1362,7 @@ mod tests { #[test] fn current_members_are_always_implicitly_next_candidate() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { assert_ok!(Elections::submit_candidacy(Origin::signed(5))); assert_ok!(Elections::submit_candidacy(Origin::signed(4))); @@ -1400,7 +1398,7 @@ mod tests { fn election_state_is_uninterrupted() { // what I mean by uninterrupted: // given no input or stimulants the same members are re-elected. - set_and_run_with_externalities(&mut ExtBuilder::default().desired_runners_up(2).build(), || { + ExtBuilder::default().desired_runners_up(2).build().execute_with(|| { assert_ok!(Elections::submit_candidacy(Origin::signed(5))); assert_ok!(Elections::submit_candidacy(Origin::signed(4))); assert_ok!(Elections::submit_candidacy(Origin::signed(3))); @@ -1433,7 +1431,7 @@ mod tests { #[test] fn remove_members_triggers_election() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { assert_ok!(Elections::submit_candidacy(Origin::signed(5))); assert_ok!(Elections::submit_candidacy(Origin::signed(4))); @@ -1459,7 +1457,7 @@ mod tests { #[test] fn seats_should_be_released_when_no_vote() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { assert_ok!(Elections::submit_candidacy(Origin::signed(5))); assert_ok!(Elections::submit_candidacy(Origin::signed(4))); assert_ok!(Elections::submit_candidacy(Origin::signed(3))); @@ -1493,7 +1491,7 @@ mod tests { #[test] fn outgoing_will_get_the_bond_back() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { assert_eq!(balances(&5), (50, 0)); assert_ok!(Elections::submit_candidacy(Origin::signed(5))); @@ -1519,7 +1517,7 @@ mod tests { #[test] fn losers_will_lose_the_bond() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { assert_ok!(Elections::submit_candidacy(Origin::signed(5))); assert_ok!(Elections::submit_candidacy(Origin::signed(3))); @@ -1542,7 +1540,7 @@ mod tests { #[test] fn incoming_outgoing_are_reported() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { assert_ok!(Elections::submit_candidacy(Origin::signed(4))); assert_ok!(Elections::submit_candidacy(Origin::signed(5))); @@ -1587,7 +1585,7 @@ mod tests { #[test] fn invalid_votes_are_moot() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { assert_ok!(Elections::submit_candidacy(Origin::signed(4))); assert_ok!(Elections::submit_candidacy(Origin::signed(3))); diff --git a/srml/elections/src/mock.rs b/srml/elections/src/mock.rs index b9e548e1ed..d48a0fd3fd 100644 --- a/srml/elections/src/mock.rs +++ b/srml/elections/src/mock.rs @@ -25,8 +25,7 @@ use support::{ }; use primitives::H256; use sr_primitives::{ - Perbill, BuildStorage, set_and_run_with_externalities, testing::Header, - traits::{BlakeTwo256, IdentityLookup, Block as BlockT}, + Perbill, BuildStorage, testing::Header, traits::{BlakeTwo256, IdentityLookup, Block as BlockT}, }; use crate as elections; @@ -283,7 +282,7 @@ pub(crate) fn locks(who: &u64) -> Vec { pub(crate) fn new_test_ext_with_candidate_holes() -> runtime_io::TestExternalities { let mut t = ExtBuilder::default().build(); - set_and_run_with_externalities(&mut t, || { + t.execute_with(|| { >::put(vec![0, 0, 1]); elections::CandidateCount::put(1); >::insert(1, (0, 2)); diff --git a/srml/elections/src/tests.rs b/srml/elections/src/tests.rs index 149e534a2f..c9bb054ab2 100644 --- a/srml/elections/src/tests.rs +++ b/srml/elections/src/tests.rs @@ -22,11 +22,10 @@ use crate::mock::*; use crate::*; use support::{assert_ok, assert_err, assert_noop}; -use sr_primitives::set_and_run_with_externalities; #[test] fn params_should_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { System::set_block_number(1); assert_eq!(Elections::next_vote_from(1), 4); assert_eq!(Elections::next_vote_from(4), 4); @@ -53,7 +52,7 @@ fn params_should_work() { #[test] fn chunking_bool_to_flag_should_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { assert_eq!(Elections::bool_to_flag(vec![]), vec![]); assert_eq!(Elections::bool_to_flag(vec![false]), vec![0]); assert_eq!(Elections::bool_to_flag(vec![true]), vec![1]); @@ -98,7 +97,7 @@ fn chunking_bool_to_flag_should_work() { #[test] fn chunking_voter_set_growth_should_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); // create 65. 64 (set0) + 1 (set1) @@ -122,7 +121,7 @@ fn chunking_voter_set_growth_should_work() { #[test] fn chunking_voter_set_reclaim_should_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); (1..=129).for_each(|i| vote(i, 0)); @@ -159,7 +158,7 @@ fn chunking_voter_set_reclaim_should_work() { #[test] fn chunking_approvals_set_growth_should_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { // create candidates and voters. (1..=250).for_each(|i| create_candidate(i, (i-1) as u32)); (1..=250).for_each(|i| vote(i, i as usize)); @@ -221,7 +220,7 @@ fn chunking_approvals_set_growth_should_work() { #[test] fn chunking_cell_status_works() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); (1..=63).for_each(|i| vote(i, 0)); @@ -240,7 +239,7 @@ fn chunking_cell_status_works() { #[test] fn chunking_voter_index_does_not_take_holes_into_account() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); // create 65. 64 (set0) + 1 (set1) @@ -265,7 +264,7 @@ fn chunking_voter_index_does_not_take_holes_into_account() { #[test] fn chunking_approval_storage_should_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); assert_ok!(Elections::submit_candidacy(Origin::signed(3), 1)); @@ -285,7 +284,7 @@ fn chunking_approval_storage_should_work() { #[test] fn voting_initial_set_approvals_ignores_voter_index() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); // Last argument is essentially irrelevant. You might get or miss a tip. @@ -299,7 +298,7 @@ fn voting_initial_set_approvals_ignores_voter_index() { } #[test] fn voting_bad_approval_index_slashes_voters_and_bond_reduces_stake() { - set_and_run_with_externalities(&mut ExtBuilder::default().voting_fee(5).voter_bond(2).build(), || { + ExtBuilder::default().voting_fee(5).voter_bond(2).build().execute_with(|| { assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); (1..=63).for_each(|i| vote(i, 0)); @@ -329,7 +328,7 @@ fn voting_bad_approval_index_slashes_voters_and_bond_reduces_stake() { #[test] fn voting_subsequent_set_approvals_checks_voter_index() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); assert_ok!(Elections::set_approvals(Origin::signed(3), vec![], 0, 0, 30)); @@ -353,7 +352,7 @@ fn voting_subsequent_set_approvals_checks_voter_index() { #[test] fn voting_cannot_lock_less_than_limit() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); assert_noop!( @@ -366,7 +365,7 @@ fn voting_cannot_lock_less_than_limit() { #[test] fn voting_locking_more_than_total_balance_is_moot() { - set_and_run_with_externalities(&mut ExtBuilder::default().voter_bond(2).build(), || { + ExtBuilder::default().voter_bond(2).build().execute_with(|| { assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); assert_eq!(balances(&3), (30, 0)); @@ -382,7 +381,7 @@ fn voting_locking_more_than_total_balance_is_moot() { #[test] fn voting_locking_stake_and_reserving_bond_works() { - set_and_run_with_externalities(&mut ExtBuilder::default().voter_bond(2).build(), || { + ExtBuilder::default().voter_bond(2).build().execute_with(|| { assert_ok!(Elections::submit_candidacy(Origin::signed(5), 0)); assert_eq!(balances(&2), (20, 0)); @@ -408,7 +407,7 @@ fn voting_locking_stake_and_reserving_bond_works() { #[test] fn voting_without_any_candidate_count_should_not_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { System::set_block_number(1); assert_eq!(Elections::candidates().len(), 0); @@ -422,7 +421,7 @@ fn voting_without_any_candidate_count_should_not_work() { #[test] fn voting_setting_an_approval_vote_count_more_than_candidate_count_should_not_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { System::set_block_number(1); assert_ok!(Elections::submit_candidacy(Origin::signed(5), 0)); @@ -437,7 +436,7 @@ fn voting_setting_an_approval_vote_count_more_than_candidate_count_should_not_wo #[test] fn voting_resubmitting_approvals_should_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { System::set_block_number(1); assert_ok!(Elections::submit_candidacy(Origin::signed(5), 0)); @@ -456,7 +455,7 @@ fn voting_resubmitting_approvals_should_work() { #[test] fn voting_retracting_voter_should_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { System::set_block_number(1); assert_ok!(Elections::submit_candidacy(Origin::signed(5), 0)); @@ -501,7 +500,7 @@ fn voting_retracting_voter_should_work() { #[test] fn voting_invalid_retraction_index_should_not_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { System::set_block_number(1); assert_ok!(Elections::submit_candidacy(Origin::signed(3), 0)); @@ -514,7 +513,7 @@ fn voting_invalid_retraction_index_should_not_work() { #[test] fn voting_overflow_retraction_index_should_not_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { System::set_block_number(1); assert_ok!(Elections::submit_candidacy(Origin::signed(3), 0)); @@ -525,7 +524,7 @@ fn voting_overflow_retraction_index_should_not_work() { #[test] fn voting_non_voter_retraction_should_not_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { System::set_block_number(1); assert_ok!(Elections::submit_candidacy(Origin::signed(3), 0)); @@ -536,7 +535,7 @@ fn voting_non_voter_retraction_should_not_work() { #[test] fn retracting_inactive_voter_should_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { System::set_block_number(4); assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); assert_ok!(Elections::set_approvals(Origin::signed(2), vec![true], 0, 0, 20)); @@ -570,7 +569,7 @@ fn retracting_inactive_voter_should_work() { #[test] fn retracting_inactive_voter_with_other_candidates_in_slots_should_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().voter_bond(2).build(), || { + ExtBuilder::default().voter_bond(2).build().execute_with(|| { System::set_block_number(4); assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); assert_ok!(Elections::set_approvals(Origin::signed(2), vec![true], 0, 0, 20)); @@ -605,7 +604,7 @@ fn retracting_inactive_voter_with_other_candidates_in_slots_should_work() { #[test] fn retracting_inactive_voter_with_bad_reporter_index_should_not_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { System::set_block_number(4); assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); assert_ok!(Elections::set_approvals(Origin::signed(2), vec![true], 0, 0, 20)); @@ -634,7 +633,7 @@ fn retracting_inactive_voter_with_bad_reporter_index_should_not_work() { #[test] fn retracting_inactive_voter_with_bad_target_index_should_not_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { System::set_block_number(4); assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); assert_ok!(Elections::set_approvals(Origin::signed(2), vec![true], 0, 0, 20)); @@ -663,7 +662,7 @@ fn retracting_inactive_voter_with_bad_target_index_should_not_work() { #[test] fn retracting_active_voter_should_slash_reporter() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { System::set_block_number(4); assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); assert_ok!(Elections::submit_candidacy(Origin::signed(3), 1)); @@ -711,7 +710,7 @@ fn retracting_active_voter_should_slash_reporter() { #[test] fn retracting_inactive_voter_by_nonvoter_should_not_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { System::set_block_number(4); assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); assert_ok!(Elections::set_approvals(Origin::signed(2), vec![true], 0, 0, 20)); @@ -740,7 +739,7 @@ fn retracting_inactive_voter_by_nonvoter_should_not_work() { #[test] fn candidacy_simple_candidate_submission_should_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { System::set_block_number(1); assert_eq!(Elections::candidates(), Vec::::new()); assert_eq!(Elections::candidate_reg_info(1), None); @@ -768,7 +767,7 @@ fn candidacy_simple_candidate_submission_should_work() { fn candidacy_submission_using_free_slot_should_work() { let mut t = new_test_ext_with_candidate_holes(); - set_and_run_with_externalities(&mut t, || { + t.execute_with(|| { System::set_block_number(1); assert_eq!(Elections::candidates(), vec![0, 0, 1]); @@ -784,7 +783,7 @@ fn candidacy_submission_using_free_slot_should_work() { fn candidacy_submission_using_alternative_free_slot_should_work() { let mut t = new_test_ext_with_candidate_holes(); - set_and_run_with_externalities(&mut t, || { + t.execute_with(|| { System::set_block_number(1); assert_eq!(Elections::candidates(), vec![0, 0, 1]); @@ -800,7 +799,7 @@ fn candidacy_submission_using_alternative_free_slot_should_work() { fn candidacy_submission_not_using_free_slot_should_not_work() { let mut t = new_test_ext_with_candidate_holes(); - set_and_run_with_externalities(&mut t, || { + t.execute_with(|| { System::set_block_number(1); assert_noop!( Elections::submit_candidacy(Origin::signed(4), 3), @@ -811,7 +810,7 @@ fn candidacy_submission_not_using_free_slot_should_not_work() { #[test] fn candidacy_bad_candidate_slot_submission_should_not_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { System::set_block_number(1); assert_eq!(Elections::candidates(), Vec::::new()); assert_noop!( @@ -823,7 +822,7 @@ fn candidacy_bad_candidate_slot_submission_should_not_work() { #[test] fn candidacy_non_free_candidate_slot_submission_should_not_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { System::set_block_number(1); assert_eq!(Elections::candidates(), Vec::::new()); assert_ok!(Elections::submit_candidacy(Origin::signed(1), 0)); @@ -837,7 +836,7 @@ fn candidacy_non_free_candidate_slot_submission_should_not_work() { #[test] fn candidacy_dupe_candidate_submission_should_not_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { System::set_block_number(1); assert_eq!(Elections::candidates(), Vec::::new()); assert_ok!(Elections::submit_candidacy(Origin::signed(1), 0)); @@ -851,7 +850,7 @@ fn candidacy_dupe_candidate_submission_should_not_work() { #[test] fn candidacy_poor_candidate_submission_should_not_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { System::set_block_number(1); assert_eq!(Elections::candidates(), Vec::::new()); assert_noop!( @@ -863,7 +862,7 @@ fn candidacy_poor_candidate_submission_should_not_work() { #[test] fn election_voting_should_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { System::set_block_number(1); assert_ok!(Elections::submit_candidacy(Origin::signed(5), 0)); @@ -892,7 +891,7 @@ fn election_voting_should_work() { #[test] fn election_proxy_voting_should_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { System::set_block_number(1); assert_ok!(Elections::submit_candidacy(Origin::signed(5), 0)); @@ -933,7 +932,7 @@ fn election_proxy_voting_should_work() { #[test] fn election_simple_tally_should_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { System::set_block_number(4); assert!(!Elections::presentation_active()); @@ -972,7 +971,7 @@ fn election_simple_tally_should_work() { #[test] fn election_seats_should_be_released() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { System::set_block_number(4); assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); assert_ok!(Elections::submit_candidacy(Origin::signed(5), 1)); @@ -1006,7 +1005,7 @@ fn election_seats_should_be_released() { #[test] fn election_presentations_with_zero_staked_deposit_should_not_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { System::set_block_number(4); assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); assert_ok!(Elections::set_approvals(Origin::signed(2), vec![true], 0, 0, 20)); @@ -1022,7 +1021,7 @@ fn election_presentations_with_zero_staked_deposit_should_not_work() { #[test] fn election_double_presentations_should_be_punished() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { assert!(Balances::can_slash(&4, 10)); System::set_block_number(4); @@ -1045,7 +1044,7 @@ fn election_double_presentations_should_be_punished() { #[test] fn election_presenting_for_double_election_should_not_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { System::set_block_number(4); assert_eq!(Elections::submit_candidacy(Origin::signed(2), 0), Ok(())); assert_ok!(Elections::set_approvals(Origin::signed(2), vec![true], 0, 0, 20)); @@ -1072,7 +1071,7 @@ fn election_presenting_for_double_election_should_not_work() { #[test] fn election_presenting_loser_should_not_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { System::set_block_number(4); assert_ok!(Elections::submit_candidacy(Origin::signed(1), 0)); assert_ok!(Elections::set_approvals(Origin::signed(6), vec![true], 0, 0, 60)); @@ -1105,7 +1104,7 @@ fn election_presenting_loser_should_not_work() { #[test] fn election_presenting_loser_first_should_not_matter() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { System::set_block_number(4); assert_ok!(Elections::submit_candidacy(Origin::signed(1), 0)); assert_ok!(Elections::set_approvals(Origin::signed(6), vec![true], 0, 0, 60)); @@ -1137,7 +1136,7 @@ fn election_presenting_loser_first_should_not_matter() { #[test] fn election_present_outside_of_presentation_period_should_not_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { System::set_block_number(4); assert!(!Elections::presentation_active()); assert_noop!( @@ -1149,7 +1148,7 @@ fn election_present_outside_of_presentation_period_should_not_work() { #[test] fn election_present_with_invalid_vote_index_should_not_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { System::set_block_number(4); assert_ok!(Elections::submit_candidacy(Origin::signed(2), 0)); assert_ok!(Elections::submit_candidacy(Origin::signed(5), 1)); @@ -1165,33 +1164,35 @@ fn election_present_with_invalid_vote_index_should_not_work() { #[test] fn election_present_when_presenter_is_poor_should_not_work() { let test_present = |p| { - set_and_run_with_externalities(&mut ExtBuilder::default() + ExtBuilder::default() .voting_fee(5) .voter_bond(2) .bad_presentation_punishment(p) - .build(), - || { - System::set_block_number(4); - let _ = Balances::make_free_balance_be(&1, 15); - assert!(!Elections::presentation_active()); - - assert_ok!(Elections::submit_candidacy(Origin::signed(1), 0)); // -3 - assert_eq!(Balances::free_balance(&1), 12); - assert_ok!(Elections::set_approvals(Origin::signed(1), vec![true], 0, 0, 15)); // -2 -5 - assert_ok!(Elections::end_block(System::block_number())); - - System::set_block_number(6); - assert_eq!(Balances::free_balance(&1), 5); - assert_eq!(Balances::reserved_balance(&1), 5); - if p > 5 { - assert_noop!(Elections::present_winner( - Origin::signed(1), 1, 10, 0), - "presenter must have sufficient slashable funds" - ); - } else { - assert_ok!(Elections::present_winner(Origin::signed(1), 1, 10, 0)); - } - }); + .build() + .execute_with(|| { + System::set_block_number(4); + let _ = Balances::make_free_balance_be(&1, 15); + assert!(!Elections::presentation_active()); + + // -3 + assert_ok!(Elections::submit_candidacy(Origin::signed(1), 0)); + assert_eq!(Balances::free_balance(&1), 12); + // -2 -5 + assert_ok!(Elections::set_approvals(Origin::signed(1), vec![true], 0, 0, 15)); + assert_ok!(Elections::end_block(System::block_number())); + + System::set_block_number(6); + assert_eq!(Balances::free_balance(&1), 5); + assert_eq!(Balances::reserved_balance(&1), 5); + if p > 5 { + assert_noop!(Elections::present_winner( + Origin::signed(1), 1, 10, 0), + "presenter must have sufficient slashable funds" + ); + } else { + assert_ok!(Elections::present_winner(Origin::signed(1), 1, 10, 0)); + } + }); }; test_present(4); test_present(6); @@ -1199,7 +1200,7 @@ fn election_present_when_presenter_is_poor_should_not_work() { #[test] fn election_invalid_present_tally_should_slash() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { System::set_block_number(4); assert!(!Elections::presentation_active()); assert_eq!(Balances::total_balance(&4), 40); @@ -1219,7 +1220,7 @@ fn election_invalid_present_tally_should_slash() { #[test] fn election_runners_up_should_be_kept() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { System::set_block_number(4); assert!(!Elections::presentation_active()); @@ -1280,7 +1281,7 @@ fn election_runners_up_should_be_kept() { #[test] fn election_second_tally_should_use_runners_up() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { System::set_block_number(4); assert_ok!(Elections::submit_candidacy(Origin::signed(1), 0)); assert_ok!(Elections::set_approvals(Origin::signed(6), vec![true], 0, 0, 60)); @@ -1335,7 +1336,7 @@ fn election_second_tally_should_use_runners_up() { #[test] fn election_loser_candidates_bond_gets_slashed() { - set_and_run_with_externalities(&mut ExtBuilder::default().desired_seats(1).build(), || { + ExtBuilder::default().desired_seats(1).build().execute_with(|| { System::set_block_number(4); assert!(!Elections::presentation_active()); @@ -1374,7 +1375,7 @@ fn election_loser_candidates_bond_gets_slashed() { #[test] fn pot_accumulating_weight_and_decaying_should_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().balance_factor(10).build(), || { + ExtBuilder::default().balance_factor(10).build().execute_with(|| { System::set_block_number(4); assert!(!Elections::presentation_active()); @@ -1502,7 +1503,7 @@ fn pot_accumulating_weight_and_decaying_should_work() { #[test] fn pot_winning_resets_accumulated_pot() { - set_and_run_with_externalities(&mut ExtBuilder::default().balance_factor(10).build(), || { + ExtBuilder::default().balance_factor(10).build().execute_with(|| { System::set_block_number(4); assert!(!Elections::presentation_active()); @@ -1564,72 +1565,88 @@ fn pot_winning_resets_accumulated_pot() { #[test] fn pot_resubmitting_approvals_stores_pot() { - set_and_run_with_externalities(&mut ExtBuilder::default() + ExtBuilder::default() .voter_bond(0) .voting_fee(0) .balance_factor(10) - .build(), - || { System::set_block_number(4); - assert!(!Elections::presentation_active()); + .build() + .execute_with(|| { + System::set_block_number(4); + assert!(!Elections::presentation_active()); - assert_ok!(Elections::submit_candidacy(Origin::signed(6), 0)); - assert_ok!(Elections::submit_candidacy(Origin::signed(5), 1)); - assert_ok!(Elections::submit_candidacy(Origin::signed(1), 2)); + assert_ok!(Elections::submit_candidacy(Origin::signed(6), 0)); + assert_ok!(Elections::submit_candidacy(Origin::signed(5), 1)); + assert_ok!(Elections::submit_candidacy(Origin::signed(1), 2)); - assert_ok!(Elections::set_approvals(Origin::signed(6), vec![true, false, false], 0, 0, 600)); - assert_ok!(Elections::set_approvals(Origin::signed(5), vec![false, true, false], 0, 1, 500)); - assert_ok!(Elections::set_approvals(Origin::signed(1), vec![false, false, true], 0, 2, 100)); + assert_ok!( + Elections::set_approvals(Origin::signed(6), vec![true, false, false], 0, 0, 600), + ); + assert_ok!( + Elections::set_approvals(Origin::signed(5), vec![false, true, false], 0, 1, 500), + ); + assert_ok!( + Elections::set_approvals(Origin::signed(1), vec![false, false, true], 0, 2, 100), + ); - assert_ok!(Elections::end_block(System::block_number())); + assert_ok!(Elections::end_block(System::block_number())); - System::set_block_number(6); - assert!(Elections::presentation_active()); + System::set_block_number(6); + assert!(Elections::presentation_active()); - assert_eq!(Elections::present_winner(Origin::signed(6), 6, 600, 0), Ok(())); - assert_eq!(Elections::present_winner(Origin::signed(5), 5, 500, 0), Ok(())); - assert_eq!(Elections::present_winner(Origin::signed(1), 1, 100, 0), Ok(())); - assert_eq!(Elections::leaderboard(), Some(vec![(0, 0), (100, 1), (500, 5), (600, 6)])); - assert_ok!(Elections::end_block(System::block_number())); + assert_eq!(Elections::present_winner(Origin::signed(6), 6, 600, 0), Ok(())); + assert_eq!(Elections::present_winner(Origin::signed(5), 5, 500, 0), Ok(())); + assert_eq!(Elections::present_winner(Origin::signed(1), 1, 100, 0), Ok(())); + assert_eq!(Elections::leaderboard(), Some(vec![(0, 0), (100, 1), (500, 5), (600, 6)])); + assert_ok!(Elections::end_block(System::block_number())); - assert_eq!(Elections::members(), vec![(6, 11), (5, 11)]); + assert_eq!(Elections::members(), vec![(6, 11), (5, 11)]); - System::set_block_number(12); - assert_ok!(Elections::retract_voter(Origin::signed(6), 0)); - assert_ok!(Elections::retract_voter(Origin::signed(5), 1)); - assert_ok!(Elections::submit_candidacy(Origin::signed(6), 0)); - assert_ok!(Elections::submit_candidacy(Origin::signed(5), 1)); - assert_ok!(Elections::set_approvals(Origin::signed(6), vec![true, false, false], 1, 0, 600)); - assert_ok!(Elections::set_approvals(Origin::signed(5), vec![false, true, false], 1, 1, 500)); - // give 1 some new high balance - let _ = Balances::make_free_balance_be(&1, 997); - assert_ok!(Elections::set_approvals(Origin::signed(1), vec![false, false, true], 1, 2, 1000)); - assert_eq!(Elections::voter_info(1).unwrap(), - VoterInfo { - stake: 1000, // 997 + 3 which is candidacy bond. - pot: Elections::get_offset(100, 1), - last_active: 1, - last_win: 1, - } - ); - assert_ok!(Elections::end_block(System::block_number())); + System::set_block_number(12); + assert_ok!(Elections::retract_voter(Origin::signed(6), 0)); + assert_ok!(Elections::retract_voter(Origin::signed(5), 1)); + assert_ok!(Elections::submit_candidacy(Origin::signed(6), 0)); + assert_ok!(Elections::submit_candidacy(Origin::signed(5), 1)); + assert_ok!( + Elections::set_approvals(Origin::signed(6), vec![true, false, false], 1, 0, 600), + ); + assert_ok!( + Elections::set_approvals(Origin::signed(5), vec![false, true, false], 1, 1, 500), + ); + // give 1 some new high balance + let _ = Balances::make_free_balance_be(&1, 997); + assert_ok!( + Elections::set_approvals(Origin::signed(1), vec![false, false, true], 1, 2, 1000), + ); + assert_eq!(Elections::voter_info(1).unwrap(), + VoterInfo { + stake: 1000, // 997 + 3 which is candidacy bond. + pot: Elections::get_offset(100, 1), + last_active: 1, + last_win: 1, + } + ); + assert_ok!(Elections::end_block(System::block_number())); - assert_eq!(Elections::members(), vec![(6, 11), (5, 11)]); + assert_eq!(Elections::members(), vec![(6, 11), (5, 11)]); - System::set_block_number(14); - assert!(Elections::presentation_active()); - assert_eq!(Elections::present_winner(Origin::signed(6), 6, 600, 1), Ok(())); - assert_eq!(Elections::present_winner(Origin::signed(5), 5, 500, 1), Ok(())); - assert_eq!(Elections::present_winner(Origin::signed(1), 1, 1000 + 96 /* pot */, 1), Ok(())); - assert_eq!(Elections::leaderboard(), Some(vec![(0, 0), (500, 5), (600, 6), (1096, 1)])); - assert_ok!(Elections::end_block(System::block_number())); + System::set_block_number(14); + assert!(Elections::presentation_active()); + assert_eq!(Elections::present_winner(Origin::signed(6), 6, 600, 1), Ok(())); + assert_eq!(Elections::present_winner(Origin::signed(5), 5, 500, 1), Ok(())); + assert_eq!( + Elections::present_winner(Origin::signed(1), 1, 1000 + 96 /* pot */, 1), + Ok(()), + ); + assert_eq!(Elections::leaderboard(), Some(vec![(0, 0), (500, 5), (600, 6), (1096, 1)])); + assert_ok!(Elections::end_block(System::block_number())); - assert_eq!(Elections::members(), vec![(1, 19), (6, 19)]); - }) + assert_eq!(Elections::members(), vec![(1, 19), (6, 19)]); + }) } #[test] fn pot_get_offset_should_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { assert_eq!(Elections::get_offset(100, 0), 0); assert_eq!(Elections::get_offset(100, 1), 96); assert_eq!(Elections::get_offset(100, 2), 96 + 93); @@ -1653,7 +1670,7 @@ fn pot_get_offset_should_work() { #[test] fn pot_get_offset_with_zero_decay() { - set_and_run_with_externalities(&mut ExtBuilder::default().decay_ratio(0).build(), || { + ExtBuilder::default().decay_ratio(0).build().execute_with(|| { assert_eq!(Elections::get_offset(100, 0), 0); assert_eq!(Elections::get_offset(100, 1), 0); assert_eq!(Elections::get_offset(100, 2), 0); diff --git a/srml/example/src/lib.rs b/srml/example/src/lib.rs index 08adf9efa7..0766468efa 100644 --- a/srml/example/src/lib.rs +++ b/srml/example/src/lib.rs @@ -638,7 +638,7 @@ mod tests { // The testing primitives are very useful for avoiding having to work with signatures // or public keys. `u64` is used as the `AccountId` and no `Signature`s are required. use sr_primitives::{ - set_and_run_with_externalities, Perbill, weights::GetDispatchInfo, testing::Header, + Perbill, weights::GetDispatchInfo, testing::Header, traits::{BlakeTwo256, OnInitialize, OnFinalize, IdentityLookup}, }; @@ -719,7 +719,7 @@ mod tests { #[test] fn it_works_for_optional_value() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { // Check that GenesisBuilder works properly. assert_eq!(Example::dummy(), Some(42)); @@ -740,7 +740,7 @@ mod tests { #[test] fn it_works_for_default_value() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { assert_eq!(Example::foo(), 24); assert_ok!(Example::accumulate_foo(Origin::signed(1), 1)); assert_eq!(Example::foo(), 25); @@ -749,7 +749,7 @@ mod tests { #[test] fn signed_ext_watch_dummy_works() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { let call = >::set_dummy(10); let info = DispatchInfo::default(); diff --git a/srml/executive/src/lib.rs b/srml/executive/src/lib.rs index f1509f1760..23c645f6ef 100644 --- a/srml/executive/src/lib.rs +++ b/srml/executive/src/lib.rs @@ -298,7 +298,6 @@ mod tests { generic::Era, Perbill, DispatchError, weights::Weight, testing::{Digest, Header, Block}, traits::{Bounded, Header as HeaderT, BlakeTwo256, IdentityLookup, ConvertInto}, transaction_validity::{InvalidTransaction, UnknownTransaction}, ApplyError, - set_and_run_with_externalities, }; use support::{ impl_outer_event, impl_outer_origin, parameter_types, impl_outer_dispatch, @@ -420,7 +419,7 @@ mod tests { let xt = sr_primitives::testing::TestXt(sign_extra(1, 0, 0), Call::Balances(BalancesCall::transfer(2, 69))); let weight = xt.get_dispatch_info().weight as u64; let mut t = runtime_io::TestExternalities::new(t); - set_and_run_with_externalities(&mut t, || { + t.execute_with(|| { Executive::initialize_block(&Header::new( 1, H256::default(), @@ -446,7 +445,7 @@ mod tests { #[test] fn block_import_works() { - set_and_run_with_externalities(&mut new_test_ext(1), || { + new_test_ext(1).execute_with(|| { Executive::execute_block(Block { header: Header { parent_hash: [69u8; 32].into(), @@ -463,7 +462,7 @@ mod tests { #[test] #[should_panic] fn block_import_of_bad_state_root_fails() { - set_and_run_with_externalities(&mut new_test_ext(1), || { + new_test_ext(1).execute_with(|| { Executive::execute_block(Block { header: Header { parent_hash: [69u8; 32].into(), @@ -480,7 +479,7 @@ mod tests { #[test] #[should_panic] fn block_import_of_bad_extrinsic_root_fails() { - set_and_run_with_externalities(&mut new_test_ext(1), || { + new_test_ext(1).execute_with(|| { Executive::execute_block(Block { header: Header { parent_hash: [69u8; 32].into(), @@ -499,7 +498,7 @@ mod tests { let mut t = new_test_ext(1); // bad nonce check! let xt = sr_primitives::testing::TestXt(sign_extra(1, 30, 0), Call::Balances(BalancesCall::transfer(33, 69))); - set_and_run_with_externalities(&mut t, || { + t.execute_with(|| { Executive::initialize_block(&Header::new( 1, H256::default(), @@ -521,7 +520,7 @@ mod tests { let encoded_len = encoded.len() as Weight; let limit = AvailableBlockRatio::get() * MaximumBlockWeight::get(); let num_to_exhaust_block = limit / encoded_len; - set_and_run_with_externalities(&mut t, || { + t.execute_with(|| { Executive::initialize_block(&Header::new( 1, H256::default(), @@ -557,7 +556,7 @@ mod tests { let x2 = sr_primitives::testing::TestXt(sign_extra(1, 2, 0), Call::Balances(BalancesCall::transfer(33, 0))); let len = xt.clone().encode().len() as u32; let mut t = new_test_ext(1); - set_and_run_with_externalities(&mut t, || { + t.execute_with(|| { assert_eq!(>::all_extrinsics_weight(), 0); assert_eq!(>::all_extrinsics_weight(), 0); @@ -581,7 +580,7 @@ mod tests { let xt = sr_primitives::testing::TestXt(None, Call::Balances(BalancesCall::set_balance(33, 69, 69))); let mut t = new_test_ext(1); - set_and_run_with_externalities(&mut t, || { + t.execute_with(|| { assert_eq!(Executive::validate_transaction(xt.clone()), Ok(Default::default())); assert_eq!( Executive::apply_extrinsic(xt), @@ -599,7 +598,7 @@ mod tests { let id: LockIdentifier = *b"0 "; let execute_with_lock = |lock: WithdrawReasons| { let mut t = new_test_ext(1); - set_and_run_with_externalities(&mut t, || { + t.execute_with(|| { as LockableCurrency>::set_lock( id, &1, diff --git a/srml/finality-tracker/src/lib.rs b/srml/finality-tracker/src/lib.rs index f00762fcdf..ba893c42d0 100644 --- a/srml/finality-tracker/src/lib.rs +++ b/srml/finality-tracker/src/lib.rs @@ -250,7 +250,7 @@ mod tests { use runtime_io::TestExternalities; use primitives::H256; use sr_primitives::{ - set_and_run_with_externalities, testing::Header, Perbill, + testing::Header, Perbill, traits::{BlakeTwo256, IdentityLookup, OnFinalize, Header as HeaderT}, }; use support::{assert_ok, impl_outer_origin, parameter_types}; @@ -322,7 +322,7 @@ mod tests { #[test] fn median_works() { let t = system::GenesisConfig::default().build_storage::().unwrap(); - set_and_run_with_externalities(&mut TestExternalities::new(t), || { + TestExternalities::new(t).execute_with(|| { FinalityTracker::update_hint(Some(500)); assert_eq!(FinalityTracker::median(), 250); assert!(NOTIFICATIONS.with(|n| n.borrow().is_empty())); @@ -332,7 +332,7 @@ mod tests { #[test] fn notifies_when_stalled() { let t = system::GenesisConfig::default().build_storage::().unwrap(); - set_and_run_with_externalities(&mut TestExternalities::new(t), || { + TestExternalities::new(t).execute_with(|| { let mut parent_hash = System::parent_hash(); for i in 2..106 { System::initialize(&i, &parent_hash, &Default::default(), &Default::default()); @@ -351,7 +351,7 @@ mod tests { #[test] fn recent_notifications_prevent_stalling() { let t = system::GenesisConfig::default().build_storage::().unwrap(); - set_and_run_with_externalities(&mut TestExternalities::new(t), || { + TestExternalities::new(t).execute_with(|| { let mut parent_hash = System::parent_hash(); for i in 2..106 { System::initialize(&i, &parent_hash, &Default::default(), &Default::default()); diff --git a/srml/generic-asset/src/tests.rs b/srml/generic-asset/src/tests.rs index 90e5775828..165936d021 100644 --- a/srml/generic-asset/src/tests.rs +++ b/srml/generic-asset/src/tests.rs @@ -22,14 +22,13 @@ use super::*; use crate::mock::{new_test_ext, ExtBuilder, GenericAsset, Origin, System, Test, TestEvent}; -use sr_primitives::set_and_run_with_externalities; use support::{assert_noop, assert_ok}; #[test] fn issuing_asset_units_to_issuer_should_work() { let balance = 100; - set_and_run_with_externalities(&mut ExtBuilder::default().free_balance((16000, 1, 100)).build(), || { + ExtBuilder::default().free_balance((16000, 1, 100)).build().execute_with(|| { let default_permission = PermissionLatest { update: Owner::Address(1), mint: Owner::Address(1), @@ -51,61 +50,55 @@ fn issuing_asset_units_to_issuer_should_work() { #[test] fn issuing_with_next_asset_id_overflow_should_not_work() { - set_and_run_with_externalities( - &mut ExtBuilder::default().free_balance((16000, 1, 100000)).build(), - || { - NextAssetId::::put(u32::max_value()); - let default_permission = PermissionLatest { - update: Owner::Address(1), - mint: Owner::Address(1), - burn: Owner::Address(1), - }; - assert_noop!( - GenericAsset::create( - Origin::signed(1), - AssetOptions { - initial_issuance: 1, - permissions: default_permission - } - ), - "No new assets id available." - ); - assert_eq!(GenericAsset::next_asset_id(), u32::max_value()); - }, - ); + ExtBuilder::default().free_balance((16000, 1, 100000)).build().execute_with(|| { + NextAssetId::::put(u32::max_value()); + let default_permission = PermissionLatest { + update: Owner::Address(1), + mint: Owner::Address(1), + burn: Owner::Address(1), + }; + assert_noop!( + GenericAsset::create( + Origin::signed(1), + AssetOptions { + initial_issuance: 1, + permissions: default_permission + } + ), + "No new assets id available." + ); + assert_eq!(GenericAsset::next_asset_id(), u32::max_value()); + }); } #[test] fn querying_total_supply_should_work() { let asset_id = 1000; - set_and_run_with_externalities( - &mut ExtBuilder::default().free_balance((16000, 1, 100000)).build(), - || { - let default_permission = PermissionLatest { - update: Owner::Address(1), - mint: Owner::Address(1), - burn: Owner::Address(1), - }; - assert_ok!(GenericAsset::create( - Origin::signed(1), - AssetOptions { - initial_issuance: 100, - permissions: default_permission - } - )); - assert_eq!(GenericAsset::free_balance(&asset_id, &1), 100); - assert_ok!(GenericAsset::transfer(Origin::signed(1), asset_id, 2, 50)); - assert_eq!(GenericAsset::free_balance(&asset_id, &1), 50); - assert_eq!(GenericAsset::free_balance(&asset_id, &2), 50); - assert_ok!(GenericAsset::transfer(Origin::signed(2), asset_id, 3, 31)); - assert_eq!(GenericAsset::free_balance(&asset_id, &1), 50); - assert_eq!(GenericAsset::free_balance(&asset_id, &2), 19); - assert_eq!(GenericAsset::free_balance(&asset_id, &3), 31); - assert_ok!(GenericAsset::transfer(Origin::signed(1), asset_id, 1, 1)); - assert_eq!(GenericAsset::free_balance(&asset_id, &1), 50); - }, - ); + ExtBuilder::default().free_balance((16000, 1, 100000)).build().execute_with(|| { + let default_permission = PermissionLatest { + update: Owner::Address(1), + mint: Owner::Address(1), + burn: Owner::Address(1), + }; + assert_ok!(GenericAsset::create( + Origin::signed(1), + AssetOptions { + initial_issuance: 100, + permissions: default_permission + } + )); + assert_eq!(GenericAsset::free_balance(&asset_id, &1), 100); + assert_ok!(GenericAsset::transfer(Origin::signed(1), asset_id, 2, 50)); + assert_eq!(GenericAsset::free_balance(&asset_id, &1), 50); + assert_eq!(GenericAsset::free_balance(&asset_id, &2), 50); + assert_ok!(GenericAsset::transfer(Origin::signed(2), asset_id, 3, 31)); + assert_eq!(GenericAsset::free_balance(&asset_id, &1), 50); + assert_eq!(GenericAsset::free_balance(&asset_id, &2), 19); + assert_eq!(GenericAsset::free_balance(&asset_id, &3), 31); + assert_ok!(GenericAsset::transfer(Origin::signed(1), asset_id, 1, 1)); + assert_eq!(GenericAsset::free_balance(&asset_id, &1), 50); + }); } // Given @@ -127,27 +120,24 @@ fn querying_total_supply_should_work() { fn transferring_amount_should_work() { let asset_id = 1000; let free_balance = 100; - set_and_run_with_externalities( - &mut ExtBuilder::default().free_balance((16000, 1, 100000)).build(), - || { - let default_permission = PermissionLatest { - update: Owner::Address(1), - mint: Owner::Address(1), - burn: Owner::Address(1), - }; - assert_ok!(GenericAsset::create( - Origin::signed(1), - AssetOptions { - initial_issuance: free_balance, - permissions: default_permission - } - )); - assert_eq!(GenericAsset::free_balance(&asset_id, &1), free_balance); - assert_ok!(GenericAsset::transfer(Origin::signed(1), asset_id, 2, 40)); - assert_eq!(GenericAsset::free_balance(&asset_id, &1), 60); - assert_eq!(GenericAsset::free_balance(&asset_id, &2), 40); - }, - ); + ExtBuilder::default().free_balance((16000, 1, 100000)).build().execute_with(|| { + let default_permission = PermissionLatest { + update: Owner::Address(1), + mint: Owner::Address(1), + burn: Owner::Address(1), + }; + assert_ok!(GenericAsset::create( + Origin::signed(1), + AssetOptions { + initial_issuance: free_balance, + permissions: default_permission + } + )); + assert_eq!(GenericAsset::free_balance(&asset_id, &1), free_balance); + assert_ok!(GenericAsset::transfer(Origin::signed(1), asset_id, 2, 40)); + assert_eq!(GenericAsset::free_balance(&asset_id, &1), 60); + assert_eq!(GenericAsset::free_balance(&asset_id, &2), 40); + }); } // Given @@ -168,55 +158,49 @@ fn transferring_amount_should_work() { #[test] fn transferring_amount_should_fail_when_transferring_more_than_free_balance() { let asset_id = 1000; - set_and_run_with_externalities( - &mut ExtBuilder::default().free_balance((16000, 1, 100000)).build(), - || { - let default_permission = PermissionLatest { - update: Owner::Address(1), - mint: Owner::Address(1), - burn: Owner::Address(1), - }; - assert_ok!(GenericAsset::create( - Origin::signed(1), - AssetOptions { - initial_issuance: 100, - permissions: default_permission - } - )); - assert_noop!( - GenericAsset::transfer(Origin::signed(1), asset_id, 2, 2000), - "balance too low to send amount" - ); - }, - ); + ExtBuilder::default().free_balance((16000, 1, 100000)).build().execute_with(|| { + let default_permission = PermissionLatest { + update: Owner::Address(1), + mint: Owner::Address(1), + burn: Owner::Address(1), + }; + assert_ok!(GenericAsset::create( + Origin::signed(1), + AssetOptions { + initial_issuance: 100, + permissions: default_permission + } + )); + assert_noop!( + GenericAsset::transfer(Origin::signed(1), asset_id, 2, 2000), + "balance too low to send amount" + ); + }); } #[test] fn transferring_less_than_one_unit_should_not_work() { let asset_id = 1000; - set_and_run_with_externalities( - &mut ExtBuilder::default().free_balance((16000, 1, 100000)).build(), - || { - let default_permission = PermissionLatest { - update: Owner::Address(1), - mint: Owner::Address(1), - burn: Owner::Address(1), - }; - assert_ok!(GenericAsset::create( - Origin::signed(1), - AssetOptions { - initial_issuance: 100, - permissions: default_permission - } - )); - assert_eq!(GenericAsset::free_balance(&asset_id, &1), 100); - assert_noop!( - GenericAsset::transfer(Origin::signed(1), asset_id, 2, 0), - "cannot transfer zero amount" - ); - }, - ); + ExtBuilder::default().free_balance((16000, 1, 100000)).build().execute_with(|| { + let default_permission = PermissionLatest { + update: Owner::Address(1), + mint: Owner::Address(1), + burn: Owner::Address(1), + }; + assert_ok!(GenericAsset::create( + Origin::signed(1), + AssetOptions { + initial_issuance: 100, + permissions: default_permission + } + )); + assert_eq!(GenericAsset::free_balance(&asset_id, &1), 100); + assert_noop!( + GenericAsset::transfer(Origin::signed(1), asset_id, 2, 0), + "cannot transfer zero amount" + ); + }); } // Given @@ -233,60 +217,54 @@ fn self_transfer_should_fail() { let asset_id = 1000; let balance = 100; - set_and_run_with_externalities( - &mut ExtBuilder::default().free_balance((16000, 1, 100000)).build(), - || { - let default_permission = PermissionLatest { - update: Owner::Address(1), - mint: Owner::Address(1), - burn: Owner::Address(1), - }; - assert_ok!(GenericAsset::create( - Origin::signed(1), - AssetOptions { - initial_issuance: balance, - permissions: default_permission - } - )); + ExtBuilder::default().free_balance((16000, 1, 100000)).build().execute_with(|| { + let default_permission = PermissionLatest { + update: Owner::Address(1), + mint: Owner::Address(1), + burn: Owner::Address(1), + }; + assert_ok!(GenericAsset::create( + Origin::signed(1), + AssetOptions { + initial_issuance: balance, + permissions: default_permission + } + )); - let initial_free_balance = GenericAsset::free_balance(&asset_id, &1); - assert_ok!(GenericAsset::transfer(Origin::signed(1), asset_id, 1, 10)); - assert_eq!(GenericAsset::free_balance(&asset_id, &1), initial_free_balance); - }, - ); + let initial_free_balance = GenericAsset::free_balance(&asset_id, &1); + assert_ok!(GenericAsset::transfer(Origin::signed(1), asset_id, 1, 10)); + assert_eq!(GenericAsset::free_balance(&asset_id, &1), initial_free_balance); + }); } #[test] fn transferring_more_units_than_total_supply_should_not_work() { let asset_id = 1000; - set_and_run_with_externalities( - &mut ExtBuilder::default().free_balance((16000, 1, 100000)).build(), - || { - let default_permission = PermissionLatest { - update: Owner::Address(1), - mint: Owner::Address(1), - burn: Owner::Address(1), - }; - assert_ok!(GenericAsset::create( - Origin::signed(1), - AssetOptions { - initial_issuance: 100, - permissions: default_permission - } - )); - assert_eq!(GenericAsset::free_balance(&asset_id, &1), 100); - assert_noop!( - GenericAsset::transfer(Origin::signed(1), asset_id, 2, 101), - "balance too low to send amount" - ); - }, - ); + ExtBuilder::default().free_balance((16000, 1, 100000)).build().execute_with(|| { + let default_permission = PermissionLatest { + update: Owner::Address(1), + mint: Owner::Address(1), + burn: Owner::Address(1), + }; + assert_ok!(GenericAsset::create( + Origin::signed(1), + AssetOptions { + initial_issuance: 100, + permissions: default_permission + } + )); + assert_eq!(GenericAsset::free_balance(&asset_id, &1), 100); + assert_noop!( + GenericAsset::transfer(Origin::signed(1), asset_id, 2, 101), + "balance too low to send amount" + ); + }); } // Ensures it uses fake money for staking asset id. #[test] fn staking_asset_id_should_return_0() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { assert_eq!(GenericAsset::staking_asset_id(), 16000); }); } @@ -294,7 +272,7 @@ fn staking_asset_id_should_return_0() { // Ensures it uses fake money for spending asset id. #[test] fn spending_asset_id_should_return_10() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { assert_eq!(GenericAsset::spending_asset_id(), 16001); }); } @@ -305,7 +283,7 @@ fn spending_asset_id_should_return_10() { // -Â total_balance should return 0 #[test] fn total_balance_should_be_zero() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { assert_eq!(GenericAsset::total_balance(&0, &0), 0); }); } @@ -323,19 +301,16 @@ fn total_balance_should_be_equal_to_account_balance() { mint: Owner::Address(1), burn: Owner::Address(1), }; - set_and_run_with_externalities( - &mut ExtBuilder::default().free_balance((16000, 1, 100000)).build(), - || { - assert_ok!(GenericAsset::create( - Origin::signed(1), - AssetOptions { - initial_issuance: 100, - permissions: default_permission - } - )); - assert_eq!(GenericAsset::total_balance(&1000, &1), 100); - }, - ); + ExtBuilder::default().free_balance((16000, 1, 100000)).build().execute_with(|| { + assert_ok!(GenericAsset::create( + Origin::signed(1), + AssetOptions { + initial_issuance: 100, + permissions: default_permission + } + )); + assert_eq!(GenericAsset::total_balance(&1000, &1), 100); + }); } // Given @@ -348,7 +323,7 @@ fn total_balance_should_be_equal_to_account_balance() { // -Â free_balance should return 50. #[test] fn free_balance_should_only_return_account_free_balance() { - set_and_run_with_externalities(&mut ExtBuilder::default().free_balance((1, 0, 50)).build(), || { + ExtBuilder::default().free_balance((1, 0, 50)).build().execute_with(|| { GenericAsset::set_reserved_balance(&1, &0, 70); assert_eq!(GenericAsset::free_balance(&1, &0), 50); }); @@ -363,7 +338,7 @@ fn free_balance_should_only_return_account_free_balance() { // -Â total_balance should equals to account balance + free balance. #[test] fn total_balance_should_be_equal_to_sum_of_account_balance_and_free_balance() { - set_and_run_with_externalities(&mut ExtBuilder::default().free_balance((1, 0, 50)).build(), || { + ExtBuilder::default().free_balance((1, 0, 50)).build().execute_with(|| { GenericAsset::set_reserved_balance(&1, &0, 70); assert_eq!(GenericAsset::total_balance(&1, &0), 120); }); @@ -378,7 +353,7 @@ fn total_balance_should_be_equal_to_sum_of_account_balance_and_free_balance() { // - reserved_balance should return 70. #[test] fn reserved_balance_should_only_return_account_reserved_balance() { - set_and_run_with_externalities(&mut ExtBuilder::default().free_balance((1, 0, 50)).build(), || { + ExtBuilder::default().free_balance((1, 0, 50)).build().execute_with(|| { GenericAsset::set_reserved_balance(&1, &0, 70); assert_eq!(GenericAsset::reserved_balance(&1, &0), 70); }); @@ -394,7 +369,7 @@ fn reserved_balance_should_only_return_account_reserved_balance() { // - reserved_balance = amount #[test] fn set_reserved_balance_should_add_balance_as_reserved() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { GenericAsset::set_reserved_balance(&1, &0, 50); assert_eq!(GenericAsset::reserved_balance(&1, &0), 50); }); @@ -410,7 +385,7 @@ fn set_reserved_balance_should_add_balance_as_reserved() { // - New free_balance should replace older free_balance. #[test] fn set_free_balance_should_add_amount_as_free_balance() { - set_and_run_with_externalities(&mut ExtBuilder::default().free_balance((1, 0, 100)).build(), || { + ExtBuilder::default().free_balance((1, 0, 100)).build().execute_with(|| { GenericAsset::set_free_balance(&1, &0, 50); assert_eq!(GenericAsset::free_balance(&1, &0), 50); }); @@ -429,7 +404,7 @@ fn set_free_balance_should_add_amount_as_free_balance() { // - new reserved_balance = original free balance + reserved amount #[test] fn reserve_should_moves_amount_from_balance_to_reserved_balance() { - set_and_run_with_externalities(&mut ExtBuilder::default().free_balance((1, 0, 100)).build(), || { + ExtBuilder::default().free_balance((1, 0, 100)).build().execute_with(|| { assert_ok!(GenericAsset::reserve(&1, &0, 70)); assert_eq!(GenericAsset::free_balance(&1, &0), 30); assert_eq!(GenericAsset::reserved_balance(&1, &0), 70); @@ -448,7 +423,7 @@ fn reserve_should_moves_amount_from_balance_to_reserved_balance() { // - Should throw an error. #[test] fn reserve_should_not_moves_amount_from_balance_to_reserved_balance() { - set_and_run_with_externalities(&mut ExtBuilder::default().free_balance((1, 0, 100)).build(), || { + ExtBuilder::default().free_balance((1, 0, 100)).build().execute_with(|| { assert_noop!(GenericAsset::reserve(&1, &0, 120), "not enough free funds"); assert_eq!(GenericAsset::free_balance(&1, &0), 100); assert_eq!(GenericAsset::reserved_balance(&1, &0), 0); @@ -466,7 +441,7 @@ fn reserve_should_not_moves_amount_from_balance_to_reserved_balance() { // - unreserved should return 20. #[test] fn unreserve_should_return_substratced_value_from_unreserved_amount_by_actual_acount_balance() { - set_and_run_with_externalities(&mut ExtBuilder::default().free_balance((1, 0, 100)).build(), || { + ExtBuilder::default().free_balance((1, 0, 100)).build().execute_with(|| { GenericAsset::set_reserved_balance(&1, &0, 100); assert_eq!(GenericAsset::unreserve(&1, &0, 120), 20); }); @@ -483,7 +458,7 @@ fn unreserve_should_return_substratced_value_from_unreserved_amount_by_actual_ac // - unreserved should return None. #[test] fn unreserve_should_return_none() { - set_and_run_with_externalities(&mut ExtBuilder::default().free_balance((1, 0, 100)).build(), || { + ExtBuilder::default().free_balance((1, 0, 100)).build().execute_with(|| { GenericAsset::set_reserved_balance(&1, &0, 100); assert_eq!(GenericAsset::unreserve(&1, &0, 50), 0); }); @@ -500,7 +475,7 @@ fn unreserve_should_return_none() { // - free_balance should be 200. #[test] fn unreserve_should_increase_free_balance_by_reserved_balance() { - set_and_run_with_externalities(&mut ExtBuilder::default().free_balance((1, 0, 100)).build(), || { + ExtBuilder::default().free_balance((1, 0, 100)).build().execute_with(|| { GenericAsset::set_reserved_balance(&1, &0, 100); GenericAsset::unreserve(&1, &0, 120); assert_eq!(GenericAsset::free_balance(&1, &0), 200); @@ -518,7 +493,7 @@ fn unreserve_should_increase_free_balance_by_reserved_balance() { // - reserved_balance should be 0. #[test] fn unreserve_should_deduct_reserved_balance_by_reserved_amount() { - set_and_run_with_externalities(&mut ExtBuilder::default().free_balance((1, 0, 100)).build(), || { + ExtBuilder::default().free_balance((1, 0, 100)).build().execute_with(|| { GenericAsset::set_free_balance(&1, &0, 100); GenericAsset::unreserve(&1, &0, 120); assert_eq!(GenericAsset::reserved_balance(&1, &0), 0); @@ -536,7 +511,7 @@ fn unreserve_should_deduct_reserved_balance_by_reserved_amount() { // - slash should return None. #[test] fn slash_should_return_slash_reserved_amount() { - set_and_run_with_externalities(&mut ExtBuilder::default().free_balance((1, 0, 100)).build(), || { + ExtBuilder::default().free_balance((1, 0, 100)).build().execute_with(|| { GenericAsset::set_reserved_balance(&1, &0, 100); assert_eq!(GenericAsset::slash(&1, &0, 70), None); }); @@ -550,7 +525,7 @@ fn slash_should_return_slash_reserved_amount() { // - Should return slashed_reserved - reserved_balance. #[test] fn slash_reserved_should_deducts_up_to_amount_from_reserved_balance() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { GenericAsset::set_reserved_balance(&1, &0, 100); assert_eq!(GenericAsset::slash_reserved(&1, &0, 150), Some(50)); }); @@ -564,7 +539,7 @@ fn slash_reserved_should_deducts_up_to_amount_from_reserved_balance() { // - Should return None. #[test] fn slash_reserved_should_return_none() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { GenericAsset::set_reserved_balance(&1, &0, 100); assert_eq!(GenericAsset::slash_reserved(&1, &0, 100), None); }); @@ -579,7 +554,7 @@ fn slash_reserved_should_return_none() { // - Should not return None. #[test] fn repatriate_reserved_return_amount_substracted_by_slash_amount() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { GenericAsset::set_reserved_balance(&1, &0, 100); assert_eq!(GenericAsset::repatriate_reserved(&1, &0, &1, 130), 30); }); @@ -594,7 +569,7 @@ fn repatriate_reserved_return_amount_substracted_by_slash_amount() { // - Should return None. #[test] fn repatriate_reserved_return_none() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { GenericAsset::set_reserved_balance(&1, &0, 100); assert_eq!(GenericAsset::repatriate_reserved(&1, &0, &1, 90), 0); }); @@ -608,7 +583,7 @@ fn repatriate_reserved_return_none() { // - Should create a new reserved asset. #[test] fn create_reserved_should_create_a_default_account_with_the_balance_given() { - set_and_run_with_externalities(&mut ExtBuilder::default().next_asset_id(10).build(), || { + ExtBuilder::default().next_asset_id(10).build().execute_with(|| { let default_permission = PermissionLatest { update: Owner::Address(1), mint: Owner::Address(1), @@ -643,7 +618,7 @@ fn create_reserved_should_create_a_default_account_with_the_balance_given() { // - Should throw a permission error #[test] fn mint_should_throw_permission_error() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { let origin = 1; let asset_id = 4; let to_account = 2; @@ -666,36 +641,33 @@ fn mint_should_throw_permission_error() { // - Should not change `origins` free_balance. #[test] fn mint_should_increase_asset() { - set_and_run_with_externalities( - &mut ExtBuilder::default().free_balance((16000, 1, 100000)).build(), - || { - let origin = 1; - let asset_id = 1000; - let to_account = 2; - let amount = 500; - let initial_issuance = 100; - - let default_permission = PermissionLatest { - update: Owner::Address(origin), - mint: Owner::Address(origin), - burn: Owner::Address(origin), - }; + ExtBuilder::default().free_balance((16000, 1, 100000)).build().execute_with(|| { + let origin = 1; + let asset_id = 1000; + let to_account = 2; + let amount = 500; + let initial_issuance = 100; - assert_ok!(GenericAsset::create( - Origin::signed(origin), - AssetOptions { - initial_issuance: initial_issuance, - permissions: default_permission - } - )); + let default_permission = PermissionLatest { + update: Owner::Address(origin), + mint: Owner::Address(origin), + burn: Owner::Address(origin), + }; - assert_ok!(GenericAsset::mint(Origin::signed(origin), asset_id, to_account, amount)); - assert_eq!(GenericAsset::free_balance(&asset_id, &to_account), amount); + assert_ok!(GenericAsset::create( + Origin::signed(origin), + AssetOptions { + initial_issuance: initial_issuance, + permissions: default_permission + } + )); - // Origin's free_balance should not change. - assert_eq!(GenericAsset::free_balance(&asset_id, &origin), initial_issuance); - }, - ); + assert_ok!(GenericAsset::mint(Origin::signed(origin), asset_id, to_account, amount)); + assert_eq!(GenericAsset::free_balance(&asset_id, &to_account), amount); + + // Origin's free_balance should not change. + assert_eq!(GenericAsset::free_balance(&asset_id, &origin), initial_issuance); + }); } // Given @@ -707,20 +679,17 @@ fn mint_should_increase_asset() { // - Should throw a permission error. #[test] fn burn_should_throw_permission_error() { - set_and_run_with_externalities( - &mut ExtBuilder::default().free_balance((16000, 1, 100000)).build(), - || { - let origin = 1; - let asset_id = 4; - let to_account = 2; - let amount = 10; - - assert_noop!( - GenericAsset::burn(Origin::signed(origin), asset_id, to_account, amount), - "The origin does not have permission to burn an asset." - ); - }, - ); + ExtBuilder::default().free_balance((16000, 1, 100000)).build().execute_with(|| { + let origin = 1; + let asset_id = 4; + let to_account = 2; + let amount = 10; + + assert_noop!( + GenericAsset::burn(Origin::signed(origin), asset_id, to_account, amount), + "The origin does not have permission to burn an asset." + ); + }); } // Given @@ -733,41 +702,38 @@ fn burn_should_throw_permission_error() { // - Should not change `origin`'s free_balance. #[test] fn burn_should_burn_an_asset() { - set_and_run_with_externalities( - &mut ExtBuilder::default().free_balance((16000, 1, 100000)).build(), - || { - let origin = 1; - let asset_id = 1000; - let to_account = 2; - let amount = 1000; - let initial_issuance = 100; - let burn_amount = 400; - let expected_amount = 600; - - let default_permission = PermissionLatest { - update: Owner::Address(origin), - mint: Owner::Address(origin), - burn: Owner::Address(origin), - }; + ExtBuilder::default().free_balance((16000, 1, 100000)).build().execute_with(|| { + let origin = 1; + let asset_id = 1000; + let to_account = 2; + let amount = 1000; + let initial_issuance = 100; + let burn_amount = 400; + let expected_amount = 600; - assert_ok!(GenericAsset::create( - Origin::signed(origin), - AssetOptions { - initial_issuance: initial_issuance, - permissions: default_permission - } - )); - assert_ok!(GenericAsset::mint(Origin::signed(origin), asset_id, to_account, amount)); + let default_permission = PermissionLatest { + update: Owner::Address(origin), + mint: Owner::Address(origin), + burn: Owner::Address(origin), + }; - assert_ok!(GenericAsset::burn( - Origin::signed(origin), - asset_id, - to_account, - burn_amount - )); - assert_eq!(GenericAsset::free_balance(&asset_id, &to_account), expected_amount); - }, - ); + assert_ok!(GenericAsset::create( + Origin::signed(origin), + AssetOptions { + initial_issuance: initial_issuance, + permissions: default_permission + } + )); + assert_ok!(GenericAsset::mint(Origin::signed(origin), asset_id, to_account, amount)); + + assert_ok!(GenericAsset::burn( + Origin::signed(origin), + asset_id, + to_account, + burn_amount + )); + assert_eq!(GenericAsset::free_balance(&asset_id, &to_account), expected_amount); + }); } // Given @@ -779,41 +745,29 @@ fn burn_should_burn_an_asset() { // - The account origin should have burn, mint and update permissions. #[test] fn check_permission_should_return_correct_permission() { - set_and_run_with_externalities( - &mut ExtBuilder::default().free_balance((16000, 1, 100000)).build(), - || { - let origin = 1; - let asset_id = 1000; - let initial_issuance = 100; - - let default_permission = PermissionLatest { - update: Owner::Address(origin), - mint: Owner::Address(origin), - burn: Owner::Address(origin), - }; + ExtBuilder::default().free_balance((16000, 1, 100000)).build().execute_with(|| { + let origin = 1; + let asset_id = 1000; + let initial_issuance = 100; - assert_ok!(GenericAsset::create( - Origin::signed(origin), - AssetOptions { - initial_issuance: initial_issuance, - permissions: default_permission - } - )); + let default_permission = PermissionLatest { + update: Owner::Address(origin), + mint: Owner::Address(origin), + burn: Owner::Address(origin), + }; - assert_eq!( - GenericAsset::check_permission(&asset_id, &origin, &PermissionType::Burn), - true - ); - assert_eq!( - GenericAsset::check_permission(&asset_id, &origin, &PermissionType::Mint), - true - ); - assert_eq!( - GenericAsset::check_permission(&asset_id, &origin, &PermissionType::Update), - true - ); - }, - ); + assert_ok!(GenericAsset::create( + Origin::signed(origin), + AssetOptions { + initial_issuance: initial_issuance, + permissions: default_permission + }, + )); + + assert!(GenericAsset::check_permission(&asset_id, &origin, &PermissionType::Burn)); + assert!(GenericAsset::check_permission(&asset_id, &origin, &PermissionType::Mint)); + assert!(GenericAsset::check_permission(&asset_id, &origin, &PermissionType::Update)); + }); } // Given @@ -825,41 +779,29 @@ fn check_permission_should_return_correct_permission() { // - The account origin should not have burn, mint and update permissions. #[test] fn check_permission_should_return_false_for_no_permission() { - set_and_run_with_externalities( - &mut ExtBuilder::default().free_balance((16000, 1, 100000)).build(), - || { - let origin = 1; - let asset_id = 1000; - let initial_issuance = 100; - - let default_permission = PermissionLatest { - update: Owner::None, - mint: Owner::None, - burn: Owner::None, - }; + ExtBuilder::default().free_balance((16000, 1, 100000)).build().execute_with(|| { + let origin = 1; + let asset_id = 1000; + let initial_issuance = 100; - assert_ok!(GenericAsset::create( - Origin::signed(origin), - AssetOptions { - initial_issuance: initial_issuance, - permissions: default_permission - } - )); + let default_permission = PermissionLatest { + update: Owner::None, + mint: Owner::None, + burn: Owner::None, + }; - assert_eq!( - GenericAsset::check_permission(&asset_id, &origin, &PermissionType::Burn), - false - ); - assert_eq!( - GenericAsset::check_permission(&asset_id, &origin, &PermissionType::Mint), - false - ); - assert_eq!( - GenericAsset::check_permission(&asset_id, &origin, &PermissionType::Update), - false - ); - }, - ); + assert_ok!(GenericAsset::create( + Origin::signed(origin), + AssetOptions { + initial_issuance: initial_issuance, + permissions: default_permission + } + )); + + assert!(!GenericAsset::check_permission(&asset_id, &origin, &PermissionType::Burn)); + assert!(!GenericAsset::check_permission(&asset_id, &origin, &PermissionType::Mint)); + assert!(!GenericAsset::check_permission(&asset_id, &origin, &PermissionType::Update)); + }); } // Given @@ -871,48 +813,39 @@ fn check_permission_should_return_false_for_no_permission() { // - The account origin should have update and mint permissions. #[test] fn update_permission_should_change_permission() { - set_and_run_with_externalities( - &mut ExtBuilder::default().free_balance((16000, 1, 100000)).build(), - || { - let origin = 1; - let asset_id = 1000; - let initial_issuance = 100; - - let default_permission = PermissionLatest { - update: Owner::Address(origin), - mint: Owner::None, - burn: Owner::None, - }; - - let new_permission = PermissionLatest { - update: Owner::Address(origin), - mint: Owner::Address(origin), - burn: Owner::None, - }; + ExtBuilder::default().free_balance((16000, 1, 100000)).build().execute_with(|| { + let origin = 1; + let asset_id = 1000; + let initial_issuance = 100; - assert_ok!(GenericAsset::create( - Origin::signed(origin), - AssetOptions { - initial_issuance: initial_issuance, - permissions: default_permission - } - )); + let default_permission = PermissionLatest { + update: Owner::Address(origin), + mint: Owner::None, + burn: Owner::None, + }; - assert_ok!(GenericAsset::update_permission( - Origin::signed(origin), - asset_id, - new_permission - )); - assert_eq!( - GenericAsset::check_permission(&asset_id, &origin, &PermissionType::Mint), - true - ); - assert_eq!( - GenericAsset::check_permission(&asset_id, &origin, &PermissionType::Burn), - false - ); - }, - ); + let new_permission = PermissionLatest { + update: Owner::Address(origin), + mint: Owner::Address(origin), + burn: Owner::None, + }; + + assert_ok!(GenericAsset::create( + Origin::signed(origin), + AssetOptions { + initial_issuance: initial_issuance, + permissions: default_permission + } + )); + + assert_ok!(GenericAsset::update_permission( + Origin::signed(origin), + asset_id, + new_permission, + )); + assert!(GenericAsset::check_permission(&asset_id, &origin, &PermissionType::Mint)); + assert!(!GenericAsset::check_permission(&asset_id, &origin, &PermissionType::Burn)); + }); } // Given @@ -923,41 +856,38 @@ fn update_permission_should_change_permission() { // - Should throw an error stating "Origin does not have enough permission to update permissions." #[test] fn update_permission_should_throw_error_when_lack_of_permissions() { - set_and_run_with_externalities( - &mut ExtBuilder::default().free_balance((16000, 1, 100000)).build(), - || { - let origin = 1; - let asset_id = 1000; - let initial_issuance = 100; - - let default_permission = PermissionLatest { - update: Owner::None, - mint: Owner::None, - burn: Owner::None, - }; - - let new_permission = PermissionLatest { - update: Owner::Address(origin), - mint: Owner::Address(origin), - burn: Owner::None, - }; - - let expected_error_message = "Origin does not have enough permission to update permissions."; + ExtBuilder::default().free_balance((16000, 1, 100000)).build().execute_with(|| { + let origin = 1; + let asset_id = 1000; + let initial_issuance = 100; - assert_ok!(GenericAsset::create( - Origin::signed(origin), - AssetOptions { - initial_issuance: initial_issuance, - permissions: default_permission - } - )); + let default_permission = PermissionLatest { + update: Owner::None, + mint: Owner::None, + burn: Owner::None, + }; - assert_noop!( - GenericAsset::update_permission(Origin::signed(origin), asset_id, new_permission), - expected_error_message - ); - }, - ); + let new_permission = PermissionLatest { + update: Owner::Address(origin), + mint: Owner::Address(origin), + burn: Owner::None, + }; + + let expected_error_message = "Origin does not have enough permission to update permissions."; + + assert_ok!(GenericAsset::create( + Origin::signed(origin), + AssetOptions { + initial_issuance: initial_issuance, + permissions: default_permission + }, + )); + + assert_noop!( + GenericAsset::update_permission(Origin::signed(origin), asset_id, new_permission), + expected_error_message, + ); + }); } // Given @@ -974,7 +904,7 @@ fn update_permission_should_throw_error_when_lack_of_permissions() { // - Permissions must have burn, mint and updatePermission for the given asset_id. #[test] fn create_asset_works_with_given_asset_id_and_from_account() { - set_and_run_with_externalities(&mut ExtBuilder::default().next_asset_id(10).build(), || { + ExtBuilder::default().next_asset_id(10).build().execute_with(|| { let origin = 1; let from_account: Option<::AccountId> = Some(1); @@ -1011,7 +941,7 @@ fn create_asset_works_with_given_asset_id_and_from_account() { // - `create_asset` should not work. #[test] fn create_asset_with_non_reserved_asset_id_should_not_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().next_asset_id(10).build(), || { + ExtBuilder::default().next_asset_id(10).build().execute_with(|| { let origin = 1; let from_account: Option<::AccountId> = Some(1); @@ -1045,7 +975,7 @@ fn create_asset_with_non_reserved_asset_id_should_not_work() { // - `create_asset` should not work. #[test] fn create_asset_with_a_taken_asset_id_should_not_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().next_asset_id(10).build(), || { + ExtBuilder::default().next_asset_id(10).build().execute_with(|| { let origin = 1; let from_account: Option<::AccountId> = Some(1); @@ -1090,7 +1020,7 @@ fn create_asset_with_a_taken_asset_id_should_not_work() { // - Should create a reserved token. #[test] fn create_asset_should_create_a_reserved_asset_when_from_account_is_none() { - set_and_run_with_externalities(&mut ExtBuilder::default().next_asset_id(10).build(), || { + ExtBuilder::default().next_asset_id(10).build().execute_with(|| { let origin = 1; let from_account: Option<::AccountId> = None; @@ -1133,7 +1063,7 @@ fn create_asset_should_create_a_reserved_asset_when_from_account_is_none() { // - Should not create a `reserved_asset`. #[test] fn create_asset_should_create_a_user_asset() { - set_and_run_with_externalities(&mut ExtBuilder::default().next_asset_id(10).build(), || { + ExtBuilder::default().next_asset_id(10).build().execute_with(|| { let origin = 1; let from_account: Option<::AccountId> = None; @@ -1180,12 +1110,11 @@ fn update_permission_should_raise_event() { burn: Owner::Address(origin), }; - set_and_run_with_externalities( - &mut ExtBuilder::default() - .next_asset_id(asset_id) - .free_balance((staking_asset_id, origin, initial_balance)) - .build(), - || { + ExtBuilder::default() + .next_asset_id(asset_id) + .free_balance((staking_asset_id, origin, initial_balance)) + .build() + .execute_with(|| { assert_ok!(GenericAsset::create( Origin::signed(origin), AssetOptions { @@ -1201,9 +1130,11 @@ fn update_permission_should_raise_event() { permissions.clone() )); + let expected_event = TestEvent::generic_asset( + RawEvent::PermissionUpdated(asset_id, permissions.clone()), + ); // Assert - assert!(System::events().iter().any(|record| record.event - == TestEvent::generic_asset(RawEvent::PermissionUpdated(asset_id, permissions.clone())))); + assert!(System::events().iter().any(|record| record.event == expected_event)); }, ); } @@ -1223,27 +1154,26 @@ fn mint_should_raise_event() { let to = 2; let amount = 100; - set_and_run_with_externalities( - &mut ExtBuilder::default() - .next_asset_id(asset_id) - .free_balance((staking_asset_id, origin, initial_balance)) - .build(), - || { + ExtBuilder::default() + .next_asset_id(asset_id) + .free_balance((staking_asset_id, origin, initial_balance)) + .build() + .execute_with(|| { assert_ok!(GenericAsset::create( Origin::signed(origin), AssetOptions { initial_issuance: 0, permissions: permissions.clone(), - } + }, )); // Act assert_ok!(GenericAsset::mint(Origin::signed(origin), asset_id, to, amount)); + let expected_event = TestEvent::generic_asset(RawEvent::Minted(asset_id, to, amount)); + // Assert - assert!(System::events() - .iter() - .any(|record| record.event == TestEvent::generic_asset(RawEvent::Minted(asset_id, to, amount)))); + assert!(System::events().iter().any(|record| record.event == expected_event)); }, ); } @@ -1262,27 +1192,26 @@ fn burn_should_raise_event() { }; let amount = 100; - set_and_run_with_externalities( - &mut ExtBuilder::default() - .next_asset_id(asset_id) - .free_balance((staking_asset_id, origin, initial_balance)) - .build(), - || { + ExtBuilder::default() + .next_asset_id(asset_id) + .free_balance((staking_asset_id, origin, initial_balance)) + .build() + .execute_with(|| { assert_ok!(GenericAsset::create( Origin::signed(origin), AssetOptions { initial_issuance: amount, permissions: permissions.clone(), - } + }, )); // Act assert_ok!(GenericAsset::burn(Origin::signed(origin), asset_id, origin, amount)); + let expected_event = TestEvent::generic_asset(RawEvent::Burned(asset_id, origin, amount)); + // Assert - assert!(System::events() - .iter() - .any(|record| record.event == TestEvent::generic_asset(RawEvent::Burned(asset_id, origin, amount)))); + assert!(System::events().iter().any(|record| record.event == expected_event)); }, ); } diff --git a/srml/grandpa/src/tests.rs b/srml/grandpa/src/tests.rs index aec75d274c..2efeb4b5bf 100644 --- a/srml/grandpa/src/tests.rs +++ b/srml/grandpa/src/tests.rs @@ -18,7 +18,7 @@ #![cfg(test)] -use sr_primitives::{set_and_run_with_externalities, testing::Digest, traits::{Header, OnFinalize}}; +use sr_primitives::{testing::Digest, traits::{Header, OnFinalize}}; use crate::mock::*; use system::{EventRecord, Phase}; use codec::{Decode, Encode}; @@ -27,7 +27,7 @@ use super::*; #[test] fn authorities_change_logged() { - set_and_run_with_externalities(&mut new_test_ext(vec![(1, 1), (2, 1), (3, 1)]), || { + new_test_ext(vec![(1, 1), (2, 1), (3, 1)]).execute_with(|| { System::initialize(&1, &Default::default(), &Default::default(), &Default::default()); Grandpa::schedule_change(to_authorities(vec![(4, 1), (5, 1), (6, 1)]), 0, None).unwrap(); @@ -55,7 +55,7 @@ fn authorities_change_logged() { #[test] fn authorities_change_logged_after_delay() { - set_and_run_with_externalities(&mut new_test_ext(vec![(1, 1), (2, 1), (3, 1)]), || { + new_test_ext(vec![(1, 1), (2, 1), (3, 1)]).execute_with(|| { System::initialize(&1, &Default::default(), &Default::default(), &Default::default()); Grandpa::schedule_change(to_authorities(vec![(4, 1), (5, 1), (6, 1)]), 1, None).unwrap(); Grandpa::on_finalize(1); @@ -88,7 +88,7 @@ fn authorities_change_logged_after_delay() { #[test] fn cannot_schedule_change_when_one_pending() { - set_and_run_with_externalities(&mut new_test_ext(vec![(1, 1), (2, 1), (3, 1)]), || { + new_test_ext(vec![(1, 1), (2, 1), (3, 1)]).execute_with(|| { System::initialize(&1, &Default::default(), &Default::default(), &Default::default()); Grandpa::schedule_change(to_authorities(vec![(4, 1), (5, 1), (6, 1)]), 1, None).unwrap(); assert!(>::exists()); @@ -131,7 +131,7 @@ fn new_decodes_from_old() { #[test] fn dispatch_forced_change() { - set_and_run_with_externalities(&mut new_test_ext(vec![(1, 1), (2, 1), (3, 1)]), || { + new_test_ext(vec![(1, 1), (2, 1), (3, 1)]).execute_with(|| { System::initialize(&1, &Default::default(), &Default::default(), &Default::default()); Grandpa::schedule_change( to_authorities(vec![(4, 1), (5, 1), (6, 1)]), @@ -203,7 +203,7 @@ fn dispatch_forced_change() { #[test] fn schedule_pause_only_when_live() { - set_and_run_with_externalities(&mut new_test_ext(vec![(1, 1), (2, 1), (3, 1)]), || { + new_test_ext(vec![(1, 1), (2, 1), (3, 1)]).execute_with(|| { // we schedule a pause at block 1 with delay of 1 System::initialize(&1, &Default::default(), &Default::default(), &Default::default()); Grandpa::schedule_pause(1).unwrap(); @@ -238,7 +238,7 @@ fn schedule_pause_only_when_live() { #[test] fn schedule_resume_only_when_paused() { - set_and_run_with_externalities(&mut new_test_ext(vec![(1, 1), (2, 1), (3, 1)]), || { + new_test_ext(vec![(1, 1), (2, 1), (3, 1)]).execute_with(|| { System::initialize(&1, &Default::default(), &Default::default(), &Default::default()); // the set is currently live, resuming it is an error diff --git a/srml/im-online/src/tests.rs b/srml/im-online/src/tests.rs index d57b9f59cb..652d751281 100644 --- a/srml/im-online/src/tests.rs +++ b/srml/im-online/src/tests.rs @@ -23,8 +23,7 @@ use crate::mock::*; use offchain::testing::TestOffchainExt; use primitives::offchain::{OpaquePeerId, OffchainExt}; use support::{dispatch, assert_noop}; -use sr_primitives::{set_and_run_with_externalities, testing::UintAuthorityId}; - +use sr_primitives::testing::UintAuthorityId; #[test] fn test_unresponsiveness_slash_fraction() { @@ -48,7 +47,7 @@ fn test_unresponsiveness_slash_fraction() { #[test] fn should_report_offline_validators() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { // given let block = 1; System::set_block_number(block); @@ -124,7 +123,7 @@ fn heartbeat( #[test] fn should_mark_online_validator_when_heartbeat_is_received() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { advance_session(); // given VALIDATORS.with(|l| *l.borrow_mut() = Some(vec![1, 2, 3, 4, 5, 6])); @@ -159,7 +158,7 @@ fn should_mark_online_validator_when_heartbeat_is_received() { #[test] fn late_heartbeat_should_fail() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { advance_session(); // given VALIDATORS.with(|l| *l.borrow_mut() = Some(vec![1, 2, 4, 4, 5, 6])); @@ -182,7 +181,7 @@ fn should_generate_heartbeats() { let (offchain, state) = TestOffchainExt::new(); ext.register_extension(OffchainExt::new(offchain)); - set_and_run_with_externalities(&mut ext, || { + ext.execute_with(|| { // given let block = 1; System::set_block_number(block); @@ -218,7 +217,7 @@ fn should_generate_heartbeats() { #[test] fn should_cleanup_received_heartbeats_on_session_end() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { advance_session(); VALIDATORS.with(|l| *l.borrow_mut() = Some(vec![1, 2, 3])); diff --git a/srml/indices/src/tests.rs b/srml/indices/src/tests.rs index 4b8f1822b4..3bcf015713 100644 --- a/srml/indices/src/tests.rs +++ b/srml/indices/src/tests.rs @@ -20,61 +20,48 @@ use super::*; use crate::mock::{Indices, new_test_ext, make_account, kill_account, TestIsDeadAccount}; -use sr_primitives::set_and_run_with_externalities; #[test] fn indexing_lookup_should_work() { - set_and_run_with_externalities( - &mut new_test_ext(), - || { - assert_eq!(Indices::lookup_index(0), Some(1)); - assert_eq!(Indices::lookup_index(1), Some(2)); - assert_eq!(Indices::lookup_index(2), Some(3)); - assert_eq!(Indices::lookup_index(3), Some(4)); - assert_eq!(Indices::lookup_index(4), None); - }, - ); + new_test_ext().execute_with(|| { + assert_eq!(Indices::lookup_index(0), Some(1)); + assert_eq!(Indices::lookup_index(1), Some(2)); + assert_eq!(Indices::lookup_index(2), Some(3)); + assert_eq!(Indices::lookup_index(3), Some(4)); + assert_eq!(Indices::lookup_index(4), None); + }); } #[test] fn default_indexing_on_new_accounts_should_work() { - set_and_run_with_externalities( - &mut new_test_ext(), - || { - assert_eq!(Indices::lookup_index(4), None); - make_account(5); - assert_eq!(Indices::lookup_index(4), Some(5)); - }, - ); + new_test_ext().execute_with(|| { + assert_eq!(Indices::lookup_index(4), None); + make_account(5); + assert_eq!(Indices::lookup_index(4), Some(5)); + }); } #[test] fn reclaim_indexing_on_new_accounts_should_work() { - set_and_run_with_externalities( - &mut new_test_ext(), - || { - assert_eq!(Indices::lookup_index(1), Some(2)); - assert_eq!(Indices::lookup_index(4), None); + new_test_ext().execute_with(|| { + assert_eq!(Indices::lookup_index(1), Some(2)); + assert_eq!(Indices::lookup_index(4), None); - kill_account(2); // index 1 no longer locked to id 2 + kill_account(2); // index 1 no longer locked to id 2 - make_account(1 + 256); // id 257 takes index 1. - assert_eq!(Indices::lookup_index(1), Some(257)); - }, - ); + make_account(1 + 256); // id 257 takes index 1. + assert_eq!(Indices::lookup_index(1), Some(257)); + }); } #[test] fn alive_account_should_prevent_reclaim() { - set_and_run_with_externalities( - &mut new_test_ext(), - || { - assert!(!TestIsDeadAccount::is_dead_account(&2)); - assert_eq!(Indices::lookup_index(1), Some(2)); - assert_eq!(Indices::lookup_index(4), None); + new_test_ext().execute_with(|| { + assert!(!TestIsDeadAccount::is_dead_account(&2)); + assert_eq!(Indices::lookup_index(1), Some(2)); + assert_eq!(Indices::lookup_index(4), None); - make_account(1 + 256); // id 257 takes index 1. - assert_eq!(Indices::lookup_index(4), Some(257)); - }, - ); + make_account(1 + 256); // id 257 takes index 1. + assert_eq!(Indices::lookup_index(4), Some(257)); + }); } diff --git a/srml/membership/src/lib.rs b/srml/membership/src/lib.rs index 1a6ca82986..0cd3b0af66 100644 --- a/srml/membership/src/lib.rs +++ b/srml/membership/src/lib.rs @@ -196,10 +196,7 @@ mod tests { use primitives::H256; // The testing primitives are very useful for avoiding having to work with signatures // or public keys. `u64` is used as the `AccountId` and no `Signature`s are requried. - use sr_primitives::{ - Perbill, traits::{BlakeTwo256, IdentityLookup}, testing::Header, - set_and_run_with_externalities, - }; + use sr_primitives::{Perbill, traits::{BlakeTwo256, IdentityLookup}, testing::Header}; use system::EnsureSignedBy; impl_outer_origin! { @@ -293,7 +290,7 @@ mod tests { #[test] fn query_membership_works() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { assert_eq!(Membership::members(), vec![10, 20, 30]); assert_eq!(MEMBERS.with(|m| m.borrow().clone()), vec![10, 20, 30]); }); @@ -301,7 +298,7 @@ mod tests { #[test] fn add_member_works() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { assert_noop!(Membership::add_member(Origin::signed(5), 15), "bad origin"); assert_noop!(Membership::add_member(Origin::signed(1), 10), "already a member"); assert_ok!(Membership::add_member(Origin::signed(1), 15)); @@ -312,7 +309,7 @@ mod tests { #[test] fn remove_member_works() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { assert_noop!(Membership::remove_member(Origin::signed(5), 20), "bad origin"); assert_noop!(Membership::remove_member(Origin::signed(2), 15), "not a member"); assert_ok!(Membership::remove_member(Origin::signed(2), 20)); @@ -323,7 +320,7 @@ mod tests { #[test] fn swap_member_works() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { assert_noop!(Membership::swap_member(Origin::signed(5), 10, 25), "bad origin"); assert_noop!(Membership::swap_member(Origin::signed(3), 15, 25), "not a member"); assert_noop!(Membership::swap_member(Origin::signed(3), 10, 30), "already a member"); @@ -337,7 +334,7 @@ mod tests { #[test] fn reset_members_works() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { assert_noop!(Membership::reset_members(Origin::signed(1), vec![20, 40, 30]), "bad origin"); assert_ok!(Membership::reset_members(Origin::signed(4), vec![20, 40, 30])); assert_eq!(Membership::members(), vec![20, 30, 40]); diff --git a/srml/offences/src/tests.rs b/srml/offences/src/tests.rs index 7604533ba5..28e655d16b 100644 --- a/srml/offences/src/tests.rs +++ b/srml/offences/src/tests.rs @@ -24,11 +24,10 @@ use crate::mock::{ offence_reports, }; use system::{EventRecord, Phase}; -use sr_primitives::set_and_run_with_externalities; #[test] fn should_report_an_authority_and_trigger_on_offence() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { // given let time_slot = 42; assert_eq!(offence_reports(KIND, time_slot), vec![]); @@ -51,7 +50,7 @@ fn should_report_an_authority_and_trigger_on_offence() { #[test] fn should_calculate_the_fraction_correctly() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { // given let time_slot = 42; assert_eq!(offence_reports(KIND, time_slot), vec![]); @@ -83,7 +82,7 @@ fn should_calculate_the_fraction_correctly() { #[test] fn should_not_report_the_same_authority_twice_in_the_same_slot() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { // given let time_slot = 42; assert_eq!(offence_reports(KIND, time_slot), vec![]); @@ -113,7 +112,7 @@ fn should_not_report_the_same_authority_twice_in_the_same_slot() { #[test] fn should_report_in_different_time_slot() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { // given let time_slot = 42; assert_eq!(offence_reports(KIND, time_slot), vec![]); @@ -143,7 +142,7 @@ fn should_report_in_different_time_slot() { #[test] fn should_deposit_event() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { // given let time_slot = 42; assert_eq!(offence_reports(KIND, time_slot), vec![]); @@ -171,7 +170,7 @@ fn should_deposit_event() { #[test] fn doesnt_deposit_event_for_dups() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { // given let time_slot = 42; assert_eq!(offence_reports(KIND, time_slot), vec![]); @@ -208,7 +207,7 @@ fn doesnt_deposit_event_for_dups() { fn should_properly_count_offences() { // We report two different authorities for the same issue. Ultimately, the 1st authority // should have `count` equal 2 and the count of the 2nd one should be equal to 1. - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { // given let time_slot = 42; assert_eq!(offence_reports(KIND, time_slot), vec![]); diff --git a/srml/randomness-collective-flip/src/lib.rs b/srml/randomness-collective-flip/src/lib.rs index 4ad0095fdf..8dedf6f570 100644 --- a/srml/randomness-collective-flip/src/lib.rs +++ b/srml/randomness-collective-flip/src/lib.rs @@ -155,7 +155,6 @@ mod tests { use primitives::H256; use sr_primitives::{ Perbill, traits::{BlakeTwo256, OnInitialize, Header as _, IdentityLookup}, testing::Header, - set_and_run_with_externalities, }; use support::{impl_outer_origin, parameter_types, traits::Randomness}; @@ -222,7 +221,7 @@ mod tests { #[test] fn test_random_material_parital() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { let genesis_hash = System::parent_hash(); setup_blocks(38); @@ -236,7 +235,7 @@ mod tests { #[test] fn test_random_material_filled() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { let genesis_hash = System::parent_hash(); setup_blocks(81); @@ -251,7 +250,7 @@ mod tests { #[test] fn test_random_material_filled_twice() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { let genesis_hash = System::parent_hash(); setup_blocks(162); @@ -266,7 +265,7 @@ mod tests { #[test] fn test_random() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { setup_blocks(162); assert_eq!(System::block_number(), 162); diff --git a/srml/scored-pool/src/tests.rs b/srml/scored-pool/src/tests.rs index cd3efb0ceb..2f47b5da6f 100644 --- a/srml/scored-pool/src/tests.rs +++ b/srml/scored-pool/src/tests.rs @@ -20,7 +20,7 @@ use super::*; use mock::*; use support::{assert_ok, assert_noop}; -use sr_primitives::{set_and_run_with_externalities, traits::OnInitialize}; +use sr_primitives::traits::OnInitialize; type ScoredPool = Module; type System = system::Module; @@ -31,7 +31,7 @@ const INDEX_ERR: &str = "index does not match requested account"; #[test] fn query_membership_works() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { assert_eq!(ScoredPool::members(), vec![20, 40]); assert_eq!(Balances::reserved_balance(&31), CandidateDeposit::get()); assert_eq!(Balances::reserved_balance(&40), CandidateDeposit::get()); @@ -41,7 +41,7 @@ fn query_membership_works() { #[test] fn submit_candidacy_must_not_work() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { assert_noop!( ScoredPool::submit_candidacy(Origin::signed(99)), "balance too low to submit candidacy" @@ -55,7 +55,7 @@ fn submit_candidacy_must_not_work() { #[test] fn submit_candidacy_works() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { // given let who = 15; @@ -70,7 +70,7 @@ fn submit_candidacy_works() { #[test] fn scoring_works() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { // given let who = 15; let score = 99; @@ -88,7 +88,7 @@ fn scoring_works() { #[test] fn scoring_same_element_with_same_score_works() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { // given let who = 31; let index = find_in_pool(who).expect("entity must be in pool") as u32; @@ -108,7 +108,7 @@ fn scoring_same_element_with_same_score_works() { #[test] fn kicking_works_only_for_authorized() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { let who = 40; let index = find_in_pool(who).expect("entity must be in pool") as u32; assert_noop!(ScoredPool::kick(Origin::signed(99), who, index), "bad origin"); @@ -117,7 +117,7 @@ fn kicking_works_only_for_authorized() { #[test] fn kicking_works() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { // given let who = 40; assert_eq!(Balances::reserved_balance(&who), CandidateDeposit::get()); @@ -137,7 +137,7 @@ fn kicking_works() { #[test] fn unscored_entities_must_not_be_used_for_filling_members() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { // given // we submit a candidacy, score will be `None` assert_ok!(ScoredPool::submit_candidacy(Origin::signed(15))); @@ -162,7 +162,7 @@ fn unscored_entities_must_not_be_used_for_filling_members() { #[test] fn refreshing_works() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { // given let who = 15; assert_ok!(ScoredPool::submit_candidacy(Origin::signed(who))); @@ -180,7 +180,7 @@ fn refreshing_works() { #[test] fn refreshing_happens_every_period() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { // given System::set_block_number(1); assert_ok!(ScoredPool::submit_candidacy(Origin::signed(15))); @@ -200,7 +200,7 @@ fn refreshing_happens_every_period() { #[test] fn withdraw_candidacy_must_only_work_for_members() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { let who = 77; let index = 0; assert_noop!( ScoredPool::withdraw_candidacy(Origin::signed(who), index), INDEX_ERR); @@ -209,7 +209,7 @@ fn withdraw_candidacy_must_only_work_for_members() { #[test] fn oob_index_should_abort() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { let who = 40; let oob_index = ScoredPool::pool().len() as u32; assert_noop!(ScoredPool::withdraw_candidacy(Origin::signed(who), oob_index), OOB_ERR); @@ -220,7 +220,7 @@ fn oob_index_should_abort() { #[test] fn index_mismatches_should_abort() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { let who = 40; let index = 3; assert_noop!(ScoredPool::withdraw_candidacy(Origin::signed(who), index), INDEX_ERR); @@ -231,7 +231,7 @@ fn index_mismatches_should_abort() { #[test] fn withdraw_unscored_candidacy_must_work() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { // given let who = 5; @@ -246,7 +246,7 @@ fn withdraw_unscored_candidacy_must_work() { #[test] fn withdraw_scored_candidacy_must_work() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { // given let who = 40; assert_eq!(Balances::reserved_balance(&who), CandidateDeposit::get()); @@ -264,7 +264,7 @@ fn withdraw_scored_candidacy_must_work() { #[test] fn candidacy_resubmitting_works() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { // given let who = 15; diff --git a/srml/session/src/historical.rs b/srml/session/src/historical.rs index af9447eb7e..08e4a6ce31 100644 --- a/srml/session/src/historical.rs +++ b/srml/session/src/historical.rs @@ -313,9 +313,7 @@ impl> support::traits::KeyOwnerProofSystem<(KeyTypeId, mod tests { use super::*; use primitives::crypto::key_types::DUMMY; - use sr_primitives::{ - traits::OnInitialize, testing::UintAuthorityId, set_and_run_with_externalities, - }; + use sr_primitives::{traits::OnInitialize, testing::UintAuthorityId}; use crate::mock::{ NEXT_VALIDATORS, force_new_session, set_next_validators, Test, System, Session, @@ -336,7 +334,7 @@ mod tests { #[test] fn generated_proof_is_good() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { set_next_validators(vec![1, 2]); force_new_session(); @@ -377,7 +375,7 @@ mod tests { #[test] fn prune_up_to_works() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { for i in 1..101u64 { set_next_validators(vec![i]); force_new_session(); diff --git a/srml/session/src/lib.rs b/srml/session/src/lib.rs index df311f5081..bb14b0d8f4 100644 --- a/srml/session/src/lib.rs +++ b/srml/session/src/lib.rs @@ -681,9 +681,7 @@ mod tests { use super::*; use support::assert_ok; use primitives::crypto::key_types::DUMMY; - use sr_primitives::{ - traits::OnInitialize, set_and_run_with_externalities, testing::UintAuthorityId, - }; + use sr_primitives::{traits::OnInitialize, testing::UintAuthorityId}; use mock::{ NEXT_VALIDATORS, SESSION_CHANGED, TEST_SESSION_CHANGED, authorities, force_new_session, set_next_validators, set_session_length, session_changed, Test, Origin, System, Session, @@ -708,7 +706,7 @@ mod tests { #[test] fn simple_setup_should_work() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { assert_eq!(authorities(), vec![UintAuthorityId(1), UintAuthorityId(2), UintAuthorityId(3)]); assert_eq!(Session::validators(), vec![1, 2, 3]); }); @@ -716,7 +714,7 @@ mod tests { #[test] fn put_get_keys() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { Session::put_keys(&10, &UintAuthorityId(10).into()); assert_eq!(Session::load_keys(&10), Some(UintAuthorityId(10).into())); }) @@ -725,7 +723,7 @@ mod tests { #[test] fn keys_cleared_on_kill() { let mut ext = new_test_ext(); - set_and_run_with_externalities(&mut ext, || { + ext.execute_with(|| { assert_eq!(Session::validators(), vec![1, 2, 3]); assert_eq!(Session::load_keys(&1), Some(UintAuthorityId(1).into())); @@ -742,7 +740,7 @@ mod tests { fn authorities_should_track_validators() { reset_before_session_end_called(); - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { set_next_validators(vec![1, 2]); force_new_session(); initialize_block(1); @@ -793,7 +791,7 @@ mod tests { #[test] fn should_work_with_early_exit() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { set_session_length(10); initialize_block(1); @@ -816,7 +814,7 @@ mod tests { #[test] fn session_change_should_work() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { // Block 1: No change initialize_block(1); assert_eq!(authorities(), vec![UintAuthorityId(1), UintAuthorityId(2), UintAuthorityId(3)]); @@ -846,7 +844,7 @@ mod tests { #[test] fn duplicates_are_not_allowed() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { System::set_block_number(1); Session::on_initialize(1); assert!(Session::set_keys(Origin::signed(4), UintAuthorityId(1).into(), vec![]).is_err()); @@ -861,7 +859,7 @@ mod tests { fn session_changed_flag_works() { reset_before_session_end_called(); - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { TEST_SESSION_CHANGED.with(|l| *l.borrow_mut() = true); force_new_session(); @@ -950,7 +948,7 @@ mod tests { #[test] fn session_keys_generate_output_works_as_set_keys_input() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { let new_keys = mock::MockSessionKeys::generate(None); assert_ok!( Session::set_keys( @@ -964,7 +962,7 @@ mod tests { #[test] fn return_true_if_more_than_third_is_disabled() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { set_next_validators(vec![1, 2, 3, 4, 5, 6, 7]); force_new_session(); initialize_block(1); @@ -977,6 +975,5 @@ mod tests { assert_eq!(Session::disable_index(2), true); assert_eq!(Session::disable_index(3), true); }); - } } diff --git a/srml/staking/src/mock.rs b/srml/staking/src/mock.rs index 9055d7db87..43bd00e3e0 100644 --- a/srml/staking/src/mock.rs +++ b/srml/staking/src/mock.rs @@ -340,8 +340,8 @@ impl ExtBuilder { keys: validators.iter().map(|x| (*x, UintAuthorityId(*x))).collect(), }.assimilate_storage(&mut storage); - let mut ext = storage.into(); - sr_primitives::set_and_run_with_externalities(&mut ext, || { + let mut ext = runtime_io::TestExternalities::from(storage); + ext.execute_with(|| { let validators = Session::validators(); SESSION.with(|x| *x.borrow_mut() = (validators.clone(), HashSet::new()) diff --git a/srml/staking/src/tests.rs b/srml/staking/src/tests.rs index 48218f9eb7..ca462b640b 100644 --- a/srml/staking/src/tests.rs +++ b/srml/staking/src/tests.rs @@ -18,16 +18,14 @@ use super::*; use mock::*; -use sr_primitives::{assert_eq_error_rate, traits::OnInitialize, set_and_run_with_externalities}; +use sr_primitives::{assert_eq_error_rate, traits::OnInitialize}; use sr_staking_primitives::offence::{OffenceDetails, OnOffenceHandler}; use support::{assert_ok, assert_noop, assert_eq_uvec, traits::{Currency, ReservableCurrency}}; #[test] fn basic_setup_works() { // Verifies initial conditions of mock - set_and_run_with_externalities(&mut ExtBuilder::default() - .build(), - || { + ExtBuilder::default().build().execute_with(|| { // Account 11 is stashed and locked, and account 10 is the controller assert_eq!(Staking::bonded(&11), Some(10)); // Account 21 is stashed and locked, and account 20 is the controller @@ -107,8 +105,7 @@ fn basic_setup_works() { #[test] fn change_controller_works() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), - || { + ExtBuilder::default().build().execute_with(|| { assert_eq!(Staking::bonded(&11), Some(10)); assert!(>::enumerate().map(|(c, _)| c).collect::>().contains(&11)); @@ -134,10 +131,7 @@ fn rewards_should_work() { // * rewards get recorded per session // * rewards get paid per Era // * Check that nominators are also rewarded - set_and_run_with_externalities(&mut ExtBuilder::default() - .nominate(false) - .build(), - || { + ExtBuilder::default().nominate(false).build().execute_with(|| { // Init some balances let _ = Balances::make_free_balance_be(&2, 500); @@ -215,10 +209,7 @@ fn multi_era_reward_should_work() { // Should check that: // The value of current_session_reward is set at the end of each era, based on // slot_stake and session_reward. - set_and_run_with_externalities(&mut ExtBuilder::default() - .nominate(false) - .build(), - || { + ExtBuilder::default().nominate(false).build().execute_with(|| { let init_balance_10 = Balances::total_balance(&10); // Set payee to controller @@ -258,122 +249,122 @@ fn staking_should_work() { // * new validators can be added to the default set // * new ones will be chosen per era // * either one can unlock the stash and back-down from being a validator via `chill`ing. - set_and_run_with_externalities(&mut ExtBuilder::default() + ExtBuilder::default() .nominate(false) .fair(false) // to give 20 more staked value - .build(), - || { - Timestamp::set_timestamp(1); // Initialize time. + .build() + .execute_with(|| { + Timestamp::set_timestamp(1); // Initialize time. - // remember + compare this along with the test. - assert_eq_uvec!(validator_controllers(), vec![20, 10]); + // remember + compare this along with the test. + assert_eq_uvec!(validator_controllers(), vec![20, 10]); - // put some money in account that we'll use. - for i in 1..5 { let _ = Balances::make_free_balance_be(&i, 2000); } + // put some money in account that we'll use. + for i in 1..5 { let _ = Balances::make_free_balance_be(&i, 2000); } - // --- Block 1: - start_session(1); - // add a new candidate for being a validator. account 3 controlled by 4. - assert_ok!(Staking::bond(Origin::signed(3), 4, 1500, RewardDestination::Controller)); - assert_ok!(Staking::validate(Origin::signed(4), ValidatorPrefs::default())); + // --- Block 1: + start_session(1); + // add a new candidate for being a validator. account 3 controlled by 4. + assert_ok!(Staking::bond(Origin::signed(3), 4, 1500, RewardDestination::Controller)); + assert_ok!(Staking::validate(Origin::signed(4), ValidatorPrefs::default())); - // No effects will be seen so far. - assert_eq_uvec!(validator_controllers(), vec![20, 10]); + // No effects will be seen so far. + assert_eq_uvec!(validator_controllers(), vec![20, 10]); - // --- Block 2: - start_session(2); + // --- Block 2: + start_session(2); - // No effects will be seen so far. Era has not been yet triggered. - assert_eq_uvec!(validator_controllers(), vec![20, 10]); + // No effects will be seen so far. Era has not been yet triggered. + assert_eq_uvec!(validator_controllers(), vec![20, 10]); - // --- Block 3: the validators will now be queued. - start_session(3); - assert_eq!(Staking::current_era(), 1); + // --- Block 3: the validators will now be queued. + start_session(3); + assert_eq!(Staking::current_era(), 1); - // --- Block 4: the validators will now be changed. - start_session(4); + // --- Block 4: the validators will now be changed. + start_session(4); - assert_eq_uvec!(validator_controllers(), vec![20, 4]); - // --- Block 4: Unstake 4 as a validator, freeing up the balance stashed in 3 - // 4 will chill - Staking::chill(Origin::signed(4)).unwrap(); + assert_eq_uvec!(validator_controllers(), vec![20, 4]); + // --- Block 4: Unstake 4 as a validator, freeing up the balance stashed in 3 + // 4 will chill + Staking::chill(Origin::signed(4)).unwrap(); - // --- Block 5: nothing. 4 is still there. - start_session(5); - assert_eq_uvec!(validator_controllers(), vec![20, 4]); + // --- Block 5: nothing. 4 is still there. + start_session(5); + assert_eq_uvec!(validator_controllers(), vec![20, 4]); - // --- Block 6: 4 will not be a validator. - start_session(7); - assert_eq_uvec!(validator_controllers(), vec![20, 10]); + // --- Block 6: 4 will not be a validator. + start_session(7); + assert_eq_uvec!(validator_controllers(), vec![20, 10]); - // Note: the stashed value of 4 is still lock - assert_eq!( - Staking::ledger(&4), - Some(StakingLedger { stash: 3, total: 1500, active: 1500, unlocking: vec![] }) - ); - // e.g. it cannot spend more than 500 that it has free from the total 2000 - assert_noop!(Balances::reserve(&3, 501), "account liquidity restrictions prevent withdrawal"); - assert_ok!(Balances::reserve(&3, 409)); - }); + // Note: the stashed value of 4 is still lock + assert_eq!( + Staking::ledger(&4), + Some(StakingLedger { stash: 3, total: 1500, active: 1500, unlocking: vec![] }) + ); + // e.g. it cannot spend more than 500 that it has free from the total 2000 + assert_noop!(Balances::reserve(&3, 501), "account liquidity restrictions prevent withdrawal"); + assert_ok!(Balances::reserve(&3, 409)); + }); } #[test] fn less_than_needed_candidates_works() { - set_and_run_with_externalities(&mut ExtBuilder::default() + ExtBuilder::default() .minimum_validator_count(1) .validator_count(4) .nominate(false) .num_validators(3) - .build(), - || { - assert_eq!(Staking::validator_count(), 4); - assert_eq!(Staking::minimum_validator_count(), 1); - assert_eq_uvec!(validator_controllers(), vec![30, 20, 10]); - - start_era(1); - - // Previous set is selected. NO election algorithm is even executed. - assert_eq_uvec!(validator_controllers(), vec![30, 20, 10]); - - // But the exposure is updated in a simple way. No external votes exists. This is purely self-vote. - assert_eq!(Staking::stakers(10).others.len(), 0); - assert_eq!(Staking::stakers(20).others.len(), 0); - assert_eq!(Staking::stakers(30).others.len(), 0); - check_exposure_all(); - check_nominator_all(); - }); + .build() + .execute_with(|| { + assert_eq!(Staking::validator_count(), 4); + assert_eq!(Staking::minimum_validator_count(), 1); + assert_eq_uvec!(validator_controllers(), vec![30, 20, 10]); + + start_era(1); + + // Previous set is selected. NO election algorithm is even executed. + assert_eq_uvec!(validator_controllers(), vec![30, 20, 10]); + + // But the exposure is updated in a simple way. No external votes exists. + // This is purely self-vote. + assert_eq!(Staking::stakers(10).others.len(), 0); + assert_eq!(Staking::stakers(20).others.len(), 0); + assert_eq!(Staking::stakers(30).others.len(), 0); + check_exposure_all(); + check_nominator_all(); + }); } #[test] fn no_candidate_emergency_condition() { - set_and_run_with_externalities(&mut ExtBuilder::default() + ExtBuilder::default() .minimum_validator_count(10) .validator_count(15) .num_validators(4) .validator_pool(true) .nominate(false) - .build(), - || { - - // initial validators - assert_eq_uvec!(validator_controllers(), vec![10, 20, 30, 40]); + .build() + .execute_with(|| { + // initial validators + assert_eq_uvec!(validator_controllers(), vec![10, 20, 30, 40]); - // set the minimum validator count. - ::MinimumValidatorCount::put(10); - ::ValidatorCount::put(15); - assert_eq!(Staking::validator_count(), 15); + // set the minimum validator count. + ::MinimumValidatorCount::put(10); + ::ValidatorCount::put(15); + assert_eq!(Staking::validator_count(), 15); - let _ = Staking::chill(Origin::signed(10)); + let _ = Staking::chill(Origin::signed(10)); - // trigger era - System::set_block_number(1); - Session::on_initialize(System::block_number()); + // trigger era + System::set_block_number(1); + Session::on_initialize(System::block_number()); - // Previous ones are elected. chill is invalidates. TODO: #2494 - assert_eq_uvec!(validator_controllers(), vec![10, 20, 30, 40]); - assert_eq!(Staking::current_elected().len(), 0); - }); + // Previous ones are elected. chill is invalidates. TODO: #2494 + assert_eq_uvec!(validator_controllers(), vec![10, 20, 30, 40]); + assert_eq!(Staking::current_elected().len(), 0); + }); } #[test] @@ -413,181 +404,181 @@ fn nominating_and_rewards_should_work() { // 10 with stake 400.0 20 with stake 600.0 30 with stake 0 // 4 has load 0.0005555555555555556 and supported // 10 with stake 600.0 20 with stake 400.0 40 with stake 0.0 - set_and_run_with_externalities(&mut ExtBuilder::default() + ExtBuilder::default() .nominate(false) .validator_pool(true) - .build(), - || { - // initial validators -- everyone is actually even. - assert_eq_uvec!(validator_controllers(), vec![40, 30]); - - // Set payee to controller - assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Controller)); - assert_ok!(Staking::set_payee(Origin::signed(20), RewardDestination::Controller)); - assert_ok!(Staking::set_payee(Origin::signed(30), RewardDestination::Controller)); - assert_ok!(Staking::set_payee(Origin::signed(40), RewardDestination::Controller)); - - // give the man some money - let initial_balance = 1000; - for i in [1, 2, 3, 4, 5, 10, 11, 20, 21].iter() { - let _ = Balances::make_free_balance_be(i, initial_balance); - } - - // bond two account pairs and state interest in nomination. - // 2 will nominate for 10, 20, 30 - assert_ok!(Staking::bond(Origin::signed(1), 2, 1000, RewardDestination::Controller)); - assert_ok!(Staking::nominate(Origin::signed(2), vec![11, 21, 31])); - // 4 will nominate for 10, 20, 40 - assert_ok!(Staking::bond(Origin::signed(3), 4, 1000, RewardDestination::Controller)); - assert_ok!(Staking::nominate(Origin::signed(4), vec![11, 21, 41])); - - // the total reward for era 0 - let total_payout_0 = current_total_payout_for_duration(3000); - assert!(total_payout_0 > 100); // Test is meaningfull if reward something - >::reward_by_ids(vec![(41, 1)]); - >::reward_by_ids(vec![(31, 1)]); - >::reward_by_ids(vec![(21, 10)]); // must be no-op - >::reward_by_ids(vec![(11, 10)]); // must be no-op - - start_era(1); - - // 10 and 20 have more votes, they will be chosen by phragmen. - assert_eq_uvec!(validator_controllers(), vec![20, 10]); - - // OLD validators must have already received some rewards. - assert_eq!(Balances::total_balance(&40), 1 + total_payout_0 / 2); - assert_eq!(Balances::total_balance(&30), 1 + total_payout_0 / 2); - - // ------ check the staked value of all parties. - - if cfg!(feature = "equalize") { - // total expo of 10, with 1200 coming from nominators (externals), according to phragmen. - assert_eq!(Staking::stakers(11).own, 1000); - assert_eq_error_rate!(Staking::stakers(11).total, 1000 + 1000, 2); - // 2 and 4 supported 10, each with stake 600, according to phragmen. - assert_eq!( - Staking::stakers(11).others.iter().map(|e| e.value).collect::>>(), - vec![600, 400] - ); - assert_eq!( - Staking::stakers(11).others.iter().map(|e| e.who).collect::>(), - vec![3, 1] - ); - // total expo of 20, with 500 coming from nominators (externals), according to phragmen. - assert_eq!(Staking::stakers(21).own, 1000); - assert_eq_error_rate!(Staking::stakers(21).total, 1000 + 1000, 2); - // 2 and 4 supported 20, each with stake 250, according to phragmen. - assert_eq!( - Staking::stakers(21).others.iter().map(|e| e.value).collect::>>(), - vec![400, 600] - ); - assert_eq!( - Staking::stakers(21).others.iter().map(|e| e.who).collect::>(), - vec![3, 1] - ); - } else { - // total expo of 10, with 1200 coming from nominators (externals), according to phragmen. - assert_eq!(Staking::stakers(11).own, 1000); - assert_eq!(Staking::stakers(11).total, 1000 + 800); - // 2 and 4 supported 10, each with stake 600, according to phragmen. - assert_eq!( - Staking::stakers(11).others.iter().map(|e| e.value).collect::>>(), - vec![400, 400] - ); - assert_eq!( - Staking::stakers(11).others.iter().map(|e| e.who).collect::>(), - vec![3, 1] - ); - // total expo of 20, with 500 coming from nominators (externals), according to phragmen. - assert_eq!(Staking::stakers(21).own, 1000); - assert_eq_error_rate!(Staking::stakers(21).total, 1000 + 1200, 2); - // 2 and 4 supported 20, each with stake 250, according to phragmen. - assert_eq!( - Staking::stakers(21).others.iter().map(|e| e.value).collect::>>(), - vec![600, 600] - ); - assert_eq!( - Staking::stakers(21).others.iter().map(|e| e.who).collect::>(), - vec![3, 1] - ); - } - - // They are not chosen anymore - assert_eq!(Staking::stakers(31).total, 0); - assert_eq!(Staking::stakers(41).total, 0); - - // the total reward for era 1 - let total_payout_1 = current_total_payout_for_duration(3000); - assert!(total_payout_1 > 100); // Test is meaningfull if reward something - >::reward_by_ids(vec![(41, 10)]); // must be no-op - >::reward_by_ids(vec![(31, 10)]); // must be no-op - >::reward_by_ids(vec![(21, 2)]); - >::reward_by_ids(vec![(11, 1)]); - - start_era(2); - - // nothing else will happen, era ends and rewards are paid again, - // it is expected that nominators will also be paid. See below - - let payout_for_10 = total_payout_1 / 3; - let payout_for_20 = 2 * total_payout_1 / 3; - if cfg!(feature = "equalize") { - // Nominator 2: has [400 / 2000 ~ 1 / 5 from 10] + [600 / 2000 ~ 3 / 10 from 20]'s reward. - assert_eq_error_rate!( - Balances::total_balance(&2), - initial_balance + payout_for_10 / 5 + payout_for_20 * 3 / 10, - 2, - ); - // Nominator 4: has [400 / 2000 ~ 1 / 5 from 20] + [600 / 2000 ~ 3 / 10 from 10]'s reward. - assert_eq_error_rate!( - Balances::total_balance(&4), - initial_balance + payout_for_20 / 5 + payout_for_10 * 3 / 10, - 2, - ); - - // Validator 10: got 1000 / 2000 external stake. - assert_eq_error_rate!( - Balances::total_balance(&10), - initial_balance + payout_for_10 / 2, - 1, - ); - // Validator 20: got 1000 / 2000 external stake. - assert_eq_error_rate!( - Balances::total_balance(&20), - initial_balance + payout_for_20 / 2, - 1, - ); - } else { - // Nominator 2: has [400/1800 ~ 2/9 from 10] + [600/2200 ~ 3/11 from 20]'s reward. ==> 2/9 + 3/11 - assert_eq_error_rate!( - Balances::total_balance(&2), - initial_balance + (2 * payout_for_10 / 9 + 3 * payout_for_20 / 11), - 1, - ); - // Nominator 4: has [400/1800 ~ 2/9 from 10] + [600/2200 ~ 3/11 from 20]'s reward. ==> 2/9 + 3/11 - assert_eq_error_rate!( - Balances::total_balance(&4), - initial_balance + (2 * payout_for_10 / 9 + 3 * payout_for_20 / 11), - 1, - ); - - // Validator 10: got 800 / 1800 external stake => 8/18 =? 4/9 => Validator's share = 5/9 - assert_eq_error_rate!( - Balances::total_balance(&10), - initial_balance + 5 * payout_for_10 / 9, - 1, - ); - // Validator 20: got 1200 / 2200 external stake => 12/22 =? 6/11 => Validator's share = 5/11 - assert_eq_error_rate!( - Balances::total_balance(&20), - initial_balance + 5 * payout_for_20 / 11, - 1, - ); - } - - check_exposure_all(); - check_nominator_all(); - }); + .build() + .execute_with(|| { + // initial validators -- everyone is actually even. + assert_eq_uvec!(validator_controllers(), vec![40, 30]); + + // Set payee to controller + assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Controller)); + assert_ok!(Staking::set_payee(Origin::signed(20), RewardDestination::Controller)); + assert_ok!(Staking::set_payee(Origin::signed(30), RewardDestination::Controller)); + assert_ok!(Staking::set_payee(Origin::signed(40), RewardDestination::Controller)); + + // give the man some money + let initial_balance = 1000; + for i in [1, 2, 3, 4, 5, 10, 11, 20, 21].iter() { + let _ = Balances::make_free_balance_be(i, initial_balance); + } + + // bond two account pairs and state interest in nomination. + // 2 will nominate for 10, 20, 30 + assert_ok!(Staking::bond(Origin::signed(1), 2, 1000, RewardDestination::Controller)); + assert_ok!(Staking::nominate(Origin::signed(2), vec![11, 21, 31])); + // 4 will nominate for 10, 20, 40 + assert_ok!(Staking::bond(Origin::signed(3), 4, 1000, RewardDestination::Controller)); + assert_ok!(Staking::nominate(Origin::signed(4), vec![11, 21, 41])); + + // the total reward for era 0 + let total_payout_0 = current_total_payout_for_duration(3000); + assert!(total_payout_0 > 100); // Test is meaningfull if reward something + >::reward_by_ids(vec![(41, 1)]); + >::reward_by_ids(vec![(31, 1)]); + >::reward_by_ids(vec![(21, 10)]); // must be no-op + >::reward_by_ids(vec![(11, 10)]); // must be no-op + + start_era(1); + + // 10 and 20 have more votes, they will be chosen by phragmen. + assert_eq_uvec!(validator_controllers(), vec![20, 10]); + + // OLD validators must have already received some rewards. + assert_eq!(Balances::total_balance(&40), 1 + total_payout_0 / 2); + assert_eq!(Balances::total_balance(&30), 1 + total_payout_0 / 2); + + // ------ check the staked value of all parties. + + if cfg!(feature = "equalize") { + // total expo of 10, with 1200 coming from nominators (externals), according to phragmen. + assert_eq!(Staking::stakers(11).own, 1000); + assert_eq_error_rate!(Staking::stakers(11).total, 1000 + 1000, 2); + // 2 and 4 supported 10, each with stake 600, according to phragmen. + assert_eq!( + Staking::stakers(11).others.iter().map(|e| e.value).collect::>>(), + vec![600, 400] + ); + assert_eq!( + Staking::stakers(11).others.iter().map(|e| e.who).collect::>(), + vec![3, 1] + ); + // total expo of 20, with 500 coming from nominators (externals), according to phragmen. + assert_eq!(Staking::stakers(21).own, 1000); + assert_eq_error_rate!(Staking::stakers(21).total, 1000 + 1000, 2); + // 2 and 4 supported 20, each with stake 250, according to phragmen. + assert_eq!( + Staking::stakers(21).others.iter().map(|e| e.value).collect::>>(), + vec![400, 600] + ); + assert_eq!( + Staking::stakers(21).others.iter().map(|e| e.who).collect::>(), + vec![3, 1] + ); + } else { + // total expo of 10, with 1200 coming from nominators (externals), according to phragmen. + assert_eq!(Staking::stakers(11).own, 1000); + assert_eq!(Staking::stakers(11).total, 1000 + 800); + // 2 and 4 supported 10, each with stake 600, according to phragmen. + assert_eq!( + Staking::stakers(11).others.iter().map(|e| e.value).collect::>>(), + vec![400, 400] + ); + assert_eq!( + Staking::stakers(11).others.iter().map(|e| e.who).collect::>(), + vec![3, 1] + ); + // total expo of 20, with 500 coming from nominators (externals), according to phragmen. + assert_eq!(Staking::stakers(21).own, 1000); + assert_eq_error_rate!(Staking::stakers(21).total, 1000 + 1200, 2); + // 2 and 4 supported 20, each with stake 250, according to phragmen. + assert_eq!( + Staking::stakers(21).others.iter().map(|e| e.value).collect::>>(), + vec![600, 600] + ); + assert_eq!( + Staking::stakers(21).others.iter().map(|e| e.who).collect::>(), + vec![3, 1] + ); + } + + // They are not chosen anymore + assert_eq!(Staking::stakers(31).total, 0); + assert_eq!(Staking::stakers(41).total, 0); + + // the total reward for era 1 + let total_payout_1 = current_total_payout_for_duration(3000); + assert!(total_payout_1 > 100); // Test is meaningfull if reward something + >::reward_by_ids(vec![(41, 10)]); // must be no-op + >::reward_by_ids(vec![(31, 10)]); // must be no-op + >::reward_by_ids(vec![(21, 2)]); + >::reward_by_ids(vec![(11, 1)]); + + start_era(2); + + // nothing else will happen, era ends and rewards are paid again, + // it is expected that nominators will also be paid. See below + + let payout_for_10 = total_payout_1 / 3; + let payout_for_20 = 2 * total_payout_1 / 3; + if cfg!(feature = "equalize") { + // Nominator 2: has [400 / 2000 ~ 1 / 5 from 10] + [600 / 2000 ~ 3 / 10 from 20]'s reward. + assert_eq_error_rate!( + Balances::total_balance(&2), + initial_balance + payout_for_10 / 5 + payout_for_20 * 3 / 10, + 2, + ); + // Nominator 4: has [400 / 2000 ~ 1 / 5 from 20] + [600 / 2000 ~ 3 / 10 from 10]'s reward. + assert_eq_error_rate!( + Balances::total_balance(&4), + initial_balance + payout_for_20 / 5 + payout_for_10 * 3 / 10, + 2, + ); + + // Validator 10: got 1000 / 2000 external stake. + assert_eq_error_rate!( + Balances::total_balance(&10), + initial_balance + payout_for_10 / 2, + 1, + ); + // Validator 20: got 1000 / 2000 external stake. + assert_eq_error_rate!( + Balances::total_balance(&20), + initial_balance + payout_for_20 / 2, + 1, + ); + } else { + // Nominator 2: has [400/1800 ~ 2/9 from 10] + [600/2200 ~ 3/11 from 20]'s reward. ==> 2/9 + 3/11 + assert_eq_error_rate!( + Balances::total_balance(&2), + initial_balance + (2 * payout_for_10 / 9 + 3 * payout_for_20 / 11), + 1, + ); + // Nominator 4: has [400/1800 ~ 2/9 from 10] + [600/2200 ~ 3/11 from 20]'s reward. ==> 2/9 + 3/11 + assert_eq_error_rate!( + Balances::total_balance(&4), + initial_balance + (2 * payout_for_10 / 9 + 3 * payout_for_20 / 11), + 1, + ); + + // Validator 10: got 800 / 1800 external stake => 8/18 =? 4/9 => Validator's share = 5/9 + assert_eq_error_rate!( + Balances::total_balance(&10), + initial_balance + 5 * payout_for_10 / 9, + 1, + ); + // Validator 20: got 1200 / 2200 external stake => 12/22 =? 6/11 => Validator's share = 5/11 + assert_eq_error_rate!( + Balances::total_balance(&20), + initial_balance + 5 * payout_for_20 / 11, + 1, + ); + } + + check_exposure_all(); + check_nominator_all(); + }); } #[test] @@ -597,7 +588,7 @@ fn nominators_also_get_slashed() { // 10 - is the controller of 11 // 11 - is the stash. // 2 - is the nominator of 20, 10 - set_and_run_with_externalities(&mut ExtBuilder::default().nominate(false).build(), || { + ExtBuilder::default().nominate(false).build().execute_with(|| { assert_eq!(Staking::validator_count(), 2); // Set payee to controller @@ -657,53 +648,49 @@ fn double_staking_should_fail() { // * an account already bonded as stash cannot be be stashed again. // * an account already bonded as stash cannot nominate. // * an account already bonded as controller can nominate. - set_and_run_with_externalities(&mut ExtBuilder::default() - .build(), - || { - let arbitrary_value = 5; - // 2 = controller, 1 stashed => ok - assert_ok!( - Staking::bond(Origin::signed(1), 2, arbitrary_value, - RewardDestination::default()) - ); - // 4 = not used so far, 1 stashed => not allowed. - assert_noop!( - Staking::bond(Origin::signed(1), 4, arbitrary_value, - RewardDestination::default()), "stash already bonded" - ); - // 1 = stashed => attempting to nominate should fail. - assert_noop!(Staking::nominate(Origin::signed(1), vec![1]), "not a controller"); - // 2 = controller => nominating should work. - assert_ok!(Staking::nominate(Origin::signed(2), vec![1])); - }); + ExtBuilder::default().build().execute_with(|| { + let arbitrary_value = 5; + // 2 = controller, 1 stashed => ok + assert_ok!( + Staking::bond(Origin::signed(1), 2, arbitrary_value, + RewardDestination::default()) + ); + // 4 = not used so far, 1 stashed => not allowed. + assert_noop!( + Staking::bond(Origin::signed(1), 4, arbitrary_value, + RewardDestination::default()), "stash already bonded" + ); + // 1 = stashed => attempting to nominate should fail. + assert_noop!(Staking::nominate(Origin::signed(1), vec![1]), "not a controller"); + // 2 = controller => nominating should work. + assert_ok!(Staking::nominate(Origin::signed(2), vec![1])); + }); } #[test] fn double_controlling_should_fail() { // should test (in the same order): // * an account already bonded as controller CANNOT be reused as the controller of another account. - set_and_run_with_externalities(&mut ExtBuilder::default() - .build(), - || { - let arbitrary_value = 5; - // 2 = controller, 1 stashed => ok - assert_ok!( - Staking::bond(Origin::signed(1), 2, arbitrary_value, - RewardDestination::default()) - ); - // 2 = controller, 3 stashed (Note that 2 is reused.) => no-op - assert_noop!( - Staking::bond(Origin::signed(3), 2, arbitrary_value, RewardDestination::default()), - "controller already paired" - ); - }); + ExtBuilder::default().build().execute_with(|| { + let arbitrary_value = 5; + // 2 = controller, 1 stashed => ok + assert_ok!(Staking::bond( + Origin::signed(1), + 2, + arbitrary_value, + RewardDestination::default(), + )); + // 2 = controller, 3 stashed (Note that 2 is reused.) => no-op + assert_noop!( + Staking::bond(Origin::signed(3), 2, arbitrary_value, RewardDestination::default()), + "controller already paired", + ); + }); } #[test] fn session_and_eras_work() { - set_and_run_with_externalities(&mut ExtBuilder::default() - .build(), - || { + ExtBuilder::default().build().execute_with(|| { assert_eq!(Staking::current_era(), 0); // Block 1: No change. @@ -745,7 +732,7 @@ fn session_and_eras_work() { #[test] fn forcing_new_era_works() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(),|| { + ExtBuilder::default().build().execute_with(|| { // normal flow of session. assert_eq!(Staking::current_era(), 0); start_session(0); @@ -784,7 +771,7 @@ fn forcing_new_era_works() { #[test] fn cannot_transfer_staked_balance() { // Tests that a stash account cannot transfer funds - set_and_run_with_externalities(&mut ExtBuilder::default().nominate(false).build(), || { + ExtBuilder::default().nominate(false).build().execute_with(|| { // Confirm account 11 is stashed assert_eq!(Staking::bonded(&11), Some(10)); // Confirm account 11 has some free balance @@ -809,11 +796,7 @@ fn cannot_transfer_staked_balance_2() { // Tests that a stash account cannot transfer funds // Same test as above but with 20, and more accurate. // 21 has 2000 free balance but 1000 at stake - set_and_run_with_externalities(&mut ExtBuilder::default() - .nominate(false) - .fair(true) - .build(), - || { + ExtBuilder::default().nominate(false).fair(true).build().execute_with(|| { // Confirm account 21 is stashed assert_eq!(Staking::bonded(&21), Some(20)); // Confirm account 21 has some free balance @@ -832,7 +815,7 @@ fn cannot_transfer_staked_balance_2() { #[test] fn cannot_reserve_staked_balance() { // Checks that a bonded account cannot reserve balance from free balance - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { // Confirm account 11 is stashed assert_eq!(Staking::bonded(&11), Some(10)); // Confirm account 11 has some free balance @@ -852,7 +835,7 @@ fn cannot_reserve_staked_balance() { #[test] fn reward_destination_works() { // Rewards go to the correct destination as determined in Payee - set_and_run_with_externalities(&mut ExtBuilder::default().nominate(false).build(), || { + ExtBuilder::default().nominate(false).build().execute_with(|| { // Check that account 11 is a validator assert!(Staking::current_elected().contains(&11)); // Check the balance of the validator account @@ -944,9 +927,7 @@ fn validator_payment_prefs_work() { // Test that validator preferences are correctly honored // Note: unstake threshold is being directly tested in slashing tests. // This test will focus on validator payment. - set_and_run_with_externalities(&mut ExtBuilder::default() - .build(), - || { + ExtBuilder::default().build().execute_with(|| { // Initial config let validator_cut = 5; let stash_initial_balance = Balances::total_balance(&11); @@ -996,8 +977,7 @@ fn bond_extra_works() { // Tests that extra `free_balance` in the stash can be added to stake // NOTE: this tests only verifies `StakingLedger` for correct updates // See `bond_extra_and_withdraw_unbonded_works` for more details and updates on `Exposure`. - set_and_run_with_externalities(&mut ExtBuilder::default().build(), - || { + ExtBuilder::default().build().execute_with(|| { // Check that account 10 is a validator assert!(>::exists(11)); // Check that account 10 is bonded to account 11 @@ -1042,10 +1022,7 @@ fn bond_extra_and_withdraw_unbonded_works() { // * It can add extra funds to the bonded account. // * it can unbond a portion of its funds from the stash account. // * Once the unbonding period is done, it can actually take the funds out of the stash. - set_and_run_with_externalities(&mut ExtBuilder::default() - .nominate(false) - .build(), - || { + ExtBuilder::default().nominate(false).build().execute_with(|| { // Set payee to controller. avoids confusion assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Controller)); @@ -1129,7 +1106,7 @@ fn bond_extra_and_withdraw_unbonded_works() { #[test] fn too_many_unbond_calls_should_not_work() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { // locked at era 0 until 3 for _ in 0..MAX_UNLOCKING_CHUNKS-1 { assert_ok!(Staking::unbond(Origin::signed(10), 1)); @@ -1158,11 +1135,7 @@ fn too_many_unbond_calls_should_not_work() { fn slot_stake_is_least_staked_validator_and_exposure_defines_maximum_punishment() { // Test that slot_stake is determined by the least staked validator // Test that slot_stake is the maximum punishment that can happen to a validator - set_and_run_with_externalities(&mut ExtBuilder::default() - .nominate(false) - .fair(false) - .build(), - || { + ExtBuilder::default().nominate(false).fair(false).build().execute_with(|| { // Confirm validator count is 2 assert_eq!(Staking::validator_count(), 2); // Confirm account 10 and 20 are validators @@ -1211,10 +1184,7 @@ fn slot_stake_is_least_staked_validator_and_exposure_defines_maximum_punishment( fn on_free_balance_zero_stash_removes_validator() { // Tests that validator storage items are cleaned up when stash is empty // Tests that storage items are untouched when controller is empty - set_and_run_with_externalities(&mut ExtBuilder::default() - .existential_deposit(10) - .build(), - || { + ExtBuilder::default().existential_deposit(10).build().execute_with(|| { // Check the balance of the validator account assert_eq!(Balances::free_balance(&10), 256); // Check the balance of the stash account @@ -1264,10 +1234,7 @@ fn on_free_balance_zero_stash_removes_validator() { fn on_free_balance_zero_stash_removes_nominator() { // Tests that nominator storage items are cleaned up when stash is empty // Tests that storage items are untouched when controller is empty - set_and_run_with_externalities(&mut ExtBuilder::default() - .existential_deposit(10) - .build(), - || { + ExtBuilder::default().existential_deposit(10).build().execute_with(|| { // Make 10 a nominator assert_ok!(Staking::nominate(Origin::signed(10), vec![20])); // Check that account 10 is a nominator @@ -1320,10 +1287,7 @@ fn on_free_balance_zero_stash_removes_nominator() { #[test] fn switching_roles() { // Test that it should be possible to switch between roles (nominator, validator, idle) with minimal overhead. - set_and_run_with_externalities(&mut ExtBuilder::default() - .nominate(false) - .build(), - || { + ExtBuilder::default().nominate(false).build().execute_with(|| { Timestamp::set_timestamp(1); // Initialize time. // Reset reward destination @@ -1389,11 +1353,7 @@ fn switching_roles() { #[test] fn wrong_vote_is_null() { - set_and_run_with_externalities(&mut ExtBuilder::default() - .nominate(false) - .validator_pool(true) - .build(), - || { + ExtBuilder::default().nominate(false).validator_pool(true).build().execute_with(|| { assert_eq_uvec!(validator_controllers(), vec![40, 30]); // put some money in account that we'll use. @@ -1417,174 +1377,173 @@ fn wrong_vote_is_null() { fn bond_with_no_staked_value() { // Behavior when someone bonds with no staked value. // Particularly when she votes and the candidate is elected. - set_and_run_with_externalities(&mut ExtBuilder::default() - .validator_count(3) - .existential_deposit(5) - .nominate(false) - .minimum_validator_count(1) - .build(), || { - // Can't bond with 1 - assert_noop!( - Staking::bond(Origin::signed(1), 2, 1, RewardDestination::Controller), - "can not bond with value less than minimum balance" - ); - // bonded with absolute minimum value possible. - assert_ok!(Staking::bond(Origin::signed(1), 2, 5, RewardDestination::Controller)); - assert_eq!(Balances::locks(&1)[0].amount, 5); + ExtBuilder::default() + .validator_count(3) + .existential_deposit(5) + .nominate(false) + .minimum_validator_count(1) + .build() + .execute_with(|| { + // Can't bond with 1 + assert_noop!( + Staking::bond(Origin::signed(1), 2, 1, RewardDestination::Controller), + "can not bond with value less than minimum balance", + ); + // bonded with absolute minimum value possible. + assert_ok!(Staking::bond(Origin::signed(1), 2, 5, RewardDestination::Controller)); + assert_eq!(Balances::locks(&1)[0].amount, 5); - // unbonding even 1 will cause all to be unbonded. - assert_ok!(Staking::unbond(Origin::signed(2), 1)); - assert_eq!( - Staking::ledger(2), - Some(StakingLedger { - stash: 1, - active: 0, - total: 5, - unlocking: vec![UnlockChunk {value: 5, era: 3}] - }) - ); + // unbonding even 1 will cause all to be unbonded. + assert_ok!(Staking::unbond(Origin::signed(2), 1)); + assert_eq!( + Staking::ledger(2), + Some(StakingLedger { + stash: 1, + active: 0, + total: 5, + unlocking: vec![UnlockChunk {value: 5, era: 3}] + }) + ); - start_era(1); - start_era(2); + start_era(1); + start_era(2); - // not yet removed. - assert_ok!(Staking::withdraw_unbonded(Origin::signed(2))); - assert!(Staking::ledger(2).is_some()); - assert_eq!(Balances::locks(&1)[0].amount, 5); + // not yet removed. + assert_ok!(Staking::withdraw_unbonded(Origin::signed(2))); + assert!(Staking::ledger(2).is_some()); + assert_eq!(Balances::locks(&1)[0].amount, 5); - start_era(3); + start_era(3); - // poof. Account 1 is removed from the staking system. - assert_ok!(Staking::withdraw_unbonded(Origin::signed(2))); - assert!(Staking::ledger(2).is_none()); - assert_eq!(Balances::locks(&1).len(), 0); - }); + // poof. Account 1 is removed from the staking system. + assert_ok!(Staking::withdraw_unbonded(Origin::signed(2))); + assert!(Staking::ledger(2).is_none()); + assert_eq!(Balances::locks(&1).len(), 0); + }); } #[test] fn bond_with_little_staked_value_bounded_by_slot_stake() { // Behavior when someone bonds with little staked value. // Particularly when she votes and the candidate is elected. - set_and_run_with_externalities(&mut ExtBuilder::default() + ExtBuilder::default() .validator_count(3) .nominate(false) .minimum_validator_count(1) - .build(), - || { - - // setup - assert_ok!(Staking::chill(Origin::signed(30))); - assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Controller)); - let init_balance_2 = Balances::free_balance(&2); - let init_balance_10 = Balances::free_balance(&10); - - // Stingy validator. - assert_ok!(Staking::bond(Origin::signed(1), 2, 1, RewardDestination::Controller)); - assert_ok!(Staking::validate(Origin::signed(2), ValidatorPrefs::default())); - - let total_payout_0 = current_total_payout_for_duration(3000); - assert!(total_payout_0 > 100); // Test is meaningfull if reward something - reward_all_elected(); - start_era(1); - - // 2 is elected. - // and fucks up the slot stake. - assert_eq_uvec!(validator_controllers(), vec![20, 10, 2]); - assert_eq!(Staking::slot_stake(), 1); - - // Old ones are rewarded. - assert_eq!(Balances::free_balance(&10), init_balance_10 + total_payout_0 / 3); - // no rewards paid to 2. This was initial election. - assert_eq!(Balances::free_balance(&2), init_balance_2); - - let total_payout_1 = current_total_payout_for_duration(3000); - assert!(total_payout_1 > 100); // Test is meaningfull if reward something - reward_all_elected(); - start_era(2); - - assert_eq_uvec!(validator_controllers(), vec![20, 10, 2]); - assert_eq!(Staking::slot_stake(), 1); - - assert_eq!(Balances::free_balance(&2), init_balance_2 + total_payout_1 / 3); - assert_eq!(Balances::free_balance(&10), init_balance_10 + total_payout_0 / 3 + total_payout_1 / 3); - check_exposure_all(); - check_nominator_all(); - }); + .build() + .execute_with(|| { + // setup + assert_ok!(Staking::chill(Origin::signed(30))); + assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Controller)); + let init_balance_2 = Balances::free_balance(&2); + let init_balance_10 = Balances::free_balance(&10); + + // Stingy validator. + assert_ok!(Staking::bond(Origin::signed(1), 2, 1, RewardDestination::Controller)); + assert_ok!(Staking::validate(Origin::signed(2), ValidatorPrefs::default())); + + let total_payout_0 = current_total_payout_for_duration(3000); + assert!(total_payout_0 > 100); // Test is meaningfull if reward something + reward_all_elected(); + start_era(1); + + // 2 is elected. + // and fucks up the slot stake. + assert_eq_uvec!(validator_controllers(), vec![20, 10, 2]); + assert_eq!(Staking::slot_stake(), 1); + + // Old ones are rewarded. + assert_eq!(Balances::free_balance(&10), init_balance_10 + total_payout_0 / 3); + // no rewards paid to 2. This was initial election. + assert_eq!(Balances::free_balance(&2), init_balance_2); + + let total_payout_1 = current_total_payout_for_duration(3000); + assert!(total_payout_1 > 100); // Test is meaningfull if reward something + reward_all_elected(); + start_era(2); + + assert_eq_uvec!(validator_controllers(), vec![20, 10, 2]); + assert_eq!(Staking::slot_stake(), 1); + + assert_eq!(Balances::free_balance(&2), init_balance_2 + total_payout_1 / 3); + assert_eq!( + Balances::free_balance(&10), + init_balance_10 + total_payout_0 / 3 + total_payout_1 / 3, + ); + check_exposure_all(); + check_nominator_all(); + }); } #[cfg(feature = "equalize")] #[test] fn phragmen_linear_worse_case_equalize() { - set_and_run_with_externalities(&mut ExtBuilder::default() + ExtBuilder::default() .nominate(false) .validator_pool(true) .fair(true) - .build(), - || { - - bond_validator(50, 1000); - bond_validator(60, 1000); - bond_validator(70, 1000); - - bond_nominator(2, 2000, vec![11]); - bond_nominator(4, 1000, vec![11, 21]); - bond_nominator(6, 1000, vec![21, 31]); - bond_nominator(8, 1000, vec![31, 41]); - bond_nominator(110, 1000, vec![41, 51]); - bond_nominator(120, 1000, vec![51, 61]); - bond_nominator(130, 1000, vec![61, 71]); - - for i in &[10, 20, 30, 40, 50, 60, 70] { - assert_ok!(Staking::set_payee(Origin::signed(*i), RewardDestination::Controller)); - } - - assert_eq_uvec!(validator_controllers(), vec![40, 30]); - assert_ok!(Staking::set_validator_count(Origin::ROOT, 7)); - - start_era(1); - - assert_eq_uvec!(validator_controllers(), vec![10, 60, 40, 20, 50, 30, 70]); - - assert_eq_error_rate!(Staking::stakers(11).total, 3000, 2); - assert_eq_error_rate!(Staking::stakers(21).total, 2255, 2); - assert_eq_error_rate!(Staking::stakers(31).total, 2255, 2); - assert_eq_error_rate!(Staking::stakers(41).total, 1925, 2); - assert_eq_error_rate!(Staking::stakers(51).total, 1870, 2); - assert_eq_error_rate!(Staking::stakers(61).total, 1890, 2); - assert_eq_error_rate!(Staking::stakers(71).total, 1800, 2); - - check_exposure_all(); - check_nominator_all(); - }) + .build() + .execute_with(|| { + bond_validator(50, 1000); + bond_validator(60, 1000); + bond_validator(70, 1000); + + bond_nominator(2, 2000, vec![11]); + bond_nominator(4, 1000, vec![11, 21]); + bond_nominator(6, 1000, vec![21, 31]); + bond_nominator(8, 1000, vec![31, 41]); + bond_nominator(110, 1000, vec![41, 51]); + bond_nominator(120, 1000, vec![51, 61]); + bond_nominator(130, 1000, vec![61, 71]); + + for i in &[10, 20, 30, 40, 50, 60, 70] { + assert_ok!(Staking::set_payee(Origin::signed(*i), RewardDestination::Controller)); + } + + assert_eq_uvec!(validator_controllers(), vec![40, 30]); + assert_ok!(Staking::set_validator_count(Origin::ROOT, 7)); + + start_era(1); + + assert_eq_uvec!(validator_controllers(), vec![10, 60, 40, 20, 50, 30, 70]); + + assert_eq_error_rate!(Staking::stakers(11).total, 3000, 2); + assert_eq_error_rate!(Staking::stakers(21).total, 2255, 2); + assert_eq_error_rate!(Staking::stakers(31).total, 2255, 2); + assert_eq_error_rate!(Staking::stakers(41).total, 1925, 2); + assert_eq_error_rate!(Staking::stakers(51).total, 1870, 2); + assert_eq_error_rate!(Staking::stakers(61).total, 1890, 2); + assert_eq_error_rate!(Staking::stakers(71).total, 1800, 2); + + check_exposure_all(); + check_nominator_all(); + }) } #[test] fn new_era_elects_correct_number_of_validators() { - set_and_run_with_externalities(&mut ExtBuilder::default() + ExtBuilder::default() .nominate(true) .validator_pool(true) .fair(true) .validator_count(1) - .build(), - || { - assert_eq!(Staking::validator_count(), 1); - assert_eq!(validator_controllers().len(), 1); - - System::set_block_number(1); - Session::on_initialize(System::block_number()); - - assert_eq!(validator_controllers().len(), 1); - check_exposure_all(); - check_nominator_all(); - }) + .build() + .execute_with(|| { + assert_eq!(Staking::validator_count(), 1); + assert_eq!(validator_controllers().len(), 1); + + System::set_block_number(1); + Session::on_initialize(System::block_number()); + + assert_eq!(validator_controllers().len(), 1); + check_exposure_all(); + check_nominator_all(); + }) } #[test] fn phragmen_should_not_overflow_validators() { - set_and_run_with_externalities(&mut ExtBuilder::default() - .nominate(false) - .build(), - || { + ExtBuilder::default().nominate(false).build().execute_with(|| { let _ = Staking::chill(Origin::signed(10)); let _ = Staking::chill(Origin::signed(20)); @@ -1607,10 +1566,7 @@ fn phragmen_should_not_overflow_validators() { #[test] fn phragmen_should_not_overflow_nominators() { - set_and_run_with_externalities(&mut ExtBuilder::default() - .nominate(false) - .build(), - || { + ExtBuilder::default().nominate(false).build().execute_with(|| { let _ = Staking::chill(Origin::signed(10)); let _ = Staking::chill(Origin::signed(20)); @@ -1632,10 +1588,7 @@ fn phragmen_should_not_overflow_nominators() { #[test] fn phragmen_should_not_overflow_ultimate() { - set_and_run_with_externalities(&mut ExtBuilder::default() - .nominate(false) - .build(), - || { + ExtBuilder::default().nominate(false).build().execute_with(|| { bond_validator(2, u64::max_value()); bond_validator(4, u64::max_value()); @@ -1654,9 +1607,7 @@ fn phragmen_should_not_overflow_ultimate() { #[test] fn reward_validator_slashing_validator_doesnt_overflow() { - set_and_run_with_externalities(&mut ExtBuilder::default() - .build(), - || { + ExtBuilder::default().build().execute_with(|| { let stake = u32::max_value() as u64 * 2; let reward_slash = u32::max_value() as u64 * 2; @@ -1687,9 +1638,7 @@ fn reward_validator_slashing_validator_doesnt_overflow() { #[test] fn reward_from_authorship_event_handler_works() { - set_and_run_with_externalities(&mut ExtBuilder::default() - .build(), - || { + ExtBuilder::default().build().execute_with(|| { use authorship::EventHandler; assert_eq!(>::author(), 11); @@ -1714,9 +1663,7 @@ fn reward_from_authorship_event_handler_works() { #[test] fn add_reward_points_fns_works() { - set_and_run_with_externalities(&mut ExtBuilder::default() - .build(), - || { + ExtBuilder::default().build().execute_with(|| { let validators = >::current_elected(); // Not mandatory but must be coherent with rewards assert_eq!(validators, vec![21, 11]); @@ -1742,7 +1689,7 @@ fn add_reward_points_fns_works() { #[test] fn unbonded_balance_is_not_slashable() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { // total amount staked is slashable. assert_eq!(Staking::slashable_balance_of(&11), 1000); @@ -1757,7 +1704,7 @@ fn unbonded_balance_is_not_slashable() { fn era_is_always_same_length() { // This ensures that the sessions is always of the same length if there is no forcing no // session changes. - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { start_era(1); assert_eq!(Staking::current_era_start_session_index(), SessionsPerEra::get()); @@ -1777,7 +1724,7 @@ fn era_is_always_same_length() { #[test] fn offence_forces_new_era() { - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { Staking::on_offence( &[OffenceDetails { offender: ( @@ -1797,7 +1744,7 @@ fn offence_forces_new_era() { fn slashing_performed_according_exposure() { // This test checks that slashing is performed according the exposure (or more precisely, // historical exposure), not the current balance. - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { assert_eq!(Staking::stakers(&11).own, 1000); // Handle an offence with a historical exposure. @@ -1825,7 +1772,7 @@ fn slashing_performed_according_exposure() { fn reporters_receive_their_slice() { // This test verifies that the reporters of the offence receive their slice from the slashed // amount. - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { // The reporters' reward is calculated from the total exposure. #[cfg(feature = "equalize")] let initial_balance = 1250; @@ -1855,44 +1802,41 @@ fn reporters_receive_their_slice() { #[test] fn invulnerables_are_not_slashed() { // For invulnerable validators no slashing is performed. - set_and_run_with_externalities( - &mut ExtBuilder::default().invulnerables(vec![11]).build(), - || { - #[cfg(feature = "equalize")] - let initial_balance = 1250; - #[cfg(not(feature = "equalize"))] - let initial_balance = 1375; - - assert_eq!(Balances::free_balance(&11), 1000); - assert_eq!(Balances::free_balance(&21), 2000); - assert_eq!(Staking::stakers(&21).total, initial_balance); - - Staking::on_offence( - &[ - OffenceDetails { - offender: (11, Staking::stakers(&11)), - reporters: vec![], - }, - OffenceDetails { - offender: (21, Staking::stakers(&21)), - reporters: vec![], - }, - ], - &[Perbill::from_percent(50), Perbill::from_percent(20)], - ); + ExtBuilder::default().invulnerables(vec![11]).build().execute_with(|| { + #[cfg(feature = "equalize")] + let initial_balance = 1250; + #[cfg(not(feature = "equalize"))] + let initial_balance = 1375; + + assert_eq!(Balances::free_balance(&11), 1000); + assert_eq!(Balances::free_balance(&21), 2000); + assert_eq!(Staking::stakers(&21).total, initial_balance); + + Staking::on_offence( + &[ + OffenceDetails { + offender: (11, Staking::stakers(&11)), + reporters: vec![], + }, + OffenceDetails { + offender: (21, Staking::stakers(&21)), + reporters: vec![], + }, + ], + &[Perbill::from_percent(50), Perbill::from_percent(20)], + ); - // The validator 11 hasn't been slashed, but 21 has been. - assert_eq!(Balances::free_balance(&11), 1000); - // 2000 - (0.2 * initial_balance) - assert_eq!(Balances::free_balance(&21), 2000 - (2 * initial_balance / 10)); - }, - ); + // The validator 11 hasn't been slashed, but 21 has been. + assert_eq!(Balances::free_balance(&11), 1000); + // 2000 - (0.2 * initial_balance) + assert_eq!(Balances::free_balance(&21), 2000 - (2 * initial_balance / 10)); + }); } #[test] fn dont_slash_if_fraction_is_zero() { // Don't slash if the fraction is zero. - set_and_run_with_externalities(&mut ExtBuilder::default().build(), || { + ExtBuilder::default().build().execute_with(|| { assert_eq!(Balances::free_balance(&11), 1000); Staking::on_offence( diff --git a/srml/support/src/lib.rs b/srml/support/src/lib.rs index 675e5b6ea8..96360b6c4e 100644 --- a/srml/support/src/lib.rs +++ b/srml/support/src/lib.rs @@ -173,10 +173,10 @@ macro_rules! assert_err { #[macro_export] #[cfg(feature = "std")] macro_rules! assert_ok { - ( $x:expr ) => { + ( $x:expr $(,)? ) => { assert_eq!($x, Ok(())); }; - ( $x:expr, $y:expr ) => { + ( $x:expr, $y:expr $(,)? ) => { assert_eq!($x, Ok($y)); } } @@ -236,7 +236,6 @@ pub use serde::{Serialize, Deserialize}; mod tests { use super::*; use codec::{Codec, EncodeLike}; - use sr_primitives::set_and_run_with_externalities; use srml_metadata::{ DecodeDifferent, StorageEntryMetadata, StorageMetadata, StorageEntryType, StorageEntryModifier, DefaultByteGetter, StorageHasher, @@ -288,7 +287,7 @@ mod tests { #[test] fn linked_map_issue_3318() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { OptionLinkedMap::insert(1, 1); assert_eq!(OptionLinkedMap::get(1), Some(1)); OptionLinkedMap::insert(1, 2); @@ -298,7 +297,7 @@ mod tests { #[test] fn linked_map_swap_works() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { OptionLinkedMap::insert(0, 0); OptionLinkedMap::insert(1, 1); OptionLinkedMap::insert(2, 2); @@ -327,7 +326,7 @@ mod tests { #[test] fn linked_map_basic_insert_remove_should_work() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { // initialized during genesis assert_eq!(Map::get(&15u32), 42u64); @@ -353,7 +352,7 @@ mod tests { #[test] fn linked_map_enumeration_and_head_should_work() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { assert_eq!(Map::head(), Some(15)); assert_eq!(Map::enumerate().collect::>(), vec![(15, 42)]); // insert / remove @@ -405,7 +404,7 @@ mod tests { #[test] fn double_map_basic_insert_remove_remove_prefix_should_work() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { type DoubleMap = DataDM; // initialized during genesis assert_eq!(DoubleMap::get(&15u32, &16u32), 42u64); @@ -445,7 +444,7 @@ mod tests { #[test] fn double_map_append_should_work() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { type DoubleMap = AppendableDM; let key1 = 17u32; diff --git a/srml/support/src/storage/storage_items.rs b/srml/support/src/storage/storage_items.rs index 4f8f194795..1854d703c0 100644 --- a/srml/support/src/storage/storage_items.rs +++ b/srml/support/src/storage/storage_items.rs @@ -759,7 +759,6 @@ mod test3 { #[allow(dead_code)] mod test_append_and_len { use runtime_io::TestExternalities; - use sr_primitives::set_and_run_with_externalities; use codec::{Encode, Decode}; pub trait Trait { @@ -801,7 +800,7 @@ mod test_append_and_len { #[test] fn default_for_option() { - set_and_run_with_externalities(&mut TestExternalities::default(), || { + TestExternalities::default().execute_with(|| { assert_eq!(OptionVec::get(), None); assert_eq!(JustVec::get(), vec![]); }); @@ -809,7 +808,7 @@ mod test_append_and_len { #[test] fn append_works() { - set_and_run_with_externalities(&mut TestExternalities::default(), || { + TestExternalities::default().execute_with(|| { let _ = MapVec::append(1, [1, 2, 3].iter()); let _ = MapVec::append(1, [4, 5].iter()); assert_eq!(MapVec::get(1), vec![1, 2, 3, 4, 5]); @@ -822,7 +821,7 @@ mod test_append_and_len { #[test] fn append_works_for_default() { - set_and_run_with_externalities(&mut TestExternalities::default(), || { + TestExternalities::default().execute_with(|| { assert_eq!(JustVecWithDefault::get(), vec![6, 9]); let _ = JustVecWithDefault::append([1].iter()); assert_eq!(JustVecWithDefault::get(), vec![6, 9, 1]); @@ -839,7 +838,7 @@ mod test_append_and_len { #[test] fn append_or_put_works() { - set_and_run_with_externalities(&mut TestExternalities::default(), || { + TestExternalities::default().execute_with(|| { let _ = MapVec::append_or_insert(1, &[1, 2, 3][..]); let _ = MapVec::append_or_insert(1, &[4, 5][..]); assert_eq!(MapVec::get(1), vec![1, 2, 3, 4, 5]); @@ -856,7 +855,7 @@ mod test_append_and_len { #[test] fn len_works() { - set_and_run_with_externalities(&mut TestExternalities::default(), || { + TestExternalities::default().execute_with(|| { JustVec::put(&vec![1, 2, 3, 4]); OptionVec::put(&vec![1, 2, 3, 4, 5]); MapVec::insert(1, &vec![1, 2, 3, 4, 5, 6]); @@ -871,7 +870,7 @@ mod test_append_and_len { #[test] fn len_works_for_default() { - set_and_run_with_externalities(&mut TestExternalities::default(), || { + TestExternalities::default().execute_with(|| { // vec assert_eq!(JustVec::get(), vec![]); assert_eq!(JustVec::decode_len(), Ok(0)); diff --git a/srml/support/test/tests/instance.rs b/srml/support/test/tests/instance.rs index c7a2d25eed..a8465adfd7 100644 --- a/srml/support/test/tests/instance.rs +++ b/srml/support/test/tests/instance.rs @@ -15,10 +15,7 @@ // along with Substrate. If not, see . #![recursion_limit="128"] -use sr_primitives::{ - generic, BuildStorage, traits::{BlakeTwo256, Block as _, Verify}, - set_and_run_with_externalities, -}; +use sr_primitives::{generic, BuildStorage, traits::{BlakeTwo256, Block as _, Verify}}; use support::{ Parameter, traits::Get, parameter_types, metadata::{ @@ -331,7 +328,7 @@ fn storage_instance_independance() { #[test] fn storage_with_instance_basic_operation() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { type Value = module2::Value; type Map = module2::Map; type LinkedMap = module2::LinkedMap; diff --git a/srml/system/benches/bench.rs b/srml/system/benches/bench.rs index 89e9af9525..1b18b55fd2 100644 --- a/srml/system/benches/bench.rs +++ b/srml/system/benches/bench.rs @@ -18,9 +18,7 @@ use criterion::{Criterion, criterion_group, criterion_main, black_box}; use srml_system as system; use support::{decl_module, decl_event, impl_outer_origin, impl_outer_event}; use primitives::H256; -use sr_primitives::{ - set_and_run_with_externalities, Perbill, traits::{BlakeTwo256, IdentityLookup}, testing::Header, -}; +use sr_primitives::{Perbill, traits::{BlakeTwo256, IdentityLookup}, testing::Header}; mod module { use super::*; @@ -89,7 +87,7 @@ fn new_test_ext() -> runtime_io::TestExternalities { fn deposit_events(n: usize) { let mut t = new_test_ext(); - set_and_run_with_externalities(&mut t, || { + t.execute_with(|| { for _ in 0..n { module::Module::::deposit_event( module::Event::Complex(vec![1, 2, 3], 2, 3, 899) diff --git a/srml/system/src/lib.rs b/srml/system/src/lib.rs index 065b23bda1..7c90f21240 100644 --- a/srml/system/src/lib.rs +++ b/srml/system/src/lib.rs @@ -1091,10 +1091,7 @@ impl Lookup for ChainContext { mod tests { use super::*; use primitives::H256; - use sr_primitives::{ - traits::{BlakeTwo256, IdentityLookup}, testing::Header, DispatchError, - set_and_run_with_externalities, - }; + use sr_primitives::{traits::{BlakeTwo256, IdentityLookup}, testing::Header, DispatchError}; use support::{impl_outer_origin, parameter_types}; impl_outer_origin! { @@ -1164,7 +1161,7 @@ mod tests { #[test] fn deposit_event_should_work() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { System::initialize(&1, &[0u8; 32].into(), &[0u8; 32].into(), &Default::default()); System::note_finished_extrinsics(); System::deposit_event(1u16); @@ -1201,10 +1198,15 @@ mod tests { #[test] fn deposit_event_topics() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { const BLOCK_NUMBER: u64 = 1; - System::initialize(&BLOCK_NUMBER, &[0u8; 32].into(), &[0u8; 32].into(), &Default::default()); + System::initialize( + &BLOCK_NUMBER, + &[0u8; 32].into(), + &[0u8; 32].into(), + &Default::default(), + ); System::note_finished_extrinsics(); let topics = vec![ @@ -1261,7 +1263,7 @@ mod tests { #[test] fn prunes_block_hash_mappings() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { // simulate import of 15 blocks for n in 1..=15 { System::initialize( @@ -1294,7 +1296,7 @@ mod tests { #[test] fn signed_ext_check_nonce_works() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { >::insert(1, 1); let info = DispatchInfo::default(); let len = 0_usize; @@ -1312,7 +1314,7 @@ mod tests { #[test] fn signed_ext_check_weight_works_normal_tx() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { let normal_limit = normal_weight_limit(); let small = DispatchInfo { weight: 100, ..Default::default() }; let medium = DispatchInfo { @@ -1339,7 +1341,7 @@ mod tests { #[test] fn signed_ext_check_weight_fee_works() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { let free = DispatchInfo { weight: 0, ..Default::default() }; let len = 0_usize; @@ -1352,7 +1354,7 @@ mod tests { #[test] fn signed_ext_check_weight_max_works() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { let max = DispatchInfo { weight: Weight::max_value(), ..Default::default() }; let len = 0_usize; let normal_limit = normal_weight_limit(); @@ -1366,7 +1368,7 @@ mod tests { #[test] fn signed_ext_check_weight_works_operational_tx() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { let normal = DispatchInfo { weight: 100, ..Default::default() }; let op = DispatchInfo { weight: 100, class: DispatchClass::Operational }; let len = 0_usize; @@ -1389,7 +1391,7 @@ mod tests { #[test] fn signed_ext_check_weight_priority_works() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { let normal = DispatchInfo { weight: 100, class: DispatchClass::Normal }; let op = DispatchInfo { weight: 100, class: DispatchClass::Operational }; let len = 0_usize; @@ -1410,7 +1412,7 @@ mod tests { #[test] fn signed_ext_check_weight_block_size_works() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { let normal = DispatchInfo::default(); let normal_limit = normal_weight_limit() as usize; let reset_check_weight = |tx, s, f| { @@ -1434,7 +1436,7 @@ mod tests { #[test] fn signed_ext_check_era_should_work() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { // future assert_eq!( CheckEra::::from(Era::mortal(4, 2)).additional_signed().err().unwrap(), @@ -1450,7 +1452,7 @@ mod tests { #[test] fn signed_ext_check_era_should_change_longevity() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { let normal = DispatchInfo { weight: 100, class: DispatchClass::Normal }; let len = 0_usize; let ext = ( diff --git a/srml/timestamp/src/lib.rs b/srml/timestamp/src/lib.rs index 8ed3aa8dc0..cdacb8a391 100644 --- a/srml/timestamp/src/lib.rs +++ b/srml/timestamp/src/lib.rs @@ -324,10 +324,7 @@ mod tests { use support::{impl_outer_origin, assert_ok, parameter_types}; use runtime_io::TestExternalities; use primitives::H256; - use sr_primitives::{ - Perbill, traits::{BlakeTwo256, IdentityLookup}, testing::Header, - set_and_run_with_externalities, - }; + use sr_primitives::{Perbill, traits::{BlakeTwo256, IdentityLookup}, testing::Header}; impl_outer_origin! { pub enum Origin for Test {} @@ -372,7 +369,7 @@ mod tests { #[test] fn timestamp_works() { let t = system::GenesisConfig::default().build_storage::().unwrap(); - set_and_run_with_externalities(&mut TestExternalities::new(t), || { + TestExternalities::new(t).execute_with(|| { Timestamp::set_timestamp(42); assert_ok!(Timestamp::dispatch(Call::set(69), Origin::NONE)); assert_eq!(Timestamp::now(), 69); @@ -383,7 +380,7 @@ mod tests { #[should_panic(expected = "Timestamp must be updated only once in the block")] fn double_timestamp_should_fail() { let t = system::GenesisConfig::default().build_storage::().unwrap(); - set_and_run_with_externalities(&mut TestExternalities::new(t), || { + TestExternalities::new(t).execute_with(|| { Timestamp::set_timestamp(42); assert_ok!(Timestamp::dispatch(Call::set(69), Origin::NONE)); let _ = Timestamp::dispatch(Call::set(70), Origin::NONE); @@ -394,7 +391,7 @@ mod tests { #[should_panic(expected = "Timestamp must increment by at least between sequential blocks")] fn block_period_minimum_enforced() { let t = system::GenesisConfig::default().build_storage::().unwrap(); - set_and_run_with_externalities(&mut TestExternalities::new(t), || { + TestExternalities::new(t).execute_with(|| { Timestamp::set_timestamp(42); let _ = Timestamp::dispatch(Call::set(46), Origin::NONE); }); diff --git a/srml/treasury/src/lib.rs b/srml/treasury/src/lib.rs index 8ccc260fa7..d5b3e6e55f 100644 --- a/srml/treasury/src/lib.rs +++ b/srml/treasury/src/lib.rs @@ -358,8 +358,7 @@ mod tests { use support::{assert_noop, assert_ok, impl_outer_origin, parameter_types}; use primitives::H256; use sr_primitives::{ - traits::{BlakeTwo256, OnFinalize, IdentityLookup}, set_and_run_with_externalities, - testing::Header, assert_eq_error_rate, + traits::{BlakeTwo256, OnFinalize, IdentityLookup}, testing::Header, assert_eq_error_rate, }; impl_outer_origin! { @@ -446,7 +445,7 @@ mod tests { #[test] fn genesis_config_works() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { assert_eq!(Treasury::pot(), 0); assert_eq!(Treasury::proposal_count(), 0); }); @@ -454,7 +453,7 @@ mod tests { #[test] fn minting_works() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { // Check that accumulate works when we have Some value in Dummy already. Treasury::on_dilution(100, 100); assert_eq!(Treasury::pot(), 100); @@ -465,7 +464,7 @@ mod tests { fn minting_works_2() { let tests = [(1, 10), (1, 20), (40, 130), (2, 66), (2, 67), (2, 100), (2, 101), (2, 134)]; for &(minted, portion) in &tests { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { let init_total_issuance = Balances::total_issuance(); Treasury::on_dilution(minted, portion); @@ -489,7 +488,7 @@ mod tests { #[test] fn spend_proposal_takes_min_deposit() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { assert_ok!(Treasury::propose_spend(Origin::signed(0), 1, 3)); assert_eq!(Balances::free_balance(&0), 99); assert_eq!(Balances::reserved_balance(&0), 1); @@ -498,7 +497,7 @@ mod tests { #[test] fn spend_proposal_takes_proportional_deposit() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { assert_ok!(Treasury::propose_spend(Origin::signed(0), 100, 3)); assert_eq!(Balances::free_balance(&0), 95); assert_eq!(Balances::reserved_balance(&0), 5); @@ -507,14 +506,14 @@ mod tests { #[test] fn spend_proposal_fails_when_proposer_poor() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { assert_noop!(Treasury::propose_spend(Origin::signed(2), 100, 3), "Proposer's balance too low"); }); } #[test] fn accepted_spend_proposal_ignored_outside_spend_period() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { Treasury::on_dilution(100, 100); assert_ok!(Treasury::propose_spend(Origin::signed(0), 100, 3)); @@ -528,7 +527,7 @@ mod tests { #[test] fn unused_pot_should_diminish() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { let init_total_issuance = Balances::total_issuance(); Treasury::on_dilution(100, 100); assert_eq!(Balances::total_issuance(), init_total_issuance + 100); @@ -541,7 +540,7 @@ mod tests { #[test] fn rejected_spend_proposal_ignored_on_spend_period() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { Treasury::on_dilution(100, 100); assert_ok!(Treasury::propose_spend(Origin::signed(0), 100, 3)); @@ -555,7 +554,7 @@ mod tests { #[test] fn reject_already_rejected_spend_proposal_fails() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { Treasury::on_dilution(100, 100); assert_ok!(Treasury::propose_spend(Origin::signed(0), 100, 3)); @@ -566,21 +565,21 @@ mod tests { #[test] fn reject_non_existant_spend_proposal_fails() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { assert_noop!(Treasury::reject_proposal(Origin::ROOT, 0), "No proposal at that index"); }); } #[test] fn accept_non_existant_spend_proposal_fails() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { assert_noop!(Treasury::approve_proposal(Origin::ROOT, 0), "No proposal at that index"); }); } #[test] fn accept_already_rejected_spend_proposal_fails() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { Treasury::on_dilution(100, 100); assert_ok!(Treasury::propose_spend(Origin::signed(0), 100, 3)); @@ -591,7 +590,7 @@ mod tests { #[test] fn accepted_spend_proposal_enacted_on_spend_period() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { Treasury::on_dilution(100, 100); assert_eq!(Treasury::pot(), 100); @@ -606,7 +605,7 @@ mod tests { #[test] fn pot_underflow_should_not_diminish() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { Treasury::on_dilution(100, 100); assert_ok!(Treasury::propose_spend(Origin::signed(0), 150, 3)); diff --git a/srml/utility/src/lib.rs b/srml/utility/src/lib.rs index a9009a3a7e..52675d24fc 100644 --- a/srml/utility/src/lib.rs +++ b/srml/utility/src/lib.rs @@ -65,10 +65,7 @@ mod tests { use support::{assert_ok, assert_noop, impl_outer_origin, parameter_types, impl_outer_dispatch}; use primitives::H256; - use sr_primitives::{ - Perbill, traits::{BlakeTwo256, IdentityLookup}, testing::Header, - set_and_run_with_externalities, - }; + use sr_primitives::{Perbill, traits::{BlakeTwo256, IdentityLookup}, testing::Header}; impl_outer_origin! { pub enum Origin for Test {} @@ -150,7 +147,7 @@ mod tests { #[test] fn batch_works() { - set_and_run_with_externalities(&mut new_test_ext(), || { + new_test_ext().execute_with(|| { assert_eq!(Balances::free_balance(1), 10); assert_eq!(Balances::free_balance(2), 0); assert_noop!(Utility::batch(Origin::signed(1), vec![ -- GitLab From ce03f373c88e28f7d23df64f8d4e2f3588c6ca3f Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Fri, 11 Oct 2019 13:59:26 +0200 Subject: [PATCH 032/167] Fix semantics of ExistenceRequirement::KeepAlive. (#3796) * Fix semantics of ExistenceRequirement::KeepAlive. * Bump runtime version --- node/runtime/src/lib.rs | 2 +- srml/balances/src/lib.rs | 11 +++++++++-- srml/balances/src/tests.rs | 36 ++++++++++++++++++++++++++++++++++++ srml/support/src/traits.rs | 3 +++ 4 files changed, 49 insertions(+), 3 deletions(-) diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index 6ecce4c481..70b1b8f16a 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -84,7 +84,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // and set impl_version to equal spec_version. If only runtime // implementation changes and behavior does not, then leave spec_version as // is and increment impl_version. - spec_version: 174, + spec_version: 175, impl_version: 175, apis: RUNTIME_API_VERSIONS, }; diff --git a/srml/balances/src/lib.rs b/srml/balances/src/lib.rs index 03e32e1ddf..b75c7a96de 100644 --- a/srml/balances/src/lib.rs +++ b/srml/balances/src/lib.rs @@ -947,8 +947,15 @@ where reason: WithdrawReason, liveness: ExistenceRequirement, ) -> result::Result { - if let Some(new_balance) = Self::free_balance(who).checked_sub(&value) { - if liveness == ExistenceRequirement::KeepAlive && new_balance < T::ExistentialDeposit::get() { + let old_balance = Self::free_balance(who); + if let Some(new_balance) = old_balance.checked_sub(&value) { + // if we need to keep the account alive... + if liveness == ExistenceRequirement::KeepAlive + // ...and it would be dead afterwards... + && new_balance < T::ExistentialDeposit::get() + // ...yet is was alive before + && old_balance >= T::ExistentialDeposit::get() + { return Err("payment would kill account") } Self::ensure_can_withdraw(who, value, reason, new_balance)?; diff --git a/srml/balances/src/tests.rs b/srml/balances/src/tests.rs index 3e7cb9a133..0b119d3ae6 100644 --- a/srml/balances/src/tests.rs +++ b/srml/balances/src/tests.rs @@ -25,6 +25,7 @@ use support::{ traits::{LockableCurrency, LockIdentifier, WithdrawReason, WithdrawReasons, Currency, ReservableCurrency} }; +use sr_primitives::weights::DispatchClass; use system::RawOrigin; const ID_1: LockIdentifier = *b"1 "; @@ -783,6 +784,41 @@ fn signed_extension_take_fees_is_bounded() { }); } +#[test] +fn signed_extension_allows_free_transactions() { + ExtBuilder::default() + .transaction_fees(100, 1, 1) + .monied(false) + .build() + .execute_with(|| { + // 1 ain't have a penny. + assert_eq!(Balances::free_balance(&1), 0); + + // like a FreeOperational + let operational_transaction = DispatchInfo { + weight: 0, + class: DispatchClass::Operational + }; + let len = 100; + assert!( + TakeFees::::from(0) + .validate(&1, CALL, operational_transaction , len) + .is_ok() + ); + + // like a FreeNormal + let free_transaction = DispatchInfo { + weight: 0, + class: DispatchClass::Normal + }; + assert!( + TakeFees::::from(0) + .validate(&1, CALL, free_transaction , len) + .is_err() + ); + }); +} + #[test] fn burn_must_work() { ExtBuilder::default().monied(true).build().execute_with(|| { diff --git a/srml/support/src/traits.rs b/srml/support/src/traits.rs index 694e6ec4b0..cd11b56612 100644 --- a/srml/support/src/traits.rs +++ b/srml/support/src/traits.rs @@ -156,6 +156,9 @@ impl OnUnbalanced for () { #[derive(Copy, Clone, Eq, PartialEq)] pub enum ExistenceRequirement { /// Operation must not result in the account going out of existence. + /// + /// Note this implies that if the account never existed in the first place, then the operation + /// may legitimately leave the account unchanged and still non-existent. KeepAlive, /// Operation may result in account going out of existence. AllowDeath, -- GitLab From 0cd9bbfb721b5f0f31982f681bdf1e77612ecc79 Mon Sep 17 00:00:00 2001 From: Caio Date: Fri, 11 Oct 2019 20:16:51 -0300 Subject: [PATCH 033/167] Fix Typo (#3805) The `chain::error::FutureResult` doc is currently referring to the wrong structure --- core/rpc/api/src/chain/error.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/rpc/api/src/chain/error.rs b/core/rpc/api/src/chain/error.rs index eccb7f4f1b..454c0887ab 100644 --- a/core/rpc/api/src/chain/error.rs +++ b/core/rpc/api/src/chain/error.rs @@ -23,7 +23,7 @@ use jsonrpc_core as rpc; /// Chain RPC Result type. pub type Result = std::result::Result; -/// State RPC future Result type. +/// Chain RPC future Result type. pub type FutureResult = Box + Send>; /// Chain RPC errors. -- GitLab From 3704e29d8df0d1aca0d2f766bbc79c2d69ae4bee Mon Sep 17 00:00:00 2001 From: yjh Date: Sat, 12 Oct 2019 17:32:29 +0800 Subject: [PATCH 034/167] fix comments (#3808) Signed-off-by: yjhmelody <465402634@qq.com> --- core/sr-primitives/src/traits.rs | 2 +- srml/system/src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/sr-primitives/src/traits.rs b/core/sr-primitives/src/traits.rs index 10c2e80658..f94a71d38a 100644 --- a/core/sr-primitives/src/traits.rs +++ b/core/sr-primitives/src/traits.rs @@ -611,7 +611,7 @@ pub trait IsMember { } /// Something which fulfills the abstract idea of a Substrate header. It has types for a `Number`, -/// a `Hash` and a `Digest`. It provides access to an `extrinsics_root`, `state_root` and +/// a `Hash` and a `Hashing`. It provides access to an `extrinsics_root`, `state_root` and /// `parent_hash`, as well as a `digest` and a block `number`. /// /// You can also create a `new` one from those fields. diff --git a/srml/system/src/lib.rs b/srml/system/src/lib.rs index 7c90f21240..71c99af3b3 100644 --- a/srml/system/src/lib.rs +++ b/srml/system/src/lib.rs @@ -48,7 +48,7 @@ //! //! - [`CheckWeight`]: Checks the weight and length of the block and ensure that it does not //! exceed the limits. -//! - ['CheckNonce']: Checks the nonce of the transaction. Contains a single payload of type +//! - [`CheckNonce`]: Checks the nonce of the transaction. Contains a single payload of type //! `T::Index`. //! - [`CheckEra`]: Checks the era of the transaction. Contains a single payload of type `Era`. //! - [`CheckGenesis`]: Checks the provided genesis hash of the transaction. Must be a part of the -- GitLab From e9db00f87b643c8506e70d0fdce3bae58026e469 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= Date: Sat, 12 Oct 2019 16:12:03 +0100 Subject: [PATCH 035/167] node: re-use testnet genesis spec for staging testnet (#3802) --- node/cli/src/chain_spec.rs | 113 ++++++++----------------------------- 1 file changed, 25 insertions(+), 88 deletions(-) diff --git a/node/cli/src/chain_spec.rs b/node/cli/src/chain_spec.rs index 905e867436..d81591290e 100644 --- a/node/cli/src/chain_spec.rs +++ b/node/cli/src/chain_spec.rs @@ -117,83 +117,19 @@ fn staging_testnet_config_genesis() -> GenesisConfig { )]; // generated with secret: subkey inspect "$secret"/fir - let endowed_accounts: Vec = vec![ + let root_key: AccountId = hex![ // 5Ff3iXP75ruzroPWRP2FYBHWnmGGBSb63857BgnzCoXNxfPo - hex!["9ee5e5bdc0ec239eb164f865ecc345ce4c88e76ee002e0f7e318097347471809"].unchecked_into(), - ]; + "9ee5e5bdc0ec239eb164f865ecc345ce4c88e76ee002e0f7e318097347471809" + ].unchecked_into(); - const ENDOWMENT: Balance = 10_000_000 * DOLLARS; - const STASH: Balance = 100 * DOLLARS; + let endowed_accounts: Vec = vec![root_key.clone()]; - GenesisConfig { - system: Some(SystemConfig { - code: WASM_BINARY.to_vec(), - changes_trie_config: Default::default(), - }), - balances: Some(BalancesConfig { - balances: endowed_accounts.iter().cloned() - .map(|k| (k, ENDOWMENT)) - .chain(initial_authorities.iter().map(|x| (x.0.clone(), STASH))) - .collect(), - vesting: vec![], - }), - indices: Some(IndicesConfig { - ids: endowed_accounts.iter().cloned() - .chain(initial_authorities.iter().map(|x| x.0.clone())) - .collect::>(), - }), - session: Some(SessionConfig { - keys: initial_authorities.iter().map(|x| { - (x.0.clone(), session_keys(x.2.clone(), x.3.clone(), x.4.clone())) - }).collect::>(), - }), - staking: Some(StakingConfig { - current_era: 0, - validator_count: 7, - minimum_validator_count: 4, - stakers: initial_authorities.iter().map(|x| { - (x.0.clone(), x.1.clone(), STASH, StakerStatus::Validator) - }).collect(), - invulnerables: initial_authorities.iter().map(|x| x.0.clone()).collect(), - slash_reward_fraction: Perbill::from_percent(10), - .. Default::default() - }), - democracy: Some(DemocracyConfig::default()), - collective_Instance1: Some(CouncilConfig { - members: vec![], - phantom: Default::default(), - }), - collective_Instance2: Some(TechnicalCommitteeConfig { - members: vec![], - phantom: Default::default(), - }), - elections: Some(ElectionsConfig { - members: vec![], - presentation_duration: 1 * DAYS, - term_duration: 28 * DAYS, - desired_seats: 0, - }), - contracts: Some(ContractsConfig { - current_schedule: Default::default(), - gas_price: 1 * MILLICENTS, - }), - sudo: Some(SudoConfig { - key: endowed_accounts[0].clone(), - }), - babe: Some(BabeConfig { - authorities: vec![], - }), - im_online: Some(ImOnlineConfig { - keys: vec![], - }), - authority_discovery: Some(AuthorityDiscoveryConfig{ - keys: vec![], - }), - grandpa: Some(GrandpaConfig { - authorities: vec![], - }), - membership_Instance1: Some(Default::default()), - } + testnet_genesis( + initial_authorities, + root_key, + Some(endowed_accounts), + false, + ) } /// Staging testnet config. @@ -257,20 +193,23 @@ pub fn testnet_genesis( const ENDOWMENT: Balance = 10_000_000 * DOLLARS; const STASH: Balance = 100 * DOLLARS; - let desired_seats = (endowed_accounts.len() / 2 - initial_authorities.len()) as u32; - GenesisConfig { system: Some(SystemConfig { code: WASM_BINARY.to_vec(), changes_trie_config: Default::default(), }), - indices: Some(IndicesConfig { - ids: endowed_accounts.clone(), - }), balances: Some(BalancesConfig { - balances: endowed_accounts.iter().map(|k| (k.clone(), ENDOWMENT)).collect(), + balances: endowed_accounts.iter().cloned() + .map(|k| (k, ENDOWMENT)) + .chain(initial_authorities.iter().map(|x| (x.0.clone(), STASH))) + .collect(), vesting: vec![], }), + indices: Some(IndicesConfig { + ids: endowed_accounts.iter().cloned() + .chain(initial_authorities.iter().map(|x| x.0.clone())) + .collect::>(), + }), session: Some(SessionConfig { keys: initial_authorities.iter().map(|x| { (x.0.clone(), session_keys(x.2.clone(), x.3.clone(), x.4.clone())) @@ -278,8 +217,8 @@ pub fn testnet_genesis( }), staking: Some(StakingConfig { current_era: 0, - minimum_validator_count: 1, - validator_count: 2, + validator_count: initial_authorities.len() as u32 * 2, + minimum_validator_count: initial_authorities.len() as u32, stakers: initial_authorities.iter().map(|x| { (x.0.clone(), x.1.clone(), STASH, StakerStatus::Validator) }).collect(), @@ -297,12 +236,10 @@ pub fn testnet_genesis( phantom: Default::default(), }), elections: Some(ElectionsConfig { - members: endowed_accounts.iter() - .filter(|&endowed| initial_authorities.iter().find(|&(_, controller, ..)| controller == endowed).is_none()) - .map(|a| (a.clone(), 1000000)).collect(), - presentation_duration: 10, - term_duration: 1000000, - desired_seats: desired_seats, + members: vec![], + presentation_duration: 1 * DAYS, + term_duration: 28 * DAYS, + desired_seats: 0, }), contracts: Some(ContractsConfig { current_schedule: contracts::Schedule { -- GitLab From 02622d9c048e1cfbd24e5d13676ab8f48c0b84a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= Date: Sat, 12 Oct 2019 18:31:49 +0100 Subject: [PATCH 036/167] deps: update clap and structopt (#3809) --- Cargo.lock | 60 +++++++----- core/cli/Cargo.toml | 4 +- core/cli/src/execution_strategy.rs | 2 +- core/cli/src/params.rs | 112 +++++++++-------------- node/cli/Cargo.toml | 4 +- node/cli/src/lib.rs | 8 +- scripts/node-template-release/Cargo.toml | 2 +- subkey/Cargo.toml | 2 +- test-utils/chain-spec-builder/Cargo.toml | 2 +- 9 files changed, 92 insertions(+), 104 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6e7dea9d1d..5a17eaed31 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -197,7 +197,7 @@ dependencies = [ "cexpr 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "clang-sys 0.26.4 (registry+https://github.com/rust-lang/crates.io-index)", - "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -400,7 +400,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "chain-spec-builder" version = "2.0.0" dependencies = [ - "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "node-cli 2.0.0", "substrate-primitives 2.0.0", "substrate-service 2.0.0", @@ -429,14 +429,14 @@ dependencies = [ [[package]] name = "clap" -version = "2.32.0" +version = "2.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "yaml-rust 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -518,7 +518,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "criterion-plot 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "csv 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2355,7 +2355,7 @@ dependencies = [ "srml-support 2.0.0", "srml-system 2.0.0", "srml-timestamp 2.0.0", - "structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", + "structopt 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "substrate-authority-discovery 2.0.0", "substrate-basic-authorship 2.0.0", "substrate-chain-spec 2.0.0", @@ -3009,6 +3009,16 @@ dependencies = [ "toml 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "proc-macro-error" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "proc-macro-hack" version = "0.5.10" @@ -4501,27 +4511,28 @@ dependencies = [ [[package]] name = "strsim" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "structopt" -version = "0.2.18" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", - "structopt-derive 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", + "structopt-derive 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "structopt-derive" -version = "0.2.18" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-error 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -4544,7 +4555,7 @@ dependencies = [ name = "subkey" version = "2.0.0" dependencies = [ - "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "hex-literal 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "node-primitives 2.0.0", @@ -4677,7 +4688,7 @@ dependencies = [ "ansi_term 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", "app_dirs 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", - "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "derive_more 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "exit-future 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4691,7 +4702,7 @@ dependencies = [ "rpassword 4.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", - "structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", + "structopt 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "substrate-client 2.0.0", "substrate-header-metadata 2.0.0", "substrate-keyring 2.0.0", @@ -5726,7 +5737,7 @@ dependencies = [ [[package]] name = "textwrap" -version = "0.10.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -6648,7 +6659,7 @@ dependencies = [ "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" "checksum chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e8493056968583b0193c1bb04d6f7684586f3726992d6c573261941a895dbd68" "checksum clang-sys 0.26.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6ef0c1bcf2e99c649104bd7a7012d8f8802684400e03db0ec0af48583c6fa0e4" -"checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e" +"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" "checksum clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "97276801e127ffb46b66ce23f35cc96bd454fa311294bced4bbace7baa8b1d17" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum cmake 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "81fb25b677f8bf1eb325017cb6bb8452f87969db0fedb4f757b297bee78a7c62" @@ -6881,6 +6892,7 @@ dependencies = [ "checksum pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f81e1644e1b54f5a68959a29aa86cde704219254669da328ecfdf6a1f09d427" "checksum primitive-types 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "83ef7b3b965c0eadcb6838f34f827e1dfb2939bdd5ebd43f9647e009b12b0371" "checksum proc-macro-crate 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e10d4b51f154c8a7fb96fd6dad097cb74b863943ec010ac94b9fd1be8861fe1e" +"checksum proc-macro-error 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "aeccfe4d5d8ea175d5f0e4a2ad0637e0f4121d63bd99d356fb1f39ab2e7c6097" "checksum proc-macro-hack 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "114cdf1f426eb7f550f01af5f53a33c0946156f6814aec939b3bd77e844f9a9d" "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" "checksum proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "90cf5f418035b98e655e9cdb225047638296b862b42411c4e45bb88d700f7fc0" @@ -6972,9 +6984,9 @@ dependencies = [ "checksum static_slice 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "92a7e0c5e3dfb52e8fbe0e63a1b947bbb17b4036408b151353c4491374931362" "checksum stream-cipher 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8131256a5896cabcf5eb04f4d6dacbe1aefda854b0d9896e09cb58829ec5638c" "checksum string 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d24114bfcceb867ca7f71a0d3fe45d45619ec47a6fbfa98cb14e14250bfa5d6d" -"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550" -"checksum structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "16c2cdbf9cc375f15d1b4141bc48aeef444806655cd0e904207edc8d68d86ed7" -"checksum structopt-derive 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "53010261a84b37689f9ed7d395165029f9cc7abb9f56bbfe86bee2597ed25107" +"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" +"checksum structopt 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6d4f66a4c0ddf7aee4677995697366de0749b0139057342eccbb609b12d0affc" +"checksum structopt-derive 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8fe0c13e476b4e21ff7f5c4ace3818b6d7bdc16897c31c73862471bc1663acae" "checksum strum 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e5d1c33039533f051704951680f1adfd468fd37ac46816ded0d9ee068e60f05f" "checksum strum_macros 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "47cd23f5c7dee395a00fa20135e2ec0fffcdfa151c56182966d7a3261343432e" "checksum substrate-bip39 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3be511be555a3633e71739a79e4ddff6a6aaa6579fa6114182a51d72c3eb93c5" @@ -6990,7 +7002,7 @@ dependencies = [ "checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" "checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" "checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e" -"checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6" +"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" "checksum tiny-bip39 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c1c5676413eaeb1ea35300a0224416f57abc3bd251657e0fafc12c47ff98c060" diff --git a/core/cli/Cargo.toml b/core/cli/Cargo.toml index b1cb1d57ca..a2723484ad 100644 --- a/core/cli/Cargo.toml +++ b/core/cli/Cargo.toml @@ -6,7 +6,7 @@ description = "Substrate CLI interface." edition = "2018" [dependencies] -clap = "~2.32.0" +clap = "2.33.0" derive_more = "0.15.0" env_logger = "0.7.0" log = "0.4.8" @@ -33,7 +33,7 @@ state-machine = { package = "substrate-state-machine", path = "../../core/state- substrate-telemetry = { path = "../../core/telemetry" } keyring = { package = "substrate-keyring", path = "../keyring" } names = "0.11.0" -structopt = "0.2.0" +structopt = "0.3.3" rpassword = "4.0.1" [dev-dependencies] diff --git a/core/cli/src/execution_strategy.rs b/core/cli/src/execution_strategy.rs index bd3030906e..93236227e5 100644 --- a/core/cli/src/execution_strategy.rs +++ b/core/cli/src/execution_strategy.rs @@ -16,7 +16,7 @@ #![allow(missing_docs)] -use structopt::clap::{arg_enum, _clap_count_exprs}; +use structopt::clap::arg_enum; arg_enum! { /// How to execute blocks diff --git a/core/cli/src/params.rs b/core/cli/src/params.rs index b453c7dabd..b949b336de 100644 --- a/core/cli/src/params.rs +++ b/core/cli/src/params.rs @@ -17,7 +17,7 @@ use crate::traits::{AugmentClap, GetLogFilter}; use std::path::PathBuf; -use structopt::{StructOpt, clap::{arg_enum, App, AppSettings, _clap_count_exprs, SubCommand, Arg}}; +use structopt::{StructOpt, clap::{arg_enum, App, AppSettings, SubCommand, Arg}}; pub use crate::execution_strategy::ExecutionStrategy; @@ -205,11 +205,9 @@ pub struct NodeKeyParams { #[structopt( long = "node-key-type", value_name = "TYPE", - raw( - possible_values = "&NodeKeyType::variants()", - case_insensitive = "true", - default_value = r#""Ed25519""# - ) + possible_values = &NodeKeyType::variants(), + case_insensitive = true, + default_value = "Ed25519" )] pub node_key_type: NodeKeyType, @@ -248,11 +246,9 @@ pub struct ExecutionStrategies { #[structopt( long = "execution-syncing", value_name = "STRATEGY", - raw( - possible_values = "&ExecutionStrategy::variants()", - case_insensitive = "true", - default_value = r#""NativeElseWasm""# - ) + possible_values = &ExecutionStrategy::variants(), + case_insensitive = true, + default_value = "NativeElseWasm" )] pub execution_syncing: ExecutionStrategy, @@ -260,11 +256,9 @@ pub struct ExecutionStrategies { #[structopt( long = "execution-import-block", value_name = "STRATEGY", - raw( - possible_values = "&ExecutionStrategy::variants()", - case_insensitive = "true", - default_value = r#""NativeElseWasm""# - ) + possible_values = &ExecutionStrategy::variants(), + case_insensitive = true, + default_value = "NativeElseWasm" )] pub execution_import_block: ExecutionStrategy, @@ -272,11 +266,9 @@ pub struct ExecutionStrategies { #[structopt( long = "execution-block-construction", value_name = "STRATEGY", - raw( - possible_values = "&ExecutionStrategy::variants()", - case_insensitive = "true", - default_value = r#""Wasm""# - ) + possible_values = &ExecutionStrategy::variants(), + case_insensitive = true, + default_value = "Wasm" )] pub execution_block_construction: ExecutionStrategy, @@ -284,11 +276,9 @@ pub struct ExecutionStrategies { #[structopt( long = "execution-offchain-worker", value_name = "STRATEGY", - raw( - possible_values = "&ExecutionStrategy::variants()", - case_insensitive = "true", - default_value = r#""Native""# - ) + possible_values = &ExecutionStrategy::variants(), + case_insensitive = true, + default_value = "Native" )] pub execution_offchain_worker: ExecutionStrategy, @@ -296,11 +286,9 @@ pub struct ExecutionStrategies { #[structopt( long = "execution-other", value_name = "STRATEGY", - raw( - possible_values = "&ExecutionStrategy::variants()", - case_insensitive = "true", - default_value = r#""Native""# - ) + possible_values = &ExecutionStrategy::variants(), + case_insensitive = true, + default_value = "Native" )] pub execution_other: ExecutionStrategy, @@ -308,17 +296,15 @@ pub struct ExecutionStrategies { #[structopt( long = "execution", value_name = "STRATEGY", - raw( - possible_values = "&ExecutionStrategy::variants()", - case_insensitive = "true", - conflicts_with_all = "&[ - \"execution_other\", - \"execution_offchain_worker\", - \"execution_block_construction\", - \"execution_import_block\", - \"execution_syncing\", - ]" - ) + possible_values = &ExecutionStrategy::variants(), + case_insensitive = true, + conflicts_with_all = &[ + "execution-other", + "execution-offchain-worker", + "execution-block-construction", + "execution-import-block", + "execution-syncing", + ] )] pub execution: Option, } @@ -377,7 +363,7 @@ pub struct RunCmd { /// allow localhost, https://polkadot.js.org and /// https://substrate-ui.parity.io origins. When running in --dev mode the /// default is to allow all origins. - #[structopt(long = "rpc-cors", value_name = "ORIGINS", parse(try_from_str = "parse_cors"))] + #[structopt(long = "rpc-cors", value_name = "ORIGINS", parse(try_from_str = parse_cors))] pub rpc_cors: Option, /// Specify the pruning mode, a number of blocks to keep or 'archive'. @@ -404,7 +390,7 @@ pub struct RunCmd { /// telemetry endpoints. Verbosity levels range from 0-9, with 0 denoting /// the least verbosity. If no verbosity level is specified the default is /// 0. - #[structopt(long = "telemetry-url", value_name = "URL VERBOSITY", parse(try_from_str = "parse_telemetry_endpoints"))] + #[structopt(long = "telemetry-url", value_name = "URL VERBOSITY", parse(try_from_str = parse_telemetry_endpoints))] pub telemetry_endpoints: Vec<(String, u8)>, /// Should execute offchain workers on every block. @@ -413,11 +399,9 @@ pub struct RunCmd { #[structopt( long = "offchain-worker", value_name = "ENABLED", - raw( - possible_values = "&OffchainWorkerEnabled::variants()", - case_insensitive = "true", - default_value = r#""WhenValidating""# - ) + possible_values = &OffchainWorkerEnabled::variants(), + case_insensitive = true, + default_value = "WhenValidating" )] pub offchain_worker: OffchainWorkerEnabled, @@ -425,11 +409,9 @@ pub struct RunCmd { #[structopt( long = "wasm-execution", value_name = "METHOD", - raw( - possible_values = "&WasmExecutionMethod::variants()", - case_insensitive = "true", - default_value = r#""Interpreted""# - ) + possible_values = &WasmExecutionMethod::variants(), + case_insensitive = true, + default_value = "Interpreted" )] pub wasm_method: WasmExecutionMethod, @@ -464,14 +446,14 @@ pub struct RunCmd { /// Use interactive shell for entering the password used by the keystore. #[structopt( long = "password-interactive", - raw(conflicts_with_all = "&[ \"password\", \"password_filename\" ]") + conflicts_with_all = &[ "password", "password-filename" ] )] pub password_interactive: bool, /// Password used by the keystore. #[structopt( long = "password", - raw(conflicts_with_all = "&[ \"password_interactive\", \"password_filename\" ]") + conflicts_with_all = &[ "password-interactive", "password-filename" ] )] pub password: Option, @@ -480,7 +462,7 @@ pub struct RunCmd { long = "password-filename", value_name = "PATH", parse(from_os_str), - raw(conflicts_with_all = "&[ \"password_interactive\", \"password\" ]") + conflicts_with_all = &[ "password-interactive", "password" ] )] pub password_filename: Option } @@ -684,11 +666,9 @@ pub struct ImportBlocksCmd { #[structopt( long = "wasm-execution", value_name = "METHOD", - raw( - possible_values = "&WasmExecutionMethod::variants()", - case_insensitive = "true", - default_value = r#""Interpreted""# - ) + possible_values = &WasmExecutionMethod::variants(), + case_insensitive = true, + default_value = "Interpreted" )] pub wasm_method: WasmExecutionMethod, @@ -696,11 +676,9 @@ pub struct ImportBlocksCmd { #[structopt( long = "execution", value_name = "STRATEGY", - raw( - possible_values = "&ExecutionStrategy::variants()", - case_insensitive = "true", - default_value = r#""NativeElseWasm""# - ) + possible_values = &ExecutionStrategy::variants(), + case_insensitive = true, + default_value = "NativeElseWasm" )] pub execution: ExecutionStrategy, } diff --git a/node/cli/Cargo.toml b/node/cli/Cargo.toml index ca3ec92630..0ddd7b49ff 100644 --- a/node/cli/Cargo.toml +++ b/node/cli/Cargo.toml @@ -35,7 +35,7 @@ grandpa_primitives = { package = "substrate-finality-grandpa-primitives", path = sr-primitives = { path = "../../core/sr-primitives" } node-executor = { path = "../executor" } substrate-telemetry = { package = "substrate-telemetry", path = "../../core/telemetry" } -structopt = "0.2.0" +structopt = "0.3.3" transaction-factory = { path = "../../test-utils/transaction-factory" } keyring = { package = "substrate-keyring", path = "../../core/keyring" } indices = { package = "srml-indices", path = "../../srml/indices" } @@ -63,4 +63,4 @@ tempfile = "3.1.0" [build-dependencies] cli = { package = "substrate-cli", path = "../../core/cli" } -structopt = "0.2.0" +structopt = "0.3.3" diff --git a/node/cli/src/lib.rs b/node/cli/src/lib.rs index a4deed37c1..7eb3bb89c3 100644 --- a/node/cli/src/lib.rs +++ b/node/cli/src/lib.rs @@ -108,11 +108,9 @@ pub struct FactoryCmd { #[structopt( long = "execution", value_name = "STRATEGY", - raw( - possible_values = "&ExecutionStrategyParam::variants()", - case_insensitive = "true", - default_value = r#""NativeElseWasm""# - ) + possible_values = &ExecutionStrategyParam::variants(), + case_insensitive = true, + default_value = "NativeElseWasm" )] pub execution: ExecutionStrategyParam, } diff --git a/scripts/node-template-release/Cargo.toml b/scripts/node-template-release/Cargo.toml index 34aadc971f..8a43435b20 100644 --- a/scripts/node-template-release/Cargo.toml +++ b/scripts/node-template-release/Cargo.toml @@ -8,7 +8,7 @@ edition = "2018" toml = "0.4" tar = "0.4" glob = "0.2" -structopt = "0.2" +structopt = "0.3" tempfile = "3" fs_extra = "1" git2 = "0.8" diff --git a/subkey/Cargo.toml b/subkey/Cargo.toml index 1b1a697d0f..d901b59d0b 100644 --- a/subkey/Cargo.toml +++ b/subkey/Cargo.toml @@ -10,7 +10,7 @@ node-runtime = { version = "*", path = "../node/runtime" } node-primitives = { version = "*", path = "../node/primitives" } sr-primitives = { version = "*", path = "../core/sr-primitives" } rand = "0.7.2" -clap = { version = "~2.32.0", features = ["yaml"] } +clap = { version = "2.33.0", features = ["yaml"] } tiny-bip39 = "0.6.2" rustc-hex = "2.0.1" substrate-bip39 = "0.3.1" diff --git a/test-utils/chain-spec-builder/Cargo.toml b/test-utils/chain-spec-builder/Cargo.toml index 0bd9b2c55c..478e230505 100644 --- a/test-utils/chain-spec-builder/Cargo.toml +++ b/test-utils/chain-spec-builder/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] edition = "2018" [dependencies] -clap = { version = "~2.32.0", features = ["yaml"] } +clap = { version = "2.33.0", features = ["yaml"] } node-cli = { path = "../../node/cli" } primitives = { package = "substrate-primitives", path = "../../core/primitives" } substrate-service = { path = "../../core/service" } -- GitLab From 64192122e3ce9d059bb15ab3e674aa6ddf670cc8 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Sun, 13 Oct 2019 17:22:53 +0200 Subject: [PATCH 037/167] Update tests.rs (#3814) --- srml/staking/src/tests.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/srml/staking/src/tests.rs b/srml/staking/src/tests.rs index ca462b640b..2cb7981154 100644 --- a/srml/staking/src/tests.rs +++ b/srml/staking/src/tests.rs @@ -218,7 +218,6 @@ fn multi_era_reward_should_work() { // Compute now as other parameter won't change let total_payout_0 = current_total_payout_for_duration(3000); assert!(total_payout_0 > 10); // Test is meaningfull if reward something - dbg!(>::slot_stake()); >::reward_by_ids(vec![(11, 1)]); start_session(0); -- GitLab From e2ce9bfeeb149ff927032164d87b2f39e7da3be9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Mon, 14 Oct 2019 20:20:07 +0200 Subject: [PATCH 038/167] Provide macro for exporting functions from wasm (#3801) The macro generates the functions with the signature we expect for wasm functions. This macro is useful for tests where we need to call into wasm. Parameter passing is done by SCALE encoding the input and output parameters. --- core/executor/runtime-test/src/lib.rs | 185 ++++++++++++++------------ core/executor/src/sandbox.rs | 36 ++--- core/executor/src/wasmi_execution.rs | 115 ++++++++++------ core/primitives/src/lib.rs | 4 + core/primitives/src/testing.rs | 116 +++++++++++++++- 5 files changed, 312 insertions(+), 144 deletions(-) diff --git a/core/executor/runtime-test/src/lib.rs b/core/executor/runtime-test/src/lib.rs index 35f3191ffd..61eca8dd4e 100644 --- a/core/executor/runtime-test/src/lib.rs +++ b/core/executor/runtime-test/src/lib.rs @@ -5,48 +5,23 @@ #[cfg(feature = "std")] include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); -use rstd::{vec::Vec, slice, vec}; +#[cfg(not(feature = "std"))] +use rstd::{vec::Vec, vec}; +#[cfg(not(feature = "std"))] use runtime_io::{ set_storage, storage, clear_prefix, blake2_128, blake2_256, twox_128, twox_256, ed25519_verify, sr25519_verify, }; +#[cfg(not(feature = "std"))] use sr_primitives::{print, traits::{BlakeTwo256, Hash}}; +#[cfg(not(feature = "std"))] use primitives::{ed25519, sr25519}; -macro_rules! impl_stubs { - ( $( $new_name:ident => $invoke:expr, )* ) => { - $( - impl_stubs!(@METHOD $new_name => $invoke); - )* - }; - ( @METHOD $new_name:ident => $invoke:expr ) => { - #[no_mangle] - pub fn $new_name(input_data: *mut u8, input_len: usize) -> u64 { - let input: &[u8] = if input_len == 0 { - &[0u8; 0] - } else { - unsafe { - slice::from_raw_parts(input_data, input_len) - } - }; - - let output: Vec = $invoke(input); - let res = output.as_ptr() as u64 + ((output.len() as u64) << 32); - - // Leak the output vector to avoid it being freed. - // This is fine in a WASM context since the heap - // will be discarded after the call. - rstd::mem::forget(output); - res - } - }; -} - -impl_stubs!( - test_data_in => |input| { +primitives::wasm_export_functions! { + fn test_data_in(input: Vec) -> Vec { print("set_storage"); - set_storage(b"input", input); + set_storage(b"input", &input); print("storage"); let foo = storage(b"foo").unwrap(); @@ -56,25 +31,44 @@ impl_stubs!( print("finished!"); b"all ok!".to_vec() - }, - test_clear_prefix => |input| { - clear_prefix(input); + } + + fn test_clear_prefix(input: Vec) -> Vec { + clear_prefix(&input); b"all ok!".to_vec() - }, - test_empty_return => |_| Vec::new(), - test_exhaust_heap => |_| Vec::with_capacity(16777216), - test_panic => |_| panic!("test panic"), - test_conditional_panic => |input: &[u8]| { + } + + fn test_empty_return() {} + + fn test_exhaust_heap() -> Vec { Vec::with_capacity(16777216) } + + fn test_panic() { panic!("test panic") } + + fn test_conditional_panic(input: Vec) -> Vec { if input.len() > 0 { panic!("test panic") } - input.to_vec() - }, - test_blake2_256 => |input| blake2_256(input).to_vec(), - test_blake2_128 => |input| blake2_128(input).to_vec(), - test_twox_256 => |input| twox_256(input).to_vec(), - test_twox_128 => |input| twox_128(input).to_vec(), - test_ed25519_verify => |input: &[u8]| { + + input + } + + fn test_blake2_256(input: Vec) -> Vec { + blake2_256(&input).to_vec() + } + + fn test_blake2_128(input: Vec) -> Vec { + blake2_128(&input).to_vec() + } + + fn test_twox_256(input: Vec) -> Vec { + twox_256(&input).to_vec() + } + + fn test_twox_128(input: Vec) -> Vec { + twox_128(&input).to_vec() + } + + fn test_ed25519_verify(input: Vec) -> bool { let mut pubkey = [0; 32]; let mut sig = [0; 64]; @@ -82,9 +76,10 @@ impl_stubs!( sig.copy_from_slice(&input[32..96]); let msg = b"all ok!"; - [ed25519_verify(&ed25519::Signature(sig), &msg[..], &ed25519::Public(pubkey)) as u8].to_vec() - }, - test_sr25519_verify => |input: &[u8]| { + ed25519_verify(&ed25519::Signature(sig), &msg[..], &ed25519::Public(pubkey)) + } + + fn test_sr25519_verify(input: Vec) -> bool { let mut pubkey = [0; 32]; let mut sig = [0; 64]; @@ -92,9 +87,10 @@ impl_stubs!( sig.copy_from_slice(&input[32..96]); let msg = b"all ok!"; - [sr25519_verify(&sr25519::Signature(sig), &msg[..], &sr25519::Public(pubkey)) as u8].to_vec() - }, - test_ordered_trie_root => |_| { + sr25519_verify(&sr25519::Signature(sig), &msg[..], &sr25519::Public(pubkey)) + } + + fn test_ordered_trie_root() -> Vec { BlakeTwo256::ordered_trie_root( vec![ b"zero"[..].into(), @@ -102,24 +98,25 @@ impl_stubs!( b"two"[..].into(), ], ).as_ref().to_vec() - }, - test_sandbox => |code: &[u8]| { - let ok = execute_sandboxed(code, &[]).is_ok(); - [ok as u8].to_vec() - }, - test_sandbox_args => |code: &[u8]| { - let ok = execute_sandboxed( - code, + } + + fn test_sandbox(code: Vec) -> bool { + execute_sandboxed(&code, &[]).is_ok() + } + + fn test_sandbox_args(code: Vec) -> bool { + execute_sandboxed( + &code, &[ sandbox::TypedValue::I32(0x12345678), sandbox::TypedValue::I64(0x1234567887654321), - ] - ).is_ok(); - [ok as u8].to_vec() - }, - test_sandbox_return_val => |code: &[u8]| { + ], + ).is_ok() + } + + fn test_sandbox_return_val(code: Vec) -> bool { let ok = match execute_sandboxed( - code, + &code, &[ sandbox::TypedValue::I32(0x1336), ] @@ -127,41 +124,43 @@ impl_stubs!( Ok(sandbox::ReturnValue::Value(sandbox::TypedValue::I32(0x1337))) => true, _ => false, }; - [ok as u8].to_vec() - }, - test_sandbox_instantiate => |code: &[u8]| { + + ok + } + + fn test_sandbox_instantiate(code: Vec) -> u8 { let env_builder = sandbox::EnvironmentDefinitionBuilder::new(); - let code = match sandbox::Instance::new(code, &env_builder, &mut ()) { + let code = match sandbox::Instance::new(&code, &env_builder, &mut ()) { Ok(_) => 0, Err(sandbox::Error::Module) => 1, Err(sandbox::Error::Execution) => 2, Err(sandbox::Error::OutOfBounds) => 3, }; - [code].to_vec() - }, - test_offchain_local_storage => |_| { + + code + } + + fn test_offchain_local_storage() -> bool { let kind = primitives::offchain::StorageKind::PERSISTENT; assert_eq!(runtime_io::local_storage_get(kind, b"test"), None); runtime_io::local_storage_set(kind, b"test", b"asd"); assert_eq!(runtime_io::local_storage_get(kind, b"test"), Some(b"asd".to_vec())); let res = runtime_io::local_storage_compare_and_set(kind, b"test", Some(b"asd"), b""); - assert_eq!(res, true); assert_eq!(runtime_io::local_storage_get(kind, b"test"), Some(b"".to_vec())); + res + } - [0].to_vec() - }, - test_offchain_local_storage_with_none => |_| { + fn test_offchain_local_storage_with_none() { let kind = primitives::offchain::StorageKind::PERSISTENT; assert_eq!(runtime_io::local_storage_get(kind, b"test"), None); let res = runtime_io::local_storage_compare_and_set(kind, b"test", None, b"value"); assert_eq!(res, true); assert_eq!(runtime_io::local_storage_get(kind, b"test"), Some(b"value".to_vec())); + } - [0].to_vec() - }, - test_offchain_http => |_| { + fn test_offchain_http() -> bool { use primitives::offchain::HttpRequestStatus; let run = || -> Option<()> { let id = runtime_io::http_request_start("POST", "http://localhost:12345", &[]).ok()?; @@ -182,16 +181,23 @@ impl_stubs!( Some(()) }; - [if run().is_some() { 0 } else { 1 }].to_vec() - }, -); + run().is_some() + } + } -fn execute_sandboxed(code: &[u8], args: &[sandbox::TypedValue]) -> Result { +#[cfg(not(feature = "std"))] +fn execute_sandboxed( + code: &[u8], + args: &[sandbox::TypedValue], +) -> Result { struct State { counter: u32, } - fn env_assert(_e: &mut State, args: &[sandbox::TypedValue]) -> Result { + fn env_assert( + _e: &mut State, + args: &[sandbox::TypedValue], + ) -> Result { if args.len() != 1 { return Err(sandbox::HostError); } @@ -202,7 +208,10 @@ fn execute_sandboxed(code: &[u8], args: &[sandbox::TypedValue]) -> Result Result { + fn env_inc_counter( + e: &mut State, + args: &[sandbox::TypedValue], + ) -> Result { if args.len() != 1 { return Err(sandbox::HostError); } diff --git a/core/executor/src/sandbox.rs b/core/executor/src/sandbox.rs index 3a213ccdf0..c4122274a9 100644 --- a/core/executor/src/sandbox.rs +++ b/core/executor/src/sandbox.rs @@ -631,11 +631,11 @@ mod tests { call $assert ) ) - "#).unwrap(); + "#).unwrap().encode(); assert_eq!( call_wasm(&mut ext, 8, &test_code[..], "test_sandbox", &code).unwrap(), - vec![1], + true.encode(), ); } @@ -673,7 +673,7 @@ mod tests { call $assert ) ) - "#).unwrap(); + "#).unwrap().encode(); let res = call_wasm(&mut ext, 8, &test_code[..], "test_exhaust_heap", &code); assert_eq!(res.is_err(), true); @@ -718,11 +718,11 @@ mod tests { call $assert ) ) - "#).unwrap(); + "#).unwrap().encode(); assert_eq!( call_wasm(&mut ext, 8, &test_code[..], "test_sandbox", &code).unwrap(), - vec![1], + true.encode(), ); } @@ -752,11 +752,11 @@ mod tests { ) ) ) - "#).unwrap(); + "#).unwrap().encode(); assert_eq!( call_wasm(&mut ext, 8, &test_code[..], "test_sandbox_args", &code).unwrap(), - vec![1], + true.encode(), ); } @@ -774,11 +774,11 @@ mod tests { ) ) ) - "#).unwrap(); + "#).unwrap().encode(); assert_eq!( call_wasm(&mut ext, 8, &test_code[..], "test_sandbox_return_val", &code).unwrap(), - vec![1], + true.encode(), ); } @@ -794,11 +794,11 @@ mod tests { (func (export "call") ) ) - "#).unwrap(); + "#).unwrap().encode(); assert_eq!( call_wasm(&mut ext, 8, &test_code[..], "test_sandbox_instantiate", &code).unwrap(), - vec![1], + 1u8.encode(), ); } @@ -808,11 +808,11 @@ mod tests { let test_code = WASM_BINARY; // Corrupted wasm file - let code = &[0, 0, 0, 0, 1, 0, 0, 0]; + let code = vec![0u8, 0, 0, 0, 1, 0, 0, 0].encode(); assert_eq!( - call_wasm(&mut ext, 8, &test_code[..], "test_sandbox_instantiate", code).unwrap(), - vec![1], + call_wasm(&mut ext, 8, &test_code[..], "test_sandbox_instantiate", &code).unwrap(), + 1u8.encode(), ); } @@ -831,11 +831,11 @@ mod tests { (start $start) ) - "#).unwrap(); + "#).unwrap().encode(); assert_eq!( call_wasm(&mut ext, 8, &test_code[..], "test_sandbox_instantiate", &code).unwrap(), - vec![0], + 0u8.encode(), ); } @@ -855,11 +855,11 @@ mod tests { (start $start) ) - "#).unwrap(); + "#).unwrap().encode(); assert_eq!( call_wasm(&mut ext, 8, &test_code[..], "test_sandbox_instantiate", &code).unwrap(), - vec![2], + 2u8.encode(), ); } } diff --git a/core/executor/src/wasmi_execution.rs b/core/executor/src/wasmi_execution.rs index 0719ff4d40..ba7738a993 100644 --- a/core/executor/src/wasmi_execution.rs +++ b/core/executor/src/wasmi_execution.rs @@ -662,6 +662,7 @@ mod tests { use runtime_test::WASM_BINARY; use substrate_offchain::testing; use trie::{TrieConfiguration, trie_types::Layout}; + use codec::{Encode, Decode}; type TestExternalities = CoreTestExternalities; @@ -694,10 +695,10 @@ mod tests { let output = call(&mut ext, 8, &test_code[..], "test_panic", &[]); assert!(output.is_err()); - let output = call(&mut ext, 8, &test_code[..], "test_conditional_panic", &[]); - assert_eq!(output.unwrap(), vec![0u8; 0]); + let output = call(&mut ext, 8, &test_code[..], "test_conditional_panic", &[0]); + assert_eq!(Decode::decode(&mut &output.unwrap()[..]), Ok(Vec::::new())); - let output = call(&mut ext, 8, &test_code[..], "test_conditional_panic", &[2]); + let output = call(&mut ext, 8, &test_code[..], "test_conditional_panic", &vec![2].encode()); assert!(output.is_err()); } @@ -707,9 +708,15 @@ mod tests { ext.set_storage(b"foo".to_vec(), b"bar".to_vec()); let test_code = WASM_BINARY; - let output = call(&mut ext, 8, &test_code[..], "test_data_in", b"Hello world").unwrap(); + let output = call( + &mut ext, + 8, + &test_code[..], + "test_data_in", + &b"Hello world".to_vec().encode(), + ).unwrap(); - assert_eq!(output, b"all ok!".to_vec()); + assert_eq!(output, b"all ok!".to_vec().encode()); let expected = TestExternalities::new((map![ b"input".to_vec() => b"Hello world".to_vec(), @@ -730,9 +737,15 @@ mod tests { let test_code = WASM_BINARY; // This will clear all entries which prefix is "ab". - let output = call(&mut ext, 8, &test_code[..], "test_clear_prefix", b"ab").unwrap(); + let output = call( + &mut ext, + 8, + &test_code[..], + "test_clear_prefix", + &b"ab".to_vec().encode(), + ).unwrap(); - assert_eq!(output, b"all ok!".to_vec()); + assert_eq!(output, b"all ok!".to_vec().encode()); let expected = TestExternalities::new((map![ b"aaa".to_vec() => b"1".to_vec(), @@ -747,12 +760,18 @@ mod tests { let mut ext = TestExternalities::default(); let test_code = WASM_BINARY; assert_eq!( - call(&mut ext, 8, &test_code[..], "test_blake2_256", &[]).unwrap(), - blake2_256(&b""[..]).encode() + call(&mut ext, 8, &test_code[..], "test_blake2_256", &[0]).unwrap(), + blake2_256(&b""[..]).to_vec().encode(), ); assert_eq!( - call(&mut ext, 8, &test_code[..], "test_blake2_256", b"Hello world!").unwrap(), - blake2_256(&b"Hello world!"[..]).encode() + call( + &mut ext, + 8, + &test_code[..], + "test_blake2_256", + &b"Hello world!".to_vec().encode(), + ).unwrap(), + blake2_256(&b"Hello world!"[..]).to_vec().encode(), ); } @@ -761,12 +780,18 @@ mod tests { let mut ext = TestExternalities::default(); let test_code = WASM_BINARY; assert_eq!( - call(&mut ext, 8, &test_code[..], "test_blake2_128", &[]).unwrap(), - blake2_128(&b""[..]).encode() + call(&mut ext, 8, &test_code[..], "test_blake2_128", &[0]).unwrap(), + blake2_128(&b""[..]).to_vec().encode(), ); assert_eq!( - call(&mut ext, 8, &test_code[..], "test_blake2_128", b"Hello world!").unwrap(), - blake2_128(&b"Hello world!"[..]).encode() + call( + &mut ext, + 8, + &test_code[..], + "test_blake2_128", + &b"Hello world!".to_vec().encode(), + ).unwrap(), + blake2_128(&b"Hello world!"[..]).to_vec().encode(), ); } @@ -775,12 +800,22 @@ mod tests { let mut ext = TestExternalities::default(); let test_code = WASM_BINARY; assert_eq!( - call(&mut ext, 8, &test_code[..], "test_twox_256", &[]).unwrap(), - hex!("99e9d85137db46ef4bbea33613baafd56f963c64b1f3685a4eb4abd67ff6203a"), + call(&mut ext, 8, &test_code[..], "test_twox_256", &[0]).unwrap(), + hex!( + "99e9d85137db46ef4bbea33613baafd56f963c64b1f3685a4eb4abd67ff6203a" + ).to_vec().encode(), ); assert_eq!( - call(&mut ext, 8, &test_code[..], "test_twox_256", b"Hello world!").unwrap(), - hex!("b27dfd7f223f177f2a13647b533599af0c07f68bda23d96d059da2b451a35a74"), + call( + &mut ext, + 8, + &test_code[..], + "test_twox_256", + &b"Hello world!".to_vec().encode(), + ).unwrap(), + hex!( + "b27dfd7f223f177f2a13647b533599af0c07f68bda23d96d059da2b451a35a74" + ).to_vec().encode(), ); } @@ -789,12 +824,18 @@ mod tests { let mut ext = TestExternalities::default(); let test_code = WASM_BINARY; assert_eq!( - call(&mut ext, 8, &test_code[..], "test_twox_128", &[]).unwrap(), - hex!("99e9d85137db46ef4bbea33613baafd5") + call(&mut ext, 8, &test_code[..], "test_twox_128", &[0]).unwrap(), + hex!("99e9d85137db46ef4bbea33613baafd5").to_vec().encode(), ); assert_eq!( - call(&mut ext, 8, &test_code[..], "test_twox_128", b"Hello world!").unwrap(), - hex!("b27dfd7f223f177f2a13647b533599af") + call( + &mut ext, + 8, + &test_code[..], + "test_twox_128", + &b"Hello world!".to_vec().encode(), + ).unwrap(), + hex!("b27dfd7f223f177f2a13647b533599af").to_vec().encode(), ); } @@ -809,8 +850,8 @@ mod tests { calldata.extend_from_slice(sig.as_ref()); assert_eq!( - call(&mut ext, 8, &test_code[..], "test_ed25519_verify", &calldata).unwrap(), - vec![1] + call(&mut ext, 8, &test_code[..], "test_ed25519_verify", &calldata.encode()).unwrap(), + true.encode(), ); let other_sig = key.sign(b"all is not ok!"); @@ -819,8 +860,8 @@ mod tests { calldata.extend_from_slice(other_sig.as_ref()); assert_eq!( - call(&mut ext, 8, &test_code[..], "test_ed25519_verify", &calldata).unwrap(), - vec![0] + call(&mut ext, 8, &test_code[..], "test_ed25519_verify", &calldata.encode()).unwrap(), + false.encode(), ); } @@ -835,8 +876,8 @@ mod tests { calldata.extend_from_slice(sig.as_ref()); assert_eq!( - call(&mut ext, 8, &test_code[..], "test_sr25519_verify", &calldata).unwrap(), - vec![1] + call(&mut ext, 8, &test_code[..], "test_sr25519_verify", &calldata.encode()).unwrap(), + true.encode(), ); let other_sig = key.sign(b"all is not ok!"); @@ -845,8 +886,8 @@ mod tests { calldata.extend_from_slice(other_sig.as_ref()); assert_eq!( - call(&mut ext, 8, &test_code[..], "test_sr25519_verify", &calldata).unwrap(), - vec![0] + call(&mut ext, 8, &test_code[..], "test_sr25519_verify", &calldata.encode()).unwrap(), + false.encode(), ); } @@ -856,8 +897,8 @@ mod tests { let trie_input = vec![b"zero".to_vec(), b"one".to_vec(), b"two".to_vec()]; let test_code = WASM_BINARY; assert_eq!( - call(&mut ext, 8, &test_code[..], "test_ordered_trie_root", &[]).unwrap(), - Layout::::ordered_trie_root(trie_input.iter()).as_fixed_bytes().encode() + call(&mut ext, 8, &test_code[..], "test_ordered_trie_root", &[0]).unwrap(), + Layout::::ordered_trie_root(trie_input.iter()).as_bytes().encode(), ); } @@ -870,8 +911,8 @@ mod tests { ext.register_extension(OffchainExt::new(offchain)); let test_code = WASM_BINARY; assert_eq!( - call(&mut ext, 8, &test_code[..], "test_offchain_local_storage", &[]).unwrap(), - vec![0] + call(&mut ext, 8, &test_code[..], "test_offchain_local_storage", &[0]).unwrap(), + true.encode(), ); assert_eq!(state.read().persistent_storage.get(b"", b"test"), Some(vec![])); } @@ -897,8 +938,8 @@ mod tests { let test_code = WASM_BINARY; assert_eq!( - call(&mut ext, 8, &test_code[..], "test_offchain_http", &[]).unwrap(), - vec![0] + call(&mut ext, 8, &test_code[..], "test_offchain_http", &[0]).unwrap(), + true.encode(), ); } } diff --git a/core/primitives/src/lib.rs b/core/primitives/src/lib.rs index b1ce6e2f97..c2d23050f9 100644 --- a/core/primitives/src/lib.rs +++ b/core/primitives/src/lib.rs @@ -39,6 +39,7 @@ use std::borrow::Cow; use serde::{Serialize, Deserialize}; #[cfg(feature = "std")] pub use serde;// << for macro +#[doc(hidden)] pub use codec::{Encode, Decode};// << for macro #[cfg(feature = "std")] @@ -82,6 +83,9 @@ pub use self::hasher::blake2::Blake2Hasher; pub use primitives_storage as storage; +#[doc(hidden)] +pub use rstd; + /// Context for executing a call into the runtime. pub enum ExecutionContext { /// Context for general importing (including own blocks). diff --git a/core/primitives/src/testing.rs b/core/primitives/src/testing.rs index 7fdefd8fe0..92a09ff044 100644 --- a/core/primitives/src/testing.rs +++ b/core/primitives/src/testing.rs @@ -129,13 +129,127 @@ impl crate::traits::BareCryptoStore for KeyStore { } } +/// Macro for exporting functions from wasm in with the expected signature for using it with the +/// wasm executor. This is useful for tests where you need to call a function in wasm. +/// +/// The input parameters are expected to be SCALE encoded and will be automatically decoded for you. +/// The output value is also SCALE encoded when returned back to the host. +/// +/// The functions are feature-gated with `#[cfg(not(feature = "std"))]`, so they are only available +/// from within wasm. +/// +/// # Example +/// +/// ``` +/// # use substrate_primitives::wasm_export_functions; +/// +/// wasm_export_functions! { +/// fn test_in_wasm(value: bool, another_value: Vec) -> bool { +/// value && another_value.is_empty() +/// } +/// +/// fn without_return_value() { +/// // do something +/// } +/// } +/// ``` +#[macro_export] +macro_rules! wasm_export_functions { + ( + $( + fn $name:ident ( + $( $arg_name:ident: $arg_ty:ty ),* $(,)? + ) $( -> $ret_ty:ty )? { $( $fn_impl:tt )* } + )* + ) => { + $( + $crate::wasm_export_functions! { + @IMPL + fn $name ( + $( $arg_name: $arg_ty ),* + ) $( -> $ret_ty )? { $( $fn_impl )* } + } + )* + }; + (@IMPL + fn $name:ident ( + $( $arg_name:ident: $arg_ty:ty ),* + ) { $( $fn_impl:tt )* } + ) => { + #[no_mangle] + #[allow(unreachable_code)] + #[cfg(not(feature = "std"))] + pub fn $name(input_data: *mut u8, input_len: usize) -> u64 { + let input: &[u8] = if input_len == 0 { + &[0u8; 0] + } else { + unsafe { + $crate::rstd::slice::from_raw_parts(input_data, input_len) + } + }; + + { + let ($( $arg_name ),*) : ($( $arg_ty ),*) = $crate::Decode::decode( + &mut &input[..], + ).expect("Input data is correctly encoded"); + + $( $fn_impl )* + } + + // We need to return *something* + let output = Vec::::new(); + let res = output.as_ptr() as u64 + ((output.len() as u64) << 32); + + // Leak the output vector to avoid it being freed. + // This is fine in a WASM context since the heap + // will be discarded after the call. + $crate::rstd::mem::forget(output); + res + } + }; + (@IMPL + fn $name:ident ( + $( $arg_name:ident: $arg_ty:ty ),* + ) $( -> $ret_ty:ty )? { $( $fn_impl:tt )* } + ) => { + #[no_mangle] + #[allow(unreachable_code)] + #[cfg(not(feature = "std"))] + pub fn $name(input_data: *mut u8, input_len: usize) -> u64 { + let input: &[u8] = if input_len == 0 { + &[0u8; 0] + } else { + unsafe { + $crate::rstd::slice::from_raw_parts(input_data, input_len) + } + }; + + let output $( : $ret_ty )? = { + let ($( $arg_name ),*) : ($( $arg_ty ),*) = $crate::Decode::decode( + &mut &input[..], + ).expect("Input data is correctly encoded"); + + $( $fn_impl )* + }; + + let output = $crate::Encode::encode(&output); + let res = output.as_ptr() as u64 + ((output.len() as u64) << 32); + + // Leak the output vector to avoid it being freed. + // This is fine in a WASM context since the heap + // will be discarded after the call. + $crate::rstd::mem::forget(output); + res + } + }; +} + #[cfg(test)] mod tests { use super::*; use crate::sr25519; use crate::testing::{ED25519, SR25519}; - #[test] fn store_key_and_extract() { let store = KeyStore::new(); -- GitLab From 1ae7a901d9b2a7f4fefc7b5f5846c2d13ef6d8c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= Date: Tue, 15 Oct 2019 01:19:01 +0100 Subject: [PATCH 039/167] grandpa: fix until imported logging arg order (#3818) --- core/finality-grandpa/src/until_imported.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/finality-grandpa/src/until_imported.rs b/core/finality-grandpa/src/until_imported.rs index b8568c1f85..119ecf95c5 100644 --- a/core/finality-grandpa/src/until_imported.rs +++ b/core/finality-grandpa/src/until_imported.rs @@ -175,9 +175,9 @@ impl Stream for UntilImported target: "afg", "Waiting to import block {} before {} {} messages can be imported. \ Possible fork?", - self.identifier, block_hash, v.len(), + self.identifier, ); *last_log = next_log; -- GitLab From 67b73c468e44839c5809245703d067dc75940076 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Tue, 15 Oct 2019 11:16:10 +0200 Subject: [PATCH 040/167] Fix asynchronous transaction rejections. (#3817) * Fix handling transaction pool errors. * Add test. * Review suggestions. --- core/rpc/api/src/subscriptions.rs | 7 +++ core/rpc/src/author/mod.rs | 71 +++++++++++++------------ core/rpc/src/author/tests.rs | 34 ++++++++++-- core/transaction-pool/graph/src/pool.rs | 2 +- 4 files changed, 73 insertions(+), 41 deletions(-) diff --git a/core/rpc/api/src/subscriptions.rs b/core/rpc/api/src/subscriptions.rs index a1e486138f..d5ca74fa60 100644 --- a/core/rpc/api/src/subscriptions.rs +++ b/core/rpc/api/src/subscriptions.rs @@ -69,6 +69,13 @@ impl Subscriptions { } } + /// Borrows the internal task executor. + /// + /// This can be used to spawn additional tasks on the underyling event loop. + pub fn executor(&self) -> &TaskExecutor { + &self.executor + } + /// Creates new subscription for given subscriber. /// /// Second parameter is a function that converts Subscriber sink into a future. diff --git a/core/rpc/src/author/mod.rs b/core/rpc/src/author/mod.rs index 9a978f22f7..82122dcf3d 100644 --- a/core/rpc/src/author/mod.rs +++ b/core/rpc/src/author/mod.rs @@ -26,10 +26,9 @@ use log::warn; use client::{self, Client}; use rpc::futures::{ Sink, Future, - stream::Stream as _, future::result, }; -use futures03::{StreamExt as _, compat::Compat}; +use futures03::{StreamExt as _, compat::Compat, future::ready}; use api::Subscriptions; use jsonrpc_pubsub::{typed::Subscriber, SubscriptionId}; use codec::{Encode, Decode}; @@ -162,42 +161,44 @@ impl AuthorApi, BlockHash

> for Author whe let best_block_hash = self.client.info().chain.best_hash; let dxt = <

::Block as traits::Block>::Extrinsic::decode(&mut &xt[..]) .map_err(error::Error::from)?; - Ok(self.pool - .submit_and_watch(&generic::BlockId::hash(best_block_hash), dxt) - .boxed() - .compat() - .map_err(|e| e.into_pool_error() - .map(error::Error::from) - .unwrap_or_else(|e| error::Error::Verification(Box::new(e)).into()) - )) + Ok( + self.pool + .submit_and_watch(&generic::BlockId::hash(best_block_hash), dxt) + .map_err(|e| e.into_pool_error() + .map(error::Error::from) + .unwrap_or_else(|e| error::Error::Verification(Box::new(e)).into()) + ) + ) }; - let future_watcher = match submit() { - Ok(future_watcher) => future_watcher, - Err(err) => { - // reject the subscriber (ignore errors - we don't care if subscriber is no longer there). - let _ = subscriber.reject(err.into()); - return; - }, - }; - - // make 'future' watcher be a future with output = stream of watcher events - let future_watcher = future_watcher - .map_err(|err| { warn!("Failed to submit extrinsic: {}", err); }) - .map(|watcher| Compat::new(watcher.into_stream().map(|v| Ok::<_, ()>(Ok(v))))); - - // convert a 'future' watcher into the stream with single element = stream of watcher events - let watcher_stream = future_watcher.into_stream(); - - // and now flatten the 'watcher_stream' so that we'll have the stream with watcher events - let watcher_stream = watcher_stream.flatten(); + let subscriptions = self.subscriptions.clone(); + let future = ready(submit()) + .and_then(|res| res) + // convert the watcher into a `Stream` + .map(|res| res.map(|watcher| watcher.into_stream().map(|v| Ok::<_, ()>(Ok(v))))) + // now handle the import result, + // start a new subscrition + .map(move |result| match result { + Ok(watcher) => { + subscriptions.add(subscriber, move |sink| { + sink + .sink_map_err(|_| unimplemented!()) + .send_all(Compat::new(watcher)) + .map(|_| ()) + }); + }, + Err(err) => { + warn!("Failed to submit extrinsic: {}", err); + // reject the subscriber (ignore errors - we don't care if subscriber is no longer there). + let _ = subscriber.reject(err.into()); + }, + }); - self.subscriptions.add(subscriber, move |sink| { - sink - .sink_map_err(|e| warn!("Error sending notifications: {:?}", e)) - .send_all(watcher_stream) - .map(|_| ()) - }); + let res = self.subscriptions.executor() + .execute(Box::new(Compat::new(future.map(|_| Ok(()))))); + if res.is_err() { + warn!("Error spawning subscription RPC task."); + } } fn unwatch_extrinsic(&self, _metadata: Option, id: SubscriptionId) -> Result { diff --git a/core/rpc/src/author/tests.rs b/core/rpc/src/author/tests.rs index 202dab4940..e8ba4c132a 100644 --- a/core/rpc/src/author/tests.rs +++ b/core/rpc/src/author/tests.rs @@ -19,18 +19,19 @@ use super::*; use std::sync::Arc; use assert_matches::assert_matches; use codec::Encode; -use transaction_pool::{ - txpool::Pool, - FullChainApi, -}; use primitives::{ H256, blake2_256, hexdisplay::HexDisplay, testing::{ED25519, SR25519, KeyStore}, ed25519, crypto::Pair, }; +use rpc::futures::Stream as _; use test_client::{ self, AccountKeyring, runtime::{Extrinsic, Transfer, SessionKeys}, DefaultTestClientBuilderExt, TestClientBuilderExt, }; +use transaction_pool::{ + txpool::Pool, + FullChainApi, +}; use tokio::runtime; fn uxt(sender: AccountKeyring, nonce: u64) -> Extrinsic { @@ -102,7 +103,7 @@ fn should_watch_extrinsic() { subscriptions: Subscriptions::new(Arc::new(runtime.executor())), keystore: keystore.clone(), }; - let (subscriber, id_rx, data) = ::jsonrpc_pubsub::typed::Subscriber::new_test("test"); + let (subscriber, id_rx, data) = jsonrpc_pubsub::typed::Subscriber::new_test("test"); // when p.watch_extrinsic(Default::default(), subscriber, uxt(AccountKeyring::Alice, 0).encode().into()); @@ -132,6 +133,29 @@ fn should_watch_extrinsic() { ); } +#[test] +fn should_return_watch_validation_error() { + //given + let mut runtime = runtime::Runtime::new().unwrap(); + let client = Arc::new(test_client::new()); + let pool = Arc::new(Pool::new(Default::default(), FullChainApi::new(client.clone()))); + let keystore = KeyStore::new(); + let p = Author { + client, + pool: pool.clone(), + subscriptions: Subscriptions::new(Arc::new(runtime.executor())), + keystore: keystore.clone(), + }; + let (subscriber, id_rx, _data) = jsonrpc_pubsub::typed::Subscriber::new_test("test"); + + // when + p.watch_extrinsic(Default::default(), subscriber, uxt(AccountKeyring::Alice, 179).encode().into()); + + // then + let res = runtime.block_on(id_rx).unwrap(); + assert!(res.is_err(), "Expected the transaction to be rejected as invalid."); +} + #[test] fn should_return_pending_extrinsics() { let runtime = runtime::Runtime::new().unwrap(); diff --git a/core/transaction-pool/graph/src/pool.rs b/core/transaction-pool/graph/src/pool.rs index 53b2a62cbe..621aeabda8 100644 --- a/core/transaction-pool/graph/src/pool.rs +++ b/core/transaction-pool/graph/src/pool.rs @@ -66,7 +66,7 @@ pub trait ChainApi: Send + Sync { /// Error type. type Error: From + error::IntoPoolError; /// Validate transaction future. - type ValidationFuture: Future> + Send; + type ValidationFuture: Future> + Send + Unpin; /// Verify extrinsic at given block. fn validate_transaction( -- GitLab From 9b8bfd72126be453cda302caff28a6c99adee14c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= Date: Tue, 15 Oct 2019 15:07:56 +0100 Subject: [PATCH 041/167] chain spec builder: add generate mode for authority keys (#3811) * core: use trait object for genesis constructor * chain-spec-builder: use structopt * chain-spec-builder: add new command to generate authority keys * chain-spec-builder: use ? in main * chain-spec-builder: fix stored and printed suri from seed * chain-spec-builder: add comment about created keystore folders * chain-spec-builder: simplify file write --- Cargo.lock | 6 +- core/chain-spec/src/chain_spec.rs | 11 +- test-utils/chain-spec-builder/Cargo.toml | 6 +- test-utils/chain-spec-builder/src/cli.yml | 24 -- test-utils/chain-spec-builder/src/main.rs | 258 ++++++++++++++++++++-- 5 files changed, 249 insertions(+), 56 deletions(-) delete mode 100644 test-utils/chain-spec-builder/src/cli.yml diff --git a/Cargo.lock b/Cargo.lock index 5a17eaed31..b8dade5e24 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -400,10 +400,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "chain-spec-builder" version = "2.0.0" dependencies = [ - "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ansi_term 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", "node-cli 2.0.0", + "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "structopt 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "substrate-keystore 2.0.0", "substrate-primitives 2.0.0", - "substrate-service 2.0.0", ] [[package]] diff --git a/core/chain-spec/src/chain_spec.rs b/core/chain-spec/src/chain_spec.rs index b4c57f1e03..8d72effc7b 100644 --- a/core/chain-spec/src/chain_spec.rs +++ b/core/chain-spec/src/chain_spec.rs @@ -20,6 +20,7 @@ use std::borrow::Cow; use std::collections::HashMap; use std::fs::File; use std::path::PathBuf; +use std::rc::Rc; use serde::{Serialize, Deserialize}; use primitives::storage::{StorageKey, StorageData}; use sr_primitives::{BuildStorage, StorageOverlay, ChildrenStorageOverlay}; @@ -31,7 +32,7 @@ use tel::TelemetryEndpoints; enum GenesisSource { File(PathBuf), Binary(Cow<'static, [u8]>), - Factory(fn() -> G), + Factory(Rc G>), } impl Clone for GenesisSource { @@ -39,7 +40,7 @@ impl Clone for GenesisSource { match *self { GenesisSource::File(ref path) => GenesisSource::File(path.clone()), GenesisSource::Binary(ref d) => GenesisSource::Binary(d.clone()), - GenesisSource::Factory(f) => GenesisSource::Factory(f), + GenesisSource::Factory(ref f) => GenesisSource::Factory(f.clone()), } } } @@ -187,10 +188,10 @@ impl ChainSpec { } /// Create hardcoded spec. - pub fn from_genesis( + pub fn from_genesis G + 'static>( name: &str, id: &str, - constructor: fn() -> G, + constructor: F, boot_nodes: Vec, telemetry_endpoints: Option, protocol_id: Option<&str>, @@ -211,7 +212,7 @@ impl ChainSpec { ChainSpec { spec, - genesis: GenesisSource::Factory(constructor), + genesis: GenesisSource::Factory(Rc::new(constructor)), } } } diff --git a/test-utils/chain-spec-builder/Cargo.toml b/test-utils/chain-spec-builder/Cargo.toml index 478e230505..324d33cbf0 100644 --- a/test-utils/chain-spec-builder/Cargo.toml +++ b/test-utils/chain-spec-builder/Cargo.toml @@ -5,7 +5,9 @@ authors = ["Parity Technologies "] edition = "2018" [dependencies] -clap = { version = "2.33.0", features = ["yaml"] } +ansi_term = "0.12.1" +keystore = { package = "substrate-keystore", path = "../../core/keystore" } node-cli = { path = "../../node/cli" } primitives = { package = "substrate-primitives", path = "../../core/primitives" } -substrate-service = { path = "../../core/service" } +rand = "0.7.2" +structopt = "0.3.3" diff --git a/test-utils/chain-spec-builder/src/cli.yml b/test-utils/chain-spec-builder/src/cli.yml deleted file mode 100644 index f4b1cb7e2e..0000000000 --- a/test-utils/chain-spec-builder/src/cli.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: chain-spec-builder -author: "azban " -about: Utility for creating chain specs primarily for testing -args: -- initial_authority_seed: - short: a - value_name: INITIAL_AUTHORITY_SEED - help: Initial authority seed - takes_value: true - multiple: true - required: true -- endowed_account_seed: - short: e - value_name: ENDOWED_ACCOUNT_SEED - help: Endowed account seed - takes_value: true - multiple: true - required: true -- sudo_key_seed: - short: u - value_name: SUDO_KEY_SEED - help: Sudo key seed - takes_value: true - required: true diff --git a/test-utils/chain-spec-builder/src/main.rs b/test-utils/chain-spec-builder/src/main.rs index 8f59c73493..22c5253b06 100644 --- a/test-utils/chain-spec-builder/src/main.rs +++ b/test-utils/chain-spec-builder/src/main.rs @@ -1,49 +1,261 @@ -use clap::{App, load_yaml}; +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +use std::{fs, path::{Path, PathBuf}}; + +use ansi_term::Style; +use rand::{Rng, distributions::Alphanumeric, rngs::OsRng}; +use structopt::StructOpt; + +use keystore::{Store as Keystore}; use node_cli::chain_spec::{self, AccountId}; -use substrate_service::chain_ops::build_spec; +use primitives::{crypto::{Public, Ss58Codec}, traits::BareCryptoStore}; -fn genesis_constructor() -> chain_spec::GenesisConfig { - let yaml = load_yaml!("./cli.yml"); - let matches = App::from_yaml(yaml).get_matches(); - let authorities = matches.values_of("initial_authority_seed") - .unwrap() - .map(chain_spec::get_authority_keys_from_seed) - .collect(); +/// A utility to easily create a testnet chain spec definition with a given set +/// of authorities and endowed accounts and/or generate random accounts. +#[derive(StructOpt)] +#[structopt(rename_all = "kebab-case")] +enum ChainSpecBuilder { + /// Create a new chain spec with the given authorities, endowed and sudo + /// accounts. + New { + /// Authority key seed. + #[structopt(long, short, required = true)] + authority_seeds: Vec, + /// Endowed account address (SS58 format). + #[structopt(long, short)] + endowed_accounts: Vec, + /// Sudo account address (SS58 format). + #[structopt(long, short)] + sudo_account: String, + /// The path where the chain spec should be saved. + #[structopt(long, short, default_value = "./chain_spec.json")] + chain_spec_path: PathBuf, + }, + /// Create a new chain spec with the given number of authorities and endowed + /// accounts. Random keys will be generated as required. + Generate { + /// The number of authorities. + #[structopt(long, short)] + authorities: usize, + /// The number of endowed accounts. + #[structopt(long, short, default_value = "0")] + endowed: usize, + /// The path where the chain spec should be saved. + #[structopt(long, short, default_value = "./chain_spec.json")] + chain_spec_path: PathBuf, + /// Path to use when saving generated keystores for each authority. + /// + /// At this path, a new folder will be created for each authority's + /// keystore named `auth-$i` where `i` is the authority index, i.e. + /// `auth-0`, `auth-1`, etc. + #[structopt(long, short)] + keystore_path: Option, + }, +} - let endowed_accounts = matches.values_of("endowed_account_seed") - .unwrap() - .map(chain_spec::get_from_seed::) - .collect(); +impl ChainSpecBuilder { + /// Returns the path where the chain spec should be saved. + fn chain_spec_path(&self) -> &Path { + match self { + ChainSpecBuilder::New { chain_spec_path, .. } => + chain_spec_path.as_path(), + ChainSpecBuilder::Generate { chain_spec_path, .. } => + chain_spec_path.as_path(), + } + } +} - let sudo_key_seed = matches.value_of("sudo_key_seed").unwrap(); - let sudo_key = chain_spec::get_from_seed::(sudo_key_seed); +fn genesis_constructor( + authority_seeds: &[String], + endowed_accounts: &[AccountId], + sudo_account: &AccountId, +) -> chain_spec::GenesisConfig { + let authorities = authority_seeds + .iter() + .map(AsRef::as_ref) + .map(chain_spec::get_authority_keys_from_seed) + .collect::>(); let enable_println = true; chain_spec::testnet_genesis( authorities, - sudo_key.into(), - Some(endowed_accounts), + sudo_account.clone(), + Some(endowed_accounts.to_vec()), enable_println, ) } -fn generate_chain_spec() -> String { +fn generate_chain_spec( + authority_seeds: Vec, + endowed_accounts: Vec, + sudo_account: String, +) -> Result { + let parse_account = |address: &String| { + AccountId::from_string(address) + .map_err(|err| format!("Failed to parse account address: {:?}", err)) + }; + + let endowed_accounts = endowed_accounts + .iter() + .map(parse_account) + .collect::, String>>()?; + + let sudo_account = parse_account(&sudo_account)?; + let chain_spec = chain_spec::ChainSpec::from_genesis( "Custom", "custom", - genesis_constructor, + move || genesis_constructor(&authority_seeds, &endowed_accounts, &sudo_account), vec![], None, None, None, Default::default(), ); - build_spec(chain_spec, false).unwrap() + + chain_spec.to_json(false).map_err(|err| err.to_string()) +} + +fn generate_authority_keys_and_store( + seeds: &[String], + keystore_path: &Path, +) -> Result<(), String> { + for (n, seed) in seeds.into_iter().enumerate() { + let keystore = Keystore::open( + keystore_path.join(format!("auth-{}", n)), + None, + ).map_err(|err| err.to_string())?; + + let (_, _, grandpa, babe, im_online) = + chain_spec::get_authority_keys_from_seed(seed); + + let insert_key = |key_type, public| { + keystore.write().insert_unknown( + key_type, + &format!("//{}", seed), + public, + ).map_err(|_| format!("Failed to insert key: {}", grandpa)) + }; + + insert_key( + primitives::crypto::key_types::BABE, + babe.as_slice(), + )?; + + insert_key( + primitives::crypto::key_types::GRANDPA, + grandpa.as_slice(), + )?; + + insert_key( + primitives::crypto::key_types::IM_ONLINE, + im_online.as_slice(), + )?; + } + + Ok(()) +} + +fn print_seeds( + authority_seeds: &[String], + endowed_seeds: &[String], + sudo_seed: &str, +) { + let header = Style::new().bold().underline(); + let entry = Style::new().bold(); + + println!("{}", header.paint("Authority seeds")); + + for (n, seed) in authority_seeds.iter().enumerate() { + println!("{} //{}", + entry.paint(format!("auth-{}:", n)), + seed, + ); + } + + println!(); + + if !endowed_seeds.is_empty() { + println!("{}", header.paint("Endowed seeds")); + for (n, seed) in endowed_seeds.iter().enumerate() { + println!("{} //{}", + entry.paint(format!("endowed-{}:", n)), + seed, + ); + } + + println!(); + } + + println!("{}", header.paint("Sudo seed")); + println!("//{}", sudo_seed); } -fn main() { - let json = generate_chain_spec(); - println!("{}", json); +fn main() -> Result<(), String> { + let builder = ChainSpecBuilder::from_args(); + let chain_spec_path = builder.chain_spec_path().to_path_buf(); + + let (authority_seeds, endowed_accounts, sudo_account) = match builder { + ChainSpecBuilder::Generate { authorities, endowed, keystore_path, .. } => { + let authorities = authorities.max(1); + let rand_str = || -> String { + OsRng.sample_iter(&Alphanumeric) + .take(32) + .collect() + }; + + let authority_seeds = (0..authorities).map(|_| rand_str()).collect::>(); + let endowed_seeds = (0..endowed).map(|_| rand_str()).collect::>(); + let sudo_seed = rand_str(); + + print_seeds( + &authority_seeds, + &endowed_seeds, + &sudo_seed, + ); + + if let Some(keystore_path) = keystore_path { + generate_authority_keys_and_store( + &authority_seeds, + &keystore_path, + )?; + } + + let endowed_accounts = endowed_seeds.iter().map(|seed| { + chain_spec::get_from_seed::(seed) + .to_ss58check() + }).collect(); + + let sudo_account = chain_spec::get_from_seed::(&sudo_seed) + .to_ss58check(); + + (authority_seeds, endowed_accounts, sudo_account) + }, + ChainSpecBuilder::New { authority_seeds, endowed_accounts, sudo_account, .. } => { + (authority_seeds, endowed_accounts, sudo_account) + }, + }; + + let json = generate_chain_spec( + authority_seeds, + endowed_accounts, + sudo_account, + )?; + + fs::write(chain_spec_path, json).map_err(|err| err.to_string()) } -- GitLab From a1d8124152d21c88085bd0c1ada709e2560e193a Mon Sep 17 00:00:00 2001 From: Demi Obenour <48690212+DemiMarie-parity@users.noreply.github.com> Date: Tue, 15 Oct 2019 12:33:34 -0400 Subject: [PATCH 042/167] Bump dependencies, respecting semver (#3812) --- Cargo.lock | 146 +++++++++++++++++++++++++++++------------------------ 1 file changed, 79 insertions(+), 67 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b8dade5e24..f83f550fdc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -112,19 +112,19 @@ dependencies = [ [[package]] name = "asn1_der" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "asn1_der_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "asn1_der_derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "asn1_der_derive" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -341,7 +341,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -627,7 +627,7 @@ dependencies = [ "bstr 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -747,7 +747,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "curve25519-dalek 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -758,7 +758,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "curve25519-dalek 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -834,22 +834,22 @@ dependencies = [ [[package]] name = "failure" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "backtrace 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)", - "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "failure_derive" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", - "synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "synstructure 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1327,7 +1327,7 @@ dependencies = [ "http 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", "http-body 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1419,7 +1419,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "iovec" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1427,7 +1427,7 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1466,7 +1466,7 @@ name = "jsonrpc-client-transports" version = "13.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.12.35 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1686,7 +1686,7 @@ dependencies = [ "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-timer 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-timer 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1694,11 +1694,11 @@ name = "libp2p-core" version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "asn1_der 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "asn1_der 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "bs58 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "ed25519-dalek 1.0.0-pre.2 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1720,7 +1720,7 @@ dependencies = [ "unsigned-varint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-timer 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-timer 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "zeroize 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1790,7 +1790,7 @@ dependencies = [ "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "unsigned-varint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-timer 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-timer 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1817,7 +1817,7 @@ dependencies = [ "uint 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "unsigned-varint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-timer 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-timer 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1839,7 +1839,7 @@ dependencies = [ "tokio-reactor 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-udp 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-timer 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-timer 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1892,7 +1892,7 @@ dependencies = [ "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-timer 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-timer 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1957,7 +1957,7 @@ dependencies = [ "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-timer 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-timer 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1968,7 +1968,7 @@ dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "get_if_addrs 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "ipnet 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ipnet 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "libp2p-core 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2222,7 +2222,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2248,7 +2248,7 @@ name = "mio-uds" version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "iovec 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2300,7 +2300,7 @@ dependencies = [ "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "openssl 0.10.25 (registry+https://github.com/rust-lang/crates.io-index)", "openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.50 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", "schannel 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", "security-framework 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "security-framework-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2703,7 +2703,7 @@ dependencies = [ "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.50 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2713,7 +2713,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "openssl-sys" -version = "0.9.50" +version = "0.9.51" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3079,7 +3079,7 @@ name = "prost-derive" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3489,7 +3489,7 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -3528,7 +3528,7 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "curve25519-dalek 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "merlin 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3627,7 +3627,7 @@ version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3759,8 +3759,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "ring 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3817,7 +3817,7 @@ dependencies = [ "substrate-state-machine 2.0.0", "substrate-test-runtime-client 2.0.0", "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", - "trybuild 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", + "trybuild 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -4414,7 +4414,7 @@ dependencies = [ "srml-support 2.0.0", "substrate-inherents 2.0.0", "substrate-primitives 2.0.0", - "trybuild 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", + "trybuild 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -5685,6 +5685,17 @@ dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "synstructure" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "sysinfo" version = "0.9.5" @@ -5768,7 +5779,7 @@ name = "tiny-bip39" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "hmac 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "once_cell 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -5809,7 +5820,7 @@ dependencies = [ "tokio-fs 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-reactor 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-sync 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-sync 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-threadpool 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -5901,7 +5912,7 @@ dependencies = [ "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-sync 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-sync 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -5911,7 +5922,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "rustls 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "webpki 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -5919,7 +5930,7 @@ dependencies = [ [[package]] name = "tokio-sync" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -5933,7 +5944,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-reactor 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -5997,7 +6008,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", @@ -6085,7 +6096,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "trybuild" -version = "1.0.16" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -6237,7 +6248,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -6362,7 +6373,7 @@ name = "wasm-bindgen-webidl" version = "0.2.51" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -6374,7 +6385,7 @@ dependencies = [ [[package]] name = "wasm-timer" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", @@ -6411,7 +6422,7 @@ name = "web-sys" version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "js-sys 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)", "sourcefile 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "wasm-bindgen 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", @@ -6472,7 +6483,7 @@ name = "which" version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -6622,8 +6633,8 @@ dependencies = [ "checksum arc-swap 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "bc4662175ead9cd84451d5c35070517777949a2ed84551764129cedb88384841" "checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee" "checksum arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" -"checksum asn1_der 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bea40e881533b1fe23afca9cd1c1ca022219a10fce604099ecfc96bfa26eaf1a" -"checksum asn1_der_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9e7f92edafad155aff997fa5b727c6429b91e996b5a5d62a2b0adbae1306b5fe" +"checksum asn1_der 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6fce6b6a0ffdafebd82c87e79e3f40e8d2c523e5fea5566ff6b90509bf98d638" +"checksum asn1_der_derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0d0864d84b8e07b145449be9a8537db86bf9de5ce03b913214694643b4743502" "checksum assert_matches 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7deb0a829ca7bcfaf5da70b073a8d128619259a7be8216a355e23f00763059e5" "checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90" "checksum autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b671c8fb71b457dd4ae18c4ba1e59aa81793daacc361d82fcd410cef0d491875" @@ -6705,8 +6716,8 @@ dependencies = [ "checksum erased-serde 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3beee4bc16478a1b26f2e80ad819a52d24745e292f521a63c16eea5f74b7eb60" "checksum error-chain 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3ab49e9dcb602294bc42f9a7dfc9bc6e936fca4418ea300dbfb84fe16de0b7d9" "checksum exit-future 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d8013f441e38e31c670e7f34ec8f1d5d3a2bd9d303c1ff83976ca886005e8f48" -"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" -"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" +"checksum failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f8273f13c977665c5db7eb2b99ae520952fe5ac831ae4cd09d80c4c7042b5ed9" +"checksum failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0bc225b78e0391e4b8683440bf2e63c2deeeb2ce5189eab46e2b68c6d3725d08" "checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" "checksum fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b1ee15a7050e5580b3712877157068ea713b245b080ff302ae2ca973cfcd9baa" "checksum finality-grandpa 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9681c1f75941ea47584573dd2bc10558b2067d460612945887e00744e43393be" @@ -6770,8 +6781,8 @@ dependencies = [ "checksum indexmap 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a61202fbe46c4a951e9404a720a0180bcf3212c750d735cb5c4ba4dc551299f3" "checksum integer-sqrt 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ea155abb3ba6f382a75f1418988c05fe82959ed9ce727de427f9cfd425b0c903" "checksum interleaved-ordered 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "141340095b15ed7491bd3d4ced9d20cebfb826174b6bb03386381f62b01e3d77" -"checksum iovec 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c9636900aa73ffed13cdbb199f17cd955670bb300927c8d25b517dfa136b6567" -"checksum ipnet 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e61c2da0d0f700c77d2d313dbf4f93e41d235fa12c6681fee06621036df4c2af" +"checksum iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" +"checksum ipnet 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc15ac2e0886d62ba078989ef6920ab23997ab0b04ca5687f1a9a7484296a48" "checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358" "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" "checksum jobserver 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "f2b1d42ef453b30b7387e113da1c83ab1605d90c5b4e0eb8e96d016ed3b8c160" @@ -6861,7 +6872,7 @@ dependencies = [ "checksum opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" "checksum openssl 0.10.25 (registry+https://github.com/rust-lang/crates.io-index)" = "2f372b2b53ce10fb823a337aaa674e3a7d072b957c6264d0f4ff0bd86e657449" "checksum openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" -"checksum openssl-sys 0.9.50 (registry+https://github.com/rust-lang/crates.io-index)" = "2c42dcccb832556b5926bc9ae61e8775f2a61e725ab07ab3d1e7fcf8ae62c3b6" +"checksum openssl-sys 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)" = "ba24190c8f0805d3bd2ce028f439fe5af1d55882bbe6261bed1dbc93b50dd6b1" "checksum output_vt100 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53cdc5b785b7a58c5aad8216b3dfa114df64b0b06ae6e1501cef91df2fbdf8f9" "checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13" "checksum parity-bytes 0.1.0 (git+https://github.com/paritytech/parity-common?rev=b0317f649ab2c665b7987b8475878fc4d2e1f81d)" = "" @@ -6946,7 +6957,7 @@ dependencies = [ "checksum rustls 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f271e3552cd835fa28c541c34a7e8fdd8cdff09d77fe4eb8f6c42e87a11b096e" "checksum rustversion 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b48139cfc215c6cc70d43c6c555a59e723c3b5adb26a4cfa09f815a5ae5871e8" "checksum rw-stream-sink 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9cbe61c20455d3015b2bb7be39e1872310283b8e5a52f5b242b0ac7581fe78" -"checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997" +"checksum ryu 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "19d2271fa48eaf61e53cc88b4ad9adcbafa2d512c531e7fadb6dc11a4d3656c5" "checksum safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7f7bf422d23a88c16d5090d455f182bc99c60af4df6a345c63428acf5129e347" "checksum safemem 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d2b08423011dae9a5ca23f07cf57dac3857f5c885d352b76f6d95f4aea9434d0" "checksum same-file 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "585e8ddcedc187886a30fa705c47985c3fa88d06624095856b36ca0b82ff4421" @@ -6998,6 +7009,7 @@ dependencies = [ "checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" "checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf" "checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f" +"checksum synstructure 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f085a5855930c0441ca1288cf044ea4aecf4f43a91668abdb870b4ba546a203" "checksum sysinfo 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d5bd3b813d94552a8033c650691645f8dd5a63d614dddd62428a95d3931ef7b6" "checksum take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" "checksum target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c63f48baada5c52e65a29eef93ab4f8982681b67f9e8d29c7b05abcfec2b9ffe" @@ -7020,7 +7032,7 @@ dependencies = [ "checksum tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "5090db468dad16e1a7a54c8c67280c5e4b544f3d3e018f0b913b400261f85926" "checksum tokio-reactor 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "c56391be9805bc80163151c0b9e5164ee64f4b0200962c346fea12773158f22d" "checksum tokio-rustls 0.10.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3e5cebc3ca33110e460c4d2e7c5e863b159fadcbf125449d896720695b2af709" -"checksum tokio-sync 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2162248ff317e2bc713b261f242b69dbb838b85248ed20bb21df56d60ea4cae7" +"checksum tokio-sync 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "d06554cce1ae4a50f42fba8023918afa931413aded705b560e29600ccf7c6d76" "checksum tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1d14b10654be682ac43efee27401d792507e30fd8d26389e1da3b185de2e4119" "checksum tokio-threadpool 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "2bd2c6a3885302581f4401c82af70d792bb9df1700e7437b0aeb4ada94d5388c" "checksum tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "f2106812d500ed25a4f38235b9cae8f78a09edf43203e16e59c3b769a342a60e" @@ -7034,7 +7046,7 @@ dependencies = [ "checksum trie-root 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0b779f7c1c8fe9276365d9d5be5c4b5adeacf545117bb3f64c974305789c5c0b" "checksum trie-standardmap 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3161ba520ab28cd8e6b68e1126f1009f6e335339d1a73b978139011703264c8" "checksum try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382" -"checksum trybuild 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)" = "10d8f366221c5a5ff8a62faa005e186fdce758949d34a9140b64a062951bae68" +"checksum trybuild 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "e6851bf8351876984fbab8a2391de6378947b898410d8714edd12164d2137127" "checksum twofish 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712d261e83e727c8e2dbb75dacac67c36e35db36a958ee504f2164fc052434e1" "checksum twox-hash 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3bfd5b7557925ce778ff9b9ef90e3ade34c524b5ff10e239c69a42d546d2af56" "checksum typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887" @@ -7069,7 +7081,7 @@ dependencies = [ "checksum wasm-bindgen-macro-support 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)" = "9c075d27b7991c68ca0f77fe628c3513e64f8c477d422b859e03f28751b46fc5" "checksum wasm-bindgen-shared 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)" = "83d61fe986a7af038dd8b5ec660e5849cbd9f38e7492b9404cc48b2b4df731d1" "checksum wasm-bindgen-webidl 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)" = "9b979afb0535fe4749906a674082db1211de8aef466331d43232f63accb7c07c" -"checksum wasm-timer 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3d6101df9a5987df809216bdda7289f52b58128e6b6a6546e9ee3e6b632b4921" +"checksum wasm-timer 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "aa3e01d234bb71760e685cfafa5e2c96f8ad877c161a721646356651069e26ac" "checksum wasmi 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f31d26deb2d9a37e6cfed420edce3ed604eab49735ba89035e13c98f9a528313" "checksum wasmi-validation 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6bc0356e3df56e639fc7f7d8a99741915531e27ed735d911ed83d7e1339c8188" "checksum web-sys 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)" = "c84440699cd02ca23bed6f045ffb1497bc18a3c2628bd13e2093186faaaacf6b" -- GitLab From ba43ca16ee4c9eb45f6eec04ebf50f38b6dd6db7 Mon Sep 17 00:00:00 2001 From: Fabio Tudone Date: Wed, 16 Oct 2019 11:02:12 +0300 Subject: [PATCH 043/167] Fix #1536: do not require to construct a block for encoding it (#3813) * Fix #1536: do not require to construct a block for encoding it * Bump `impl_version` * Improve `Block::encode_from` signature and rustdoc (from review by @bkchr) --- core/client/src/client.rs | 8 ++++---- core/sr-primitives/src/generic/block.rs | 3 +++ core/sr-primitives/src/testing.rs | 3 +++ core/sr-primitives/src/traits.rs | 2 ++ node/runtime/src/lib.rs | 2 +- 5 files changed, 13 insertions(+), 5 deletions(-) diff --git a/core/client/src/client.rs b/core/client/src/client.rs index 34334b1388..796520cb7f 100644 --- a/core/client/src/client.rs +++ b/core/client/src/client.rs @@ -1059,10 +1059,10 @@ impl Client where } }; - let encoded_block = ::new( - import_headers.pre().clone(), - body.unwrap_or_default(), - ).encode(); + let encoded_block = ::encode_from( + import_headers.pre(), + &body.unwrap_or_default() + ); let (_, storage_update, changes_update) = self.executor .call_at_state::<_, _, NeverNativeValue, fn() -> _>( diff --git a/core/sr-primitives/src/generic/block.rs b/core/sr-primitives/src/generic/block.rs index 736ad0cbbb..29fcaab572 100644 --- a/core/sr-primitives/src/generic/block.rs +++ b/core/sr-primitives/src/generic/block.rs @@ -93,6 +93,9 @@ where fn new(header: Self::Header, extrinsics: Vec) -> Self { Block { header, extrinsics } } + fn encode_from(header: &Self::Header, extrinsics: &[Self::Extrinsic]) -> Vec { + (header, extrinsics).encode() + } } /// Abstraction over a substrate block and justification. diff --git a/core/sr-primitives/src/testing.rs b/core/sr-primitives/src/testing.rs index 5391735576..b790347118 100644 --- a/core/sr-primitives/src/testing.rs +++ b/core/sr-primitives/src/testing.rs @@ -259,6 +259,9 @@ impl) -> Self { Block { header, extrinsics } } + fn encode_from(header: &Self::Header, extrinsics: &[Self::Extrinsic]) -> Vec { + (header, extrinsics).encode() + } } impl<'a, Xt> Deserialize<'a> for Block where Block: Decode { diff --git a/core/sr-primitives/src/traits.rs b/core/sr-primitives/src/traits.rs index f94a71d38a..a589f5f389 100644 --- a/core/sr-primitives/src/traits.rs +++ b/core/sr-primitives/src/traits.rs @@ -687,6 +687,8 @@ pub trait Block: Clone + Send + Sync + Codec + Eq + MaybeSerializeDebugButNotDes fn hash(&self) -> Self::Hash { <::Hashing as Hash>::hash_of(self.header()) } + /// Create an encoded block from the given `header` and `extrinsics` without requiring to create an instance. + fn encode_from(header: &Self::Header, extrinsics: &[Self::Extrinsic]) -> Vec; } /// Something that acts like an `Extrinsic`. diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index 70b1b8f16a..d8fc9a1a57 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -85,7 +85,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // implementation changes and behavior does not, then leave spec_version as // is and increment impl_version. spec_version: 175, - impl_version: 175, + impl_version: 176, apis: RUNTIME_API_VERSIONS, }; -- GitLab From 297956d124b3fed191876e3f902de9a2a89c84ba Mon Sep 17 00:00:00 2001 From: Ashley Date: Wed, 16 Oct 2019 10:59:25 +0100 Subject: [PATCH 044/167] WIP: Node role RPC call (#3719) * Add a Node Role RPC call * Formatting * Fix tests * Change tests to use NodeRole::Authority so I don't forget to update the test * Improve role checking * return a vec instead * fix tests --- core/rpc/api/src/system/helpers.rs | 25 +++++++++++++++++++------ core/rpc/api/src/system/mod.rs | 6 +++++- core/rpc/src/system/mod.rs | 10 +++++++++- core/rpc/src/system/tests.rs | 11 +++++++++++ core/service/src/lib.rs | 19 ++++++++++++++++++- 5 files changed, 62 insertions(+), 9 deletions(-) diff --git a/core/rpc/api/src/system/helpers.rs b/core/rpc/api/src/system/helpers.rs index 00e2ba9f40..10319d57b6 100644 --- a/core/rpc/api/src/system/helpers.rs +++ b/core/rpc/api/src/system/helpers.rs @@ -50,6 +50,14 @@ pub struct Health { pub should_have_peers: bool, } +impl fmt::Display for Health { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "{} peers ({})", self.peers, if self.is_syncing { + "syncing" + } else { "idle" }) + } +} + /// Network Peer information #[derive(Debug, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] @@ -66,12 +74,17 @@ pub struct PeerInfo { pub best_number: Number, } -impl fmt::Display for Health { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "{} peers ({})", self.peers, if self.is_syncing { - "syncing" - } else { "idle" }) - } +/// The role the node is running as +#[derive(Debug, PartialEq, Serialize, Deserialize)] +pub enum NodeRole { + /// The node is a full node + Full, + /// The node is a light client + LightClient, + /// The node is an authority + Authority, + /// An unknown role with a bit number + UnknownRole(u8) } #[cfg(test)] diff --git a/core/rpc/api/src/system/mod.rs b/core/rpc/api/src/system/mod.rs index b5eacc5d61..f59fd84c7c 100644 --- a/core/rpc/api/src/system/mod.rs +++ b/core/rpc/api/src/system/mod.rs @@ -24,7 +24,7 @@ use jsonrpc_derive::rpc; use self::error::Result; -pub use self::helpers::{Properties, SystemInfo, Health, PeerInfo}; +pub use self::helpers::{Properties, SystemInfo, Health, PeerInfo, NodeRole}; pub use self::gen_client::Client as SystemClient; /// Substrate system RPC API @@ -64,4 +64,8 @@ pub trait SystemApi { // TODO: make this stable and move structs https://github.com/paritytech/substrate/issues/1890 #[rpc(name = "system_networkState", returns = "jsonrpc_core::Value")] fn system_network_state(&self) -> Receiver; + + /// Returns the roles the node is running as. + #[rpc(name = "system_nodeRoles", returns = "Vec")] + fn system_node_roles(&self) -> Receiver>; } diff --git a/core/rpc/src/system/mod.rs b/core/rpc/src/system/mod.rs index 8eeff6758b..8907151d9a 100644 --- a/core/rpc/src/system/mod.rs +++ b/core/rpc/src/system/mod.rs @@ -25,7 +25,7 @@ use sr_primitives::traits::{self, Header as HeaderT}; use self::error::Result; pub use api::system::*; -pub use self::helpers::{Properties, SystemInfo, Health, PeerInfo}; +pub use self::helpers::{Properties, SystemInfo, Health, PeerInfo, NodeRole}; pub use self::gen_client::Client as SystemClient; /// System API implementation @@ -42,6 +42,8 @@ pub enum Request { Peers(oneshot::Sender::Number>>>), /// Must return the state of the network. NetworkState(oneshot::Sender), + /// Must return the node role. + NodeRoles(oneshot::Sender>) } impl System { @@ -94,4 +96,10 @@ impl SystemApi::Number> for Sy let _ = self.send_back.unbounded_send(Request::NetworkState(tx)); Receiver(Compat::new(rx)) } + + fn system_node_roles(&self) -> Receiver> { + let (tx, rx) = oneshot::channel(); + let _ = self.send_back.unbounded_send(Request::NodeRoles(tx)); + Receiver(Compat::new(rx)) + } } diff --git a/core/rpc/src/system/tests.rs b/core/rpc/src/system/tests.rs index 5b271af9ac..1c532be372 100644 --- a/core/rpc/src/system/tests.rs +++ b/core/rpc/src/system/tests.rs @@ -79,6 +79,9 @@ fn api>>(sync: T) -> System { average_upload_per_sec: 0, peerset: serde_json::Value::Null, }).unwrap()); + }, + Request::NodeRoles(sender) => { + let _ = sender.send(vec![NodeRole::Authority]); } }; @@ -221,3 +224,11 @@ fn system_network_state() { } ); } + +#[test] +fn system_node_roles() { + assert_eq!( + wait_receiver(api(None).system_node_roles()), + vec![NodeRole::Authority] + ); +} \ No newline at end of file diff --git a/core/service/src/lib.rs b/core/service/src/lib.rs index fccf04d8a1..5dd9ea8270 100644 --- a/core/service/src/lib.rs +++ b/core/service/src/lib.rs @@ -368,6 +368,7 @@ macro_rules! new_impl { let _ = to_spawn_tx.unbounded_send(Box::new(build_network_future( + $config.roles, network_mut, client.clone(), network_status_sinks.clone(), @@ -662,6 +663,7 @@ fn build_network_future< S: network::specialization::NetworkSpecialization, H: network::ExHashT > ( + roles: Roles, mut network: network::NetworkWorker, client: Arc, status_sinks: Arc, NetworkState)>>>>, @@ -669,7 +671,7 @@ fn build_network_future< should_have_peers: bool, dht_event_tx: Option>, ) -> impl Future { - // Compatibility shim while we're transitionning to stable Futures. + // Compatibility shim while we're transitioning to stable Futures. // See https://github.com/paritytech/substrate/issues/3099 let mut rpc_rx = futures03::compat::Compat::new(rpc_rx.map(|v| Ok::<_, ()>(v))); @@ -725,6 +727,21 @@ fn build_network_future< let _ = sender.send(network_state); } } + rpc::system::Request::NodeRoles(sender) => { + use rpc::system::NodeRole; + + let node_roles = (0 .. 8) + .filter(|&bit_number| (roles.bits() >> bit_number) & 1 == 1) + .map(|bit_number| match Roles::from_bits(1 << bit_number) { + Some(Roles::AUTHORITY) => NodeRole::Authority, + Some(Roles::LIGHT) => NodeRole::LightClient, + Some(Roles::FULL) => NodeRole::Full, + _ => NodeRole::UnknownRole(bit_number), + }) + .collect(); + + let _ = sender.send(node_roles); + } }; } -- GitLab From ead7e0efda5f216ba13992ea6832ac4b70772204 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Wed, 16 Oct 2019 12:40:35 +0200 Subject: [PATCH 045/167] Move srml RPC extensions to separate crates (#3791) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Move srml-system RPC out. * Fix tests for system-rpc module. * Contracts RPC moved. * Fix rpc test. * Clean up. * Update lockfile. * Bump runtime version. * Update srml/contracts/rpc/runtime-api/src/lib.rs Co-Authored-By: Bastian Köcher * Bump impl version. --- Cargo.lock | 75 ++++++++++++---- Cargo.toml | 1 + core/rpc/src/state/tests.rs | 2 +- core/test-runtime/Cargo.toml | 2 + core/test-runtime/src/lib.rs | 12 +++ core/test-runtime/src/system.rs | 19 ++-- node/primitives/Cargo.toml | 8 -- node/primitives/src/lib.rs | 45 ---------- node/rpc/Cargo.toml | 17 +--- node/rpc/src/lib.rs | 25 ++---- node/runtime/Cargo.toml | 4 + node/runtime/src/lib.rs | 12 +-- srml/contracts/rpc/Cargo.toml | 17 ++++ srml/contracts/rpc/runtime-api/Cargo.toml | 20 +++++ srml/contracts/rpc/runtime-api/src/lib.rs | 64 +++++++++++++ .../contracts/rpc/src/lib.rs | 41 +++++---- srml/system/rpc/Cargo.toml | 23 +++++ srml/system/rpc/runtime-api/Cargo.toml | 16 ++++ srml/system/rpc/runtime-api/src/lib.rs | 34 +++++++ .../accounts.rs => srml/system/rpc/src/lib.rs | 89 ++++++++++--------- 20 files changed, 344 insertions(+), 182 deletions(-) create mode 100644 srml/contracts/rpc/Cargo.toml create mode 100644 srml/contracts/rpc/runtime-api/Cargo.toml create mode 100644 srml/contracts/rpc/runtime-api/src/lib.rs rename node/rpc/src/contracts.rs => srml/contracts/rpc/src/lib.rs (74%) create mode 100644 srml/system/rpc/Cargo.toml create mode 100644 srml/system/rpc/runtime-api/Cargo.toml create mode 100644 srml/system/rpc/runtime-api/src/lib.rs rename node/rpc/src/accounts.rs => srml/system/rpc/src/lib.rs (64%) diff --git a/Cargo.lock b/Cargo.lock index f83f550fdc..b42da79f88 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2417,12 +2417,8 @@ dependencies = [ name = "node-primitives" version = "2.0.0" dependencies = [ - "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", - "sr-std 2.0.0", - "substrate-client 2.0.0", "substrate-primitives 2.0.0", "substrate-serializer 2.0.0", ] @@ -2431,23 +2427,12 @@ dependencies = [ name = "node-rpc" version = "2.0.0" dependencies = [ - "env_logger 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-core-client 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-derive 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-pubsub 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "node-primitives 2.0.0", - "node-runtime 2.0.0", - "node-testing 2.0.0", - "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", + "srml-contracts-rpc 2.0.0", + "srml-system-rpc 2.0.0", "substrate-client 2.0.0", - "substrate-keyring 2.0.0", - "substrate-primitives 2.0.0", - "substrate-rpc-primitives 2.0.0", "substrate-transaction-pool 2.0.0", ] @@ -2484,6 +2469,7 @@ dependencies = [ "srml-balances 2.0.0", "srml-collective 2.0.0", "srml-contracts 2.0.0", + "srml-contracts-rpc-runtime-api 2.0.0", "srml-democracy 2.0.0", "srml-elections 2.0.0", "srml-executive 2.0.0", @@ -2500,6 +2486,7 @@ dependencies = [ "srml-sudo 2.0.0", "srml-support 2.0.0", "srml-system 2.0.0", + "srml-system-rpc-runtime-api 2.0.0", "srml-timestamp 2.0.0", "srml-treasury 2.0.0", "srml-utility 2.0.0", @@ -4047,6 +4034,31 @@ dependencies = [ "wasmi-validation 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "srml-contracts-rpc" +version = "2.0.0" +dependencies = [ + "jsonrpc-core 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core-client 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-derive 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-primitives 2.0.0", + "srml-contracts-rpc-runtime-api 2.0.0", + "substrate-client 2.0.0", + "substrate-rpc-primitives 2.0.0", +] + +[[package]] +name = "srml-contracts-rpc-runtime-api" +version = "2.0.0" +dependencies = [ + "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-std 2.0.0", + "substrate-client 2.0.0", +] + [[package]] name = "srml-democracy" version = "2.0.0" @@ -4434,6 +4446,34 @@ dependencies = [ "substrate-primitives 2.0.0", ] +[[package]] +name = "srml-system-rpc" +version = "2.0.0" +dependencies = [ + "env_logger 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core-client 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-derive 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-primitives 2.0.0", + "srml-system-rpc-runtime-api 2.0.0", + "substrate-client 2.0.0", + "substrate-primitives 2.0.0", + "substrate-test-runtime-client 2.0.0", + "substrate-transaction-pool 2.0.0", +] + +[[package]] +name = "srml-system-rpc-runtime-api" +version = "2.0.0" +dependencies = [ + "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "substrate-client 2.0.0", +] + [[package]] name = "srml-timestamp" version = "2.0.0" @@ -5535,6 +5575,7 @@ dependencies = [ "srml-executive 2.0.0", "srml-support 2.0.0", "srml-system 2.0.0", + "srml-system-rpc-runtime-api 2.0.0", "srml-timestamp 2.0.0", "substrate-application-crypto 2.0.0", "substrate-client 2.0.0", diff --git a/Cargo.toml b/Cargo.toml index 7e34a0bd6c..6508e2b41e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -103,6 +103,7 @@ members = [ "srml/staking/reward-curve", "srml/sudo", "srml/system", + "srml/system/rpc", "srml/timestamp", "srml/treasury", "srml/utility", diff --git a/core/rpc/src/state/tests.rs b/core/rpc/src/state/tests.rs index ba1aac4cc3..3790b3ea11 100644 --- a/core/rpc/src/state/tests.rs +++ b/core/rpc/src/state/tests.rs @@ -282,7 +282,7 @@ fn should_return_runtime_version() { \"specVersion\":1,\"implVersion\":1,\"apis\":[[\"0xdf6acb689907609b\",2],\ [\"0x37e397fc7c91f5e4\",1],[\"0xd2bc9897eed08f15\",1],[\"0x40fe3ad401f8959a\",3],\ [\"0xc6e9a76309f39b09\",1],[\"0xdd718d5cc53262d4\",1],[\"0xcbca25e39f142387\",1],\ - [\"0xf78b278be53f454c\",1],[\"0xab3c0572291feb8b\",1]]}"; + [\"0xf78b278be53f454c\",1],[\"0xab3c0572291feb8b\",1],[\"0xbc9d89904f5b923f\",1]]}"; let runtime_version = api.runtime_version(None.into()).wait().unwrap(); let serialized = serde_json::to_string(&runtime_version).unwrap(); diff --git a/core/test-runtime/Cargo.toml b/core/test-runtime/Cargo.toml index 313db0fd07..fec9128ef5 100644 --- a/core/test-runtime/Cargo.toml +++ b/core/test-runtime/Cargo.toml @@ -31,6 +31,7 @@ cfg-if = "0.1.10" srml-babe = { path = "../../srml/babe", default-features = false } srml-timestamp = { path = "../../srml/timestamp", default-features = false } srml-system = { path = "../../srml/system", default-features = false } +srml-system-rpc-runtime-api = { path = "../../srml/system/rpc/runtime-api", default-features = false } [dev-dependencies] substrate-executor = { path = "../executor" } @@ -68,6 +69,7 @@ std = [ "srml-babe/std", "srml-timestamp/std", "srml-system/std", + "srml-system-rpc-runtime-api/std", "app-crypto/std", "session/std", ] diff --git a/core/test-runtime/src/lib.rs b/core/test-runtime/src/lib.rs index e75cb69149..fddee22be2 100644 --- a/core/test-runtime/src/lib.rs +++ b/core/test-runtime/src/lib.rs @@ -648,6 +648,12 @@ cfg_if! { SessionKeys::generate(None) } } + + impl srml_system_rpc_runtime_api::AccountNonceApi for Runtime { + fn account_nonce(_account: AccountId) -> Index { + 0 + } + } } } else { impl_runtime_apis! { @@ -858,6 +864,12 @@ cfg_if! { SessionKeys::generate(None) } } + + impl srml_system_rpc_runtime_api::AccountNonceApi for Runtime { + fn account_nonce(_account: AccountId) -> Index { + 0 + } + } } } } diff --git a/core/test-runtime/src/system.rs b/core/test-runtime/src/system.rs index f3359aa1ba..d06bef5923 100644 --- a/core/test-runtime/src/system.rs +++ b/core/test-runtime/src/system.rs @@ -18,7 +18,7 @@ //! and depositing logs. use rstd::prelude::*; -use runtime_io::{storage_root, storage_changes_root, twox_128, blake2_256}; +use runtime_io::{storage_root, storage_changes_root, blake2_256}; use runtime_support::storage::{self, StorageValue, StorageMap}; use runtime_support::storage_items; use sr_primitives::{ @@ -170,22 +170,14 @@ pub fn validate_transaction(utx: Extrinsic) -> TransactionValidity { return InvalidTransaction::Future.into(); } - let hash = |from: &AccountId, nonce: u64| { - twox_128(&nonce.to_keyed_vec(&from.encode())).to_vec() - }; + let encode = |from: &AccountId, nonce: u64| (from, nonce).encode(); let requires = if tx.nonce != expected_nonce && tx.nonce > 0 { - let mut deps = Vec::new(); - deps.push(hash(&tx.from, tx.nonce - 1)); - deps + vec![encode(&tx.from, tx.nonce - 1)] } else { - Vec::new() + vec![] }; - let provides = { - let mut p = Vec::new(); - p.push(hash(&tx.from, tx.nonce)); - p - }; + let provides = vec![encode(&tx.from, tx.nonce)]; Ok(ValidTransaction { priority: tx.amount, @@ -324,6 +316,7 @@ mod tests { use crate::{Header, Transfer, WASM_BINARY}; use primitives::{NeverNativeValue, map, traits::CodeExecutor}; use substrate_executor::{NativeExecutor, WasmExecutionMethod, native_executor_instance}; + use runtime_io::twox_128; // Declare an instance of the native executor dispatch for the test runtime. native_executor_instance!( diff --git a/node/primitives/Cargo.toml b/node/primitives/Cargo.toml index 266720b024..25725449a3 100644 --- a/node/primitives/Cargo.toml +++ b/node/primitives/Cargo.toml @@ -5,11 +5,7 @@ authors = ["Parity Technologies "] edition = "2018" [dependencies] -client = { package = "substrate-client", path = "../../core/client", default-features = false } -codec = { package = "parity-scale-codec", version = "1.0.0", default-features = false, features = ["derive"] } primitives = { package = "substrate-primitives", path = "../../core/primitives", default-features = false } -rstd = { package = "sr-std", path = "../../core/sr-std", default-features = false } -serde = { version = "1.0.101", optional = true, features = ["derive"] } sr-primitives = { path = "../../core/sr-primitives", default-features = false } [dev-dependencies] @@ -19,10 +15,6 @@ pretty_assertions = "0.6.1" [features] default = ["std"] std = [ - "client/std", - "codec/std", "primitives/std", - "rstd/std", - "serde", "sr-primitives/std", ] diff --git a/node/primitives/src/lib.rs b/node/primitives/src/lib.rs index 907b78a017..b8abdd7421 100644 --- a/node/primitives/src/lib.rs +++ b/node/primitives/src/lib.rs @@ -20,15 +20,10 @@ #![cfg_attr(not(feature = "std"), no_std)] -use rstd::prelude::*; use sr_primitives::{ generic, traits::{Verify, BlakeTwo256}, OpaqueExtrinsic, AnySignature }; -#[cfg(feature = "std")] -use serde::{Serialize, Deserialize}; -use codec::{Encode, Decode}; - /// An index to a block. pub type BlockNumber = u32; @@ -72,43 +67,3 @@ pub type BlockId = generic::BlockId; /// Opaque, encoded, unchecked extrinsic. pub type UncheckedExtrinsic = OpaqueExtrinsic; -/// A result of execution of a contract. -#[derive(Eq, PartialEq, Encode, Decode)] -#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))] -pub enum ContractExecResult { - /// The contract returned successfully. - /// - /// There is a status code and, optionally, some data returned by the contract. - Success { - /// Status code returned by the contract. - status: u8, - /// Output data returned by the contract. - /// - /// Can be empty. - data: Vec, - }, - /// The contract execution either trapped or returned an error. - Error, -} - -client::decl_runtime_apis! { - /// The API to query account account nonce (aka index). - pub trait AccountNonceApi { - /// Get current account nonce of given `AccountId`. - fn account_nonce(account: AccountId) -> Index; - } - - /// The API to interact with contracts without using executive. - pub trait ContractsApi { - /// Perform a call from a specified account to a given contract. - /// - /// See the contracts' `call` dispatchable function for more details. - fn call( - origin: AccountId, - dest: AccountId, - value: Balance, - gas_limit: u64, - input_data: Vec, - ) -> ContractExecResult; - } -} diff --git a/node/rpc/Cargo.toml b/node/rpc/Cargo.toml index 6985d94e54..5d2ca81e0f 100644 --- a/node/rpc/Cargo.toml +++ b/node/rpc/Cargo.toml @@ -7,21 +7,8 @@ edition = "2018" [dependencies] client = { package = "substrate-client", path = "../../core/client" } jsonrpc-core = "13.2.0" -jsonrpc-core-client = "13.2.0" -jsonrpc-derive = "13.2.0" -jsonrpc-pubsub = "13.2.0" -keyring = { package = "substrate-keyring", path = "../../core/keyring" } -log = "0.4.8" node-primitives = { path = "../primitives" } -codec = { package = "parity-scale-codec", version = "1.0.0" } -serde = { version = "1.0.101", features = ["derive"] } sr-primitives = { path = "../../core/sr-primitives" } -substrate-primitives = { path = "../../core/primitives" } -rpc-primitives = { package = "substrate-rpc-primitives", path = "../../core/rpc/primitives" } +srml-contracts-rpc = { path = "../../srml/contracts/rpc/" } +srml-system-rpc = { path = "../../srml/system/rpc/" } transaction_pool = { package = "substrate-transaction-pool", path = "../../core/transaction-pool" } - -[dev-dependencies] -node-testing = { path = "../testing" } -node-runtime = { path = "../runtime" } -env_logger = "0.7.0" -futures03 = { package = "futures-preview", version = "=0.3.0-alpha.19" } diff --git a/node/rpc/src/lib.rs b/node/rpc/src/lib.rs index 43f723f796..398d458e63 100644 --- a/node/rpc/src/lib.rs +++ b/node/rpc/src/lib.rs @@ -25,43 +25,32 @@ //! The RPCs available in this crate however can make some assumptions //! about how the runtime is constructed and what `SRML` modules //! are part of it. Therefore all node-runtime-specific RPCs can -//! be placed here. +//! be placed here or imported from corresponding `SRML` RPC definitions. #![warn(missing_docs)] use std::sync::Arc; -use node_primitives::{Block, AccountNonceApi, ContractsApi}; +use node_primitives::{Block, AccountId, Index, Balance}; use sr_primitives::traits::ProvideRuntimeApi; use transaction_pool::txpool::{ChainApi, Pool}; -pub mod accounts; -pub mod contracts; - -mod constants { - /// A status code indicating an error happened while trying to call into the runtime. - /// - /// This typically means that the runtime trapped. - pub const RUNTIME_ERROR: i64 = 1; -} - /// Instantiate all RPC extensions. pub fn create(client: Arc, pool: Arc>) -> jsonrpc_core::IoHandler where C: ProvideRuntimeApi, C: client::blockchain::HeaderBackend, C: Send + Sync + 'static, - C::Api: AccountNonceApi + ContractsApi, + C::Api: srml_system_rpc::AccountNonceApi, + C::Api: srml_contracts_rpc::ContractsRuntimeApi, P: ChainApi + Sync + Send + 'static, M: jsonrpc_core::Metadata + Default, { - use self::{ - accounts::{Accounts, AccountsApi}, - contracts::{Contracts, ContractsApi}, - }; + use srml_system_rpc::{System, SystemApi}; + use srml_contracts_rpc::{Contracts, ContractsApi}; let mut io = jsonrpc_core::IoHandler::default(); io.extend_with( - AccountsApi::to_delegate(Accounts::new(client.clone(), pool)) + SystemApi::to_delegate(System::new(client.clone(), pool)) ); io.extend_with( ContractsApi::to_delegate(Contracts::new(client)) diff --git a/node/runtime/Cargo.toml b/node/runtime/Cargo.toml index a47d652100..f9818c096e 100644 --- a/node/runtime/Cargo.toml +++ b/node/runtime/Cargo.toml @@ -31,6 +31,7 @@ babe = { package = "srml-babe", path = "../../srml/babe", default-features = fal balances = { package = "srml-balances", path = "../../srml/balances", default-features = false } collective = { package = "srml-collective", path = "../../srml/collective", default-features = false } contracts = { package = "srml-contracts", path = "../../srml/contracts", default-features = false } +contracts-rpc-runtime-api = { package = "srml-contracts-rpc-runtime-api", path = "../../srml/contracts/rpc/runtime-api/", default-features = false } democracy = { package = "srml-democracy", path = "../../srml/democracy", default-features = false } elections = { package = "srml-elections", path = "../../srml/elections", default-features = false } executive = { package = "srml-executive", path = "../../srml/executive", default-features = false } @@ -47,6 +48,7 @@ srml-staking-reward-curve = { path = "../../srml/staking/reward-curve"} sudo = { package = "srml-sudo", path = "../../srml/sudo", default-features = false } support = { package = "srml-support", path = "../../srml/support", default-features = false } system = { package = "srml-system", path = "../../srml/system", default-features = false } +system-rpc-runtime-api = { package = "srml-system-rpc-runtime-api", path = "../../srml/system/rpc/runtime-api/", default-features = false } timestamp = { package = "srml-timestamp", path = "../../srml/timestamp", default-features = false } treasury = { package = "srml-treasury", path = "../../srml/treasury", default-features = false } utility = { package = "srml-utility", path = "../../srml/utility", default-features = false } @@ -67,6 +69,7 @@ std = [ "codec/std", "collective/std", "contracts/std", + "contracts-rpc-runtime-api/std", "democracy/std", "elections/std", "executive/std", @@ -93,6 +96,7 @@ std = [ "sudo/std", "support/std", "system/std", + "system-rpc-runtime-api/std", "timestamp/std", "treasury/std", "utility/std", diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index d8fc9a1a57..fd31969efa 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -27,7 +27,7 @@ use support::{ use primitives::u32_trait::{_1, _2, _3, _4}; use node_primitives::{ AccountId, AccountIndex, Balance, BlockNumber, Hash, Index, - Moment, Signature, ContractExecResult, + Moment, Signature, }; use babe_primitives::{AuthorityId as BabeId, AuthoritySignature as BabeSignature}; use grandpa::fg_primitives; @@ -84,7 +84,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // and set impl_version to equal spec_version. If only runtime // implementation changes and behavior does not, then leave spec_version as // is and increment impl_version. - spec_version: 175, + spec_version: 176, impl_version: 176, apis: RUNTIME_API_VERSIONS, }; @@ -660,20 +660,22 @@ impl_runtime_apis! { } } - impl node_primitives::AccountNonceApi for Runtime { + impl system_rpc_runtime_api::AccountNonceApi for Runtime { fn account_nonce(account: AccountId) -> Index { System::account_nonce(account) } } - impl node_primitives::ContractsApi for Runtime { + impl contracts_rpc_runtime_api::ContractsApi for Runtime { fn call( origin: AccountId, dest: AccountId, value: Balance, gas_limit: u64, input_data: Vec, - ) -> ContractExecResult { + ) -> contracts_rpc_runtime_api::ContractExecResult { + use contracts_rpc_runtime_api::ContractExecResult; + let exec_result = Contracts::bare_call( origin, dest.into(), diff --git a/srml/contracts/rpc/Cargo.toml b/srml/contracts/rpc/Cargo.toml new file mode 100644 index 0000000000..8ebb714e20 --- /dev/null +++ b/srml/contracts/rpc/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "srml-contracts-rpc" +version = "2.0.0" +authors = ["Parity Technologies "] +edition = "2018" + +[dependencies] +client = { package = "substrate-client", path = "../../../core/client" } +codec = { package = "parity-scale-codec", version = "1.0.0" } +jsonrpc-core = "13.2.0" +jsonrpc-core-client = "13.2.0" +jsonrpc-derive = "13.2.0" +rpc-primitives = { package = "substrate-rpc-primitives", path = "../../../core/rpc/primitives" } +serde = { version = "1.0.101", features = ["derive"] } +sr-primitives = { path = "../../../core/sr-primitives" } +srml-contracts-rpc-runtime-api = { path = "./runtime-api" } + diff --git a/srml/contracts/rpc/runtime-api/Cargo.toml b/srml/contracts/rpc/runtime-api/Cargo.toml new file mode 100644 index 0000000000..fce82aed2a --- /dev/null +++ b/srml/contracts/rpc/runtime-api/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "srml-contracts-rpc-runtime-api" +version = "2.0.0" +authors = ["Parity Technologies "] +edition = "2018" + +[dependencies] +client = { package = "substrate-client", path = "../../../../core/client", default-features = false } +codec = { package = "parity-scale-codec", version = "1.0.0", default-features = false, features = ["derive"] } +rstd = { package = "sr-std", path = "../../../../core/sr-std", default-features = false } +serde = { version = "1.0.101", optional = true, features = ["derive"] } + +[features] +default = ["std"] +std = [ + "client/std", + "codec/std", + "rstd/std", + "serde", +] diff --git a/srml/contracts/rpc/runtime-api/src/lib.rs b/srml/contracts/rpc/runtime-api/src/lib.rs new file mode 100644 index 0000000000..a5b56888ce --- /dev/null +++ b/srml/contracts/rpc/runtime-api/src/lib.rs @@ -0,0 +1,64 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +//! Runtime API definition required by Contracts RPC extensions. +//! +//! This API should be imported and implemented by the runtime, +//! of a node that wants to use the custom RPC extension +//! adding Contracts access methods. + +#![cfg_attr(not(feature = "std"), no_std)] + +use rstd::vec::Vec; +use codec::{Encode, Decode, Codec}; + +/// A result of execution of a contract. +#[derive(Eq, PartialEq, Encode, Decode)] +#[cfg_attr(feature = "std", derive(Debug, serde::Serialize, serde::Deserialize))] +pub enum ContractExecResult { + /// The contract returned successfully. + /// + /// There is a status code and, optionally, some data returned by the contract. + Success { + /// Status code returned by the contract. + status: u8, + /// Output data returned by the contract. + /// + /// Can be empty. + data: Vec, + }, + /// The contract execution either trapped or returned an error. + Error, +} + +client::decl_runtime_apis! { + /// The API to interact with contracts without using executive. + pub trait ContractsApi where + AccountId: Codec, + Balance: Codec, + { + /// Perform a call from a specified account to a given contract. + /// + /// See the contracts' `call` dispatchable function for more details. + fn call( + origin: AccountId, + dest: AccountId, + value: Balance, + gas_limit: u64, + input_data: Vec, + ) -> ContractExecResult; + } +} diff --git a/node/rpc/src/contracts.rs b/srml/contracts/rpc/src/lib.rs similarity index 74% rename from node/rpc/src/contracts.rs rename to srml/contracts/rpc/src/lib.rs index 3da2478dab..7e17aaaf17 100644 --- a/node/rpc/src/contracts.rs +++ b/srml/contracts/rpc/src/lib.rs @@ -20,22 +20,23 @@ use std::sync::Arc; use serde::{Serialize, Deserialize}; use client::blockchain::HeaderBackend; +use codec::Codec; use jsonrpc_core::{Error, ErrorCode, Result}; use jsonrpc_derive::rpc; -use node_primitives::{ - AccountId, Balance, Block, BlockId, ContractExecResult, ContractsApi as ContractsRuntimeApi, -}; -use sr_primitives::traits::{ - self, - Block as BlockT, +use sr_primitives::{ + generic::BlockId, + traits::{Block as BlockT, ProvideRuntimeApi}, }; use rpc_primitives::number; +pub use srml_contracts_rpc_runtime_api::{ContractExecResult, ContractsApi as ContractsRuntimeApi}; +pub use self::gen_client::Client as ContractsClient; + /// A struct that encodes RPC parameters required for a call to a smart-contract. #[derive(Serialize, Deserialize)] #[serde(rename_all="camelCase")] #[serde(deny_unknown_fields)] -pub struct CallRequest { +pub struct CallRequest { origin: AccountId, dest: AccountId, value: Balance, @@ -45,7 +46,7 @@ pub struct CallRequest { /// Contracts RPC methods. #[rpc] -pub trait ContractsApi { +pub trait ContractsApi { /// Executes a call to a contract. /// /// This call is performed locally without submitting any transactions. Thus executing this @@ -55,33 +56,39 @@ pub trait ContractsApi { #[rpc(name = "contracts_call")] fn call( &self, - call_request: CallRequest, + call_request: CallRequest, at: Option, ) -> Result; } /// An implementation of contract specific RPC methods. -pub struct Contracts { +pub struct Contracts { client: Arc, + _marker: std::marker::PhantomData, } -impl Contracts { +impl Contracts { /// Create new `Contracts` with the given reference to the client. pub fn new(client: Arc) -> Self { - Contracts { client } + Contracts { client, _marker: Default::default() } } } -impl ContractsApi<::Hash> for Contracts +const RUNTIME_ERROR: i64 = 1; + +impl ContractsApi<::Hash, AccountId, Balance> for Contracts where + Block: BlockT, C: Send + Sync + 'static, - C: traits::ProvideRuntimeApi, + C: ProvideRuntimeApi, C: HeaderBackend, - C::Api: ContractsRuntimeApi, + C::Api: ContractsRuntimeApi, + AccountId: Codec, + Balance: Codec, { fn call( &self, - call_request: CallRequest, + call_request: CallRequest, at: Option<::Hash>, ) -> Result { let api = self.client.runtime_api(); @@ -106,7 +113,7 @@ where let exec_result = api .call(&at, origin, dest, value, gas_limit, input_data) .map_err(|e| Error { - code: ErrorCode::ServerError(crate::constants::RUNTIME_ERROR), + code: ErrorCode::ServerError(RUNTIME_ERROR), message: "Runtime trapped while executing a contract.".into(), data: Some(format!("{:?}", e).into()), })?; diff --git a/srml/system/rpc/Cargo.toml b/srml/system/rpc/Cargo.toml new file mode 100644 index 0000000000..04856a817f --- /dev/null +++ b/srml/system/rpc/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "srml-system-rpc" +version = "2.0.0" +authors = ["Parity Technologies "] +edition = "2018" + +[dependencies] +client = { package = "substrate-client", path = "../../../core/client" } +codec = { package = "parity-scale-codec", version = "1.0.0" } +jsonrpc-core = "13.2.0" +jsonrpc-core-client = "13.2.0" +jsonrpc-derive = "13.2.0" +log = "0.4.8" +serde = { version = "1.0.101", features = ["derive"] } +sr-primitives = { path = "../../../core/sr-primitives" } +srml-system-rpc-runtime-api = { path = "./runtime-api" } +substrate-primitives = { path = "../../../core/primitives" } +transaction_pool = { package = "substrate-transaction-pool", path = "../../../core/transaction-pool" } + +[dev-dependencies] +test-client = { package = "substrate-test-runtime-client", path = "../../../core/test-runtime/client" } +env_logger = "0.7.0" +futures03 = { package = "futures-preview", version = "=0.3.0-alpha.19" } diff --git a/srml/system/rpc/runtime-api/Cargo.toml b/srml/system/rpc/runtime-api/Cargo.toml new file mode 100644 index 0000000000..fc525d8fce --- /dev/null +++ b/srml/system/rpc/runtime-api/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "srml-system-rpc-runtime-api" +version = "2.0.0" +authors = ["Parity Technologies "] +edition = "2018" + +[dependencies] +client = { package = "substrate-client", path = "../../../../core/client", default-features = false } +codec = { package = "parity-scale-codec", version = "1.0.0", default-features = false } + +[features] +default = ["std"] +std = [ + "client/std", + "codec/std", +] diff --git a/srml/system/rpc/runtime-api/src/lib.rs b/srml/system/rpc/runtime-api/src/lib.rs new file mode 100644 index 0000000000..45af0241e0 --- /dev/null +++ b/srml/system/rpc/runtime-api/src/lib.rs @@ -0,0 +1,34 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +//! Runtime API definition required by System RPC extensions. +//! +//! This API should be imported and implemented by the runtime, +//! of a node that wants to use the custom RPC extension +//! adding System access methods. + +#![cfg_attr(not(feature = "std"), no_std)] + +client::decl_runtime_apis! { + /// The API to query account nonce (aka transaction index). + pub trait AccountNonceApi where + AccountId: codec::Codec, + Index: codec::Codec, + { + /// Get current account nonce of given `AccountId`. + fn account_nonce(account: AccountId) -> Index; + } +} diff --git a/node/rpc/src/accounts.rs b/srml/system/rpc/src/lib.rs similarity index 64% rename from node/rpc/src/accounts.rs rename to srml/system/rpc/src/lib.rs index 6c8e60736a..c6c0a658fb 100644 --- a/node/rpc/src/accounts.rs +++ b/srml/system/rpc/src/lib.rs @@ -14,58 +14,66 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -//! Node-specific RPC methods for Accounts. +//! System SRML specific RPC methods. use std::sync::Arc; +use codec::{self, Codec, Encode}; use client::blockchain::HeaderBackend; use jsonrpc_core::{Result, Error, ErrorCode}; use jsonrpc_derive::rpc; -use node_primitives::{ - AccountId, Index, AccountNonceApi, Block, BlockId, +use sr_primitives::{ + generic::BlockId, + traits, }; -use codec::Encode; -use sr_primitives::traits; use substrate_primitives::hexdisplay::HexDisplay; use transaction_pool::txpool::{self, Pool}; -pub use self::gen_client::Client as AccountsClient; +pub use srml_system_rpc_runtime_api::AccountNonceApi; +pub use self::gen_client::Client as SystemClient; -/// Accounts RPC methods. +/// System RPC methods. #[rpc] -pub trait AccountsApi { +pub trait SystemApi { /// Returns the next valid index (aka nonce) for given account. /// /// This method takes into consideration all pending transactions /// currently in the pool and if no transactions are found in the pool /// it fallbacks to query the index from the runtime (aka. state nonce). - #[rpc(name = "account_nextIndex")] + #[rpc(name = "system_accountNextIndex", alias("account_nextIndex"))] fn nonce(&self, account: AccountId) -> Result; } -/// An implementation of Accounts specific RPC methods. -pub struct Accounts { +const RUNTIME_ERROR: i64 = 1; + +/// An implementation of System-specific RPC methods. +pub struct System { client: Arc, pool: Arc>, + _marker: std::marker::PhantomData, } -impl Accounts { - /// Create new `Accounts` given client and transaction pool. +impl System { + /// Create new `System` given client and transaction pool. pub fn new(client: Arc, pool: Arc>) -> Self { - Accounts { + System { client, - pool + pool, + _marker: Default::default(), } } } -impl AccountsApi for Accounts +impl SystemApi for System where C: traits::ProvideRuntimeApi, C: HeaderBackend, C: Send + Sync + 'static, - C::Api: AccountNonceApi, + C::Api: AccountNonceApi, P: txpool::ChainApi + Sync + Send + 'static, + Block: traits::Block, + AccountId: Clone + std::fmt::Display + Codec, + Index: Clone + std::fmt::Display + Codec + traits::SimpleArithmetic, { fn nonce(&self, account: AccountId) -> Result { let api = self.client.runtime_api(); @@ -73,7 +81,7 @@ where let at = BlockId::hash(best); let nonce = api.account_nonce(&at, account.clone()).map_err(|e| Error { - code: ErrorCode::ServerError(crate::constants::RUNTIME_ERROR), + code: ErrorCode::ServerError(RUNTIME_ERROR), message: "Unable to query nonce.".into(), data: Some(format!("{:?}", e).into()), })?; @@ -85,12 +93,12 @@ where // Since extrinsics are opaque to us, we look for them using // `provides` tag. And increment the nonce if we find a transaction // that matches the current one. - let mut current_nonce = nonce; - let mut current_tag = (account.clone(), nonce).encode(); + let mut current_nonce = nonce.clone(); + let mut current_tag = (account.clone(), nonce.clone()).encode(); for tx in self.pool.ready() { log::debug!( target: "rpc", - "Current nonce to {:?}, checking {} vs {:?}", + "Current nonce to {}, checking {} vs {:?}", current_nonce, HexDisplay::from(¤t_tag), tx.provides.iter().map(|x| format!("{}", HexDisplay::from(x))).collect::>(), @@ -98,8 +106,8 @@ where // since transactions in `ready()` need to be ordered by nonce // it's fine to continue with current iterator. if tx.provides.get(0) == Some(¤t_tag) { - current_nonce += 1; - current_tag = (account.clone(), current_nonce).encode(); + current_nonce += traits::One::one(); + current_tag = (account.clone(), current_nonce.clone()).encode(); } } @@ -112,42 +120,37 @@ mod tests { use super::*; use futures03::executor::block_on; - use node_runtime::{CheckedExtrinsic, Call, TimestampCall}; - use codec::Decode; - use node_testing::{ - client::{ClientExt, TestClientBuilder, TestClientBuilderExt}, - keyring::{self, alice, signed_extra}, + use test_client::{ + runtime::Transfer, + AccountKeyring, }; - const VERSION: u32 = node_runtime::VERSION.spec_version; - #[test] fn should_return_next_nonce_for_some_account() { // given let _ = env_logger::try_init(); - let client = Arc::new(TestClientBuilder::new().build()); + let client = Arc::new(test_client::new()); let pool = Arc::new(Pool::new(Default::default(), transaction_pool::FullChainApi::new(client.clone()))); - let new_transaction = |extra| { - let ex = CheckedExtrinsic { - signed: Some((alice().into(), extra)), - function: Call::Timestamp(TimestampCall::set(5)), + let new_transaction = |nonce: u64| { + let t = Transfer { + from: AccountKeyring::Alice.into(), + to: AccountKeyring::Bob.into(), + amount: 5, + nonce, }; - let xt = keyring::sign(ex, VERSION, client.genesis_hash().into()); - // Convert to OpaqueExtrinsic - let encoded = xt.encode(); - node_primitives::UncheckedExtrinsic::decode(&mut &*encoded).unwrap() + t.into_signed_tx() }; // Populate the pool - let ext0 = new_transaction(signed_extra(0, 0)); + let ext0 = new_transaction(0); block_on(pool.submit_one(&BlockId::number(0), ext0)).unwrap(); - let ext1 = new_transaction(signed_extra(1, 0)); + let ext1 = new_transaction(1); block_on(pool.submit_one(&BlockId::number(0), ext1)).unwrap(); - let accounts = Accounts::new(client, pool); + let accounts = System::new(client, pool); // when - let nonce = accounts.nonce(alice().into()); + let nonce = accounts.nonce(AccountKeyring::Alice.into()); // then assert_eq!(nonce.unwrap(), 2); -- GitLab From e0f3fa3845654770f6d96dbaa2d3a76842ad44f3 Mon Sep 17 00:00:00 2001 From: thiolliere Date: Wed, 16 Oct 2019 15:47:46 +0200 Subject: [PATCH 046/167] Refactor decl storage (#3765) * split implementation in multiple files: * transformation -> genesis_config/ getters.rs instance_trait.rs metadata.rs mod.rs store_trait.rs * mod.rs -> parser.rs * impl.rs -> storage_struct.rs * parser is isolated into parse module, it could be improved as well but this can be done in another PR * modules contains a defintion of decl_storage input which must be ok to work with. * implementation change: * T: Trait might be more often bound to 'static (anyway we only use static one and it is needed for metadata current implementation). * GenesisConfig no longer requires its fields to be Clone (possible since to EncodeLike feature) * builder for map storages must return precise type Vec<(key, value)> --- node/runtime/src/lib.rs | 4 +- srml/support/procedural/src/lib.rs | 2 +- .../src/storage/genesis_config/builder_def.rs | 111 ++ .../genesis_config/genesis_config_def.rs | 144 ++ .../src/storage/genesis_config/mod.rs | 203 +++ .../support/procedural/src/storage/getters.rs | 80 ++ srml/support/procedural/src/storage/impls.rs | 418 ------ .../procedural/src/storage/instance_trait.rs | 196 +++ .../procedural/src/storage/metadata.rs | 230 +++ srml/support/procedural/src/storage/mod.rs | 521 ++++--- srml/support/procedural/src/storage/parse.rs | 377 +++++ .../procedural/src/storage/storage_struct.rs | 220 +++ .../procedural/src/storage/store_trait.rs | 54 + .../procedural/src/storage/transformation.rs | 1264 ----------------- srml/support/procedural/tools/src/syn_ext.rs | 12 +- 15 files changed, 1978 insertions(+), 1858 deletions(-) create mode 100644 srml/support/procedural/src/storage/genesis_config/builder_def.rs create mode 100644 srml/support/procedural/src/storage/genesis_config/genesis_config_def.rs create mode 100644 srml/support/procedural/src/storage/genesis_config/mod.rs create mode 100644 srml/support/procedural/src/storage/getters.rs delete mode 100644 srml/support/procedural/src/storage/impls.rs create mode 100644 srml/support/procedural/src/storage/instance_trait.rs create mode 100644 srml/support/procedural/src/storage/metadata.rs create mode 100644 srml/support/procedural/src/storage/parse.rs create mode 100644 srml/support/procedural/src/storage/storage_struct.rs create mode 100644 srml/support/procedural/src/storage/store_trait.rs delete mode 100644 srml/support/procedural/src/storage/transformation.rs diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index fd31969efa..63fc856013 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -84,8 +84,8 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // and set impl_version to equal spec_version. If only runtime // implementation changes and behavior does not, then leave spec_version as // is and increment impl_version. - spec_version: 176, - impl_version: 176, + spec_version: 177, + impl_version: 177, apis: RUNTIME_API_VERSIONS, }; diff --git a/srml/support/procedural/src/lib.rs b/srml/support/procedural/src/lib.rs index a9cfa8d30d..38d404712e 100644 --- a/srml/support/procedural/src/lib.rs +++ b/srml/support/procedural/src/lib.rs @@ -213,5 +213,5 @@ use proc_macro::TokenStream; /// #[proc_macro] pub fn decl_storage(input: TokenStream) -> TokenStream { - storage::transformation::decl_storage_impl(input) + storage::decl_storage_impl(input) } diff --git a/srml/support/procedural/src/storage/genesis_config/builder_def.rs b/srml/support/procedural/src/storage/genesis_config/builder_def.rs new file mode 100644 index 0000000000..60f094e9fe --- /dev/null +++ b/srml/support/procedural/src/storage/genesis_config/builder_def.rs @@ -0,0 +1,111 @@ +// Copyright 2017-2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +//! Builder logic definition used to build genesis storage. + +use srml_support_procedural_tools::syn_ext as ext; +use proc_macro2::TokenStream; +use syn::spanned::Spanned; +use quote::{quote, quote_spanned}; +use super::super::{DeclStorageDefExt, StorageLineTypeDef}; + +/// Definition of builder blocks, each block insert some value in the storage. +/// They must be called inside externalities, and with `self` being the genesis config. +pub struct BuilderDef { + /// Contains: + /// * build block for storage with build attribute. + /// * build block for storage with config attribute and no build attribute. + /// * build block for extra genesis build expression. + pub blocks: Vec, + /// The build blocks requires generic traits. + pub is_generic: bool, +} + +impl BuilderDef { + pub fn from_def(scrate: &TokenStream, def: &DeclStorageDefExt) -> Self { + let mut blocks = Vec::new(); + let mut is_generic = false; + + for line in def.storage_lines.iter() { + let storage_struct = &line.storage_struct; + let storage_trait = &line.storage_trait; + let value_type = &line.value_type; + + // Contains the data to inset at genesis either from build or config. + let mut data = None; + + if let Some(builder) = &line.build { + is_generic |= ext::expr_contains_ident(&builder, &def.module_runtime_generic); + is_generic |= line.is_generic; + + data = Some(quote_spanned!(builder.span() => &(#builder)(&self))); + } else if let Some(config) = &line.config { + is_generic |= line.is_generic; + + data = Some(quote!(&self.#config;)); + }; + + if let Some(data) = data { + blocks.push(match &line.storage_type { + StorageLineTypeDef::Simple(_) => { + quote!{{ + let v: &#value_type = #data; + <#storage_struct as #scrate::#storage_trait>::put::<&#value_type>(v); + }} + }, + StorageLineTypeDef::Map(map) | StorageLineTypeDef::LinkedMap(map) => { + let key = &map.key; + quote!{{ + let data: &#scrate::rstd::vec::Vec<(#key, #value_type)> = #data; + data.iter().for_each(|(k, v)| { + <#storage_struct as #scrate::#storage_trait>::insert::< + &#key, &#value_type + >(k, v); + }); + }} + }, + StorageLineTypeDef::DoubleMap(map) => { + let key1 = &map.key1; + let key2 = &map.key2; + quote!{{ + let data: &#scrate::rstd::vec::Vec<(#key1, #key2, #value_type)> = #data; + data.iter().for_each(|(k1, k2, v)| { + <#storage_struct as #scrate::#storage_trait>::insert::< + &#key1, &#key2, &#value_type + >(k1, k2, v); + }); + }} + }, + }); + } + } + + if let Some(builder) = def.extra_genesis_build.as_ref() { + is_generic |= ext::expr_contains_ident(&builder, &def.module_runtime_generic); + + blocks.push(quote_spanned! { builder.span() => + let extra_genesis_builder: fn(&Self) = #builder; + extra_genesis_builder(&self); + }); + } + + + Self { + blocks, + is_generic, + } + } +} diff --git a/srml/support/procedural/src/storage/genesis_config/genesis_config_def.rs b/srml/support/procedural/src/storage/genesis_config/genesis_config_def.rs new file mode 100644 index 0000000000..f9d2f8abe8 --- /dev/null +++ b/srml/support/procedural/src/storage/genesis_config/genesis_config_def.rs @@ -0,0 +1,144 @@ +// Copyright 2017-2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +//! Genesis config defintion. + +use srml_support_procedural_tools::syn_ext as ext; +use proc_macro2::TokenStream; +use syn::parse_quote; +use quote::quote; +use super::super::{DeclStorageDefExt, StorageLineTypeDef}; + +pub struct GenesisConfigFieldDef { + pub doc: Vec, + pub name: syn::Ident, + pub typ: syn::Type, + pub default: TokenStream, +} + +pub struct GenesisConfigDef { + pub is_generic: bool, + pub fields: Vec, + /// For example: `, I: Instance=DefaultInstance>`. + pub genesis_struct_decl: TokenStream, + /// For example: ``. + pub genesis_struct: TokenStream, + /// For example: `, I: Instance>`. + pub genesis_impl: TokenStream, + /// The where clause to use to constrain generics if genesis config is generic. + pub genesis_where_clause: Option, +} + +impl GenesisConfigDef { + pub fn from_def(def: &DeclStorageDefExt) -> Self { + let fields = Self::get_genesis_config_field_defs(def); + + let is_generic = fields.iter() + .any(|field| ext::type_contains_ident(&field.typ, &def.module_runtime_generic)); + + let ( + genesis_struct_decl, + genesis_impl, + genesis_struct, + genesis_where_clause + ) = if is_generic { + let runtime_generic = &def.module_runtime_generic; + let runtime_trait = &def.module_runtime_trait; + let optional_instance = &def.optional_instance; + let optional_instance_bound = &def.optional_instance_bound; + let optional_instance_bound_optional_default = &def.optional_instance_bound_optional_default; + let where_clause = &def.where_clause; + ( + quote!(<#runtime_generic: #runtime_trait, #optional_instance_bound_optional_default>), + quote!(<#runtime_generic: #runtime_trait, #optional_instance_bound>), + quote!(<#runtime_generic, #optional_instance>), + where_clause.clone(), + ) + } else { + (quote!(), quote!(), quote!(), None) + }; + + Self { + is_generic, + fields, + genesis_struct_decl, + genesis_struct, + genesis_impl, + genesis_where_clause, + } + } + + fn get_genesis_config_field_defs(def: &DeclStorageDefExt) -> Vec { + let mut config_field_defs = Vec::new(); + + for (config_field, line) in def.storage_lines.iter() + .filter_map(|line| line.config.as_ref().map(|config_field| (config_field.clone(), line))) + { + let value_type = &line.value_type; + + let typ = match &line.storage_type { + StorageLineTypeDef::Simple(_) => (*value_type).clone(), + StorageLineTypeDef::Map(map) | StorageLineTypeDef::LinkedMap(map) => { + let key = &map.key; + parse_quote!( Vec<(#key, #value_type)> ) + }, + StorageLineTypeDef::DoubleMap(map) => { + let key1 = &map.key1; + let key2 = &map.key2; + + parse_quote!( Vec<(#key1, #key2, #value_type)> ) + }, + }; + + let default = line.default_value.as_ref() + .map(|d| { + if line.is_option { + quote!( #d.unwrap_or_default() ) + } else { + quote!( #d ) + } + }) + .unwrap_or_else(|| quote!( Default::default() )); + + config_field_defs.push(GenesisConfigFieldDef { + doc: line.doc_attrs.clone(), + name: config_field, + typ, + default, + }); + } + + for line in &def.extra_genesis_config_lines { + let doc = line.attrs.iter() + .filter_map(|a| a.parse_meta().ok()) + .filter(|m| m.name() == "doc") + .collect(); + + let default = line.default.as_ref().map(|e| quote!( #e )) + .unwrap_or_else(|| quote!( Default::default() )); + + + config_field_defs.push(GenesisConfigFieldDef { + doc, + name: line.name.clone(), + typ: line.typ.clone(), + default, + }); + } + + config_field_defs + } +} diff --git a/srml/support/procedural/src/storage/genesis_config/mod.rs b/srml/support/procedural/src/storage/genesis_config/mod.rs new file mode 100644 index 0000000000..57de1e34a8 --- /dev/null +++ b/srml/support/procedural/src/storage/genesis_config/mod.rs @@ -0,0 +1,203 @@ +// Copyright 2017-2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +//! Declaration of genesis config structure and implementation of build storage trait and +//! functions. + +use proc_macro2::{TokenStream, Span}; +use quote::quote; +use super::{DeclStorageDefExt, instance_trait::DEFAULT_INSTANTIABLE_TRAIT_NAME}; +use genesis_config_def::GenesisConfigDef; +use builder_def::BuilderDef; + +mod genesis_config_def; +mod builder_def; + +const DEFAULT_INSTANCE_NAME: &str = "__GeneratedInstance"; + +fn decl_genesis_config_and_impl_default( + scrate: &TokenStream, + genesis_config: &GenesisConfigDef, +) -> TokenStream { + let config_fields = genesis_config.fields.iter().map(|field| { + let (name, typ, doc) = (&field.name, &field.typ, &field.doc); + quote!( #( #[ #doc] )* pub #name: #typ, ) + }); + + let config_field_defaults = genesis_config.fields.iter().map(|field| { + let (name, default, doc) = (&field.name, &field.default, &field.doc); + quote!( #( #[ #doc] )* #name: #default, ) + }); + + let serde_bug_bound = if !genesis_config.fields.is_empty() { + let mut b_ser = String::new(); + let mut b_dser = String::new(); + + for typ in genesis_config.fields.iter().map(|c| &c.typ) { + let typ = quote!( #typ ); + b_ser.push_str(&format!("{} : {}::serde::Serialize, ", typ, scrate)); + b_dser.push_str(&format!("{} : {}::serde::de::DeserializeOwned, ", typ, scrate)); + } + + quote! { + #[serde(bound(serialize = #b_ser))] + #[serde(bound(deserialize = #b_dser))] + } + } else { + quote!() + }; + + let genesis_struct_decl = &genesis_config.genesis_struct_decl; + let genesis_struct = &genesis_config.genesis_struct; + let genesis_impl = &genesis_config.genesis_impl; + let genesis_where_clause = &genesis_config.genesis_where_clause; + + quote!( + #[derive(#scrate::Serialize, #scrate::Deserialize)] + #[cfg(feature = "std")] + #[serde(rename_all = "camelCase")] + #[serde(deny_unknown_fields)] + #serde_bug_bound + pub struct GenesisConfig#genesis_struct_decl #genesis_where_clause { + #( #config_fields )* + } + + #[cfg(feature = "std")] + impl#genesis_impl Default for GenesisConfig#genesis_struct #genesis_where_clause { + fn default() -> Self { + GenesisConfig { + #( #config_field_defaults )* + } + } + } + ) +} + +fn impl_build_storage( + scrate: &TokenStream, + def: &DeclStorageDefExt, + genesis_config: &GenesisConfigDef, + builders: &BuilderDef, +) -> TokenStream { + let runtime_generic = &def.module_runtime_generic; + let runtime_trait = &def.module_runtime_trait; + let optional_instance = &def.optional_instance; + let optional_instance_bound = &def.optional_instance_bound; + let where_clause = &def.where_clause; + + let inherent_instance = def.optional_instance.clone().unwrap_or_else(|| { + let name = syn::Ident::new(DEFAULT_INSTANCE_NAME, Span::call_site()); + quote!( #name ) + }); + let inherent_instance_bound = def.optional_instance_bound.clone().unwrap_or_else(|| { + let bound = syn::Ident::new(DEFAULT_INSTANTIABLE_TRAIT_NAME, Span::call_site()); + quote!( #inherent_instance: #bound ) + }); + + let build_storage_impl = quote!( + <#runtime_generic: #runtime_trait, #inherent_instance_bound> + ); + + let genesis_struct = &genesis_config.genesis_struct; + let genesis_impl = &genesis_config.genesis_impl; + let genesis_where_clause = &genesis_config.genesis_where_clause; + + let ( + fn_generic, + fn_traitinstance, + fn_where_clause + ) = if !genesis_config.is_generic && builders.is_generic { + ( + quote!( <#runtime_generic: #runtime_trait, #optional_instance_bound> ), + quote!( #runtime_generic, #optional_instance ), + Some(&def.where_clause), + ) + } else { + (quote!(), quote!(), None) + }; + + let builder_blocks = &builders.blocks; + + let build_storage_impl_trait = quote!( + #scrate::sr_primitives::BuildModuleGenesisStorage<#runtime_generic, #inherent_instance> + ); + + quote!{ + #[cfg(feature = "std")] + impl#genesis_impl GenesisConfig#genesis_struct #genesis_where_clause { + pub fn build_storage #fn_generic (self) -> std::result::Result< + ( + #scrate::sr_primitives::StorageOverlay, + #scrate::sr_primitives::ChildrenStorageOverlay, + ), + String + > #fn_where_clause { + let mut storage = (Default::default(), Default::default()); + self.assimilate_storage::<#fn_traitinstance>(&mut storage)?; + Ok(storage) + } + + /// Assimilate the storage for this module into pre-existing overlays. + pub fn assimilate_storage #fn_generic ( + self, + tuple_storage: &mut ( + #scrate::sr_primitives::StorageOverlay, + #scrate::sr_primitives::ChildrenStorageOverlay, + ), + ) -> std::result::Result<(), String> #fn_where_clause { + #scrate::with_storage(tuple_storage, || { + #( #builder_blocks )* + Ok(()) + }) + } + } + + #[cfg(feature = "std")] + impl#build_storage_impl #build_storage_impl_trait for GenesisConfig#genesis_struct + #where_clause + { + fn build_module_genesis_storage( + self, + storage: &mut ( + #scrate::sr_primitives::StorageOverlay, + #scrate::sr_primitives::ChildrenStorageOverlay, + ), + ) -> std::result::Result<(), String> { + self.assimilate_storage::<#fn_traitinstance> (storage) + } + } + } +} + +pub fn genesis_config_and_build_storage( + scrate: &TokenStream, + def: &DeclStorageDefExt, +) -> TokenStream { + let builders = BuilderDef::from_def(scrate, def); + if !builders.blocks.is_empty() { + let genesis_config = &GenesisConfigDef::from_def(def); + let decl_genesis_config_and_impl_default = + decl_genesis_config_and_impl_default(scrate, genesis_config); + let impl_build_storage = impl_build_storage(scrate, def, genesis_config, &builders); + + quote!{ + #decl_genesis_config_and_impl_default + #impl_build_storage + } + } else { + quote!() + } +} diff --git a/srml/support/procedural/src/storage/getters.rs b/srml/support/procedural/src/storage/getters.rs new file mode 100644 index 0000000000..f30e489eb5 --- /dev/null +++ b/srml/support/procedural/src/storage/getters.rs @@ -0,0 +1,80 @@ +// Copyright 2017-2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +//! Implementation of getters on module structure. + +use proc_macro2::TokenStream; +use quote::quote; +use super::{DeclStorageDefExt, StorageLineTypeDef}; + +pub fn impl_getters(scrate: &TokenStream, def: &DeclStorageDefExt) -> TokenStream { + let mut getters = TokenStream::new(); + + for (get_fn, line) in def.storage_lines.iter() + .filter_map(|line| line.getter.as_ref().map(|get_fn| (get_fn, line))) + { + let attrs = &line.doc_attrs; + + let storage_struct = &line.storage_struct; + let storage_trait = &line.storage_trait; + + let getter = match &line.storage_type { + StorageLineTypeDef::Simple(value) => { + quote!{ + #( #[ #attrs ] )* + pub fn #get_fn() -> #value { + <#storage_struct as #scrate::#storage_trait>::get() + } + } + }, + StorageLineTypeDef::Map(map) | StorageLineTypeDef::LinkedMap(map) => { + let key = &map.key; + let value = &map.value; + quote!{ + #( #[ #attrs ] )* + pub fn #get_fn>(key: K) -> #value { + <#storage_struct as #scrate::#storage_trait>::get(key) + } + } + }, + StorageLineTypeDef::DoubleMap(map) => { + let key1 = &map.key1; + let key2 = &map.key2; + let value = &map.value; + quote!{ + pub fn #get_fn(k1: KArg1, k2: KArg2) -> #value + where + KArg1: #scrate::codec::EncodeLike<#key1>, + KArg2: #scrate::codec::EncodeLike<#key2>, + { + <#storage_struct as #scrate::#storage_trait>::get(k1, k2) + } + } + }, + }; + getters.extend(getter); + } + + let module_struct = &def.module_struct; + let module_impl = &def.module_impl; + let where_clause = &def.where_clause; + + quote!( + impl#module_impl #module_struct #where_clause { + #getters + } + ) +} diff --git a/srml/support/procedural/src/storage/impls.rs b/srml/support/procedural/src/storage/impls.rs deleted file mode 100644 index ee6fa9a164..0000000000 --- a/srml/support/procedural/src/storage/impls.rs +++ /dev/null @@ -1,418 +0,0 @@ -// Copyright 2019 Parity Technologies (UK) Ltd. -// This file is part of Substrate. - -// Substrate is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Substrate is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Substrate. If not, see . - -use crate::storage::transformation::{DeclStorageTypeInfos, InstanceOpts}; - -use srml_support_procedural_tools::syn_ext as ext; -use proc_macro2::TokenStream as TokenStream2; -use syn::Ident; -use quote::quote; - -fn from_optional_value_to_query(is_option: bool, fielddefault: TokenStream2) -> TokenStream2 { - if !is_option { - // raw type case - quote!( v.unwrap_or_else(|| #fielddefault ) ) - } else { - // Option<> type case - quote!( v.or_else(|| #fielddefault ) ) - } -} - -fn from_query_to_optional_value(is_option: bool) -> TokenStream2 { - if !is_option { - // raw type case - quote!( Some(v) ) - } else { - // Option<> type case - quote!( v ) - } -} - -// prefix for consts in trait Instance -pub(crate) const PREFIX_FOR: &str = "PREFIX_FOR_"; -pub(crate) const HEAD_KEY_FOR: &str = "HEAD_KEY_FOR_"; - -pub(crate) struct Impls<'a, I: Iterator> { - pub scrate: &'a TokenStream2, - pub visibility: &'a syn::Visibility, - pub traitinstance: &'a syn::Ident, - pub traittype: &'a syn::TypeParamBound, - pub instance_opts: &'a InstanceOpts, - pub type_infos: DeclStorageTypeInfos<'a>, - pub fielddefault: TokenStream2, - pub prefix: String, - pub cratename: &'a syn::Ident, - pub name: &'a syn::Ident, - pub attrs: I, - pub where_clause: &'a Option, -} - -impl<'a, I: Iterator> Impls<'a, I> { - pub fn simple_value(self) -> TokenStream2 { - let Self { - scrate, - visibility, - traitinstance, - traittype, - instance_opts, - type_infos, - fielddefault, - prefix, - name, - attrs, - where_clause, - .. - } = self; - let DeclStorageTypeInfos { typ, value_type, is_option, .. } = type_infos; - - let from_optional_value_to_query = from_optional_value_to_query(is_option, fielddefault); - let from_query_to_optional_value = from_query_to_optional_value(is_option); - - let InstanceOpts { - equal_default_instance, - bound_instantiable, - instance, - .. - } = instance_opts; - - let final_prefix = if let Some(instance) = instance { - let const_name = Ident::new(&format!("{}{}", PREFIX_FOR, name.to_string()), proc_macro2::Span::call_site()); - quote!{ #instance::#const_name.as_bytes() } - } else { - quote!{ #prefix.as_bytes() } - }; - - let (struct_trait, impl_trait, trait_and_instance, where_clause) = if ext::type_contains_ident( - value_type, traitinstance - ) { - ( - quote!(#traitinstance: #traittype, #instance #bound_instantiable #equal_default_instance), - quote!(#traitinstance: #traittype, #instance #bound_instantiable), - quote!(#traitinstance, #instance), - where_clause.clone(), - ) - } else { - ( - quote!(#instance #bound_instantiable #equal_default_instance), - quote!(#instance #bound_instantiable), - quote!(#instance), - None, - ) - }; - - // generator for value - quote! { - #( #[ #attrs ] )* - #visibility struct #name<#struct_trait>( - #scrate::rstd::marker::PhantomData<(#trait_and_instance)> - ) #where_clause; - - impl<#impl_trait> #scrate::storage::generator::StorageValue<#typ> - for #name<#trait_and_instance> #where_clause - { - type Query = #value_type; - - fn unhashed_key() -> &'static [u8] { - #final_prefix - } - - fn from_optional_value_to_query(v: Option<#typ>) -> Self::Query { - #from_optional_value_to_query - } - - fn from_query_to_optional_value(v: Self::Query) -> Option<#typ> { - #from_query_to_optional_value - } - } - } - } - - pub fn map(self, hasher: TokenStream2, kty: &syn::Type) -> TokenStream2 { - let Self { - scrate, - visibility, - traitinstance, - traittype, - instance_opts, - type_infos, - fielddefault, - prefix, - name, - attrs, - where_clause, - .. - } = self; - let DeclStorageTypeInfos { typ, value_type, is_option, .. } = type_infos; - - let from_optional_value_to_query = from_optional_value_to_query(is_option, fielddefault); - let from_query_to_optional_value = from_query_to_optional_value(is_option); - - let InstanceOpts { - equal_default_instance, - bound_instantiable, - instance, - .. - } = instance_opts; - - let final_prefix = if let Some(instance) = instance { - let const_name = syn::Ident::new( - &format!("{}{}", PREFIX_FOR, name.to_string()), - proc_macro2::Span::call_site(), - ); - quote! { #instance::#const_name.as_bytes() } - } else { - quote! { #prefix.as_bytes() } - }; - - let trait_required = ext::type_contains_ident(value_type, traitinstance) - || ext::type_contains_ident(kty, traitinstance); - - let (struct_trait, impl_trait, trait_and_instance, where_clause) = if trait_required { - ( - quote!(#traitinstance: #traittype, #instance #bound_instantiable #equal_default_instance), - quote!(#traitinstance: #traittype, #instance #bound_instantiable), - quote!(#traitinstance, #instance), - where_clause.clone(), - ) - } else { - ( - quote!(#instance #bound_instantiable #equal_default_instance), - quote!(#instance #bound_instantiable), - quote!(#instance), - None, - ) - }; - - // generator for map - quote!{ - #( #[ #attrs ] )* - #visibility struct #name<#struct_trait>( - #scrate::rstd::marker::PhantomData<(#trait_and_instance)> - ) #where_clause; - - impl<#impl_trait> #scrate::storage::generator::StorageMap<#kty, #typ> - for #name<#trait_and_instance> #where_clause - { - type Query = #value_type; - type Hasher = #scrate::#hasher; - - fn prefix() -> &'static [u8] { - #final_prefix - } - - fn from_optional_value_to_query(v: Option<#typ>) -> Self::Query { - #from_optional_value_to_query - } - - fn from_query_to_optional_value(v: Self::Query) -> Option<#typ> { - #from_query_to_optional_value - } - } - } - } - - pub fn linked_map(self, hasher: TokenStream2, kty: &syn::Type) -> TokenStream2 { - let Self { - scrate, - visibility, - traitinstance, - traittype, - instance_opts, - type_infos, - fielddefault, - prefix, - name, - attrs, - where_clause, - .. - } = self; - - let InstanceOpts { - equal_default_instance, - bound_instantiable, - instance, - .. - } = instance_opts; - - let final_prefix = if let Some(instance) = instance { - let const_name = Ident::new( - &format!("{}{}", PREFIX_FOR, name.to_string()), proc_macro2::Span::call_site() - ); - quote!{ #instance::#const_name.as_bytes() } - } else { - quote!{ #prefix.as_bytes() } - }; - - // make sure to use different prefix for head and elements. - let head_key = if let Some(instance) = instance { - let const_name = Ident::new( - &format!("{}{}", HEAD_KEY_FOR, name.to_string()), proc_macro2::Span::call_site() - ); - quote!{ #instance::#const_name.as_bytes() } - } else { - let head_key = format!("head of {}", prefix); - quote!{ #head_key.as_bytes() } - }; - - let DeclStorageTypeInfos { typ, value_type, is_option, .. } = type_infos; - - let from_optional_value_to_query = from_optional_value_to_query(is_option, fielddefault); - let from_query_to_optional_value = from_query_to_optional_value(is_option); - - let trait_required = ext::type_contains_ident(value_type, traitinstance) - || ext::type_contains_ident(kty, traitinstance); - - let (struct_trait, impl_trait, trait_and_instance, where_clause) = if trait_required { - ( - quote!(#traitinstance: #traittype, #instance #bound_instantiable #equal_default_instance), - quote!(#traitinstance: #traittype, #instance #bound_instantiable), - quote!(#traitinstance, #instance), - where_clause.clone(), - ) - } else { - ( - quote!(#instance #bound_instantiable #equal_default_instance), - quote!(#instance #bound_instantiable), - quote!(#instance), - None, - ) - }; - - // generator for linked map - quote! { - #( #[ #attrs ] )* - #visibility struct #name<#struct_trait>( - #scrate::rstd::marker::PhantomData<(#trait_and_instance)> - ) #where_clause; - - impl<#impl_trait> #scrate::storage::generator::StorageLinkedMap<#kty, #typ> - for #name<#trait_and_instance> #where_clause - { - type Query = #value_type; - type Hasher = #scrate::#hasher; - - fn prefix() -> &'static [u8] { - #final_prefix - } - - fn head_key() -> &'static [u8] { - #head_key - } - - fn from_optional_value_to_query(v: Option<#typ>) -> Self::Query { - #from_optional_value_to_query - } - - fn from_query_to_optional_value(v: Self::Query) -> Option<#typ> { - #from_query_to_optional_value - } - } - } - } - - pub fn double_map( - self, - hasher: TokenStream2, - k1ty: &syn::Type, - k2ty: &syn::Type, - k2_hasher: TokenStream2, - ) -> TokenStream2 { - let Self { - scrate, - visibility, - traitinstance, - traittype, - type_infos, - fielddefault, - prefix, - name, - attrs, - instance_opts, - where_clause, - .. - } = self; - - let DeclStorageTypeInfos { typ, value_type, is_option, .. } = type_infos; - - let from_optional_value_to_query = from_optional_value_to_query(is_option, fielddefault); - let from_query_to_optional_value = from_query_to_optional_value(is_option); - - let InstanceOpts { - equal_default_instance, - bound_instantiable, - instance, - .. - } = instance_opts; - - let final_prefix = if let Some(instance) = instance { - let const_name = Ident::new( - &format!("{}{}", PREFIX_FOR, name.to_string()), proc_macro2::Span::call_site() - ); - quote!{ #instance::#const_name.as_bytes() } - } else { - quote!{ #prefix.as_bytes() } - }; - - let (struct_trait, impl_trait, trait_and_instance, where_clause) = if ext::type_contains_ident( - value_type, traitinstance - ) || ext::type_contains_ident(k1ty, traitinstance) || ext::type_contains_ident(k2ty, traitinstance) - { - ( - quote!(#traitinstance: #traittype, #instance #bound_instantiable #equal_default_instance), - quote!(#traitinstance: #traittype, #instance #bound_instantiable), - quote!(#traitinstance, #instance), - where_clause.clone(), - ) - } else { - ( - quote!(#instance #bound_instantiable #equal_default_instance), - quote!(#instance #bound_instantiable), - quote!(#instance), - None, - ) - }; - - // generator for double map - quote!{ - #( #[ #attrs ] )* - #visibility struct #name<#struct_trait> ( - #scrate::rstd::marker::PhantomData<(#trait_and_instance)> - ) #where_clause; - - impl<#impl_trait> #scrate::storage::generator::StorageDoubleMap<#k1ty, #k2ty, #typ> - for #name<#trait_and_instance> #where_clause - { - type Query = #value_type; - - type Hasher1 = #scrate::#hasher; - - type Hasher2 = #scrate::#k2_hasher; - - fn key1_prefix() -> &'static [u8] { - #final_prefix - } - - fn from_optional_value_to_query(v: Option<#typ>) -> Self::Query { - #from_optional_value_to_query - } - - fn from_query_to_optional_value(v: Self::Query) -> Option<#typ> { - #from_query_to_optional_value - } - } - } - } -} diff --git a/srml/support/procedural/src/storage/instance_trait.rs b/srml/support/procedural/src/storage/instance_trait.rs new file mode 100644 index 0000000000..fe81dfe0db --- /dev/null +++ b/srml/support/procedural/src/storage/instance_trait.rs @@ -0,0 +1,196 @@ +// Copyright 2017-2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +//! Implementation of the trait instance and the instance structures implementing it. +//! (For not instantiable traits there is still the inherent instance implemented). + +use proc_macro2::{TokenStream, Span}; +use quote::quote; +use super::{DeclStorageDefExt, StorageLineTypeDef}; + +const NUMBER_OF_INSTANCE: usize = 16; +const INHERENT_INSTANCE_NAME: &str = "__InherentHiddenInstance"; +pub(crate) const DEFAULT_INSTANTIABLE_TRAIT_NAME: &str = "__GeneratedInstantiable"; + +// prefix for consts in trait Instance +pub(crate) const PREFIX_FOR: &str = "PREFIX_FOR_"; +pub(crate) const HEAD_KEY_FOR: &str = "HEAD_KEY_FOR_"; + +// Used to generate the const: +// `const $name: &'static str = $value_prefix ++ instance_prefix ++ $value_suffix` +struct InstanceConstDef { + name: syn::Ident, + value_prefix: String, + value_suffix: String, +} + +// Used to generate an instance implementation. +struct InstanceDef { + prefix: String, + instance_struct: syn::Ident, + doc: TokenStream, +} + +pub fn decl_and_impl(scrate: &TokenStream, def: &DeclStorageDefExt) -> TokenStream { + let mut impls = TokenStream::new(); + + let mut const_defs = vec![]; + + for line in def.storage_lines.iter() { + let storage_prefix = format!("{} {}", def.crate_name, line.name); + + let const_name = syn::Ident::new( + &format!("{}{}", PREFIX_FOR, line.name.to_string()), proc_macro2::Span::call_site() + ); + const_defs.push(InstanceConstDef { + name: const_name, + value_prefix: String::new(), + value_suffix: storage_prefix.clone(), + }); + + if let StorageLineTypeDef::LinkedMap(_) = line.storage_type { + let const_name = syn::Ident::new( + &format!("{}{}", HEAD_KEY_FOR, line.name.to_string()), proc_macro2::Span::call_site() + ); + const_defs.push(InstanceConstDef { + name: const_name, + value_prefix: "head of ".into(), + value_suffix: storage_prefix, + }); + } + } + + impls.extend(create_instance_trait(&const_defs, def)); + + // Implementation of instances. + if let Some(module_instance) = &def.module_instance { + let instance_defs = (0..NUMBER_OF_INSTANCE) + .map(|i| { + let name = format!("Instance{}", i); + InstanceDef { + instance_struct: syn::Ident::new(&name, proc_macro2::Span::call_site()), + prefix: name, + doc: quote!(#[doc=r"Module instance"]), + } + }) + .chain( + module_instance.instance_default.as_ref().map(|ident| InstanceDef { + prefix: String::new(), + instance_struct: ident.clone(), + doc: quote!(#[doc=r"Default module instance"]), + }) + ); + + for instance_def in instance_defs { + impls.extend(create_and_impl_instance_struct(scrate, &instance_def, &const_defs, def)); + } + } + + // The name of the inherently available instance. + let inherent_instance = syn::Ident::new(INHERENT_INSTANCE_NAME, Span::call_site()); + + // Implementation of inherent instance. + if let Some(default_instance) = def.module_instance.as_ref() + .and_then(|i| i.instance_default.as_ref()) + { + impls.extend(quote! { + #[doc(hidden)] + pub type #inherent_instance = #default_instance; + }); + } else { + let instance_def = InstanceDef { + prefix: String::new(), + instance_struct: inherent_instance, + doc: quote!(#[doc(hidden)]), + }; + impls.extend(create_and_impl_instance_struct(scrate, &instance_def, &const_defs, def)); + } + + impls +} + +fn create_instance_trait( + const_defs: &[InstanceConstDef], + def: &DeclStorageDefExt, +) -> TokenStream { + let instance_trait = def.module_instance.as_ref().map(|i| i.instance_trait.clone()) + .unwrap_or_else(|| syn::Ident::new(DEFAULT_INSTANTIABLE_TRAIT_NAME, Span::call_site())); + + let mut const_impls = TokenStream::new(); + for const_def in const_defs { + let const_name = &const_def.name; + const_impls.extend(quote! { + const #const_name: &'static str; + }); + } + + let optional_hide = if def.module_instance.is_some() { + quote!() + } else { + quote!(#[doc(hidden)]) + }; + + quote! { + /// Tag a type as an instance of a module. + /// + /// Defines storage prefixes, they must be unique. + #optional_hide + pub trait #instance_trait: 'static { + /// The prefix used by any storage entry of an instance. + const PREFIX: &'static str; + #const_impls + } + } +} + +fn create_and_impl_instance_struct( + scrate: &TokenStream, + instance_def: &InstanceDef, + const_defs: &[InstanceConstDef], + def: &DeclStorageDefExt, +) -> TokenStream { + let mut const_impls = TokenStream::new(); + + for const_def in const_defs { + let const_value = format!( + "{}{}{}", const_def.value_prefix, instance_def.prefix, const_def.value_suffix + ); + let const_name = &const_def.name; + + const_impls.extend(quote! { + const #const_name: &'static str = #const_value; + }); + } + + let instance_trait = def.module_instance.as_ref().map(|i| i.instance_trait.clone()) + .unwrap_or_else(|| syn::Ident::new(DEFAULT_INSTANTIABLE_TRAIT_NAME, Span::call_site())); + + let instance_struct = &instance_def.instance_struct; + let prefix = format!("{}{}", instance_def.prefix, def.crate_name.to_string()); + let doc = &instance_def.doc; + + quote! { + // Those trait are derived because of wrong bounds for generics + #[cfg_attr(feature = "std", derive(Debug))] + #[derive(Clone, Eq, PartialEq, #scrate::codec::Encode, #scrate::codec::Decode)] + #doc + pub struct #instance_struct; + impl #instance_trait for #instance_struct { + const PREFIX: &'static str = #prefix; + #const_impls + } + } +} diff --git a/srml/support/procedural/src/storage/metadata.rs b/srml/support/procedural/src/storage/metadata.rs new file mode 100644 index 0000000000..e280c7d8a2 --- /dev/null +++ b/srml/support/procedural/src/storage/metadata.rs @@ -0,0 +1,230 @@ +// Copyright 2017-2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +//! Implementation of `storage_metadata` on module structure, used by construct_runtime. + +use srml_support_procedural_tools::clean_type_string; +use proc_macro2::TokenStream; +use quote::quote; +use super::{DeclStorageDefExt, StorageLineDefExt, StorageLineTypeDef}; + +fn storage_line_metadata_type(scrate: &TokenStream, line: &StorageLineDefExt) -> TokenStream { + let value_type = &line.value_type; + let value_type = clean_type_string("e!( #value_type ).to_string()); + match &line.storage_type { + StorageLineTypeDef::Simple(_) => { + quote!{ + #scrate::metadata::StorageEntryType::Plain( + #scrate::metadata::DecodeDifferent::Encode(#value_type), + ) + } + }, + StorageLineTypeDef::Map(map) => { + let hasher = map.hasher.into_metadata(); + let key = &map.key; + let key = clean_type_string("e!(#key).to_string()); + quote!{ + #scrate::metadata::StorageEntryType::Map { + hasher: #scrate::metadata::#hasher, + key: #scrate::metadata::DecodeDifferent::Encode(#key), + value: #scrate::metadata::DecodeDifferent::Encode(#value_type), + is_linked: false, + } + } + }, + StorageLineTypeDef::LinkedMap(map) => { + let hasher = map.hasher.into_metadata(); + let key = &map.key; + let key = clean_type_string("e!(#key).to_string()); + quote!{ + #scrate::metadata::StorageEntryType::Map { + hasher: #scrate::metadata::#hasher, + key: #scrate::metadata::DecodeDifferent::Encode(#key), + value: #scrate::metadata::DecodeDifferent::Encode(#value_type), + is_linked: true, + } + } + }, + StorageLineTypeDef::DoubleMap(map) => { + let hasher1 = map.hasher1.into_metadata(); + let hasher2 = map.hasher2.into_metadata(); + let key1 = &map.key1; + let key1 = clean_type_string("e!(#key1).to_string()); + let key2 = &map.key2; + let key2 = clean_type_string("e!(#key2).to_string()); + quote!{ + #scrate::metadata::StorageEntryType::DoubleMap { + hasher: #scrate::metadata::#hasher1, + key1: #scrate::metadata::DecodeDifferent::Encode(#key1), + key2: #scrate::metadata::DecodeDifferent::Encode(#key2), + value: #scrate::metadata::DecodeDifferent::Encode(#value_type), + key2_hasher: #scrate::metadata::#hasher2, + } + } + }, + } +} + +fn default_byte_getter( + scrate: &TokenStream, + line: &StorageLineDefExt, + def: &DeclStorageDefExt, +) -> (TokenStream, TokenStream) { + let default = line.default_value.as_ref().map(|d| quote!( #d )) + .unwrap_or_else(|| quote!( Default::default() )); + + let str_name = line.name.to_string(); + let struct_name = syn::Ident::new(&("__GetByteStruct".to_string() + &str_name), line.name.span()); + let cache_name = syn::Ident::new(&("__CACHE_GET_BYTE_STRUCT_".to_string() + &str_name), line.name.span()); + + let runtime_generic = &def.module_runtime_generic; + let runtime_trait = &def.module_runtime_trait; + let optional_instance_bound_optional_default = &def.optional_instance_bound_optional_default; + let optional_instance_bound = &def.optional_instance_bound; + let optional_instance = &def.optional_instance; + let optional_comma_instance = optional_instance.as_ref().map(|i| quote!(, #i)); + let where_clause = &def.where_clause; + + let query_type = &line.query_type; + + let struct_def = quote! { + #[doc(hidden)] + pub struct #struct_name< + #runtime_generic, #optional_instance_bound_optional_default + >(pub #scrate::rstd::marker::PhantomData<(#runtime_generic #optional_comma_instance)>); + + #[cfg(feature = "std")] + #[allow(non_upper_case_globals)] + static #cache_name: #scrate::once_cell::sync::OnceCell<#scrate::rstd::vec::Vec> = + #scrate::once_cell::sync::OnceCell::new(); + + #[cfg(feature = "std")] + impl<#runtime_generic: #runtime_trait, #optional_instance_bound> + #scrate::metadata::DefaultByte + for #struct_name<#runtime_generic, #optional_instance> + #where_clause + { + fn default_byte(&self) -> #scrate::rstd::vec::Vec { + use #scrate::codec::Encode; + #cache_name.get_or_init(|| { + let def_val: #query_type = #default; + <#query_type as Encode>::encode(&def_val) + }).clone() + } + } + + unsafe impl<#runtime_generic: #runtime_trait, #optional_instance_bound> Send + for #struct_name<#runtime_generic, #optional_instance> #where_clause {} + + unsafe impl<#runtime_generic: #runtime_trait, #optional_instance_bound> Sync + for #struct_name<#runtime_generic, #optional_instance> #where_clause {} + + #[cfg(not(feature = "std"))] + impl<#runtime_generic: #runtime_trait, #optional_instance_bound> + #scrate::metadata::DefaultByte + for #struct_name<#runtime_generic, #optional_instance> + #where_clause + { + fn default_byte(&self) -> #scrate::rstd::vec::Vec { + use #scrate::codec::Encode; + let def_val: #query_type = #default; + <#query_type as Encode>::encode(&def_val) + } + } + }; + let struct_instance = quote!( + #struct_name::<#runtime_generic, #optional_instance>(#scrate::rstd::marker::PhantomData) + ); + + (struct_def, struct_instance) +} + +pub fn impl_metadata(scrate: &TokenStream, def: &DeclStorageDefExt) -> TokenStream { + let mut entries = TokenStream::new(); + let mut default_byte_getter_struct_defs = TokenStream::new(); + + for line in def.storage_lines.iter() { + let str_name = line.name.to_string(); + + let modifier = if line.is_option { + quote!(#scrate::metadata::StorageEntryModifier::Optional) + } else { + quote!(#scrate::metadata::StorageEntryModifier::Default) + }; + + let ty = storage_line_metadata_type(scrate, line); + + let ( + default_byte_getter_struct_def, + default_byte_getter_struct_instance, + ) = default_byte_getter(scrate, line, def); + + let mut docs = TokenStream::new(); + for attr in line.attrs.iter().filter_map(|v| v.parse_meta().ok()) { + if let syn::Meta::NameValue(meta) = attr { + if meta.ident == "doc" { + let lit = meta.lit; + docs.extend(quote!(#lit,)); + } + } + } + + let entry = quote! { + #scrate::metadata::StorageEntryMetadata { + name: #scrate::metadata::DecodeDifferent::Encode(#str_name), + modifier: #modifier, + ty: #ty, + default: #scrate::metadata::DecodeDifferent::Encode( + #scrate::metadata::DefaultByteGetter(&#default_byte_getter_struct_instance) + ), + documentation: #scrate::metadata::DecodeDifferent::Encode(&[ #docs ]), + }, + }; + + default_byte_getter_struct_defs.extend(default_byte_getter_struct_def); + entries.extend(entry); + } + + let prefix = if let Some(instance) = &def.module_instance { + let instance_generic = &instance.instance_generic; + quote!(#instance_generic::PREFIX) + } else { + let prefix = def.crate_name.to_string(); + quote!(#prefix) + }; + + let store_metadata = quote!( + #scrate::metadata::StorageMetadata { + prefix: #scrate::metadata::DecodeDifferent::Encode(#prefix), + entries: #scrate::metadata::DecodeDifferent::Encode(&[ #entries ][..]), + } + ); + + let module_struct = &def.module_struct; + let module_impl = &def.module_impl; + let where_clause = &def.where_clause; + + quote!( + #default_byte_getter_struct_defs + + impl#module_impl #module_struct #where_clause { + #[doc(hidden)] + pub fn storage_metadata() -> #scrate::metadata::StorageMetadata { + #store_metadata + } + } + ) +} diff --git a/srml/support/procedural/src/storage/mod.rs b/srml/support/procedural/src/storage/mod.rs index 4253206f44..9a6931d87e 100644 --- a/srml/support/procedural/src/storage/mod.rs +++ b/srml/support/procedural/src/storage/mod.rs @@ -14,191 +14,358 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -// tag::description[] -//! `decl_storage` macro -// end::description[] +//! `decl_storage` input definition and expansion. + +mod storage_struct; +mod parse; +mod store_trait; +mod getters; +mod metadata; +mod instance_trait; +mod genesis_config; -use srml_support_procedural_tools::{ToTokens, Parse, syn_ext as ext}; -use syn::{Ident, Token}; -use proc_macro2::TokenStream as TokenStream2; use quote::quote; +use srml_support_procedural_tools::{ + generate_crate_access, generate_hidden_includes, syn_ext as ext +}; -mod impls; - -pub mod transformation; - -mod keyword { - syn::custom_keyword!(hiddencrate); - syn::custom_keyword!(add_extra_genesis); - syn::custom_keyword!(extra_genesis_skip_phantom_data_field); - syn::custom_keyword!(config); - syn::custom_keyword!(build); - syn::custom_keyword!(get); - syn::custom_keyword!(map); - syn::custom_keyword!(linked_map); - syn::custom_keyword!(double_map); - syn::custom_keyword!(blake2_256); - syn::custom_keyword!(blake2_128); - syn::custom_keyword!(twox_256); - syn::custom_keyword!(twox_128); - syn::custom_keyword!(twox_64_concat); - syn::custom_keyword!(hasher); +/// All informations contained in input of decl_storage +pub struct DeclStorageDef { + /// Name of the module used to import hidden imports. + hidden_crate: Option, + /// Visibility of store trait. + visibility: syn::Visibility, + /// Name of store trait: usually `Store`. + store_trait: syn::Ident, + /// Module name used by construct_runtime: usually `Module`. + module_name: syn::Ident, + /// Usually `T`. + module_runtime_generic: syn::Ident, + /// Usually `Trait` + module_runtime_trait: syn::Path, + /// For instantiable module: usually `I: Instance=DefaultInstance`. + module_instance: Option, + /// Where claused used to constrain T and I even more. + where_clause: Option, + /// The extra build function used to build storage at genesis. + extra_genesis_build: Option, + /// The extra genesis config fields. + extra_genesis_config_lines: Vec, + /// Definition of storages. + storage_lines: Vec, + /// Name of the crate, used for storage prefixes. + crate_name: syn::Ident, } -/// Parsing usage only -#[derive(Parse, ToTokens, Debug)] -struct StorageDefinition { - pub hidden_crate: ext::Opt, - pub visibility: syn::Visibility, - pub trait_token: Token![trait], - pub ident: Ident, - pub for_token: Token![for], - pub module_ident: Ident, - pub mod_lt_token: Token![<], - pub mod_param: syn::GenericParam, - pub mod_instance_param_token: Option, - pub mod_instance: Option, - pub mod_instantiable_token: Option, - pub mod_instantiable: Option, - pub mod_default_instance_token: Option, - pub mod_default_instance: Option, - pub mod_gt_token: Token![>], - pub as_token: Token![as], - pub crate_ident: Ident, - pub where_clause: Option, - pub content: ext::Braces>, - pub extra_genesis: ext::Opt, +impl syn::parse::Parse for DeclStorageDef { + fn parse(input: syn::parse::ParseStream) -> syn::Result { + parse::parse(input) + } } -#[derive(Parse, ToTokens, Debug)] -struct SpecificHiddenCrate { - pub keyword: keyword::hiddencrate, - pub ident: ext::Parens, +/// Extended version of `DeclStorageDef` with useful precomputed value. +pub struct DeclStorageDefExt { + /// Name of the module used to import hidden imports. + hidden_crate: Option, + /// Visibility of store trait. + visibility: syn::Visibility, + /// Name of store trait: usually `Store`. + store_trait: syn::Ident, + /// Module name used by construct_runtime: usually `Module`. + #[allow(unused)] + module_name: syn::Ident, + /// Usually `T`. + module_runtime_generic: syn::Ident, + /// Usually `Trait`. + module_runtime_trait: syn::Path, + /// For instantiable module: usually `I: Instance=DefaultInstance`. + module_instance: Option, + /// Where claused used to constrain T and I even more. + where_clause: Option, + /// The extra build function used to build storage at genesis. + extra_genesis_build: Option, + /// The extra genesis config fields. + extra_genesis_config_lines: Vec, + /// Definition of storages. + storage_lines: Vec, + /// Name of the crate, used for storage prefixes. + crate_name: syn::Ident, + /// Full struct expansion: `Module`. + module_struct: proc_macro2::TokenStream, + /// Impl block for module: ``. + module_impl: proc_macro2::TokenStream, + /// For instantiable: `I`. + optional_instance: Option, + /// For instantiable: `I: Instance`. + optional_instance_bound: Option, + /// For instantiable: `I: Instance = DefaultInstance`. + optional_instance_bound_optional_default: Option, } -#[derive(Parse, ToTokens, Debug)] -struct AddExtraGenesis { - pub extragenesis_keyword: keyword::add_extra_genesis, - pub content: ext::Braces, -} +impl From for DeclStorageDefExt { + fn from(mut def: DeclStorageDef) -> Self { + let storage_lines = def.storage_lines.drain(..).collect::>(); + let storage_lines = storage_lines.into_iter() + .map(|line| StorageLineDefExt::from_def(line, &def)) + .collect(); + + let ( + optional_instance, + optional_instance_bound, + optional_instance_bound_optional_default, + ) = if let Some(instance) = def.module_instance.as_ref() { + let instance_generic = &instance.instance_generic; + let instance_trait= &instance.instance_trait; + let optional_equal_instance_default = instance.instance_default.as_ref() + .map(|d| quote!( = #d )); + ( + Some(quote!(#instance_generic)), + Some(quote!(#instance_generic: #instance_trait)), + Some(quote!(#instance_generic: #instance_trait #optional_equal_instance_default)), + ) + } else { + (None, None, None) + }; + + let module_runtime_generic = &def.module_runtime_generic; + let module_runtime_trait = &def.module_runtime_trait; + let module_name = &def.module_name; -#[derive(Parse, ToTokens, Debug)] -struct AddExtraGenesisContent { - pub lines: ext::Punctuated, + let module_struct = quote!( + #module_name<#module_runtime_generic, #optional_instance> + ); + + let module_impl = quote!( + <#module_runtime_generic: #module_runtime_trait + 'static, #optional_instance_bound> + ); + + Self { + hidden_crate: def.hidden_crate, + visibility: def.visibility, + store_trait: def.store_trait, + module_name: def.module_name, + module_runtime_generic: def.module_runtime_generic, + module_runtime_trait: def.module_runtime_trait, + module_instance: def.module_instance, + where_clause: def.where_clause, + extra_genesis_build: def.extra_genesis_build, + extra_genesis_config_lines: def.extra_genesis_config_lines, + crate_name: def.crate_name, + storage_lines, + module_struct, + module_impl, + optional_instance, + optional_instance_bound, + optional_instance_bound_optional_default, + } + } } -#[derive(Parse, ToTokens, Debug)] -enum AddExtraGenesisLineEnum { - AddExtraGenesisLine(AddExtraGenesisLine), - AddExtraGenesisBuild(DeclStorageBuild), +/// Usually `I: Instance=DefaultInstance`. +pub struct ModuleInstanceDef { + /// Usually: `I`. + instance_generic: syn::Ident, + /// Usually: `Instance`. + instance_trait: syn::Ident, + /// Usually: `DefaultInstance`. + instance_default: Option, } -#[derive(Parse, ToTokens, Debug)] -struct AddExtraGenesisLine { - pub attrs: ext::OuterAttributes, - pub config_keyword: keyword::config, - pub extra_field: ext::Parens, - pub coldot_token: Token![:], - pub extra_type: syn::Type, - pub default_value: ext::Opt, +pub struct StorageLineDef { + attrs: Vec, + /// Visibility of the storage struct. + visibility: syn::Visibility, + name: syn::Ident, + /// The name of getter function to be implemented on Module struct. + getter: Option, + /// The name of the field to be used in genesis config if any. + config: Option, + /// The build function of the storage if any. + build: Option, + /// Default value of genesis config field and also for storage when no value available. + default_value: Option, + storage_type: StorageLineTypeDef, } -#[derive(Parse, ToTokens, Debug)] -struct DeclStorageLine { - // attrs (main use case is doc) - pub attrs: ext::OuterAttributes, - // visibility (no need to make optional - pub visibility: syn::Visibility, - // name - pub name: Ident, - pub getter: ext::Opt, - pub config: ext::Opt, - pub build: ext::Opt, - pub coldot_token: Token![:], - pub storage_type: DeclStorageType, - pub default_value: ext::Opt, +pub struct StorageLineDefExt { + #[allow(unused)] + attrs: Vec, + /// Visibility of the storage struct. + visibility: syn::Visibility, + name: syn::Ident, + /// The name of getter function to be implemented on Module struct. + getter: Option, + /// The name of the field to be used in genesis config if any. + config: Option, + /// The build function of the storage if any. + build: Option, + /// Default value of genesis config field and also for storage when no value available. + default_value: Option, + storage_type: StorageLineTypeDef, + doc_attrs: Vec, + /// Either the type stored in storage or wrapped in an Option. + query_type: syn::Type, + /// The type stored in storage. + value_type: syn::Type, + /// Full struct, for example: `StorageName`. + storage_struct: proc_macro2::TokenStream, + /// If storage is generic over runtime then `T`. + optional_storage_runtime_comma: Option, + /// If storage is generic over runtime then `T: Trait`. + optional_storage_runtime_bound_comma: Option, + /// The where clause to use to constrain generics if storage is generic over runtime. + optional_storage_where_clause: Option, + /// Full trait, for example: `storage::StorageMap`. + storage_trait: proc_macro2::TokenStream, + /// Full trait, for example: `storage::generator::StorageMap`. + storage_generator_trait: proc_macro2::TokenStream, + /// Weither the storage is generic. + is_generic: bool, + /// Weither the storage value is an option. + is_option: bool, } +impl StorageLineDefExt { + fn from_def(storage_def: StorageLineDef, def: &DeclStorageDef) -> Self { + let is_generic = match &storage_def.storage_type { + StorageLineTypeDef::Simple(value) => { + ext::type_contains_ident(&value, &def.module_runtime_generic) + }, + StorageLineTypeDef::Map(map) => { + ext::type_contains_ident(&map.key, &def.module_runtime_generic) + || ext::type_contains_ident(&map.value, &def.module_runtime_generic) + } + StorageLineTypeDef::LinkedMap(map) => { + ext::type_contains_ident(&map.key, &def.module_runtime_generic) + || ext::type_contains_ident(&map.value, &def.module_runtime_generic) + } + StorageLineTypeDef::DoubleMap(map) => { + ext::type_contains_ident(&map.key1, &def.module_runtime_generic) + || ext::type_contains_ident(&map.key2, &def.module_runtime_generic) + || ext::type_contains_ident(&map.value, &def.module_runtime_generic) + } + }; -#[derive(Parse, ToTokens, Debug)] -struct DeclStorageGetter { - pub getter_keyword: keyword::get, - pub getfn: ext::Parens, -} + let query_type = match &storage_def.storage_type { + StorageLineTypeDef::Simple(value) => value.clone(), + StorageLineTypeDef::Map(map) => map.value.clone(), + StorageLineTypeDef::LinkedMap(map) => map.value.clone(), + StorageLineTypeDef::DoubleMap(map) => map.value.clone(), + }; + let is_option = ext::extract_type_option(&query_type).is_some(); + let value_type = ext::extract_type_option(&query_type).unwrap_or(query_type.clone()); -#[derive(Parse, ToTokens, Debug)] -struct DeclStorageConfig { - pub config_keyword: keyword::config, - pub expr: ext::Parens>, -} + let module_runtime_generic = &def.module_runtime_generic; + let module_runtime_trait = &def.module_runtime_trait; + let optional_storage_runtime_comma = if is_generic { + Some(quote!( #module_runtime_generic, )) + } else { + None + }; + let optional_storage_runtime_bound_comma = if is_generic { + Some(quote!( #module_runtime_generic: #module_runtime_trait, )) + } else { + None + }; -#[derive(Parse, ToTokens, Debug)] -struct DeclStorageBuild { - pub build_keyword: keyword::build, - pub expr: ext::Parens, -} + let storage_name = &storage_def.name; + let optional_instance_generic = def.module_instance.as_ref().map(|i| { + let instance_generic = &i.instance_generic; + quote!( #instance_generic ) + }); + let storage_struct = quote!( + #storage_name<#optional_storage_runtime_comma #optional_instance_generic> + ); -#[derive(Parse, ToTokens, Debug)] -enum DeclStorageType { - Map(DeclStorageMap), - LinkedMap(DeclStorageLinkedMap), - DoubleMap(DeclStorageDoubleMap), - Simple(syn::Type), + let optional_storage_where_clause = if is_generic { + def.where_clause.as_ref().map(|w| quote!( #w )) + } else { + None + }; + + let storage_trait_trunkated = match &storage_def.storage_type { + StorageLineTypeDef::Simple(_) => { + quote!( StorageValue<#value_type> ) + }, + StorageLineTypeDef::Map(map) => { + let key = &map.key; + quote!( StorageMap<#key, #value_type> ) + }, + StorageLineTypeDef::LinkedMap(map) => { + let key = &map.key; + quote!( StorageLinkedMap<#key, #value_type> ) + }, + StorageLineTypeDef::DoubleMap(map) => { + let key1 = &map.key1; + let key2 = &map.key2; + quote!( StorageDoubleMap<#key1, #key2, #value_type> ) + }, + }; + + let storage_trait = quote!( storage::#storage_trait_trunkated ); + let storage_generator_trait = quote!( storage::generator::#storage_trait_trunkated ); + + let doc_attrs = storage_def.attrs.iter() + .filter_map(|a| a.parse_meta().ok()) + .filter(|m| m.name() == "doc") + .collect(); + + Self { + attrs: storage_def.attrs, + visibility: storage_def.visibility, + name: storage_def.name, + getter: storage_def.getter, + config: storage_def.config, + build: storage_def.build, + default_value: storage_def.default_value, + storage_type: storage_def.storage_type, + doc_attrs, + query_type, + value_type, + storage_struct, + optional_storage_runtime_comma, + optional_storage_runtime_bound_comma, + optional_storage_where_clause, + storage_trait, + storage_generator_trait, + is_generic, + is_option, + } + } } -#[derive(Parse, ToTokens, Debug)] -struct DeclStorageMap { - pub map_keyword: keyword::map, - pub hasher: ext::Opt, - pub key: syn::Type, - pub ass_keyword: Token![=>], - pub value: syn::Type, +pub enum StorageLineTypeDef { + Map(MapDef), + LinkedMap(MapDef), + DoubleMap(DoubleMapDef), + Simple(syn::Type), } -#[derive(Parse, ToTokens, Debug)] -struct DeclStorageLinkedMap { - pub map_keyword: keyword::linked_map, - pub hasher: ext::Opt, +pub struct MapDef { + pub hasher: HasherKind, pub key: syn::Type, - pub ass_keyword: Token![=>], + /// This is the query value not the inner value used in storage trait implementation. pub value: syn::Type, } -#[derive(Parse, ToTokens, Debug)] -struct DeclStorageDoubleMap { - pub map_keyword: keyword::double_map, - pub hasher: ext::Opt, +pub struct DoubleMapDef { + pub hasher1: HasherKind, + pub hasher2: HasherKind, pub key1: syn::Type, - pub comma_keyword: Token![,], - pub key2_hasher: Hasher, - pub key2: ext::Parens, - pub ass_keyword: Token![=>], + pub key2: syn::Type, + /// This is the query value not the inner value used in storage trait implementation. pub value: syn::Type, } -#[derive(Parse, ToTokens, Debug)] -enum Hasher { - Blake2_256(keyword::blake2_256), - Blake2_128(keyword::blake2_128), - Twox256(keyword::twox_256), - Twox128(keyword::twox_128), - Twox64Concat(keyword::twox_64_concat), -} - -#[derive(Parse, ToTokens, Debug)] -struct DeclStorageDefault { - pub equal_token: Token![=], - pub expr: syn::Expr, -} - -#[derive(Parse, ToTokens, Debug)] -struct SetHasher { - pub hasher_keyword: keyword::hasher, - pub inner: ext::Parens, +pub struct ExtraGenesisLineDef { + attrs: Vec, + name: syn::Ident, + typ: syn::Type, + default: Option, } #[derive(Debug, Clone)] -enum HasherKind { +pub enum HasherKind { Blake2_256, Blake2_128, Twox256, @@ -206,26 +373,8 @@ enum HasherKind { Twox64Concat, } -impl From<&SetHasher> for HasherKind { - fn from(set_hasher: &SetHasher) -> Self { - (&set_hasher.inner.content).into() - } -} - -impl From<&Hasher> for HasherKind { - fn from(hasher: &Hasher) -> Self { - match hasher { - Hasher::Blake2_256(_) => HasherKind::Blake2_256, - Hasher::Blake2_128(_) => HasherKind::Blake2_128, - Hasher::Twox256(_) => HasherKind::Twox256, - Hasher::Twox128(_) => HasherKind::Twox128, - Hasher::Twox64Concat(_) => HasherKind::Twox64Concat, - } - } -} - impl HasherKind { - fn into_storage_hasher_struct(&self) -> TokenStream2 { + fn to_storage_hasher_struct(&self) -> proc_macro2::TokenStream { match self { HasherKind::Blake2_256 => quote!( Blake2_256 ), HasherKind::Blake2_128 => quote!( Blake2_128 ), @@ -235,7 +384,7 @@ impl HasherKind { } } - fn into_metadata(&self) -> TokenStream2 { + fn into_metadata(&self) -> proc_macro2::TokenStream { match self { HasherKind::Blake2_256 => quote!( StorageHasher::Blake2_256 ), HasherKind::Blake2_128 => quote!( StorageHasher::Blake2_128 ), @@ -245,3 +394,39 @@ impl HasherKind { } } } + +/// Full implementation of decl_storage. +pub fn decl_storage_impl(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + let def = syn::parse_macro_input!(input as DeclStorageDef); + let def_ext = DeclStorageDefExt::from(def); + + let hidden_crate_name = def_ext.hidden_crate.as_ref().map(|i| i.to_string()) + .unwrap_or_else(|| "decl_storage".to_string()); + + let scrate = generate_crate_access(&hidden_crate_name, "srml-support"); + let scrate_decl = generate_hidden_includes(&hidden_crate_name, "srml-support"); + + let store_trait = store_trait::decl_and_impl(&def_ext); + let getters = getters::impl_getters(&scrate, &def_ext); + let metadata = metadata::impl_metadata(&scrate, &def_ext); + let instance_trait = instance_trait::decl_and_impl(&scrate, &def_ext); + let genesis_config = genesis_config::genesis_config_and_build_storage(&scrate, &def_ext); + let storage_struct = storage_struct::decl_and_impl(&scrate, &def_ext); + + quote!( + use #scrate::{ + StorageValue as _, + StorageMap as _, + StorageLinkedMap as _, + StorageDoubleMap as _ + }; + + #scrate_decl + #store_trait + #getters + #metadata + #instance_trait + #genesis_config + #storage_struct + ).into() +} diff --git a/srml/support/procedural/src/storage/parse.rs b/srml/support/procedural/src/storage/parse.rs new file mode 100644 index 0000000000..8464077ca2 --- /dev/null +++ b/srml/support/procedural/src/storage/parse.rs @@ -0,0 +1,377 @@ +// Copyright 2017-2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +//! Parsing of decl_storage input. + +use srml_support_procedural_tools::{ToTokens, Parse, syn_ext as ext}; +use syn::{Ident, Token}; + +mod keyword { + syn::custom_keyword!(hiddencrate); + syn::custom_keyword!(add_extra_genesis); + syn::custom_keyword!(extra_genesis_skip_phantom_data_field); + syn::custom_keyword!(config); + syn::custom_keyword!(build); + syn::custom_keyword!(get); + syn::custom_keyword!(map); + syn::custom_keyword!(linked_map); + syn::custom_keyword!(double_map); + syn::custom_keyword!(blake2_256); + syn::custom_keyword!(blake2_128); + syn::custom_keyword!(twox_256); + syn::custom_keyword!(twox_128); + syn::custom_keyword!(twox_64_concat); + syn::custom_keyword!(hasher); +} + +/// Parsing usage only +#[derive(Parse, ToTokens, Debug)] +struct StorageDefinition { + pub hidden_crate: ext::Opt, + pub visibility: syn::Visibility, + pub trait_token: Token![trait], + pub ident: Ident, + pub for_token: Token![for], + pub module_ident: Ident, + pub mod_lt_token: Token![<], + pub mod_param_generic: syn::Ident, + pub mod_param_bound_token: Option, + pub mod_param_bound: syn::Path, + pub mod_instance_param_token: Option, + pub mod_instance: Option, + pub mod_instantiable_token: Option, + pub mod_instantiable: Option, + pub mod_default_instance_token: Option, + pub mod_default_instance: Option, + pub mod_gt_token: Token![>], + pub as_token: Token![as], + pub crate_ident: Ident, + pub where_clause: Option, + pub content: ext::Braces>, + pub extra_genesis: ext::Opt, +} + +#[derive(Parse, ToTokens, Debug)] +struct SpecificHiddenCrate { + pub keyword: keyword::hiddencrate, + pub ident: ext::Parens, +} + +#[derive(Parse, ToTokens, Debug)] +struct AddExtraGenesis { + pub extragenesis_keyword: keyword::add_extra_genesis, + pub content: ext::Braces, +} + +#[derive(Parse, ToTokens, Debug)] +struct AddExtraGenesisContent { + pub lines: ext::Punctuated, +} + +#[derive(Parse, ToTokens, Debug)] +enum AddExtraGenesisLineEnum { + AddExtraGenesisLine(AddExtraGenesisLine), + AddExtraGenesisBuild(DeclStorageBuild), +} + +#[derive(Parse, ToTokens, Debug)] +struct AddExtraGenesisLine { + pub attrs: ext::OuterAttributes, + pub config_keyword: keyword::config, + pub extra_field: ext::Parens, + pub coldot_token: Token![:], + pub extra_type: syn::Type, + pub default_value: ext::Opt, +} + +#[derive(Parse, ToTokens, Debug)] +struct DeclStorageLine { + // attrs (main use case is doc) + pub attrs: ext::OuterAttributes, + // visibility (no need to make optional + pub visibility: syn::Visibility, + // name + pub name: Ident, + pub getter: ext::Opt, + pub config: ext::Opt, + pub build: ext::Opt, + pub coldot_token: Token![:], + pub storage_type: DeclStorageType, + pub default_value: ext::Opt, +} + + +#[derive(Parse, ToTokens, Debug)] +struct DeclStorageGetter { + pub getter_keyword: keyword::get, + pub getfn: ext::Parens, +} + +#[derive(Parse, ToTokens, Debug)] +struct DeclStorageConfig { + pub config_keyword: keyword::config, + pub expr: ext::Parens>, +} + +#[derive(Parse, ToTokens, Debug)] +struct DeclStorageBuild { + pub build_keyword: keyword::build, + pub expr: ext::Parens, +} + +#[derive(Parse, ToTokens, Debug)] +enum DeclStorageType { + Map(DeclStorageMap), + LinkedMap(DeclStorageLinkedMap), + DoubleMap(DeclStorageDoubleMap), + Simple(syn::Type), +} + +#[derive(Parse, ToTokens, Debug)] +struct DeclStorageMap { + pub map_keyword: keyword::map, + pub hasher: ext::Opt, + pub key: syn::Type, + pub ass_keyword: Token![=>], + pub value: syn::Type, +} + +#[derive(Parse, ToTokens, Debug)] +struct DeclStorageLinkedMap { + pub map_keyword: keyword::linked_map, + pub hasher: ext::Opt, + pub key: syn::Type, + pub ass_keyword: Token![=>], + pub value: syn::Type, +} + +#[derive(Parse, ToTokens, Debug)] +struct DeclStorageDoubleMap { + pub map_keyword: keyword::double_map, + pub hasher: ext::Opt, + pub key1: syn::Type, + pub comma_keyword: Token![,], + pub key2_hasher: Hasher, + pub key2: ext::Parens, + pub ass_keyword: Token![=>], + pub value: syn::Type, +} + +#[derive(Parse, ToTokens, Debug)] +enum Hasher { + Blake2_256(keyword::blake2_256), + Blake2_128(keyword::blake2_128), + Twox256(keyword::twox_256), + Twox128(keyword::twox_128), + Twox64Concat(keyword::twox_64_concat), +} + +#[derive(Parse, ToTokens, Debug)] +struct DeclStorageDefault { + pub equal_token: Token![=], + pub expr: syn::Expr, +} + +#[derive(Parse, ToTokens, Debug)] +struct SetHasher { + pub hasher_keyword: keyword::hasher, + pub inner: ext::Parens, +} + +impl From for super::HasherKind { + fn from(set_hasher: SetHasher) -> Self { + set_hasher.inner.content.into() + } +} + +impl From for super::HasherKind { + fn from(hasher: Hasher) -> Self { + match hasher { + Hasher::Blake2_256(_) => super::HasherKind::Blake2_256, + Hasher::Blake2_128(_) => super::HasherKind::Blake2_128, + Hasher::Twox256(_) => super::HasherKind::Twox256, + Hasher::Twox128(_) => super::HasherKind::Twox128, + Hasher::Twox64Concat(_) => super::HasherKind::Twox64Concat, + } + } +} + +fn get_module_instance( + instance: Option, + instantiable: Option, + default_instance: Option, +) -> syn::Result> { + let right_syntax = "Should be $Instance: $Instantiable = $DefaultInstance"; + + match (instance, instantiable, default_instance) { + (Some(instance), Some(instantiable), default_instance) => { + Ok(Some(super::ModuleInstanceDef { + instance_generic: instance, + instance_trait: instantiable, + instance_default: default_instance, + })) + }, + (None, None, None) => Ok(None), + (Some(instance), None, _) => Err( + syn::Error::new( + instance.span(), + format!( + "Expect instantiable trait bound for instance: {}. {}", + instance, + right_syntax, + ) + ) + ), + (None, Some(instantiable), _) => Err( + syn::Error::new( + instantiable.span(), + format!( + "Expect instance generic for bound instantiable: {}. {}", + instantiable, + right_syntax, + ) + ) + ), + (None, _, Some(default_instance)) => Err( + syn::Error::new( + default_instance.span(), + format!( + "Expect instance generic for default instance: {}. {}", + default_instance, + right_syntax, + ) + ) + ), + } +} + +pub fn parse(input: syn::parse::ParseStream) -> syn::Result { + use syn::parse::Parse; + use syn::spanned::Spanned; + + let def = StorageDefinition::parse(input)?; + + let module_instance = get_module_instance( + def.mod_instance, + def.mod_instantiable, + def.mod_default_instance, + )?; + + let mut extra_genesis_config_lines = vec![]; + let mut extra_genesis_build = None; + + for line in def.extra_genesis.inner.into_iter() + .flat_map(|o| o.content.content.lines.inner.into_iter()) + { + match line { + AddExtraGenesisLineEnum::AddExtraGenesisLine(def) => { + extra_genesis_config_lines.push(super::ExtraGenesisLineDef{ + attrs: def.attrs.inner, + name: def.extra_field.content, + typ: def.extra_type, + default: def.default_value.inner.map(|o| o.expr), + }); + } + AddExtraGenesisLineEnum::AddExtraGenesisBuild(def) => { + if extra_genesis_build.is_some() { + return Err(syn::Error::new( + def.span(), + "Only one build expression allowed for extra genesis" + )) + } + + extra_genesis_build = Some(def.expr.content); + } + } + } + + let mut storage_lines = vec![]; + + for line in def.content.content.inner.into_iter() { + let getter = line.getter.inner.map(|o| o.getfn.content); + let config = if let Some(config) = line.config.inner { + if let Some(ident) = config.expr.content { + Some(ident) + } else if let Some(ident) = getter.clone() { + Some(ident) + } else { + return Err(syn::Error::new( + config.span(), + "Invalid storage definiton, couldn't find config identifier: storage must either have a get \ + identifier `get(ident)` or a defined config identifier `config(ident)`" + )) + } + } else { + None + }; + + let storage_type = match line.storage_type { + DeclStorageType::Map(map) => super::StorageLineTypeDef::Map( + super::MapDef { + hasher: map.hasher.inner.map(Into::into) + .unwrap_or(super::HasherKind::Blake2_256), + key: map.key, + value: map.value, + } + ), + DeclStorageType::LinkedMap(map) => super::StorageLineTypeDef::LinkedMap( + super::MapDef { + hasher: map.hasher.inner.map(Into::into) + .unwrap_or(super::HasherKind::Blake2_256), + key: map.key, + value: map.value, + } + ), + DeclStorageType::DoubleMap(map) => super::StorageLineTypeDef::DoubleMap( + super::DoubleMapDef { + hasher1: map.hasher.inner.map(Into::into) + .unwrap_or(super::HasherKind::Blake2_256), + hasher2: map.key2_hasher.into(), + key1: map.key1, + key2: map.key2.content, + value: map.value, + } + ), + DeclStorageType::Simple(expr) => super::StorageLineTypeDef::Simple(expr), + }; + + storage_lines.push(super::StorageLineDef { + attrs: line.attrs.inner, + visibility: line.visibility, + name: line.name, + getter, + config, + build: line.build.inner.map(|o| o.expr.content), + default_value: line.default_value.inner.map(|o| o.expr), + storage_type, + }) + } + + Ok(super::DeclStorageDef { + hidden_crate: def.hidden_crate.inner.map(|i| i.ident.content), + visibility: def.visibility, + module_name: def.module_ident, + store_trait: def.ident, + module_runtime_generic: def.mod_param_generic, + module_runtime_trait: def.mod_param_bound, + where_clause: def.where_clause, + crate_name: def.crate_ident, + module_instance, + extra_genesis_build, + extra_genesis_config_lines, + storage_lines, + }) +} diff --git a/srml/support/procedural/src/storage/storage_struct.rs b/srml/support/procedural/src/storage/storage_struct.rs new file mode 100644 index 0000000000..e195fb53e8 --- /dev/null +++ b/srml/support/procedural/src/storage/storage_struct.rs @@ -0,0 +1,220 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +//! Implementation of storage structures and implementation of storage traits on them. + +use proc_macro2::TokenStream; +use quote::quote; +use super::{ + DeclStorageDefExt, StorageLineTypeDef, + instance_trait::{PREFIX_FOR, HEAD_KEY_FOR}, +}; + +fn from_optional_value_to_query(is_option: bool, default: &Option) -> TokenStream { + let default = default.as_ref().map(|d| quote!( #d )) + .unwrap_or_else(|| quote!( Default::default() )); + + if !is_option { + // raw type case + quote!( v.unwrap_or_else(|| #default ) ) + } else { + // Option<> type case + quote!( v.or_else(|| #default ) ) + } +} + +fn from_query_to_optional_value(is_option: bool) -> TokenStream { + if !is_option { + // raw type case + quote!( Some(v) ) + } else { + // Option<> type case + quote!( v ) + } +} + +pub fn decl_and_impl(scrate: &TokenStream, def: &DeclStorageDefExt) -> TokenStream { + let mut impls = TokenStream::new(); + + for line in &def.storage_lines { + + // Propagate doc attributes. + let attrs = &line.doc_attrs; + + let visibility = &line.visibility; + let optional_storage_runtime_comma = &line.optional_storage_runtime_comma; + let optional_storage_runtime_bound_comma = &line.optional_storage_runtime_bound_comma; + let optional_storage_where_clause = &line.optional_storage_where_clause; + let optional_instance_bound_optional_default = &def.optional_instance_bound_optional_default; + let optional_instance_bound = &def.optional_instance_bound; + let optional_instance = &def.optional_instance; + let name = &line.name; + + let struct_decl = quote!( + #( #[ #attrs ] )* + #visibility struct #name< + #optional_storage_runtime_bound_comma #optional_instance_bound_optional_default + >( + #scrate::rstd::marker::PhantomData< + (#optional_storage_runtime_comma #optional_instance) + > + ) #optional_storage_where_clause; + ); + + let from_query_to_optional_value = from_query_to_optional_value(line.is_option); + let from_optional_value_to_query = + from_optional_value_to_query(line.is_option, &line.default_value); + + let final_prefix = if let Some(instance) = def.module_instance.as_ref() { + let instance = &instance.instance_generic; + let const_name = syn::Ident::new( + &format!("{}{}", PREFIX_FOR, line.name.to_string()), proc_macro2::Span::call_site() + ); + quote!( #instance::#const_name.as_bytes() ) + } else { + let prefix = format!("{} {}", def.crate_name, line.name); + quote!( #prefix.as_bytes() ) + }; + + + let storage_generator_trait = &line.storage_generator_trait; + let storage_struct = &line.storage_struct; + let impl_trait = quote!( #optional_storage_runtime_bound_comma #optional_instance_bound ); + let value_type = &line.value_type; + let query_type = &line.query_type; + + let struct_impl = match &line.storage_type { + StorageLineTypeDef::Simple(_) => { + quote!( + impl<#impl_trait> #scrate::#storage_generator_trait for #storage_struct + #optional_storage_where_clause + { + type Query = #query_type; + + fn unhashed_key() -> &'static [u8] { + #final_prefix + } + + fn from_optional_value_to_query(v: Option<#value_type>) -> Self::Query { + #from_optional_value_to_query + } + + fn from_query_to_optional_value(v: Self::Query) -> Option<#value_type> { + #from_query_to_optional_value + } + } + ) + }, + StorageLineTypeDef::Map(map) => { + let hasher = map.hasher.to_storage_hasher_struct(); + quote!( + impl<#impl_trait> #scrate::#storage_generator_trait for #storage_struct + #optional_storage_where_clause + { + type Query = #query_type; + type Hasher = #scrate::#hasher; + + fn prefix() -> &'static [u8] { + #final_prefix + } + + fn from_optional_value_to_query(v: Option<#value_type>) -> Self::Query { + #from_optional_value_to_query + } + + fn from_query_to_optional_value(v: Self::Query) -> Option<#value_type> { + #from_query_to_optional_value + } + } + ) + }, + StorageLineTypeDef::LinkedMap(map) => { + let hasher = map.hasher.to_storage_hasher_struct(); + + // make sure to use different prefix for head and elements. + let head_key = if let Some(instance) = def.module_instance.as_ref() { + let instance = &instance.instance_generic; + let const_name = syn::Ident::new( + &format!("{}{}", HEAD_KEY_FOR, line.name.to_string()), proc_macro2::Span::call_site() + ); + quote!( #instance::#const_name.as_bytes() ) + } else { + let prefix = format!("head of {} {}", def.crate_name, line.name); + quote!( #prefix.as_bytes() ) + }; + + quote!( + impl<#impl_trait> #scrate::#storage_generator_trait for #storage_struct + #optional_storage_where_clause + { + type Query = #query_type; + type Hasher = #scrate::#hasher; + + fn prefix() -> &'static [u8] { + #final_prefix + } + + fn head_key() -> &'static [u8] { + #head_key + } + + fn from_optional_value_to_query(v: Option<#value_type>) -> Self::Query { + #from_optional_value_to_query + } + + fn from_query_to_optional_value(v: Self::Query) -> Option<#value_type> { + #from_query_to_optional_value + } + } + ) + }, + StorageLineTypeDef::DoubleMap(map) => { + let hasher1 = map.hasher1.to_storage_hasher_struct(); + let hasher2 = map.hasher2.to_storage_hasher_struct(); + quote!( + impl<#impl_trait> #scrate::#storage_generator_trait for #storage_struct + #optional_storage_where_clause + { + type Query = #query_type; + + type Hasher1 = #scrate::#hasher1; + + type Hasher2 = #scrate::#hasher2; + + fn key1_prefix() -> &'static [u8] { + #final_prefix + } + + fn from_optional_value_to_query(v: Option<#value_type>) -> Self::Query { + #from_optional_value_to_query + } + + fn from_query_to_optional_value(v: Self::Query) -> Option<#value_type> { + #from_query_to_optional_value + } + } + ) + } + }; + + impls.extend(quote!( + #struct_decl + #struct_impl + )) + } + + impls +} diff --git a/srml/support/procedural/src/storage/store_trait.rs b/srml/support/procedural/src/storage/store_trait.rs new file mode 100644 index 0000000000..4c9d96b6bb --- /dev/null +++ b/srml/support/procedural/src/storage/store_trait.rs @@ -0,0 +1,54 @@ +// Copyright 2017-2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +//! Declaration of store trait and implementation on module structure. + +use proc_macro2::TokenStream; +use quote::quote; +use super::DeclStorageDefExt; + +pub fn decl_and_impl(def: &DeclStorageDefExt) -> TokenStream { + let decl_store_items = def.storage_lines.iter() + .map(|sline| &sline.name) + .fold(TokenStream::new(), |mut items, name| { + items.extend(quote!(type #name;)); + items + }); + + let impl_store_items = def.storage_lines.iter() + .fold(TokenStream::new(), |mut items, line| { + let name = &line.name; + let storage_struct = &line.storage_struct; + + items.extend(quote!(type #name = #storage_struct;)); + items + }); + + let visibility = &def.visibility; + let store_trait = &def.store_trait; + let module_struct = &def.module_struct; + let module_impl = &def.module_impl; + let where_clause = &def.where_clause; + + quote!( + #visibility trait #store_trait { + #decl_store_items + } + impl#module_impl #store_trait for #module_struct #where_clause { + #impl_store_items + } + ) +} diff --git a/srml/support/procedural/src/storage/transformation.rs b/srml/support/procedural/src/storage/transformation.rs deleted file mode 100644 index c6a3a1f668..0000000000 --- a/srml/support/procedural/src/storage/transformation.rs +++ /dev/null @@ -1,1264 +0,0 @@ -// Copyright 2017-2019 Parity Technologies (UK) Ltd. -// This file is part of Substrate. - -// Substrate is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Substrate is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Substrate. If not, see . - -//! `decl_storage` macro transformation - -use srml_support_procedural_tools::syn_ext as ext; -use srml_support_procedural_tools::{ - generate_crate_access, generate_hidden_includes, clean_type_string -}; - -use proc_macro::TokenStream; -use proc_macro2::{TokenStream as TokenStream2, Span}; - -use syn::{ - Ident, - GenericParam, - WhereClause, - spanned::Spanned, - parse::{ - Error, - Result, - }, - parse_macro_input, -}; -use quote::{quote, quote_spanned}; - -use super::*; - -const NUMBER_OF_INSTANCE: usize = 16; -const DEFAULT_INSTANTIABLE_TRAIT_NAME: &str = "__GeneratedInstantiable"; -const DEFAULT_INSTANCE_NAME: &str = "__GeneratedInstance"; -const INHERENT_INSTANCE_NAME: &str = "__InherentHiddenInstance"; - -// try macro but returning tokenized error -macro_rules! try_tok(( $expre : expr ) => { - match $expre { - Ok(r) => r, - Err (err) => { - return err.to_compile_error().into() - } - } -}); - -pub fn decl_storage_impl(input: TokenStream) -> TokenStream { - let def = parse_macro_input!(input as StorageDefinition); - - let StorageDefinition { - hidden_crate, - visibility, - ident: storetype, - module_ident, - mod_param: strait, - mod_instance, - mod_instantiable, - mod_default_instance, - crate_ident: cratename, - content: ext::Braces { content: storage_lines, ..}, - extra_genesis, - where_clause, - .. - } = def; - - let instance_opts = match get_instance_opts( - mod_instance, - mod_instantiable, - mod_default_instance - ) { - Ok(opts) => opts, - Err(err) => return err.to_compile_error().into(), - }; - - let hidden_crate_name = hidden_crate.inner.map(|rc| rc.ident.content).map(|i| i.to_string()) - .unwrap_or_else(|| "decl_storage".to_string()); - let scrate = generate_crate_access(&hidden_crate_name, "srml-support"); - let scrate_decl = generate_hidden_includes( - &hidden_crate_name, - "srml-support", - ); - - let ( - traitinstance, - traittypes, - ) = if let GenericParam::Type(syn::TypeParam {ident, bounds, ..}) = strait { - (ident, bounds) - } else { - return try_tok!(Err(Error::new(strait.span(), "Missing declare store generic params"))); - }; - - let traittype = if let Some(traittype) = traittypes.first() { - traittype.into_value() - } else { - return try_tok!(Err(Error::new(traittypes.span(), "Trait bound expected"))); - }; - - let extra_genesis = try_tok!(decl_store_extra_genesis( - &scrate, - &traitinstance, - &traittype, - &instance_opts, - &storage_lines, - &extra_genesis.inner, - &where_clause, - )); - let decl_storage_items = decl_storage_items( - &scrate, - &traitinstance, - &traittype, - &instance_opts, - &cratename, - &storage_lines, - &where_clause, - ).unwrap_or_else(|err| err.to_compile_error()); - - let decl_store_items = decl_store_items( - &storage_lines, - ); - let impl_store_items = impl_store_items( - &traitinstance, - &instance_opts.instance, - &storage_lines, - ); - let impl_store_fns = impl_store_fns( - &scrate, - &traitinstance, - &instance_opts.instance, - &storage_lines, - ); - let (store_default_struct, store_metadata) = store_functions_to_metadata( - &scrate, - &traitinstance, - &traittype, - &instance_opts, - &storage_lines, - &where_clause, - &cratename, - ); - - let InstanceOpts { - instance, - bound_instantiable, - .. - } = instance_opts; - - let expanded = quote! { - use #scrate::{ - StorageValue as _, - StorageMap as _, - StorageLinkedMap as _, - StorageDoubleMap as _ - }; - - #scrate_decl - #decl_storage_items - #visibility trait #storetype { - #decl_store_items - } - #store_default_struct - impl<#traitinstance: #traittype, #instance #bound_instantiable> #storetype - for #module_ident<#traitinstance, #instance> #where_clause - { - #impl_store_items - } - impl<#traitinstance: 'static + #traittype, #instance #bound_instantiable> - #module_ident<#traitinstance, #instance> #where_clause - { - #impl_store_fns - #[doc(hidden)] - pub fn storage_metadata() -> #scrate::metadata::StorageMetadata { - #store_metadata - } - } - - #extra_genesis - }; - - expanded.into() -} - -fn decl_store_extra_genesis( - scrate: &TokenStream2, - traitinstance: &Ident, - traittype: &syn::TypeParamBound, - instance_opts: &InstanceOpts, - storage_lines: &ext::Punctuated, - extra_genesis: &Option, - where_clause: &Option, -) -> Result { - - let InstanceOpts { - equal_default_instance, - bound_instantiable, - instance, - .. - } = instance_opts; - - let mut is_trait_needed = false; - let mut serde_complete_bound = Vec::new(); - let mut config_field = TokenStream2::new(); - let mut config_field_default = TokenStream2::new(); - let mut builders = TokenStream2::new(); - let mut assimilate_require_generic = instance.is_some(); - let mut builders_clone_bound = Vec::new(); - - for sline in storage_lines.inner.iter() { - let DeclStorageLine { - attrs, - name, - getter, - config, - build, - storage_type, - default_value, - .. - } = sline; - - let type_infos = get_type_infos(storage_type); - - let opt_build = build - .inner - .as_ref() - .map(|b| { - assimilate_require_generic |= ext::expr_contains_ident(&b.expr.content, traitinstance); - &b.expr.content - }) - .map(|b| quote!( #b )); - - // need build line - let builder = if let Some(ref config) = config.inner { - let ident = if let Some(ident) = config.expr.content.as_ref() { - quote!( #ident ) - } else if let Some(ref getter) = getter.inner { - let ident = &getter.getfn.content; - quote!( #ident ) - } else { - return Err( - Error::new_spanned( - name, - "Invalid storage definiton, couldn't find config identifier: storage must either have a get identifier \ - `get(ident)` or a defined config identifier `config(ident)`" - ) - ); - }; - - if ext::type_contains_ident(type_infos.value_type, traitinstance) { - is_trait_needed = true; - } - - if opt_build.is_none() { - builders_clone_bound.push(type_infos.value_type.clone()); - } - - let value_type = &type_infos.value_type; - serde_complete_bound.push(quote!( #value_type )); - match type_infos.kind { - DeclStorageTypeInfosKind::Map { key_type, .. } => { - serde_complete_bound.push(quote!( #key_type )); - is_trait_needed = is_trait_needed - || ext::type_contains_ident(key_type, traitinstance); - - if opt_build.is_none() { - builders_clone_bound.push(key_type.clone()); - } - }, - DeclStorageTypeInfosKind::DoubleMap { key1_type, key2_type, .. } => { - serde_complete_bound.push(quote!( #key1_type )); - serde_complete_bound.push(quote!( #key2_type )); - is_trait_needed = is_trait_needed - || ext::type_contains_ident(key1_type, traitinstance) - || ext::type_contains_ident(key2_type, traitinstance); - if opt_build.is_none() { - builders_clone_bound.push(key1_type.clone()); - builders_clone_bound.push(key2_type.clone()); - } - }, - _ => {}, - } - - if type_infos.is_option { - serde_complete_bound.push(type_infos.typ.clone()); - } - - // Propagate doc attributes. - let attrs = attrs.inner.iter().filter_map(|a| a.parse_meta().ok()).filter(|m| m.name() == "doc"); - - let storage_type = type_infos.typ.clone(); - config_field.extend(match type_infos.kind { - DeclStorageTypeInfosKind::Simple => { - quote!( #( #[ #attrs ] )* pub #ident: #storage_type, ) - }, - DeclStorageTypeInfosKind::Map {key_type, .. } => { - quote!( #( #[ #attrs ] )* pub #ident: Vec<(#key_type, #storage_type)>, ) - }, - DeclStorageTypeInfosKind::DoubleMap {key1_type, key2_type, .. } => { - quote!( #( #[ #attrs ] )* pub #ident: Vec<(#key1_type, #key2_type, #storage_type)>, ) - }, - }); - - let fielddefault = default_value.inner.as_ref().map(|d| &d.expr).map(|d| - if type_infos.is_option { - quote!( #d.unwrap_or_default() ) - } else { - quote!( #d ) - }).unwrap_or_else(|| quote!( Default::default() )); - - config_field_default.extend(quote!( #ident: #fielddefault, )); - - opt_build.or_else(|| Some(quote!( (|config: &Self| config.#ident.clone()) ))) - } else { - opt_build - }; - - let typ = type_infos.typ; - if let Some(builder) = builder { - builders.extend(match type_infos.kind { - DeclStorageTypeInfosKind::Simple => { - let struct_trait = if ext::type_contains_ident(&type_infos.value_type, traitinstance) { - assimilate_require_generic = true; - quote!(#traitinstance,) - } else { - quote!() - }; - - quote!{{ - let v = (#builder)(&self); - < - #name<#struct_trait #instance> as - #scrate::storage::StorageValue<#typ> - >::put::<#typ>(v); - }} - }, - DeclStorageTypeInfosKind::Map { key_type, is_linked, .. } => { - let struct_trait = if ext::type_contains_ident(&type_infos.value_type, traitinstance) - || ext::type_contains_ident(key_type, traitinstance) - { - assimilate_require_generic = true; - quote!(#traitinstance,) - } else { - quote!() - }; - - let map = if is_linked { - quote! { StorageLinkedMap } - } else { - quote! { StorageMap } - }; - - quote!{{ - let data = (#builder)(&self); - data.into_iter().for_each(|(k, v)| { - < - #name<#struct_trait #instance> as - #scrate::storage::#map<#key_type, #typ> - >::insert::<#key_type, #typ>(k, v); - }); - }} - }, - DeclStorageTypeInfosKind::DoubleMap { key1_type, key2_type, .. } => { - let struct_trait = if ext::type_contains_ident(&type_infos.value_type, traitinstance) - || ext::type_contains_ident(key1_type, traitinstance) - || ext::type_contains_ident(key2_type, traitinstance) - { - assimilate_require_generic = true; - quote!(#traitinstance,) - } else { - quote!() - }; - - quote!{{ - let data = (#builder)(&self); - data.into_iter().for_each(|(k1, k2, v)| { - < - #name<#struct_trait #instance> as - #scrate::storage::StorageDoubleMap<#key1_type, #key2_type, #typ> - >::insert::<#key1_type, #key2_type, #typ>(k1, k2, v); - }); - }} - }, - }); - } - } - - let mut has_scall = false; - let mut scall = quote!{ let scall: fn(&Self) = |_| {}; scall }; - let mut genesis_extrafields = TokenStream2::new(); - let mut genesis_extrafields_default = TokenStream2::new(); - - // extra genesis - if let Some(eg) = extra_genesis { - for ex_content in eg.content.content.lines.inner.iter() { - match ex_content { - AddExtraGenesisLineEnum::AddExtraGenesisLine(AddExtraGenesisLine { - attrs, - extra_field, - extra_type, - default_value, - .. - }) => { - if ext::type_contains_ident(&extra_type, traitinstance) { - is_trait_needed = true; - } - - serde_complete_bound.push(quote!( #extra_type )); - - let extrafield = &extra_field.content; - genesis_extrafields.extend(quote!{ - #attrs pub #extrafield: #extra_type, - }); - let extra_default = default_value.inner.as_ref().map(|d| &d.expr).map(|e| quote!{ #e }) - .unwrap_or_else(|| quote!( Default::default() )); - genesis_extrafields_default.extend(quote!{ - #extrafield: #extra_default, - }); - }, - AddExtraGenesisLineEnum::AddExtraGenesisBuild(DeclStorageBuild{ expr, .. }) => { - if has_scall { - return Err(Error::new(expr.span(), "Only one build expression allowed for extra genesis")); - } - assimilate_require_generic |= ext::expr_contains_ident(&expr.content, traitinstance); - let content = &expr.content; - scall = quote_spanned! { expr.span() => - let scall: fn(&Self) = #content; scall - }; - has_scall = true; - }, - } - } - } - - let serde_bug_bound = if !serde_complete_bound.is_empty() { - let mut b_ser = String::new(); - let mut b_dser = String::new(); - - serde_complete_bound.into_iter().for_each(|bound| { - let stype = quote!(#bound); - b_ser.push_str(&format!("{} : {}::serde::Serialize, ", stype, scrate)); - b_dser.push_str(&format!("{} : {}::serde::de::DeserializeOwned, ", stype, scrate)); - }); - - quote! { - #[serde(bound(serialize = #b_ser))] - #[serde(bound(deserialize = #b_dser))] - } - } else { - quote!() - }; - - let is_extra_genesis_needed = has_scall - || !config_field.is_empty() - || !genesis_extrafields.is_empty() - || !builders.is_empty(); - if is_extra_genesis_needed { - let (inherent_instance, inherent_bound_instantiable) = if instance.is_some() { - (instance.clone(), bound_instantiable.clone()) - } else { - let instantiable = Ident::new(DEFAULT_INSTANTIABLE_TRAIT_NAME, Span::call_site()); - ( - Some(Ident::new(DEFAULT_INSTANCE_NAME, Span::call_site())), - quote!(: #instantiable), - ) - }; - - let (fparam_struct, fparam_impl, sparam, build_storage_impl) = if is_trait_needed { - ( - quote!(<#traitinstance: #traittype, #instance #bound_instantiable #equal_default_instance>), - quote!(<#traitinstance: #traittype, #instance #bound_instantiable>), - quote!(<#traitinstance, #instance>), - quote!(<#traitinstance: #traittype, #inherent_instance #inherent_bound_instantiable>), - ) - } else { - // do not even need type parameter - ( - quote!(), - quote!(), - quote!(), - quote!(<#traitinstance: #traittype, #inherent_instance #inherent_bound_instantiable>), - ) - }; - - let (fn_generic, fn_traitinstance) = if !is_trait_needed && assimilate_require_generic { - ( - quote!( <#traitinstance: #traittype, #instance #bound_instantiable> ), - quote!( #traitinstance, #instance ) - ) - } else { - (quote!(), quote!()) - }; - - let impl_trait = quote!(BuildModuleGenesisStorage<#traitinstance, #inherent_instance>); - - let extend_where_clause = |to_extend: &mut WhereClause| { - if let Some(where_clause) = where_clause { - to_extend.predicates.extend(where_clause.predicates.iter().cloned()); - } - }; - - let mut genesis_where_clause: WhereClause = syn::parse_quote!( - where #( #builders_clone_bound: Clone ),* - ); - let mut fn_where_clause = genesis_where_clause.clone(); - - - let mut build_storage_where_clause = genesis_where_clause.clone(); - extend_where_clause(&mut build_storage_where_clause); - - if is_trait_needed { - extend_where_clause(&mut genesis_where_clause); - } else if assimilate_require_generic { - extend_where_clause(&mut fn_where_clause); - } - - let res = quote!{ - #[derive(#scrate::Serialize, #scrate::Deserialize)] - #[cfg(feature = "std")] - #[serde(rename_all = "camelCase")] - #[serde(deny_unknown_fields)] - #serde_bug_bound - pub struct GenesisConfig#fparam_struct #genesis_where_clause { - #config_field - #genesis_extrafields - } - - #[cfg(feature = "std")] - impl#fparam_impl Default for GenesisConfig#sparam #genesis_where_clause { - fn default() -> Self { - GenesisConfig { - #config_field_default - #genesis_extrafields_default - } - } - } - - #[cfg(feature = "std")] - impl#fparam_impl GenesisConfig#sparam #genesis_where_clause { - pub fn build_storage #fn_generic (self) -> std::result::Result< - ( - #scrate::sr_primitives::StorageOverlay, - #scrate::sr_primitives::ChildrenStorageOverlay, - ), - String - > #fn_where_clause { - let mut storage = (Default::default(), Default::default()); - self.assimilate_storage::<#fn_traitinstance>(&mut storage)?; - Ok(storage) - } - - /// Assimilate the storage for this module into pre-existing overlays. - pub fn assimilate_storage #fn_generic ( - self, - tuple_storage: &mut ( - #scrate::sr_primitives::StorageOverlay, - #scrate::sr_primitives::ChildrenStorageOverlay, - ), - ) -> std::result::Result<(), String> #fn_where_clause { - #scrate::with_storage(tuple_storage, || { - #builders - - #scall(&self); - - Ok(()) - }) - } - } - - #[cfg(feature = "std")] - impl#build_storage_impl #scrate::sr_primitives::#impl_trait - for GenesisConfig#sparam #build_storage_where_clause - { - fn build_module_genesis_storage( - self, - storage: &mut ( - #scrate::sr_primitives::StorageOverlay, - #scrate::sr_primitives::ChildrenStorageOverlay, - ), - ) -> std::result::Result<(), String> { - self.assimilate_storage::<#fn_traitinstance> (storage) - } - } - }; - - Ok(res) - } else { - Ok(quote!()) - } -} - -fn create_and_impl_instance( - instance_prefix: &str, - ident: &Ident, - doc: &TokenStream2, - const_names: &[(Ident, String, String)], - scrate: &TokenStream2, - instantiable: &Ident, - cratename: &Ident, -) -> TokenStream2 { - let mut const_impls = TokenStream2::new(); - - for (const_name, const_value_prefix, const_value_suffix) in const_names { - let const_value = format!("{}{}{}", const_value_prefix, instance_prefix, const_value_suffix); - const_impls.extend(quote! { - const #const_name: &'static str = #const_value; - }); - } - - let prefix = format!("{}{}", instance_prefix, cratename.to_string()); - - quote! { - // Those trait are derived because of wrong bounds for generics - #[cfg_attr(feature = "std", derive(Debug))] - #[derive(Clone, Eq, PartialEq, #scrate::codec::Encode, #scrate::codec::Decode)] - #doc - pub struct #ident; - impl #instantiable for #ident { - const PREFIX: &'static str = #prefix; - #const_impls - } - } -} - -fn decl_storage_items( - scrate: &TokenStream2, - traitinstance: &Ident, - traittype: &syn::TypeParamBound, - instance_opts: &InstanceOpts, - cratename: &Ident, - storage_lines: &ext::Punctuated, - where_clause: &Option, -) -> syn::Result { - let mut impls = TokenStream2::new(); - - let InstanceOpts { - instance, - default_instance, - instantiable, - .. - } = instance_opts; - - let build_prefix = |cratename, name| format!("{} {}", cratename, name); - - // Build Instantiable trait - let mut const_names = vec![]; - - for sline in storage_lines.inner.iter() { - let DeclStorageLine { - storage_type, - name, - .. - } = sline; - - let prefix = build_prefix(cratename, name); - - let type_infos = get_type_infos(storage_type); - - let const_name = syn::Ident::new( - &format!("{}{}", impls::PREFIX_FOR, name.to_string()), proc_macro2::Span::call_site() - ); - const_names.push((const_name, String::new(), prefix.clone())); - - if let DeclStorageTypeInfosKind::Map { is_linked: true, .. } = type_infos.kind { - let const_name = syn::Ident::new( - &format!("{}{}", impls::HEAD_KEY_FOR, name.to_string()), proc_macro2::Span::call_site() - ); - const_names.push((const_name, "head of ".into(), prefix)); - } - } - - let instantiable = instantiable - .clone() - .unwrap_or_else(|| Ident::new(DEFAULT_INSTANTIABLE_TRAIT_NAME, Span::call_site())); - - // Declare Instance trait - { - let mut const_impls = TokenStream2::new(); - for (const_name, ..) in &const_names { - const_impls.extend(quote! { - const #const_name: &'static str; - }); - } - - let hide = if instance.is_some() { - quote!() - } else { - quote!(#[doc(hidden)]) - }; - - impls.extend(quote! { - /// Tag a type as an instance of a module. - /// - /// Defines storage prefixes, they must be unique. - #hide - pub trait #instantiable: 'static { - /// The prefix used by any storage entry of an instance. - const PREFIX: &'static str; - #const_impls - } - }); - } - - if instance.is_some() { - let instances = (0..NUMBER_OF_INSTANCE) - .map(|i| { - let name = format!("Instance{}", i); - let ident = Ident::new(&name, proc_macro2::Span::call_site()); - (name, ident, quote! {#[doc=r"Module instance"]}) - }) - .chain( - default_instance - .clone() - .map(|ident| - (String::new(), ident, quote! {#[doc=r"Default module instance"]}) - ) - ); - - // Impl Instance trait for instances - for (instance_prefix, ident, doc) in instances { - impls.extend( - create_and_impl_instance( - &instance_prefix, &ident, &doc, &const_names, scrate, &instantiable, cratename - ) - ); - } - } - - // The name of the inherently available instance. - let inherent_instance = Ident::new(INHERENT_INSTANCE_NAME, Span::call_site()); - - if default_instance.is_some() { - impls.extend(quote! { - #[doc(hidden)] - pub type #inherent_instance = #default_instance; - }); - } else { - impls.extend( - create_and_impl_instance( - "", - &inherent_instance, - "e!(#[doc(hidden)]), - &const_names, - scrate, - &instantiable, - cratename, - ) - ); - } - - for sline in storage_lines.inner.iter() { - let DeclStorageLine { - attrs, - name, - storage_type, - default_value, - visibility, - .. - } = sline; - - let type_infos = get_type_infos(storage_type); - - if type_infos.is_option && default_value.inner.is_some() { - return Err(syn::Error::new_spanned( - default_value, - "Default values for Option types are not supported" - )); - } - - let fielddefault = default_value.inner - .as_ref() - .map(|d| &d.expr) - .map(|d| quote!( #d )) - .unwrap_or_else(|| quote!{ Default::default() }); - let kind = type_infos.kind.clone(); - // Propagate doc attributes. - let attrs = attrs.inner.iter().filter_map(|a| a.parse_meta().ok()).filter(|m| m.name() == "doc"); - - let i = impls::Impls { - scrate, - visibility, - cratename, - traitinstance, - traittype, - instance_opts, - type_infos, - fielddefault, - prefix: build_prefix(cratename, name), - name, - attrs, - where_clause, - }; - - let implementation = match kind { - DeclStorageTypeInfosKind::Simple => { - i.simple_value() - }, - DeclStorageTypeInfosKind::Map { key_type, is_linked: false, hasher } => { - i.map(hasher.into_storage_hasher_struct(), key_type) - }, - DeclStorageTypeInfosKind::Map { key_type, is_linked: true, hasher } => { - i.linked_map(hasher.into_storage_hasher_struct(), key_type) - }, - DeclStorageTypeInfosKind::DoubleMap { key1_type, key2_type, key2_hasher, hasher } => { - i.double_map(hasher.into_storage_hasher_struct(), key1_type, key2_type, key2_hasher.into_storage_hasher_struct()) - }, - }; - impls.extend(implementation) - } - - Ok(impls) -} - -fn decl_store_items(storage_lines: &ext::Punctuated) -> TokenStream2 { - storage_lines.inner.iter().map(|sline| &sline.name) - .fold(TokenStream2::new(), |mut items, name| { - items.extend(quote!(type #name;)); - items - }) -} - -fn impl_store_items( - traitinstance: &Ident, - instance: &Option, - storage_lines: &ext::Punctuated, -) -> TokenStream2 { - storage_lines.inner - .iter() - .fold(TokenStream2::new(), |mut items, line| { - let name = &line.name; - let type_infos = get_type_infos(&line.storage_type); - let requires_trait = match type_infos.kind { - DeclStorageTypeInfosKind::Simple => { - ext::type_contains_ident(&type_infos.value_type, traitinstance) - }, - DeclStorageTypeInfosKind::Map { key_type, .. } => { - ext::type_contains_ident(&type_infos.value_type, traitinstance) - || ext::type_contains_ident(key_type, traitinstance) - } - DeclStorageTypeInfosKind::DoubleMap { key1_type, key2_type, .. } => { - ext::type_contains_ident(&type_infos.value_type, traitinstance) - || ext::type_contains_ident(key1_type, traitinstance) - || ext::type_contains_ident(key2_type, traitinstance) - } - }; - - let struct_trait = if requires_trait { - quote!(#traitinstance,) - } else { - quote!() - }; - - items.extend( - quote!( - type #name = #name<#struct_trait #instance>; - ) - ); - items - }) -} - -fn impl_store_fns( - scrate: &TokenStream2, - traitinstance: &Ident, - instance: &Option, - storage_lines: &ext::Punctuated, -) -> TokenStream2 { - let mut items = TokenStream2::new(); - for sline in storage_lines.inner.iter() { - let DeclStorageLine { - attrs, - name, - getter, - storage_type, - .. - } = sline; - - if let Some(getter) = getter.inner.as_ref() { - let get_fn = &getter.getfn.content; - - let type_infos = get_type_infos(storage_type); - let value_type = type_infos.value_type; - - // Propagate doc attributes. - let attrs = attrs.inner.iter().filter_map(|a| a.parse_meta().ok()).filter(|m| m.name() == "doc"); - - let typ = type_infos.typ; - let item = match type_infos.kind { - DeclStorageTypeInfosKind::Simple => { - let struct_trait = if ext::type_contains_ident(&type_infos.value_type, traitinstance) { - quote!(#traitinstance,) - } else { - quote!() - }; - - quote!{ - #( #[ #attrs ] )* - pub fn #get_fn() -> #value_type { - < - #name<#struct_trait #instance> as - #scrate::storage::StorageValue<#typ> - >::get() - } - } - }, - DeclStorageTypeInfosKind::Map { key_type, is_linked, .. } => { - let struct_trait = if ext::type_contains_ident(&type_infos.value_type, traitinstance) - || ext::type_contains_ident(key_type, traitinstance) - { - quote!(#traitinstance,) - } else { - quote!() - }; - - let map = if is_linked { - quote! { StorageLinkedMap } - } else { - quote! { StorageMap } - }; - - quote!{ - #( #[ #attrs ] )* - pub fn #get_fn>(key: K) -> #value_type { - < - #name<#struct_trait #instance> as - #scrate::storage::#map<#key_type, #typ> - >::get(key) - } - } - } - DeclStorageTypeInfosKind::DoubleMap { key1_type, key2_type, .. } => { - let struct_trait = if ext::type_contains_ident(&type_infos.value_type, traitinstance) - || ext::type_contains_ident(key1_type, traitinstance) - || ext::type_contains_ident(key2_type, traitinstance) - { - quote!(#traitinstance,) - } else { - quote!() - }; - - quote!{ - pub fn #get_fn(k1: KArg1, k2: KArg2) -> #value_type - where - KArg1: #scrate::codec::EncodeLike<#key1_type>, - KArg2: #scrate::codec::EncodeLike<#key2_type>, - { - < - #name<#struct_trait #instance> as - #scrate::storage::StorageDoubleMap<#key1_type, #key2_type, #typ> - >::get(k1, k2) - } - } - } - }; - items.extend(item); - } - } - items -} - -fn store_functions_to_metadata ( - scrate: &TokenStream2, - traitinstance: &Ident, - traittype: &syn::TypeParamBound, - instance_opts: &InstanceOpts, - storage_lines: &ext::Punctuated, - where_clause: &Option, - cratename: &Ident, -) -> (TokenStream2, TokenStream2) { - let InstanceOpts { - comma_instance, - equal_default_instance, - bound_instantiable, - instance, - .. - } = instance_opts; - - let mut items = TokenStream2::new(); - let mut default_getter_struct_def = TokenStream2::new(); - for sline in storage_lines.inner.iter() { - let DeclStorageLine { - attrs, - name, - storage_type, - default_value, - .. - } = sline; - - let type_infos = get_type_infos(storage_type); - let value_type = type_infos.value_type; - - let typ = type_infos.typ; - let styp = clean_type_string(&typ.to_string()); - let stype = match type_infos.kind { - DeclStorageTypeInfosKind::Simple => { - quote!{ - #scrate::metadata::StorageEntryType::Plain( - #scrate::metadata::DecodeDifferent::Encode(#styp), - ) - } - }, - DeclStorageTypeInfosKind::Map { key_type, is_linked, hasher } => { - let hasher = hasher.into_metadata(); - let kty = clean_type_string("e!(#key_type).to_string()); - quote!{ - #scrate::metadata::StorageEntryType::Map { - hasher: #scrate::metadata::#hasher, - key: #scrate::metadata::DecodeDifferent::Encode(#kty), - value: #scrate::metadata::DecodeDifferent::Encode(#styp), - is_linked: #is_linked, - } - } - }, - DeclStorageTypeInfosKind::DoubleMap { key1_type, key2_type, key2_hasher, hasher } => { - let hasher = hasher.into_metadata(); - let k1ty = clean_type_string("e!(#key1_type).to_string()); - let k2ty = clean_type_string("e!(#key2_type).to_string()); - let k2_hasher = key2_hasher.into_metadata(); - quote!{ - #scrate::metadata::StorageEntryType::DoubleMap { - hasher: #scrate::metadata::#hasher, - key1: #scrate::metadata::DecodeDifferent::Encode(#k1ty), - key2: #scrate::metadata::DecodeDifferent::Encode(#k2ty), - value: #scrate::metadata::DecodeDifferent::Encode(#styp), - key2_hasher: #scrate::metadata::#k2_hasher, - } - } - }, - }; - let modifier = if type_infos.is_option { - quote!{ - #scrate::metadata::StorageEntryModifier::Optional - } - } else { - quote!{ - #scrate::metadata::StorageEntryModifier::Default - } - }; - let default = default_value.inner.as_ref().map(|d| &d.expr) - .map(|d| { - quote!( #d ) - }) - .unwrap_or_else(|| quote!( Default::default() )); - let mut docs = TokenStream2::new(); - for attr in attrs.inner.iter().filter_map(|v| v.parse_meta().ok()) { - if let syn::Meta::NameValue(syn::MetaNameValue{ - ref ident, - ref lit, - .. - }) = attr { - if ident == "doc" { - docs.extend(quote!(#lit,)); - } - } - } - let str_name = name.to_string(); - let struct_name = proc_macro2::Ident::new(&("__GetByteStruct".to_string() + &str_name), name.span()); - let cache_name = proc_macro2::Ident::new(&("__CACHE_GET_BYTE_STRUCT_".to_string() + &str_name), name.span()); - - let item = quote! { - #scrate::metadata::StorageEntryMetadata { - name: #scrate::metadata::DecodeDifferent::Encode(#str_name), - modifier: #modifier, - ty: #stype, - default: #scrate::metadata::DecodeDifferent::Encode( - #scrate::metadata::DefaultByteGetter( - &#struct_name::<#traitinstance, #instance>(#scrate::rstd::marker::PhantomData) - ) - ), - documentation: #scrate::metadata::DecodeDifferent::Encode(&[ #docs ]), - }, - }; - items.extend(item); - - let def_get = quote! { - #[doc(hidden)] - pub struct #struct_name< - #traitinstance, #instance #bound_instantiable #equal_default_instance - >(pub #scrate::rstd::marker::PhantomData<(#traitinstance #comma_instance)>); - - #[cfg(feature = "std")] - #[allow(non_upper_case_globals)] - static #cache_name: #scrate::once_cell::sync::OnceCell< - #scrate::rstd::vec::Vec - > = #scrate::once_cell::sync::OnceCell::new(); - - #[cfg(feature = "std")] - impl<#traitinstance: #traittype, #instance #bound_instantiable> #scrate::metadata::DefaultByte - for #struct_name<#traitinstance, #instance> #where_clause - { - fn default_byte(&self) -> #scrate::rstd::vec::Vec { - use #scrate::codec::Encode; - #cache_name.get_or_init(|| { - let def_val: #value_type = #default; - <#value_type as Encode>::encode(&def_val) - }).clone() - } - } - - unsafe impl<#traitinstance: #traittype, #instance #bound_instantiable> Send - for #struct_name<#traitinstance, #instance> #where_clause {} - - unsafe impl<#traitinstance: #traittype, #instance #bound_instantiable> Sync - for #struct_name<#traitinstance, #instance> #where_clause {} - - #[cfg(not(feature = "std"))] - impl<#traitinstance: #traittype, #instance #bound_instantiable> #scrate::metadata::DefaultByte - for #struct_name<#traitinstance, #instance> #where_clause - { - fn default_byte(&self) -> #scrate::rstd::vec::Vec { - use #scrate::codec::Encode; - let def_val: #value_type = #default; - <#value_type as Encode>::encode(&def_val) - } - } - }; - - default_getter_struct_def.extend(def_get); - } - - let prefix = cratename.to_string(); - let prefix = instance.as_ref().map_or_else(|| quote!(#prefix), |i| quote!(#i::PREFIX)); - - (default_getter_struct_def, quote!{ - #scrate::metadata::StorageMetadata { - prefix: #scrate::metadata::DecodeDifferent::Encode(#prefix), - entries: #scrate::metadata::DecodeDifferent::Encode(&[ #items ][..]), - } - }) -} - - -#[derive(Debug, Clone)] -pub(crate) struct DeclStorageTypeInfos<'a> { - pub is_option: bool, - pub typ: TokenStream2, - pub value_type: &'a syn::Type, - kind: DeclStorageTypeInfosKind<'a>, -} - -#[derive(Debug, Clone)] -enum DeclStorageTypeInfosKind<'a> { - Simple, - Map { - hasher: HasherKind, - key_type: &'a syn::Type, - is_linked: bool, - }, - DoubleMap { - hasher: HasherKind, - key1_type: &'a syn::Type, - key2_type: &'a syn::Type, - key2_hasher: HasherKind, - } -} - -fn get_type_infos(storage_type: &DeclStorageType) -> DeclStorageTypeInfos { - let (value_type, kind) = match storage_type { - DeclStorageType::Simple(ref st) => (st, DeclStorageTypeInfosKind::Simple), - DeclStorageType::Map(ref map) => (&map.value, DeclStorageTypeInfosKind::Map { - hasher: map.hasher.inner.as_ref().map(|h| h.into()).unwrap_or(HasherKind::Blake2_256), - key_type: &map.key, - is_linked: false, - }), - DeclStorageType::LinkedMap(ref map) => (&map.value, DeclStorageTypeInfosKind::Map { - hasher: map.hasher.inner.as_ref().map(|h| h.into()).unwrap_or(HasherKind::Blake2_256), - key_type: &map.key, - is_linked: true, - }), - DeclStorageType::DoubleMap(ref map) => (&map.value, DeclStorageTypeInfosKind::DoubleMap { - hasher: map.hasher.inner.as_ref().map(|h| h.into()).unwrap_or(HasherKind::Blake2_256), - key1_type: &map.key1, - key2_type: &map.key2.content, - key2_hasher: (&map.key2_hasher).into(), - }), - }; - - let extracted_type = ext::extract_type_option(value_type); - let is_option = extracted_type.is_some(); - let typ = extracted_type.unwrap_or(quote!( #value_type )); - - DeclStorageTypeInfos { - is_option, - typ, - value_type, - kind, - } - -} - -#[derive(Default)] -pub(crate) struct InstanceOpts { - pub instance: Option, - pub default_instance: Option, - pub instantiable: Option, - pub comma_instance: TokenStream2, - pub equal_default_instance: TokenStream2, - pub bound_instantiable: TokenStream2, -} - -fn get_instance_opts( - instance: Option, - instantiable: Option, - default_instance: Option, -) -> Result { - let right_syntax = "Should be $Instance: $Instantiable = $DefaultInstance"; - - match (instance, instantiable, default_instance) { - (Some(instance), Some(instantiable), default_instance) => { - let (equal_default_instance, default_instance) = if let Some(def) = default_instance { - (quote!{= #def}, Some(def)) - } else { - (quote!(), None) - }; - - Ok(InstanceOpts { - comma_instance: quote!{, #instance}, - equal_default_instance, - bound_instantiable: quote!{: #instantiable}, - instance: Some(instance), - default_instance, - instantiable: Some(instantiable), - }) - }, - (None, None, None) => Ok(Default::default()), - (Some(instance), None, _) => Err( - Error::new( - instance.span(), - format!( - "Expect instantiable trait bound for instance: {}. {}", - instance, - right_syntax, - ) - ) - ), - (None, Some(instantiable), _) => Err( - Error::new( - instantiable.span(), - format!( - "Expect instance generic for bound instantiable: {}. {}", - instantiable, - right_syntax, - ) - ) - ), - (None, _, Some(default_instance)) => Err( - Error::new( - default_instance.span(), - format!( - "Expect instance generic for default instance: {}. {}", - default_instance, - right_syntax, - ) - ) - ), - } -} diff --git a/srml/support/procedural/tools/src/syn_ext.rs b/srml/support/procedural/tools/src/syn_ext.rs index 1033ebcce2..1658a6b4ae 100644 --- a/srml/support/procedural/tools/src/syn_ext.rs +++ b/srml/support/procedural/tools/src/syn_ext.rs @@ -184,13 +184,15 @@ impl ToTokens for Opt

{ } } -pub fn extract_type_option(typ: &syn::Type) -> Option { +pub fn extract_type_option(typ: &syn::Type) -> Option { if let syn::Type::Path(ref path) = typ { let v = path.path.segments.last()?; if v.value().ident == "Option" { - if let syn::PathArguments::AngleBracketed(ref a) = v.value().arguments { - let args = &a.args; - return Some(quote!{ #args }) + // Option has only one type argument in angle bracket. + if let syn::PathArguments::AngleBracketed(a) = &v.value().arguments { + if let syn::GenericArgument::Type(typ) = a.args.last()?.value() { + return Some(typ.clone()) + } } } } @@ -253,4 +255,4 @@ pub fn expr_contains_ident(expr: &syn::Expr, ident: &Ident) -> bool { visit::visit_expr(&mut visit, expr); visit.result -} \ No newline at end of file +} -- GitLab From 0cd7260ef8025ec770a24ee374f3a27fe5b1ebf1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 16 Oct 2019 21:00:31 +0200 Subject: [PATCH 047/167] Make `wasmi_execution` public to use it from tests (#3829) * Make `wasmi_execution` public to use it from tests * Make `WasmRuntime` accessible as well * Add `call_in_wasm` instead of making stuff public * Use `WasmRuntime` * Move test * More feedback --- core/executor/src/error.rs | 6 ++++ core/executor/src/lib.rs | 48 +++++++++++++++++++++++++++++++ core/executor/src/wasm_runtime.rs | 20 +++++++++---- 3 files changed, 69 insertions(+), 5 deletions(-) diff --git a/core/executor/src/error.rs b/core/executor/src/error.rs index 6b3c45ee49..e1221bea54 100644 --- a/core/executor/src/error.rs +++ b/core/executor/src/error.rs @@ -99,6 +99,12 @@ impl From for Error { } } +impl From for Error { + fn from(err: WasmError) -> Error { + Error::Other(err.to_string()) + } +} + /// Type for errors occurring during Wasm runtime construction. #[derive(Debug, derive_more::Display)] pub enum WasmError { diff --git a/core/executor/src/lib.rs b/core/executor/src/lib.rs index ccc78afdb4..582ebbca34 100644 --- a/core/executor/src/lib.rs +++ b/core/executor/src/lib.rs @@ -50,6 +50,33 @@ pub use primitives::traits::Externalities; pub use wasm_interface; pub use wasm_runtime::WasmExecutionMethod; +/// Call the given `function` in the given wasm `code`. +/// +/// The signature of `function` needs to follow the default Substrate function signature. +/// +/// - `call_data`: Will be given as input parameters to `function` +/// - `execution_method`: The execution method to use. +/// - `ext`: The externalities that should be set while executing the wasm function. +/// - `heap_pages`: The number of heap pages to allocate. +/// +/// Returns the `Vec` that contains the return value of the function. +pub fn call_in_wasm( + function: &str, + call_data: &[u8], + execution_method: WasmExecutionMethod, + ext: &mut E, + code: &[u8], + heap_pages: u64, +) -> error::Result> { + let mut instance = wasm_runtime::create_wasm_runtime_with_code( + ext, + execution_method, + heap_pages, + code, + )?; + instance.call(ext, function, call_data) +} + /// Provides runtime information. pub trait RuntimeInfo { /// Native runtime information. @@ -61,3 +88,24 @@ pub trait RuntimeInfo { ext: &mut E, ) -> Option; } + +#[cfg(test)] +mod tests { + use super::*; + use runtime_test::WASM_BINARY; + use runtime_io::TestExternalities; + + #[test] + fn call_in_interpreted_wasm_works() { + let mut ext = TestExternalities::default(); + let res = call_in_wasm( + "test_empty_return", + &[], + WasmExecutionMethod::Interpreted, + &mut ext, + &WASM_BINARY, + 8, + ).unwrap(); + assert_eq!(res, vec![0u8; 0]); + } +} diff --git a/core/executor/src/wasm_runtime.rs b/core/executor/src/wasm_runtime.rs index d88ae7b9ed..8d2291fe04 100644 --- a/core/executor/src/wasm_runtime.rs +++ b/core/executor/src/wasm_runtime.rs @@ -157,17 +157,27 @@ impl RuntimesCache { } } -fn create_wasm_runtime( +/// Create a wasm runtime with the given `code`. +pub fn create_wasm_runtime_with_code( ext: &mut E, wasm_method: WasmExecutionMethod, heap_pages: u64, + code: &[u8], ) -> Result, WasmError> { - let code = ext - .original_storage(well_known_keys::CODE) - .ok_or(WasmError::CodeNotFound)?; match wasm_method { WasmExecutionMethod::Interpreted => - wasmi_execution::create_instance(ext, &code, heap_pages) + wasmi_execution::create_instance(ext, code, heap_pages) .map(|runtime| -> Box { Box::new(runtime) }), } } + +fn create_wasm_runtime( + ext: &mut E, + wasm_method: WasmExecutionMethod, + heap_pages: u64, +) -> Result, WasmError> { + let code = ext + .original_storage(well_known_keys::CODE) + .ok_or(WasmError::CodeNotFound)?; + create_wasm_runtime_with_code(ext, wasm_method, heap_pages, &code) +} -- GitLab From 0b2606e91e823bd12f3aa0f1b32f65cf2d918bb9 Mon Sep 17 00:00:00 2001 From: Ashley Date: Thu, 17 Oct 2019 11:34:03 +0100 Subject: [PATCH 048/167] Add error types to BABE and PoW (#3827) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add an error type to Babe * Add an error type to PoW * Simplify error enum variant names * Update core/consensus/babe/src/lib.rs Co-Authored-By: Bastian Köcher * Add missing newline * Split up DataProvider into CreateInherents and CheckInherents --- Cargo.lock | 2 + core/consensus/babe/Cargo.toml | 1 + core/consensus/babe/src/lib.rs | 145 ++++++++++++++++-------- core/consensus/babe/src/tests.rs | 6 +- core/consensus/babe/src/verification.rs | 45 +++----- core/consensus/pow/Cargo.toml | 1 + core/consensus/pow/src/lib.rs | 97 +++++++++++----- 7 files changed, 191 insertions(+), 106 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b42da79f88..1fd3c18534 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4869,6 +4869,7 @@ dependencies = [ name = "substrate-consensus-babe" version = "2.0.0" dependencies = [ + "derive_more 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "fork-tree 2.0.0", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4945,6 +4946,7 @@ dependencies = [ name = "substrate-consensus-pow" version = "2.0.0" dependencies = [ + "derive_more 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "futures-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/core/consensus/babe/Cargo.toml b/core/consensus/babe/Cargo.toml index b1c2c31f7d..30b7c1f8d6 100644 --- a/core/consensus/babe/Cargo.toml +++ b/core/consensus/babe/Cargo.toml @@ -36,6 +36,7 @@ schnorrkel = { version = "0.8.5", features = ["preaudit_deprecated"] } rand = "0.7.2" merlin = "1.2.1" pdqselect = "0.1.0" +derive_more = "0.15.0" [dev-dependencies] keyring = { package = "substrate-keyring", path = "../../keyring" } diff --git a/core/consensus/babe/src/lib.rs b/core/consensus/babe/src/lib.rs index 0eacf1407e..287b26a300 100644 --- a/core/consensus/babe/src/lib.rs +++ b/core/consensus/babe/src/lib.rs @@ -66,7 +66,7 @@ use consensus_common::ImportResult; use consensus_common::import_queue::{ BoxJustificationImport, BoxFinalityProofImport, }; -use sr_primitives::{generic::{BlockId, OpaqueDigestItemId}, Justification}; +use sr_primitives::{generic::{BlockId, OpaqueDigestItemId}, Justification, RuntimeString}; use sr_primitives::traits::{ Block as BlockT, Header, DigestItemFor, ProvideRuntimeApi, Zero, @@ -102,6 +102,7 @@ use log::{warn, debug, info, trace}; use slots::{SlotWorker, SlotData, SlotInfo, SlotCompatible}; use epoch_changes::descendent_query; use header_metadata::HeaderMetadata; +use schnorrkel::SignatureError; mod aux_schema; mod verification; @@ -114,13 +115,71 @@ pub use babe_primitives::{ }; pub use epoch_changes::{EpochChanges, EpochChangesFor, SharedEpochChanges}; -macro_rules! babe_err { - ($($i: expr),+) => { - { - debug!(target: "babe", $($i),+); - format!($($i),+) - } - }; + +#[derive(derive_more::Display, Debug)] +enum Error { + #[display(fmt = "Multiple BABE pre-runtime digests, rejecting!")] + MultiplePreRuntimeDigests, + #[display(fmt = "No BABE pre-runtime digest found")] + NoPreRuntimeDigest, + #[display(fmt = "Multiple BABE epoch change digests, rejecting!")] + MultipleEpochChangeDigests, + #[display(fmt = "Could not extract timestamp and slot: {:?}", _0)] + Extraction(consensus_common::Error), + #[display(fmt = "Could not fetch epoch at {:?}", _0)] + FetchEpoch(B::Hash), + #[display(fmt = "Header {:?} rejected: too far in the future", _0)] + TooFarInFuture(B::Hash), + #[display(fmt = "Parent ({}) of {} unavailable. Cannot import", _0, _1)] + ParentUnavailable(B::Hash, B::Hash), + #[display(fmt = "Slot number must increase: parent slot: {}, this slot: {}", _0, _1)] + SlotNumberMustIncrease(u64, u64), + #[display(fmt = "Header {:?} has a bad seal", _0)] + HeaderBadSeal(B::Hash), + #[display(fmt = "Header {:?} is unsealed", _0)] + HeaderUnsealed(B::Hash), + #[display(fmt = "Slot author not found")] + SlotAuthorNotFound, + #[display(fmt = "Secondary slot assignments are disabled for the current epoch.")] + SecondarySlotAssignmentsDisabled, + #[display(fmt = "Bad signature on {:?}", _0)] + BadSignature(B::Hash), + #[display(fmt = "Invalid author: Expected secondary author: {:?}, got: {:?}.", _0, _1)] + InvalidAuthor(AuthorityId, AuthorityId), + #[display(fmt = "No secondary author expected.")] + NoSecondaryAuthorExpected, + #[display(fmt = "VRF verification of block by author {:?} failed: threshold {} exceeded", _0, _1)] + VRFVerificationOfBlockFailed(AuthorityId, u128), + #[display(fmt = "VRF verification failed: {:?}", _0)] + VRFVerificationFailed(SignatureError), + #[display(fmt = "Could not fetch parent header: {:?}", _0)] + FetchParentHeader(client::error::Error), + #[display(fmt = "Expected epoch change to happen at {:?}, s{}", _0, _1)] + ExpectedEpochChange(B::Hash, u64), + #[display(fmt = "Could not look up epoch: {:?}", _0)] + CouldNotLookUpEpoch(Box>), + #[display(fmt = "Block {} is not valid under any epoch.", _0)] + BlockNotValid(B::Hash), + #[display(fmt = "Unexpected epoch change")] + UnexpectedEpochChange, + #[display(fmt = "Parent block of {} has no associated weight", _0)] + ParentBlockNoAssociatedWeight(B::Hash), + #[display(fmt = "Checking inherents failed: {}", _0)] + CheckInherents(String), + Client(client::error::Error), + Runtime(RuntimeString), + ForkTree(Box>), +} + +impl std::convert::From> for String { + fn from(error: Error) -> String { + error.to_string() + } +} + +fn babe_err(error: Error) -> Error { + debug!(target: "babe", "{}", error); + error } macro_rules! babe_info { @@ -385,7 +444,7 @@ impl slots::SimpleSlotWorker for BabeWorker Result { self.env.init(block).map_err(|e| { - consensus_common::Error::ClientImport(format!("{:?}", e)).into() + consensus_common::Error::ClientImport(format!("{:?}", e)) }) } } @@ -410,7 +469,7 @@ impl SlotWorker for BabeWorker where /// Extract the BABE pre digest from the given header. Pre-runtime digests are /// mandatory, the function will return `Err` if none is found. -fn find_pre_digest(header: &H) -> Result +fn find_pre_digest(header: &B::Header) -> Result> { // genesis block doesn't contain a pre digest so let's generate a // dummy one to not break any invariants in the rest of the code @@ -425,17 +484,17 @@ fn find_pre_digest(header: &H) -> Result for log in header.digest().logs() { trace!(target: "babe", "Checking log {:?}, looking for pre runtime digest", log); match (log.as_babe_pre_digest(), pre_digest.is_some()) { - (Some(_), true) => Err(babe_err!("Multiple BABE pre-runtime digests, rejecting!"))?, + (Some(_), true) => return Err(babe_err(Error::MultiplePreRuntimeDigests)), (None, _) => trace!(target: "babe", "Ignoring digest not meant for us"), (s, false) => pre_digest = s, } } - pre_digest.ok_or_else(|| babe_err!("No BABE pre-runtime digest found")) + pre_digest.ok_or_else(|| babe_err(Error::NoPreRuntimeDigest)) } /// Extract the BABE epoch change digest from the given header, if it exists. fn find_next_epoch_digest(header: &B::Header) - -> Result, String> + -> Result, Error> where DigestItemFor: CompatibleDigestItem, { let mut epoch_digest: Option<_> = None; @@ -443,7 +502,7 @@ fn find_next_epoch_digest(header: &B::Header) trace!(target: "babe", "Checking log {:?}, looking for epoch change digest.", log); let log = log.try_to::(OpaqueDigestItemId::Consensus(&BABE_ENGINE_ID)); match (log, epoch_digest.is_some()) { - (Some(ConsensusLog::NextEpochData(_)), true) => Err(babe_err!("Multiple BABE epoch change digests, rejecting!"))?, + (Some(ConsensusLog::NextEpochData(_)), true) => return Err(babe_err(Error::MultipleEpochChangeDigests)), (Some(ConsensusLog::NextEpochData(epoch)), false) => epoch_digest = Some(epoch), _ => trace!(target: "babe", "Ignoring digest not meant for us"), } @@ -493,20 +552,20 @@ impl BabeVerifier { block: Block, block_id: BlockId, inherent_data: InherentData, - ) -> Result<(), String> + ) -> Result<(), Error> where PRA: ProvideRuntimeApi, PRA::Api: BlockBuilderApi { let inherent_res = self.api.runtime_api().check_inherents( &block_id, block, inherent_data, - ).map_err(|e| format!("{:?}", e))?; + ).map_err(Error::Client)?; if !inherent_res.ok() { inherent_res .into_errors() .try_for_each(|(i, e)| { - Err(self.inherent_data_providers.error_to_string(&i, &e)) + Err(Error::CheckInherents(self.inherent_data_providers.error_to_string(&i, &e))) }) } else { Ok(()) @@ -585,18 +644,18 @@ impl Verifier for BabeVerifier::Runtime)?; let (_, slot_now, _) = self.time_source.extract_timestamp_and_slot(&inherent_data) - .map_err(|e| format!("Could not extract timestamp and slot: {:?}", e))?; + .map_err(Error::::Extraction)?; let hash = header.hash(); let parent_hash = *header.parent_hash(); let parent_header_metadata = self.client.header_metadata(parent_hash) - .map_err(|e| format!("Could not fetch parent header: {:?}", e))?; + .map_err(Error::::FetchParentHeader)?; - let pre_digest = find_pre_digest::(&header)?; + let pre_digest = find_pre_digest::(&header)?; let epoch = { let epoch_changes = self.epoch_changes.lock(); epoch_changes.epoch_for_child_of( @@ -606,8 +665,8 @@ impl Verifier for BabeVerifier::ForkTree(Box::new(e)))? + .ok_or_else(|| Error::::FetchEpoch(parent_hash))? }; // We add one to the current slot to allow for some small drift. @@ -691,7 +750,7 @@ impl Verifier for BabeVerifier ?hash, "a" => ?a, "b" => ?b ); - Err(format!("Header {:?} rejected: too far in the future", hash)) + Err(Error::::TooFarInFuture(hash).into()) } } } @@ -787,10 +846,10 @@ impl BlockImport for BabeBlockImport return Ok(ImportResult::AlreadyInChain), Ok(blockchain::BlockStatus::Unknown) => {}, - Err(e) => return Err(ConsensusError::ClientImport(e.to_string()).into()), + Err(e) => return Err(ConsensusError::ClientImport(e.to_string())), } - let pre_digest = find_pre_digest::(&block.header) + let pre_digest = find_pre_digest::(&block.header) .expect("valid babe headers must contain a predigest; \ header has been already verified; qed"); let slot_number = pre_digest.slot_number(); @@ -798,13 +857,11 @@ impl BlockImport for BabeBlockImport::ParentUnavailable(parent_hash, hash) + ).into()))?; - let parent_slot = find_pre_digest::(&parent_header) + let parent_slot = find_pre_digest::(&parent_header) .map(|d| d.slot_number()) .expect("parent is non-genesis; valid BABE headers contain a pre-digest; \ header has already been verified; qed"); @@ -812,11 +869,9 @@ impl BlockImport for BabeBlockImport::SlotNumberMustIncrease(parent_slot, slot_number) + ).into()) ); } @@ -834,7 +889,7 @@ impl BlockImport for BabeBlockImport::ParentBlockNoAssociatedWeight(hash)).into() ))? }; @@ -846,10 +901,10 @@ impl BlockImport for BabeBlockImport| ConsensusError::ChainLookup( - babe_err!("Could not look up epoch: {:?}", e) + babe_err(Error::::CouldNotLookUpEpoch(Box::new(e))).into() ))? .ok_or_else(|| ConsensusError::ClientImport( - babe_err!("Block {} is not valid under any epoch.", hash) + babe_err(Error::::BlockNotValid(hash)).into() ))?; let first_in_epoch = parent_slot < epoch.as_ref().start_slot; @@ -860,7 +915,7 @@ impl BlockImport for BabeBlockImport(&block.header) - .map_err(|e| ConsensusError::from(ConsensusError::ClientImport(e.to_string())))?; + .map_err(|e| ConsensusError::ClientImport(e.to_string()))?; match (first_in_epoch, next_epoch_digest.is_some()) { (true, true) => {}, @@ -868,12 +923,12 @@ impl BlockImport for BabeBlockImport { return Err( ConsensusError::ClientImport( - babe_err!("Expected epoch change to happen at {:?}, s{}", hash, slot_number), + babe_err(Error::::ExpectedEpochChange(hash, slot_number)).into(), ) ); }, (false, true) => { - return Err(ConsensusError::ClientImport("Unexpected epoch change".into())); + return Err(ConsensusError::ClientImport(Error::::UnexpectedEpochChange.into())); }, } @@ -917,7 +972,7 @@ impl BlockImport for BabeBlockImport( .expect("best finalized hash was given by client; \ finalized headers must exist in db; qed"); - find_pre_digest::(&finalized_header) + find_pre_digest::(&finalized_header) .expect("finalized header must be valid; \ valid blocks have a pre-digest; qed") .slot_number() diff --git a/core/consensus/babe/src/tests.rs b/core/consensus/babe/src/tests.rs index e6883977a0..2e236f190b 100644 --- a/core/consensus/babe/src/tests.rs +++ b/core/consensus/babe/src/tests.rs @@ -81,7 +81,7 @@ impl Environment for DummyFactory { -> Result { - let parent_slot = crate::find_pre_digest(parent_header) + let parent_slot = crate::find_pre_digest::(parent_header) .expect("parent header has a pre-digest") .slot_number(); @@ -109,7 +109,7 @@ impl DummyProposer { Err(e) => return future::ready(Err(e)), }; - let this_slot = crate::find_pre_digest(block.header()) + let this_slot = crate::find_pre_digest::(block.header()) .expect("baked block has valid pre-digest") .slot_number(); @@ -535,7 +535,7 @@ fn propose_and_import_block( let mut proposer = proposer_factory.init(parent).unwrap(); let slot_number = slot_number.unwrap_or_else(|| { - let parent_pre_digest = find_pre_digest(parent).unwrap(); + let parent_pre_digest = find_pre_digest::(parent).unwrap(); parent_pre_digest.slot_number() + 1 }); diff --git a/core/consensus/babe/src/verification.rs b/core/consensus/babe/src/verification.rs index 05d6102450..36e34dfb95 100644 --- a/core/consensus/babe/src/verification.rs +++ b/core/consensus/babe/src/verification.rs @@ -22,7 +22,7 @@ use babe_primitives::{Epoch, BabePreDigest, CompatibleDigestItem, AuthorityId}; use babe_primitives::{AuthoritySignature, SlotNumber, AuthorityIndex, AuthorityPair}; use slots::CheckedHeader; use log::{debug, trace}; -use super::{find_pre_digest, BlockT}; +use super::{find_pre_digest, babe_err, BlockT, Error}; use super::authorship::{make_transcript, calculate_primary_threshold, check_primary_threshold, secondary_slot_author}; /// BABE verification parameters @@ -41,15 +41,6 @@ pub(super) struct VerificationParams<'a, B: 'a + BlockT> { pub(super) config: &'a super::Config, } -macro_rules! babe_err { - ($($i: expr),+) => { - { - debug!(target: "babe", $($i),+); - format!($($i),+) - } - }; -} - /// Check a header has been signed by the right key. If the slot is too far in /// the future, an error will be returned. If successful, returns the pre-header /// and the digest item containing the seal. @@ -63,7 +54,7 @@ macro_rules! babe_err { /// with each having different validation logic. pub(super) fn check_header( params: VerificationParams, -) -> Result>, String> where +) -> Result>, Error> where DigestItemFor: CompatibleDigestItem, { let VerificationParams { @@ -75,16 +66,16 @@ pub(super) fn check_header( } = params; let authorities = &epoch.authorities; - let pre_digest = pre_digest.map(Ok).unwrap_or_else(|| find_pre_digest::(&header))?; + let pre_digest = pre_digest.map(Ok).unwrap_or_else(|| find_pre_digest::(&header))?; trace!(target: "babe", "Checking header"); let seal = match header.digest_mut().pop() { Some(x) => x, - None => return Err(babe_err!("Header {:?} is unsealed", header.hash())), + None => return Err(babe_err(Error::HeaderUnsealed(header.hash()))), }; let sig = seal.as_babe_seal().ok_or_else(|| { - babe_err!("Header {:?} has a bad seal", header.hash()) + babe_err(Error::HeaderBadSeal(header.hash())) })?; // the pre-hash of the header doesn't include the seal @@ -98,7 +89,7 @@ pub(super) fn check_header( let author = match authorities.get(pre_digest.authority_index() as usize) { Some(author) => author.0.clone(), - None => return Err(babe_err!("Slot author not found")), + None => return Err(babe_err(Error::SlotAuthorNotFound)), }; match &pre_digest { @@ -128,7 +119,7 @@ pub(super) fn check_header( )?; }, _ => { - return Err(babe_err!("Secondary slot assignments are disabled for the current epoch.")); + return Err(babe_err(Error::SecondarySlotAssignmentsDisabled)); } } @@ -156,7 +147,7 @@ fn check_primary_header( signature: AuthoritySignature, epoch: &Epoch, c: (u64, u64), -) -> Result<(), String> { +) -> Result<(), Error> { let (vrf_output, vrf_proof, authority_index, slot_number) = pre_digest; let author = &epoch.authorities[authority_index as usize].0; @@ -172,7 +163,7 @@ fn check_primary_header( schnorrkel::PublicKey::from_bytes(author.as_slice()).and_then(|p| { p.vrf_verify(transcript, vrf_output, vrf_proof) }).map_err(|s| { - babe_err!("VRF verification failed: {:?}", s) + babe_err(Error::VRFVerificationFailed(s)) })? }; @@ -183,13 +174,12 @@ fn check_primary_header( ); if !check_primary_threshold(&inout, threshold) { - return Err(babe_err!("VRF verification of block by author {:?} failed: \ - threshold {} exceeded", author, threshold)); + return Err(babe_err(Error::VRFVerificationOfBlockFailed(author.clone(), threshold))); } Ok(()) } else { - Err(babe_err!("Bad signature on {:?}", pre_hash)) + Err(babe_err(Error::BadSignature(pre_hash))) } } @@ -202,7 +192,7 @@ fn check_secondary_header( pre_digest: (AuthorityIndex, SlotNumber), signature: AuthoritySignature, epoch: &Epoch, -) -> Result<(), String> { +) -> Result<(), Error> { let (authority_index, slot_number) = pre_digest; // check the signature is valid under the expected authority and @@ -211,22 +201,17 @@ fn check_secondary_header( slot_number, &epoch.authorities, epoch.randomness, - ).ok_or_else(|| "No secondary author expected.".to_string())?; + ).ok_or_else(|| Error::NoSecondaryAuthorExpected)?; let author = &epoch.authorities[authority_index as usize].0; if expected_author != author { - let msg = format!("Invalid author: Expected secondary author: {:?}, got: {:?}.", - expected_author, - author, - ); - - return Err(msg); + return Err(Error::InvalidAuthor(expected_author.clone(), author.clone())); } if AuthorityPair::verify(&signature, pre_hash.as_ref(), author) { Ok(()) } else { - Err(format!("Bad signature on {:?}", pre_hash)) + Err(Error::BadSignature(pre_hash)) } } diff --git a/core/consensus/pow/Cargo.toml b/core/consensus/pow/Cargo.toml index 54dd58c467..86efcbb95d 100644 --- a/core/consensus/pow/Cargo.toml +++ b/core/consensus/pow/Cargo.toml @@ -16,3 +16,4 @@ pow-primitives = { package = "substrate-consensus-pow-primitives", path = "primi consensus-common = { package = "substrate-consensus-common", path = "../common" } log = "0.4.8" futures-preview = { version = "0.3.0-alpha.19", features = ["compat"] } +derive_more = "0.15.0" diff --git a/core/consensus/pow/src/lib.rs b/core/consensus/pow/src/lib.rs index 766c1c63e0..040eb01d9c 100644 --- a/core/consensus/pow/src/lib.rs +++ b/core/consensus/pow/src/lib.rs @@ -37,7 +37,7 @@ use client::{ block_builder::api::BlockBuilder as BlockBuilderApi, backend::AuxStore, well_known_cache_keys::Id as CacheKeyId, }; -use sr_primitives::Justification; +use sr_primitives::{Justification, RuntimeString}; use sr_primitives::generic::{BlockId, Digest, DigestItem}; use sr_primitives::traits::{Block as BlockT, Header as HeaderT, ProvideRuntimeApi}; use srml_timestamp::{TimestampInherentData, InherentError as TIError}; @@ -46,12 +46,50 @@ use primitives::H256; use inherents::{InherentDataProviders, InherentData}; use consensus_common::{ BlockImportParams, BlockOrigin, ForkChoiceStrategy, SyncOracle, Environment, Proposer, - SelectChain, + SelectChain, Error as ConsensusError }; use consensus_common::import_queue::{BoxBlockImport, BasicQueue, Verifier}; use codec::{Encode, Decode}; use log::*; +#[derive(derive_more::Display, Debug)] +pub enum Error { + #[display(fmt = "Header uses the wrong engine {:?}", _0)] + WrongEngine([u8; 4]), + #[display(fmt = "Header {:?} is unsealed", _0)] + HeaderUnsealed(B::Hash), + #[display(fmt = "PoW validation error: invalid seal")] + InvalidSeal, + #[display(fmt = "Rejecting block too far in future")] + TooFarInFuture, + #[display(fmt = "Fetching best header failed using select chain: {:?}", _0)] + BestHeaderSelectChain(ConsensusError), + #[display(fmt = "Fetching best header failed: {:?}", _0)] + BestHeader(client::error::Error), + #[display(fmt = "Best header does not exist")] + NoBestHeader, + #[display(fmt = "Block proposing error: {:?}", _0)] + BlockProposingError(String), + #[display(fmt = "Fetch best hash failed via select chain: {:?}", _0)] + BestHashSelectChain(ConsensusError), + #[display(fmt = "Error with block built on {:?}: {:?}", _0, _1)] + BlockBuiltError(B::Hash, ConsensusError), + #[display(fmt = "Creating inherents failed: {}", _0)] + CreateInherents(RuntimeString), + #[display(fmt = "Checking inherents failed: {}", _0)] + CheckInherents(String), + Client(client::error::Error), + Codec(codec::Error), + Environment(String), + Runtime(RuntimeString) +} + +impl std::convert::From> for String { + fn from(error: Error) -> String { + error.to_string() + } +} + /// Auxiliary storage prefix for PoW engine. pub const POW_AUX_PREFIX: [u8; 4] = *b"PoW:"; @@ -74,12 +112,12 @@ impl PowAux where Difficulty: Decode + Default, { /// Read the auxiliary from client. - pub fn read(client: &C, hash: &H256) -> Result { + pub fn read(client: &C, hash: &H256) -> Result> { let key = aux_key(hash); - match client.get_aux(&key).map_err(|e| format!("{:?}", e))? { + match client.get_aux(&key).map_err(Error::Client)? { Some(bytes) => Self::decode(&mut &bytes[..]) - .map_err(|e| format!("{:?}", e)), + .map_err(Error::Codec), None => Ok(Self::default()), } } @@ -91,7 +129,7 @@ pub trait PowAlgorithm { type Difficulty: TotalDifficulty + Default + Encode + Decode + Ord + Clone + Copy; /// Get the next block's difficulty. - fn difficulty(&self, parent: &BlockId) -> Result; + fn difficulty(&self, parent: &BlockId) -> Result>; /// Verify proof of work against the given difficulty. fn verify( &self, @@ -99,7 +137,7 @@ pub trait PowAlgorithm { pre_hash: &H256, seal: &Seal, difficulty: Self::Difficulty, - ) -> Result; + ) -> Result>; /// Mine a seal that satisfies the given difficulty. fn mine( &self, @@ -107,7 +145,7 @@ pub trait PowAlgorithm { pre_hash: &H256, difficulty: Self::Difficulty, round: u32, - ) -> Result, String>; + ) -> Result, Error>; } /// A verifier for PoW blocks. @@ -134,7 +172,7 @@ impl, C, S, Algorithm> PowVerifier { &self, mut header: B::Header, parent_block_id: BlockId, - ) -> Result<(B::Header, Algorithm::Difficulty, DigestItem), String> where + ) -> Result<(B::Header, Algorithm::Difficulty, DigestItem), Error> where Algorithm: PowAlgorithm, { let hash = header.hash(); @@ -144,10 +182,10 @@ impl, C, S, Algorithm> PowVerifier { if id == POW_ENGINE_ID { (DigestItem::Seal(id, seal.clone()), seal) } else { - return Err(format!("Header uses the wrong engine {:?}", id)) + return Err(Error::WrongEngine(id)) } }, - _ => return Err(format!("Header {:?} is unsealed", hash)), + _ => return Err(Error::HeaderUnsealed(hash)), }; let pre_hash = header.hash(); @@ -159,7 +197,7 @@ impl, C, S, Algorithm> PowVerifier { &inner_seal, difficulty, )? { - return Err("PoW validation error: invalid seal".into()); + return Err(Error::InvalidSeal); } Ok((header, difficulty, seal)) @@ -171,7 +209,7 @@ impl, C, S, Algorithm> PowVerifier { block_id: BlockId, inherent_data: InherentData, timestamp_now: u64, - ) -> Result<(), String> where + ) -> Result<(), Error> where C: ProvideRuntimeApi, C::Api: BlockBuilderApi { const MAX_TIMESTAMP_DRIFT_SECS: u64 = 60; @@ -184,7 +222,7 @@ impl, C, S, Algorithm> PowVerifier { &block_id, block, inherent_data, - ).map_err(|e| format!("{:?}", e))?; + ).map_err(Error::Client)?; if !inherent_res.ok() { inherent_res @@ -192,13 +230,15 @@ impl, C, S, Algorithm> PowVerifier { .try_for_each(|(i, e)| match TIError::try_from(&i, &e) { Some(TIError::ValidAtTimestamp(timestamp)) => { if timestamp > timestamp_now + MAX_TIMESTAMP_DRIFT_SECS { - return Err("Rejecting block too far in future".into()); + return Err(Error::TooFarInFuture); } Ok(()) }, - Some(TIError::Other(e)) => Err(e.into()), - None => Err(self.inherent_data_providers.error_to_string(&i, &e)), + Some(TIError::Other(e)) => Err(Error::Runtime(e)), + None => Err(Error::CheckInherents( + self.inherent_data_providers.error_to_string(&i, &e) + )), }) } else { Ok(()) @@ -231,8 +271,8 @@ impl, C, S, Algorithm> Verifier for PowVerifier(self.client.as_ref(), &best_hash)?; + let mut aux = PowAux::read::<_, B>(self.client.as_ref(), &parent_hash)?; let (checked_header, difficulty, seal) = self.check_header( header, @@ -390,7 +430,7 @@ fn mine_loop, C, Algorithm, E, SO, S>( build_time: std::time::Duration, select_chain: Option<&S>, inherent_data_providers: &inherents::InherentDataProviders, -) -> Result<(), String> where +) -> Result<(), Error> where C: HeaderBackend + AuxStore, Algorithm: PowAlgorithm, E: Environment, @@ -408,23 +448,24 @@ fn mine_loop, C, Algorithm, E, SO, S>( let (best_hash, best_header) = match select_chain { Some(select_chain) => { let header = select_chain.best_chain() - .map_err(|e| format!("Fetching best header failed using select chain: {:?}", e))?; + .map_err(Error::BestHeaderSelectChain)?; let hash = header.hash(); (hash, header) }, None => { let hash = client.info().best_hash; let header = client.header(BlockId::Hash(hash)) - .map_err(|e| format!("Fetching best header failed: {:?}", e))? - .ok_or("Best header does not exist")?; + .map_err(Error::BestHeader)? + .ok_or(Error::NoBestHeader)?; (hash, header) }, }; let mut aux = PowAux::read(client, &best_hash)?; - let mut proposer = env.init(&best_header).map_err(|e| format!("{:?}", e))?; + let mut proposer = env.init(&best_header) + .map_err(|e| Error::Environment(format!("{:?}", e)))?; let inherent_data = inherent_data_providers - .create_inherent_data().map_err(String::from)?; + .create_inherent_data().map_err(Error::CreateInherents)?; let mut inherent_digest = Digest::default(); if let Some(preruntime) = &preruntime { inherent_digest.push(DigestItem::PreRuntime(POW_ENGINE_ID, preruntime.to_vec())); @@ -433,7 +474,7 @@ fn mine_loop, C, Algorithm, E, SO, S>( inherent_data, inherent_digest, build_time.clone(), - )).map_err(|e| format!("Block proposing error: {:?}", e))?; + )).map_err(|e| Error::BlockProposingError(format!("{:?}", e)))?; let (header, body) = block.deconstruct(); let (difficulty, seal) = { @@ -470,7 +511,7 @@ fn mine_loop, C, Algorithm, E, SO, S>( let key = aux_key(&hash); let best_hash = match select_chain { Some(select_chain) => select_chain.best_chain() - .map_err(|e| format!("Fetch best hash failed via select chain: {:?}", e))? + .map_err(Error::BestHashSelectChain)? .hash(), None => client.info().best_hash, }; @@ -493,6 +534,6 @@ fn mine_loop, C, Algorithm, E, SO, S>( }; block_import.import_block(import_block, HashMap::default()) - .map_err(|e| format!("Error with block built on {:?}: {:?}", best_hash, e))?; + .map_err(|e| Error::BlockBuiltError(best_hash, e))?; } } -- GitLab From 165e7c93ae0593a93634139e4a74371bb35cfaac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Thu, 17 Oct 2019 12:54:28 +0200 Subject: [PATCH 049/167] Make `VersionInfo` derive `Clone` (#3839) --- core/cli/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/core/cli/src/lib.rs b/core/cli/src/lib.rs index d4bb4f6f0d..c5af33b738 100644 --- a/core/cli/src/lib.rs +++ b/core/cli/src/lib.rs @@ -79,6 +79,7 @@ const NODE_KEY_SECP256K1_FILE: &str = "secret"; const NODE_KEY_ED25519_FILE: &str = "secret_ed25519"; /// Executable version. Used to pass version information from the root crate. +#[derive(Clone)] pub struct VersionInfo { /// Implementaiton name. pub name: &'static str, -- GitLab From df1582beef2d47109a0adcb14376420b1a99e157 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Thu, 17 Oct 2019 14:21:32 +0200 Subject: [PATCH 050/167] refactor: Transaction-Payment module (#3816) * Initial draft that compiles * Extract payment stuff from balances * Extract multiplier update stuff from system * Some fixes. * Update len-fee as well * some review comments. * Remove todo * bump --- Cargo.lock | 22 + Cargo.toml | 1 + core/sr-primitives/src/sr_arithmetic.rs | 39 +- core/sr-primitives/src/weights.rs | 76 ---- core/test-runtime/src/lib.rs | 1 - node-template/runtime/Cargo.toml | 2 + node-template/runtime/src/lib.rs | 22 +- node-template/runtime/src/template.rs | 1 - node/cli/Cargo.toml | 1 + node/cli/src/factory_impl.rs | 2 +- node/cli/src/service.rs | 4 +- node/executor/Cargo.toml | 1 + node/executor/src/lib.rs | 81 ++-- node/runtime/Cargo.toml | 2 + node/runtime/src/constants.rs | 8 +- node/runtime/src/impls.rs | 169 +++++--- node/runtime/src/lib.rs | 26 +- node/testing/Cargo.toml | 1 + node/testing/src/keyring.rs | 2 +- srml/assets/src/lib.rs | 1 - srml/aura/src/mock.rs | 1 - srml/authority-discovery/src/lib.rs | 1 - srml/authorship/src/lib.rs | 1 - srml/babe/src/mock.rs | 1 - srml/balances/Cargo.toml | 1 + srml/balances/src/lib.rs | 141 +------ srml/balances/src/mock.rs | 56 +-- srml/balances/src/tests.rs | 99 +---- srml/collective/src/lib.rs | 1 - srml/contracts/src/lib.rs | 2 +- srml/contracts/src/tests.rs | 7 - srml/council/src/lib.rs | 7 - srml/democracy/src/lib.rs | 7 - srml/elections-phragmen/src/lib.rs | 7 - srml/elections/src/mock.rs | 7 - srml/example/src/lib.rs | 7 - srml/executive/Cargo.toml | 1 + srml/executive/src/lib.rs | 20 +- srml/finality-tracker/src/lib.rs | 1 - srml/generic-asset/src/lib.rs | 1 - srml/generic-asset/src/mock.rs | 1 - srml/grandpa/src/mock.rs | 1 - srml/im-online/src/mock.rs | 1 - srml/indices/src/mock.rs | 1 - srml/membership/src/lib.rs | 1 - srml/offences/src/mock.rs | 1 - srml/randomness-collective-flip/src/lib.rs | 1 - srml/scored-pool/src/mock.rs | 7 - srml/session/src/mock.rs | 1 - srml/staking/src/mock.rs | 7 - srml/system/benches/bench.rs | 1 - srml/system/src/lib.rs | 28 +- srml/timestamp/src/lib.rs | 1 - srml/transaction-payment/Cargo.toml | 27 ++ srml/transaction-payment/src/lib.rs | 455 +++++++++++++++++++++ srml/treasury/src/lib.rs | 7 - srml/utility/src/lib.rs | 7 - subkey/Cargo.toml | 1 + subkey/src/main.rs | 2 +- 59 files changed, 785 insertions(+), 597 deletions(-) create mode 100644 srml/transaction-payment/Cargo.toml create mode 100644 srml/transaction-payment/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 1fd3c18534..c1aec02c00 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2357,6 +2357,7 @@ dependencies = [ "srml-support 2.0.0", "srml-system 2.0.0", "srml-timestamp 2.0.0", + "srml-transaction-payment 2.0.0", "structopt 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "substrate-authority-discovery 2.0.0", "substrate-basic-authorship 2.0.0", @@ -2403,6 +2404,7 @@ dependencies = [ "srml-support 2.0.0", "srml-system 2.0.0", "srml-timestamp 2.0.0", + "srml-transaction-payment 2.0.0", "srml-treasury 2.0.0", "substrate-executor 2.0.0", "substrate-primitives 2.0.0", @@ -2488,6 +2490,7 @@ dependencies = [ "srml-system 2.0.0", "srml-system-rpc-runtime-api 2.0.0", "srml-timestamp 2.0.0", + "srml-transaction-payment 2.0.0", "srml-treasury 2.0.0", "srml-utility 2.0.0", "substrate-authority-discovery-primitives 2.0.0", @@ -2552,6 +2555,7 @@ dependencies = [ "srml-support 2.0.0", "srml-system 2.0.0", "srml-timestamp 2.0.0", + "srml-transaction-payment 2.0.0", "substrate-client 2.0.0", "substrate-consensus-babe-primitives 2.0.0", "substrate-offchain-primitives 2.0.0", @@ -2579,6 +2583,7 @@ dependencies = [ "srml-support 2.0.0", "srml-system 2.0.0", "srml-timestamp 2.0.0", + "srml-transaction-payment 2.0.0", "srml-treasury 2.0.0", "substrate-client 2.0.0", "substrate-executor 2.0.0", @@ -3988,6 +3993,7 @@ dependencies = [ "sr-std 2.0.0", "srml-support 2.0.0", "srml-system 2.0.0", + "srml-transaction-payment 2.0.0", "substrate-keyring 2.0.0", "substrate-primitives 2.0.0", ] @@ -4138,6 +4144,7 @@ dependencies = [ "srml-indices 2.0.0", "srml-support 2.0.0", "srml-system 2.0.0", + "srml-transaction-payment 2.0.0", "substrate-primitives 2.0.0", ] @@ -4490,6 +4497,20 @@ dependencies = [ "substrate-primitives 2.0.0", ] +[[package]] +name = "srml-transaction-payment" +version = "2.0.0" +dependencies = [ + "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-io 2.0.0", + "sr-primitives 2.0.0", + "sr-std 2.0.0", + "srml-balances 2.0.0", + "srml-support 2.0.0", + "srml-system 2.0.0", + "substrate-primitives 2.0.0", +] + [[package]] name = "srml-treasury" version = "2.0.0" @@ -4608,6 +4629,7 @@ dependencies = [ "sr-primitives 2.0.0", "srml-balances 2.0.0", "srml-system 2.0.0", + "srml-transaction-payment 2.0.0", "substrate-bip39 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "substrate-primitives 2.0.0", "tiny-bip39 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index 6508e2b41e..5b012be0e9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -106,6 +106,7 @@ members = [ "srml/system/rpc", "srml/timestamp", "srml/treasury", + "srml/transaction-payment", "srml/utility", "node/cli", "node/executor", diff --git a/core/sr-primitives/src/sr_arithmetic.rs b/core/sr-primitives/src/sr_arithmetic.rs index 043a383a33..5f5b5dc1e5 100644 --- a/core/sr-primitives/src/sr_arithmetic.rs +++ b/core/sr-primitives/src/sr_arithmetic.rs @@ -543,7 +543,6 @@ implement_per_thing!( /// An unsigned fixed point number. Can hold any value in the range [-9_223_372_036, 9_223_372_036] /// with fixed point accuracy of one billion. -#[cfg_attr(feature = "std", derive(Debug))] #[derive(Encode, Decode, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] pub struct Fixed64(i64); @@ -668,6 +667,13 @@ impl CheckedAdd for Fixed64 { } } +#[cfg(feature = "std")] +impl rstd::fmt::Debug for Fixed64 { + fn fmt(&self, f: &mut rstd::fmt::Formatter<'_>) -> rstd::fmt::Result { + write!(f, "Fixed64({},{})", self.0 / DIV, (self.0 % DIV) / 1000) + } +} + /// Infinite precision unsigned integer for substrate runtime. pub mod biguint { use super::Zero; @@ -981,8 +987,6 @@ pub mod biguint { let mut q = Self::with_capacity(m + 1); let mut r = Self::with_capacity(n); - debug_assert!(other.msb() != 0); - // PROOF: 0 <= normalizer_bits < SHIFT 0 <= normalizer < B. all conversions are // safe. let normalizer_bits = other.msb().leading_zeros() as Single; @@ -2136,6 +2140,35 @@ mod tests_fixed64 { assert_eq!(max(), Fixed64::from_natural(9_223_372_037)); } + #[test] + fn fixed_64_growth_decrease_curve() { + let test_set = vec![0u32, 1, 10, 1000, 1_000_000_000]; + + // negative (1/2) + let mut fm = Fixed64::from_rational(-1, 2); + test_set.clone().into_iter().for_each(|i| { + assert_eq!(fm.saturated_multiply_accumulate(i) as i32, i as i32 - i as i32 / 2); + }); + + // unit (1) multiplier + fm = Fixed64::from_parts(0); + test_set.clone().into_iter().for_each(|i| { + assert_eq!(fm.saturated_multiply_accumulate(i), i); + }); + + // i.5 multiplier + fm = Fixed64::from_rational(1, 2); + test_set.clone().into_iter().for_each(|i| { + assert_eq!(fm.saturated_multiply_accumulate(i), i * 3 / 2); + }); + + // dual multiplier + fm = Fixed64::from_rational(1, 1); + test_set.clone().into_iter().for_each(|i| { + assert_eq!(fm.saturated_multiply_accumulate(i), i * 2); + }); + } + macro_rules! saturating_mul_acc_test { ($num_type:tt) => { assert_eq!( diff --git a/core/sr-primitives/src/weights.rs b/core/sr-primitives/src/weights.rs index 28f1b2fe0c..2ffd4ee391 100644 --- a/core/sr-primitives/src/weights.rs +++ b/core/sr-primitives/src/weights.rs @@ -23,9 +23,6 @@ //! Note that the decl_module macro _cannot_ enforce this and will simply fail if an invalid struct //! (something that does not implement `Weighable`) is passed in. -use crate::{Fixed64, traits::Saturating}; -use crate::codec::{Encode, Decode}; - pub use crate::transaction_validity::TransactionPriority; use crate::traits::Bounded; @@ -167,76 +164,3 @@ impl Default for SimpleDispatchInfo { SimpleDispatchInfo::FixedNormal(10_000) } } - -/// Representation of a weight multiplier. This represents how a fee value can be computed from a -/// weighted transaction. -/// -/// This is basically a wrapper for the `Fixed64` type a slightly tailored multiplication to u32 -/// in the form of the `apply_to` method. -#[cfg_attr(feature = "std", derive(Debug))] -#[derive(Encode, Decode, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] -pub struct WeightMultiplier(Fixed64); - -impl WeightMultiplier { - /// Apply the inner Fixed64 as a weight multiplier to a weight value. - /// - /// This will perform a saturated `weight + weight * self.0`. - pub fn apply_to(&self, weight: Weight) -> Weight { - self.0.saturated_multiply_accumulate(weight) - } - - /// build self from raw parts per billion. - #[cfg(feature = "std")] - pub fn from_parts(parts: i64) -> Self { - Self(Fixed64::from_parts(parts)) - } - - /// build self from a fixed64 value. - pub fn from_fixed(f: Fixed64) -> Self { - Self(f) - } - - /// Approximate the fraction `n/d`. - pub fn from_rational(n: i64, d: u64) -> Self { - Self(Fixed64::from_rational(n, d)) - } -} - -impl Saturating for WeightMultiplier { - fn saturating_add(self, rhs: Self) -> Self { - Self(self.0.saturating_add(rhs.0)) - } - fn saturating_mul(self, rhs: Self) -> Self { - Self(self.0.saturating_mul(rhs.0)) - - } - fn saturating_sub(self, rhs: Self) -> Self { - Self(self.0.saturating_sub(rhs.0)) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn multiplier_apply_to_works() { - let test_set = vec![0, 1, 10, 1000, 1_000_000_000]; - - // negative (1/2) - let mut fm = WeightMultiplier::from_rational(-1, 2); - test_set.clone().into_iter().for_each(|i| { assert_eq!(fm.apply_to(i) as i32, i as i32 - i as i32 / 2); }); - - // unit (1) multiplier - fm = WeightMultiplier::from_parts(0); - test_set.clone().into_iter().for_each(|i| { assert_eq!(fm.apply_to(i), i); }); - - // i.5 multiplier - fm = WeightMultiplier::from_rational(1, 2); - test_set.clone().into_iter().for_each(|i| { assert_eq!(fm.apply_to(i), i * 3 / 2); }); - - // dual multiplier - fm = WeightMultiplier::from_rational(1, 1); - test_set.clone().into_iter().for_each(|i| { assert_eq!(fm.apply_to(i), i * 2); }); - } -} diff --git a/core/test-runtime/src/lib.rs b/core/test-runtime/src/lib.rs index fddee22be2..3cb89de56f 100644 --- a/core/test-runtime/src/lib.rs +++ b/core/test-runtime/src/lib.rs @@ -382,7 +382,6 @@ impl srml_system::Trait for Runtime { type Lookup = IdentityLookup; type Header = Header; type Event = Event; - type WeightMultiplierUpdate = (); type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; type MaximumBlockLength = MaximumBlockLength; diff --git a/node-template/runtime/Cargo.toml b/node-template/runtime/Cargo.toml index 76821b6dfd..96484c16ae 100644 --- a/node-template/runtime/Cargo.toml +++ b/node-template/runtime/Cargo.toml @@ -24,6 +24,7 @@ randomness-collective-flip = { package = "srml-randomness-collective-flip", path system = { package = "srml-system", path = "../../srml/system", default_features = false } timestamp = { package = "srml-timestamp", path = "../../srml/timestamp", default_features = false } sudo = { package = "srml-sudo", path = "../../srml/sudo", default_features = false } +transaction-payment = { package = "srml-transaction-payment", path = "../../srml/transaction-payment", default_features = false } sr-primitives = { path = "../../core/sr-primitives", default_features = false } client = { package = "substrate-client", path = "../../core/client", default_features = false } offchain-primitives = { package = "substrate-offchain-primitives", path = "../../core/offchain/primitives", default-features = false } @@ -51,6 +52,7 @@ std = [ "system/std", "timestamp/std", "sudo/std", + "transaction-payment/std", "version/std", "serde", "safe-mix/std", diff --git a/node-template/runtime/src/lib.rs b/node-template/runtime/src/lib.rs index 0e9b8050f0..da49ad4474 100644 --- a/node-template/runtime/src/lib.rs +++ b/node-template/runtime/src/lib.rs @@ -166,18 +166,17 @@ impl system::Trait for Runtime { type Header = generic::Header; /// The ubiquitous event type. type Event = Event; - /// Update weight (to fee) multiplier per-block. - type WeightMultiplierUpdate = (); /// The ubiquitous origin type. type Origin = Origin; /// Maximum number of block number to block hash mappings to keep (oldest pruned first). type BlockHashCount = BlockHashCount; - /// Maximum weight of each block. With a default weight system of 1byte == 1weight, 4mb is ok. + /// Maximum weight of each block. type MaximumBlockWeight = MaximumBlockWeight; /// Maximum size of all encoded transactions (in bytes) that are allowed in one block. type MaximumBlockLength = MaximumBlockLength; /// Portion of the block weight that is available to all normal transactions. type AvailableBlockRatio = AvailableBlockRatio; + /// Version of the runtime. type Version = Version; } @@ -223,8 +222,6 @@ parameter_types! { pub const ExistentialDeposit: u128 = 500; pub const TransferFee: u128 = 0; pub const CreationFee: u128 = 0; - pub const TransactionBaseFee: u128 = 0; - pub const TransactionByteFee: u128 = 1; } impl balances::Trait for Runtime { @@ -236,15 +233,25 @@ impl balances::Trait for Runtime { type OnNewAccount = Indices; /// The ubiquitous event type. type Event = Event; - type TransactionPayment = (); type DustRemoval = (); type TransferPayment = (); type ExistentialDeposit = ExistentialDeposit; type TransferFee = TransferFee; type CreationFee = CreationFee; +} + +parameter_types! { + pub const TransactionBaseFee: Balance = 0; + pub const TransactionByteFee: Balance = 1; +} + +impl transaction_payment::Trait for Runtime { + type Currency = balances::Module; + type OnTransactionPayment = (); type TransactionBaseFee = TransactionBaseFee; type TransactionByteFee = TransactionByteFee; type WeightToFee = ConvertInto; + type FeeMultiplierUpdate = (); } impl sudo::Trait for Runtime { @@ -269,6 +276,7 @@ construct_runtime!( Grandpa: grandpa::{Module, Call, Storage, Config, Event}, Indices: indices::{default, Config}, Balances: balances::{default, Error}, + TransactionPayment: transaction_payment::{Module, Storage}, Sudo: sudo, // Used for the module template in `./template.rs` TemplateModule: template::{Module, Call, Storage, Event}, @@ -293,7 +301,7 @@ pub type SignedExtra = ( system::CheckEra, system::CheckNonce, system::CheckWeight, - balances::TakeFees + transaction_payment::ChargeTransactionPayment ); /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; diff --git a/node-template/runtime/src/template.rs b/node-template/runtime/src/template.rs index eb4398787d..8c6c35edc4 100644 --- a/node-template/runtime/src/template.rs +++ b/node-template/runtime/src/template.rs @@ -100,7 +100,6 @@ mod tests { type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type WeightMultiplierUpdate = (); type Event = (); type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; diff --git a/node/cli/Cargo.toml b/node/cli/Cargo.toml index 0ddd7b49ff..5fa92360d6 100644 --- a/node/cli/Cargo.toml +++ b/node/cli/Cargo.toml @@ -45,6 +45,7 @@ finality_tracker = { package = "srml-finality-tracker", path = "../../srml/final contracts = { package = "srml-contracts", path = "../../srml/contracts" } system = { package = "srml-system", path = "../../srml/system" } balances = { package = "srml-balances", path = "../../srml/balances" } +transaction-payment = { package = "srml-transaction-payment", path = "../../srml/transaction-payment" } support = { package = "srml-support", path = "../../srml/support", default-features = false } im_online = { package = "srml-im-online", path = "../../srml/im-online", default-features = false } sr-authority-discovery = { package = "srml-authority-discovery", path = "../../srml/authority-discovery", default-features = false } diff --git a/node/cli/src/factory_impl.rs b/node/cli/src/factory_impl.rs index 827b8e308c..84c24f2af0 100644 --- a/node/cli/src/factory_impl.rs +++ b/node/cli/src/factory_impl.rs @@ -56,7 +56,7 @@ impl FactoryState { system::CheckEra::from(Era::mortal(256, phase)), system::CheckNonce::from(index), system::CheckWeight::new(), - balances::TakeFees::from(0), + transaction_payment::ChargeTransactionPayment::from(0), Default::default(), ) } diff --git a/node/cli/src/service.rs b/node/cli/src/service.rs index 7012a3d6ce..485cd325b0 100644 --- a/node/cli/src/service.rs +++ b/node/cli/src/service.rs @@ -528,14 +528,14 @@ mod tests { let check_era = system::CheckEra::from(Era::Immortal); let check_nonce = system::CheckNonce::from(index); let check_weight = system::CheckWeight::new(); - let take_fees = balances::TakeFees::from(0); + let payment = transaction_payment::ChargeTransactionPayment::from(0); let extra = ( check_version, check_genesis, check_era, check_nonce, check_weight, - take_fees, + payment, Default::default(), ); let raw_payload = SignedPayload::from_raw( diff --git a/node/executor/Cargo.toml b/node/executor/Cargo.toml index 63f1c8c0f4..1908443ca9 100644 --- a/node/executor/Cargo.toml +++ b/node/executor/Cargo.toml @@ -22,6 +22,7 @@ test-client = { package = "substrate-test-client", path = "../../core/test-clien sr-primitives = { path = "../../core/sr-primitives" } runtime_support = { package = "srml-support", path = "../../srml/support" } balances = { package = "srml-balances", path = "../../srml/balances" } +transaction-payment = { package = "srml-transaction-payment", path = "../../srml/transaction-payment" } session = { package = "srml-session", path = "../../srml/session" } system = { package = "srml-system", path = "../../srml/system" } timestamp = { package = "srml-timestamp", path = "../../srml/timestamp" } diff --git a/node/executor/src/lib.rs b/node/executor/src/lib.rs index 2c2ad479f5..3558987716 100644 --- a/node/executor/src/lib.rs +++ b/node/executor/src/lib.rs @@ -46,16 +46,16 @@ mod tests { traits::{CodeExecutor, Externalities}, storage::well_known_keys, }; use sr_primitives::{ - assert_eq_error_rate, + Fixed64, traits::{Header as HeaderT, Hash as HashT, Convert}, ApplyResult, - transaction_validity::InvalidTransaction, weights::{WeightMultiplier, GetDispatchInfo}, + transaction_validity::InvalidTransaction, weights::GetDispatchInfo, }; use contracts::ContractAddressFor; use substrate_executor::{NativeExecutor, WasmExecutionMethod}; use system::{EventRecord, Phase}; use node_runtime::{ Header, Block, UncheckedExtrinsic, CheckedExtrinsic, Call, Runtime, Balances, BuildStorage, - System, Event, TransferFee, TransactionBaseFee, TransactionByteFee, + System, TransactionPayment, Event, TransferFee, TransactionBaseFee, TransactionByteFee, constants::currency::*, impls::WeightToFee, }; use node_primitives::{Balance, Hash, BlockNumber}; @@ -88,17 +88,15 @@ mod tests { } /// Default transfer fee - fn transfer_fee(extrinsic: &E) -> Balance { + fn transfer_fee(extrinsic: &E, fee_multiplier: Fixed64) -> Balance { let length_fee = TransactionBaseFee::get() + TransactionByteFee::get() * (extrinsic.encode().len() as Balance); let weight = default_transfer_call().get_dispatch_info().weight; - // NOTE: this is really hard to apply, since the multiplier of each block needs to be fetched - // before the block, while we compute this after the block. - // weight = >::next_weight_multiplier().apply_to(weight); - let weight_fee = ::WeightToFee::convert(weight); - length_fee + weight_fee + TransferFee::get() + let weight_fee = ::WeightToFee::convert(weight); + + fee_multiplier.saturated_multiply_accumulate(length_fee + weight_fee) + TransferFee::get() } fn default_transfer_call() -> balances::Call { @@ -217,6 +215,9 @@ mod tests { None, ).0; assert!(r.is_ok()); + + let fm = t.execute_with(TransactionPayment::next_fee_multiplier); + let r = executor().call::<_, NeverNativeValue, fn() -> _>( &mut t, "BlockBuilder_apply_extrinsic", @@ -227,7 +228,7 @@ mod tests { assert!(r.is_ok()); t.execute_with(|| { - assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - transfer_fee(&xt())); + assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - transfer_fee(&xt(), fm)); assert_eq!(Balances::total_balance(&bob()), 69 * DOLLARS); }); } @@ -253,6 +254,9 @@ mod tests { None, ).0; assert!(r.is_ok()); + + let fm = t.execute_with(TransactionPayment::next_fee_multiplier); + let r = executor().call::<_, NeverNativeValue, fn() -> _>( &mut t, "BlockBuilder_apply_extrinsic", @@ -263,7 +267,7 @@ mod tests { assert!(r.is_ok()); t.execute_with(|| { - assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - transfer_fee(&xt())); + assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - transfer_fee(&xt(), fm)); assert_eq!(Balances::total_balance(&bob()), 69 * DOLLARS); }); } @@ -425,6 +429,9 @@ mod tests { let (block1, block2) = blocks(); + let mut alice_last_known_balance: Balance = Default::default(); + let mut fm = t.execute_with(TransactionPayment::next_fee_multiplier); + executor().call::<_, NeverNativeValue, fn() -> _>( &mut t, "Core_execute_block", @@ -434,8 +441,9 @@ mod tests { ).0.unwrap(); t.execute_with(|| { - assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - transfer_fee(&xt())); + assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - transfer_fee(&xt(), fm)); assert_eq!(Balances::total_balance(&bob()), 169 * DOLLARS); + alice_last_known_balance = Balances::total_balance(&alice()); let events = vec![ EventRecord { phase: Phase::ApplyExtrinsic(0), @@ -460,6 +468,9 @@ mod tests { ]; assert_eq!(System::events(), events); }); + + fm = t.execute_with(TransactionPayment::next_fee_multiplier); + executor().call::<_, NeverNativeValue, fn() -> _>( &mut t, "Core_execute_block", @@ -471,15 +482,13 @@ mod tests { t.execute_with(|| { // NOTE: fees differ slightly in tests that execute more than one block due to the // weight update. Hence, using `assert_eq_error_rate`. - assert_eq_error_rate!( + assert_eq!( Balances::total_balance(&alice()), - 32 * DOLLARS - 2 * transfer_fee(&xt()), - 10_000 + alice_last_known_balance - 10 * DOLLARS - transfer_fee(&xt(), fm), ); - assert_eq_error_rate!( + assert_eq!( Balances::total_balance(&bob()), - 179 * DOLLARS - transfer_fee(&xt()), - 10_000 + 179 * DOLLARS - transfer_fee(&xt(), fm), ); let events = vec![ EventRecord { @@ -532,6 +541,9 @@ mod tests { let (block1, block2) = blocks(); + let mut alice_last_known_balance: Balance = Default::default(); + let mut fm = t.execute_with(TransactionPayment::next_fee_multiplier); + executor().call::<_, NeverNativeValue, fn() -> _>( &mut t, "Core_execute_block", @@ -541,10 +553,13 @@ mod tests { ).0.unwrap(); t.execute_with(|| { - assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - transfer_fee(&xt())); + assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - transfer_fee(&xt(), fm)); assert_eq!(Balances::total_balance(&bob()), 169 * DOLLARS); + alice_last_known_balance = Balances::total_balance(&alice()); }); + fm = t.execute_with(TransactionPayment::next_fee_multiplier); + executor().call::<_, NeverNativeValue, fn() -> _>( &mut t, "Core_execute_block", @@ -554,15 +569,13 @@ mod tests { ).0.unwrap(); t.execute_with(|| { - assert_eq_error_rate!( + assert_eq!( Balances::total_balance(&alice()), - 32 * DOLLARS - 2 * transfer_fee(&xt()), - 10_000 + alice_last_known_balance - 10 * DOLLARS - transfer_fee(&xt(), fm), ); - assert_eq_error_rate!( + assert_eq!( Balances::total_balance(&bob()), - 179 * DOLLARS - 1 * transfer_fee(&xt()), - 10_000 + 179 * DOLLARS - 1 * transfer_fee(&xt(), fm), ); }); } @@ -824,6 +837,7 @@ mod tests { None, ).0; assert!(r.is_ok()); + let fm = t.execute_with(TransactionPayment::next_fee_multiplier); let r = executor().call::<_, NeverNativeValue, fn() -> _>( &mut t, "BlockBuilder_apply_extrinsic", @@ -837,7 +851,7 @@ mod tests { .expect("Extrinsic did not fail"); t.execute_with(|| { - assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - 1 * transfer_fee(&xt())); + assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - 1 * transfer_fee(&xt(), fm)); assert_eq!(Balances::total_balance(&bob()), 69 * DOLLARS); }); } @@ -890,13 +904,14 @@ mod tests { #[test] - fn weight_multiplier_increases_and_decreases_on_big_weight() { + fn fee_multiplier_increases_and_decreases_on_big_weight() { let mut t = new_test_ext(COMPACT_CODE, false); - let mut prev_multiplier = WeightMultiplier::default(); + // initial fee multiplier must be zero + let mut prev_multiplier = Fixed64::from_parts(0); t.execute_with(|| { - assert_eq!(System::next_weight_multiplier(), prev_multiplier); + assert_eq!(TransactionPayment::next_fee_multiplier(), prev_multiplier); }); let mut tt = new_test_ext(COMPACT_CODE, false); @@ -948,7 +963,7 @@ mod tests { // weight multiplier is increased for next block. t.execute_with(|| { - let fm = System::next_weight_multiplier(); + let fm = TransactionPayment::next_fee_multiplier(); println!("After a big block: {:?} -> {:?}", prev_multiplier, fm); assert!(fm > prev_multiplier); prev_multiplier = fm; @@ -965,7 +980,7 @@ mod tests { // weight multiplier is increased for next block. t.execute_with(|| { - let fm = System::next_weight_multiplier(); + let fm = TransactionPayment::next_fee_multiplier(); println!("After a small block: {:?} -> {:?}", prev_multiplier, fm); assert!(fm < prev_multiplier); }); @@ -978,7 +993,7 @@ mod tests { // weight of transfer call as of now: 1_000_000 // if weight of the cheapest weight would be 10^7, this would be 10^9, which is: // - 1 MILLICENTS in substrate node. - // - 1 milldot based on current polkadot runtime. + // - 1 milli-dot based on current polkadot runtime. // (this baed on assigning 0.1 CENT to the cheapest tx with `weight = 100`) let mut t = TestExternalities::::new_with_code(COMPACT_CODE, (map![ >::hashed_key_for(alice()) => { @@ -1052,6 +1067,7 @@ mod tests { fn block_weight_capacity_report() { // Just report how many transfer calls you could fit into a block. The number should at least // be a few hundred (250 at the time of writing but can change over time). Runs until panic. + use node_primitives::Index; // execution ext. let mut t = new_test_ext(COMPACT_CODE, false); @@ -1118,6 +1134,7 @@ mod tests { // Just report how big a block can get. Executes until panic. Should be ignored unless if // manually inspected. The number should at least be a few megabytes (5 at the time of // writing but can change over time). + use node_primitives::Index; // execution ext. let mut t = new_test_ext(COMPACT_CODE, false); diff --git a/node/runtime/Cargo.toml b/node/runtime/Cargo.toml index f9818c096e..af66c0432f 100644 --- a/node/runtime/Cargo.toml +++ b/node/runtime/Cargo.toml @@ -52,6 +52,7 @@ system-rpc-runtime-api = { package = "srml-system-rpc-runtime-api", path = "../. timestamp = { package = "srml-timestamp", path = "../../srml/timestamp", default-features = false } treasury = { package = "srml-treasury", path = "../../srml/treasury", default-features = false } utility = { package = "srml-utility", path = "../../srml/utility", default-features = false } +transaction-payment = { package = "srml-transaction-payment", path = "../../srml/transaction-payment", default-features = false } [build-dependencies] wasm-builder-runner = { package = "substrate-wasm-builder-runner", version = "1.0.2", path = "../../core/utils/wasm-builder-runner" } @@ -100,5 +101,6 @@ std = [ "timestamp/std", "treasury/std", "utility/std", + "transaction-payment/std", "version/std", ] diff --git a/node/runtime/src/constants.rs b/node/runtime/src/constants.rs index 79d3dbd8eb..ca57bdc8ba 100644 --- a/node/runtime/src/constants.rs +++ b/node/runtime/src/constants.rs @@ -67,10 +67,10 @@ pub mod time { pub const DAYS: BlockNumber = HOURS * 24; } -// CRITICAL NOTE: The system module maintains two constants: a _maximum_ block weight and a -// _ratio_ of it yielding the portion which is accessible to normal transactions (reserving the rest -// for operational ones). `TARGET_BLOCK_FULLNESS` is entirely independent and the system module is -// not aware of if, nor should it care about it. This constant simply denotes on which ratio of the +// CRITICAL NOTE: The system module maintains two constants: a _maximum_ block weight and a _ratio_ +// of it yielding the portion which is accessible to normal transactions (reserving the rest for +// operational ones). `TARGET_BLOCK_FULLNESS` is entirely independent and the system module is not +// aware of if, nor should it care about it. This constant simply denotes on which ratio of the // _maximum_ block weight we tweak the fees. It does NOT care about the type of the dispatch. // // For the system to be configured in a sane way, `TARGET_BLOCK_FULLNESS` should always be less than diff --git a/node/runtime/src/impls.rs b/node/runtime/src/impls.rs index 2e1fcc8826..2193845020 100644 --- a/node/runtime/src/impls.rs +++ b/node/runtime/src/impls.rs @@ -17,7 +17,7 @@ //! Some configurable implementations as associated type for the substrate runtime. use node_primitives::Balance; -use sr_primitives::weights::{Weight, WeightMultiplier}; +use sr_primitives::weights::Weight; use sr_primitives::traits::{Convert, Saturating}; use sr_primitives::Fixed64; use support::traits::{OnUnbalanced, Currency}; @@ -82,10 +82,10 @@ impl Convert for WeightToFee { /// next_weight = weight * (1 + (v . diff) + (v . diff)^2 / 2) /// /// https://research.web3.foundation/en/latest/polkadot/Token%20Economics/#relay-chain-transaction-fees -pub struct WeightMultiplierUpdateHandler; +pub struct FeeMultiplierUpdateHandler; -impl Convert<(Weight, WeightMultiplier), WeightMultiplier> for WeightMultiplierUpdateHandler { - fn convert(previous_state: (Weight, WeightMultiplier)) -> WeightMultiplier { +impl Convert<(Weight, Fixed64), Fixed64> for FeeMultiplierUpdateHandler { + fn convert(previous_state: (Weight, Fixed64)) -> Fixed64 { let (block_weight, multiplier) = previous_state; let max_weight = MaximumBlockWeight::get(); let target_weight = (TARGET_BLOCK_FULLNESS * max_weight) as u128; @@ -113,17 +113,17 @@ impl Convert<(Weight, WeightMultiplier), WeightMultiplier> for WeightMultiplierU // Note: this is merely bounded by how big the multiplier and the inner value can go, // not by any economical reasoning. let excess = first_term.saturating_add(second_term); - multiplier.saturating_add(WeightMultiplier::from_fixed(excess)) + multiplier.saturating_add(excess) } else { - // first_term > second_term + // Proof: first_term > second_term. Safe subtraction. let negative = first_term - second_term; - multiplier.saturating_sub(WeightMultiplier::from_fixed(negative)) + multiplier.saturating_sub(negative) // despite the fact that apply_to saturates weight (final fee cannot go below 0) // it is crucially important to stop here and don't further reduce the weight fee // multiplier. While at -1, it means that the network is so un-congested that all // transactions have no weight fee. We stop here and only increase if the network // became more busy. - .max(WeightMultiplier::from_rational(-1, 1)) + .max(Fixed64::from_rational(-1, 1)) } } } @@ -132,7 +132,6 @@ impl Convert<(Weight, WeightMultiplier), WeightMultiplier> for WeightMultiplierU mod tests { use super::*; use sr_primitives::weights::Weight; - use sr_primitives::Perbill; use crate::{MaximumBlockWeight, AvailableBlockRatio, Runtime}; use crate::constants::currency::*; @@ -145,8 +144,7 @@ mod tests { } // poc reference implementation. - #[allow(dead_code)] - fn weight_multiplier_update(block_weight: Weight) -> Perbill { + fn fee_multiplier_update(block_weight: Weight, previous: Fixed64) -> Fixed64 { let block_weight = block_weight as f32; let v: f32 = 0.00004; @@ -157,53 +155,84 @@ mod tests { // Current saturation in terms of weight let s = block_weight; - let fm = 1.0 + (v * (s/m - ss/m)) + (v.powi(2) * (s/m - ss/m).powi(2)) / 2.0; - // return a per-bill-like value. - let fm = if fm >= 1.0 { fm - 1.0 } else { 1.0 - fm }; - Perbill::from_parts((fm * 1_000_000_000_f32) as u32) + let fm = (v * (s/m - ss/m)) + (v.powi(2) * (s/m - ss/m).powi(2)) / 2.0; + let addition_fm = Fixed64::from_parts((fm * 1_000_000_000_f32) as i64); + previous.saturating_add(addition_fm) } - fn wm(parts: i64) -> WeightMultiplier { - WeightMultiplier::from_parts(parts) + fn fm(parts: i64) -> Fixed64 { + Fixed64::from_parts(parts) + } + + #[test] + fn fee_multiplier_update_poc_works() { + let fm = Fixed64::from_rational(0, 1); + let test_set = vec![ + // TODO: this has a rounding error and fails. + // (0, fm.clone()), + (100, fm.clone()), + (target(), fm.clone()), + (max() / 2, fm.clone()), + (max(), fm.clone()), + ]; + test_set.into_iter().for_each(|(w, fm)| { + assert_eq!( + fee_multiplier_update(w, fm), + FeeMultiplierUpdateHandler::convert((w, fm)), + "failed for weight {} and prev fm {:?}", + w, + fm, + ); + }) } #[test] fn empty_chain_simulation() { // just a few txs per_block. let block_weight = 1000; - let mut wm = WeightMultiplier::default(); + let mut fm = Fixed64::default(); let mut iterations: u64 = 0; loop { - let next = WeightMultiplierUpdateHandler::convert((block_weight, wm)); - wm = next; - if wm == WeightMultiplier::from_rational(-1, 1) { break; } + let next = FeeMultiplierUpdateHandler::convert((block_weight, fm)); + fm = next; + if fm == Fixed64::from_rational(-1, 1) { break; } iterations += 1; } - println!("iteration {}, new wm = {:?}. Weight fee is now zero", iterations, wm); + println!("iteration {}, new fm = {:?}. Weight fee is now zero", iterations, fm); } #[test] #[ignore] fn congested_chain_simulation() { // `cargo test congested_chain_simulation -- --nocapture` to get some insight. + // almost full. The entire quota of normal transactions is taken. let block_weight = AvailableBlockRatio::get() * max(); - let tx_weight = 1000; - let mut wm = WeightMultiplier::default(); + + // default minimum substrate weight + let tx_weight = 10_000u32; + + // initial value of system + let mut fm = Fixed64::default(); + assert_eq!(fm, Fixed64::from_parts(0)); + let mut iterations: u64 = 0; loop { - let next = WeightMultiplierUpdateHandler::convert((block_weight, wm)); - if wm == next { break; } - wm = next; + let next = FeeMultiplierUpdateHandler::convert((block_weight, fm)); + if fm == next { break; } + fm = next; iterations += 1; - let fee = ::WeightToFee::convert(wm.apply_to(tx_weight)); + let fee = ::WeightToFee::convert(tx_weight); + let adjusted_fee = fm.saturated_multiply_accumulate(fee); println!( - "iteration {}, new wm = {:?}. Fee at this point is: {} millicents, {} cents, {} dollars", + "iteration {}, new fm = {:?}. Fee at this point is: \ + {} units, {} millicents, {} cents, {} dollars", iterations, - wm, - fee / MILLICENTS, - fee / CENTS, - fee / DOLLARS + fm, + adjusted_fee, + adjusted_fee / MILLICENTS, + adjusted_fee / CENTS, + adjusted_fee / DOLLARS ); } } @@ -212,65 +241,65 @@ mod tests { fn stateless_weight_mul() { // Light block. Fee is reduced a little. assert_eq!( - WeightMultiplierUpdateHandler::convert((target() / 4, WeightMultiplier::default())), - wm(-7500) + FeeMultiplierUpdateHandler::convert((target() / 4, Fixed64::default())), + fm(-7500) ); // a bit more. Fee is decreased less, meaning that the fee increases as the block grows. assert_eq!( - WeightMultiplierUpdateHandler::convert((target() / 2, WeightMultiplier::default())), - wm(-5000) + FeeMultiplierUpdateHandler::convert((target() / 2, Fixed64::default())), + fm(-5000) ); // ideal. Original fee. No changes. assert_eq!( - WeightMultiplierUpdateHandler::convert((target(), WeightMultiplier::default())), - wm(0) + FeeMultiplierUpdateHandler::convert((target(), Fixed64::default())), + fm(0) ); // // More than ideal. Fee is increased. assert_eq!( - WeightMultiplierUpdateHandler::convert(((target() * 2), WeightMultiplier::default())), - wm(10000) + FeeMultiplierUpdateHandler::convert(((target() * 2), Fixed64::default())), + fm(10000) ); } #[test] fn stateful_weight_mul_grow_to_infinity() { assert_eq!( - WeightMultiplierUpdateHandler::convert((target() * 2, WeightMultiplier::default())), - wm(10000) + FeeMultiplierUpdateHandler::convert((target() * 2, Fixed64::default())), + fm(10000) ); assert_eq!( - WeightMultiplierUpdateHandler::convert((target() * 2, wm(10000))), - wm(20000) + FeeMultiplierUpdateHandler::convert((target() * 2, fm(10000))), + fm(20000) ); assert_eq!( - WeightMultiplierUpdateHandler::convert((target() * 2, wm(20000))), - wm(30000) + FeeMultiplierUpdateHandler::convert((target() * 2, fm(20000))), + fm(30000) ); // ... assert_eq!( - WeightMultiplierUpdateHandler::convert((target() * 2, wm(1_000_000_000))), - wm(1_000_000_000 + 10000) + FeeMultiplierUpdateHandler::convert((target() * 2, fm(1_000_000_000))), + fm(1_000_000_000 + 10000) ); } #[test] fn stateful_weight_mil_collapse_to_minus_one() { assert_eq!( - WeightMultiplierUpdateHandler::convert((0, WeightMultiplier::default())), - wm(-10000) + FeeMultiplierUpdateHandler::convert((0, Fixed64::default())), + fm(-10000) ); assert_eq!( - WeightMultiplierUpdateHandler::convert((0, wm(-10000))), - wm(-20000) + FeeMultiplierUpdateHandler::convert((0, fm(-10000))), + fm(-20000) ); assert_eq!( - WeightMultiplierUpdateHandler::convert((0, wm(-20000))), - wm(-30000) + FeeMultiplierUpdateHandler::convert((0, fm(-20000))), + fm(-30000) ); // ... assert_eq!( - WeightMultiplierUpdateHandler::convert((0, wm(1_000_000_000 * -1))), - wm(-1_000_000_000) + FeeMultiplierUpdateHandler::convert((0, fm(1_000_000_000 * -1))), + fm(-1_000_000_000) ); } @@ -278,20 +307,30 @@ mod tests { fn weight_to_fee_should_not_overflow_on_large_weights() { let kb = 1024 as Weight; let mb = kb * kb; - let max_fm = WeightMultiplier::from_fixed(Fixed64::from_natural(i64::max_value())); - - vec![0, 1, 10, 1000, kb, 10 * kb, 100 * kb, mb, 10 * mb, Weight::max_value() / 2, Weight::max_value()] - .into_iter() - .for_each(|i| { - WeightMultiplierUpdateHandler::convert((i, WeightMultiplier::default())); - }); + let max_fm = Fixed64::from_natural(i64::max_value()); + + vec![ + 0, + 1, + 10, + 1000, + kb, + 10 * kb, + 100 * kb, + mb, + 10 * mb, + Weight::max_value() / 2, + Weight::max_value() + ].into_iter().for_each(|i| { + FeeMultiplierUpdateHandler::convert((i, Fixed64::default())); + }); // Some values that are all above the target and will cause an increase. let t = target(); vec![t + 100, t * 2, t * 4] .into_iter() .for_each(|i| { - let fm = WeightMultiplierUpdateHandler::convert(( + let fm = FeeMultiplierUpdateHandler::convert(( i, max_fm )); diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index 63fc856013..fdf0bfdc14 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -65,7 +65,7 @@ pub use staking::StakerStatus; /// Implementations of some helper traits passed into runtime modules as associated types. pub mod impls; -use impls::{CurrencyToVoteHandler, WeightMultiplierUpdateHandler, Author, WeightToFee}; +use impls::{CurrencyToVoteHandler, FeeMultiplierUpdateHandler, Author, WeightToFee}; /// Constant values used within the runtime. pub mod constants; @@ -84,8 +84,8 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // and set impl_version to equal spec_version. If only runtime // implementation changes and behavior does not, then leave spec_version as // is and increment impl_version. - spec_version: 177, - impl_version: 177, + spec_version: 178, + impl_version: 178, apis: RUNTIME_API_VERSIONS, }; @@ -125,7 +125,6 @@ impl system::Trait for Runtime { type AccountId = AccountId; type Lookup = Indices; type Header = generic::Header; - type WeightMultiplierUpdate = WeightMultiplierUpdateHandler; type Event = Event; type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; @@ -161,8 +160,6 @@ parameter_types! { pub const ExistentialDeposit: Balance = 1 * DOLLARS; pub const TransferFee: Balance = 1 * CENTS; pub const CreationFee: Balance = 1 * CENTS; - pub const TransactionBaseFee: Balance = 1 * CENTS; - pub const TransactionByteFee: Balance = 10 * MILLICENTS; } impl balances::Trait for Runtime { @@ -170,15 +167,25 @@ impl balances::Trait for Runtime { type OnFreeBalanceZero = ((Staking, Contracts), Session); type OnNewAccount = Indices; type Event = Event; - type TransactionPayment = DealWithFees; type DustRemoval = (); type TransferPayment = (); type ExistentialDeposit = ExistentialDeposit; type TransferFee = TransferFee; type CreationFee = CreationFee; +} + +parameter_types! { + pub const TransactionBaseFee: Balance = 1 * CENTS; + pub const TransactionByteFee: Balance = 10 * MILLICENTS; +} + +impl transaction_payment::Trait for Runtime { + type Currency = Balances; + type OnTransactionPayment = DealWithFees; type TransactionBaseFee = TransactionBaseFee; type TransactionByteFee = TransactionByteFee; type WeightToFee = WeightToFee; + type FeeMultiplierUpdate = FeeMultiplierUpdateHandler; } parameter_types! { @@ -480,7 +487,7 @@ impl system::offchain::CreateTransaction for Runtim system::CheckEra::::from(generic::Era::mortal(period, current_block)), system::CheckNonce::::from(index), system::CheckWeight::::new(), - balances::TakeFees::::from(tip), + transaction_payment::ChargeTransactionPayment::::from(tip), Default::default(), ); let raw_payload = SignedPayload::new(call, extra).ok()?; @@ -504,6 +511,7 @@ construct_runtime!( Authorship: authorship::{Module, Call, Storage, Inherent}, Indices: indices, Balances: balances::{default, Error}, + TransactionPayment: transaction_payment::{Module, Storage}, Staking: staking::{default, OfflineWorker}, Session: session::{Module, Call, Storage, Event, Config}, Democracy: democracy::{Module, Call, Storage, Config, Event}, @@ -540,7 +548,7 @@ pub type SignedExtra = ( system::CheckEra, system::CheckNonce, system::CheckWeight, - balances::TakeFees, + transaction_payment::ChargeTransactionPayment, contracts::CheckBlockGasLimit, ); /// Unchecked extrinsic type as expected by this runtime. diff --git a/node/testing/Cargo.toml b/node/testing/Cargo.toml index e622e35d4a..8a4c08ed11 100644 --- a/node/testing/Cargo.toml +++ b/node/testing/Cargo.toml @@ -27,4 +27,5 @@ system = { package = "srml-system", path = "../../srml/system" } test-client = { package = "substrate-test-client", path = "../../core/test-client" } timestamp = { package = "srml-timestamp", path = "../../srml/timestamp" } treasury = { package = "srml-treasury", path = "../../srml/treasury" } +transaction-payment = { package = "srml-transaction-payment", path = "../../srml/transaction-payment" } wabt = "0.9.2" diff --git a/node/testing/src/keyring.rs b/node/testing/src/keyring.rs index 0c6eb478cc..853ca0ef6d 100644 --- a/node/testing/src/keyring.rs +++ b/node/testing/src/keyring.rs @@ -72,7 +72,7 @@ pub fn signed_extra(nonce: Index, extra_fee: Balance) -> SignedExtra { system::CheckEra::from(Era::mortal(256, 0)), system::CheckNonce::from(nonce), system::CheckWeight::new(), - balances::TakeFees::from(extra_fee), + transaction_payment::ChargeTransactionPayment::from(extra_fee), Default::default(), ) } diff --git a/srml/assets/src/lib.rs b/srml/assets/src/lib.rs index de95caf88f..37845c3a14 100644 --- a/srml/assets/src/lib.rs +++ b/srml/assets/src/lib.rs @@ -271,7 +271,6 @@ mod tests { type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type WeightMultiplierUpdate = (); type Event = (); type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; diff --git a/srml/aura/src/mock.rs b/srml/aura/src/mock.rs index 7ebfd2a533..5c55e8bdd5 100644 --- a/srml/aura/src/mock.rs +++ b/srml/aura/src/mock.rs @@ -54,7 +54,6 @@ impl system::Trait for Test { type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type WeightMultiplierUpdate = (); type Event = (); type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; diff --git a/srml/authority-discovery/src/lib.rs b/srml/authority-discovery/src/lib.rs index 177e11c4c0..2c923103a8 100644 --- a/srml/authority-discovery/src/lib.rs +++ b/srml/authority-discovery/src/lib.rs @@ -204,7 +204,6 @@ mod tests { type AccountId = AuthorityId; type Lookup = IdentityLookup; type Header = Header; - type WeightMultiplierUpdate = (); type Event = (); type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; diff --git a/srml/authorship/src/lib.rs b/srml/authorship/src/lib.rs index dcd1985664..b42104a26b 100644 --- a/srml/authorship/src/lib.rs +++ b/srml/authorship/src/lib.rs @@ -442,7 +442,6 @@ mod tests { type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type WeightMultiplierUpdate = (); type Event = (); type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; diff --git a/srml/babe/src/mock.rs b/srml/babe/src/mock.rs index 582299f11c..5a6b80a2a6 100644 --- a/srml/babe/src/mock.rs +++ b/srml/babe/src/mock.rs @@ -62,7 +62,6 @@ impl system::Trait for Test { type AccountId = DummyValidatorId; type Lookup = IdentityLookup; type Header = Header; - type WeightMultiplierUpdate = (); type Event = (); type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; diff --git a/srml/balances/Cargo.toml b/srml/balances/Cargo.toml index d2b6e00d98..f7f6041c6b 100644 --- a/srml/balances/Cargo.toml +++ b/srml/balances/Cargo.toml @@ -17,6 +17,7 @@ system = { package = "srml-system", path = "../system", default-features = false [dev-dependencies] runtime-io = { package = "sr-io", path = "../../core/sr-io" } primitives = { package = "substrate-primitives", path = "../../core/primitives" } +transaction-payment = { package = "srml-transaction-payment", path = "../transaction-payment" } [features] default = ["std"] diff --git a/srml/balances/src/lib.rs b/srml/balances/src/lib.rs index b75c7a96de..4f8edc5428 100644 --- a/srml/balances/src/lib.rs +++ b/srml/balances/src/lib.rs @@ -86,17 +86,6 @@ //! //! - `vesting_balance` - Get the amount that is currently being vested and cannot be transferred out of this account. //! -//! ### Signed Extensions -//! -//! The balances module defines the following extensions: -//! -//! - [`TakeFees`]: Consumes fees proportional to the length and weight of the transaction. -//! Additionally, it can contain a single encoded payload as a `tip`. The inclusion priority -//! is increased proportional to the tip. -//! -//! Lookup the runtime aggregator file (e.g. `node/runtime`) to see the full list of signed -//! extensions included in a chain. -//! //! ## Usage //! //! The following examples show how to use the Balances module in your custom module. @@ -171,15 +160,11 @@ use support::{ dispatch::Result, }; use sr_primitives::{ - transaction_validity::{ - TransactionPriority, ValidTransaction, InvalidTransaction, TransactionValidityError, - TransactionValidity, - }, traits::{ Zero, SimpleArithmetic, StaticLookup, Member, CheckedAdd, CheckedSub, MaybeSerializeDebug, - Saturating, Bounded, SignedExtension, SaturatedConversion, Convert, + Saturating, Bounded, }, - weights::{DispatchInfo, SimpleDispatchInfo, Weight}, + weights::SimpleDispatchInfo, }; use system::{IsDeadAccount, OnNewAccount, ensure_signed, ensure_root}; @@ -210,15 +195,6 @@ pub trait Subtrait: system::Trait { /// The fee required to create an account. type CreationFee: Get; - - /// The fee to be paid for making a transaction; the base. - type TransactionBaseFee: Get; - - /// The fee to be paid for making a transaction; the per-byte portion. - type TransactionByteFee: Get; - - /// Convert a weight value into a deductible fee based on the currency type. - type WeightToFee: Convert; } pub trait Trait: system::Trait { @@ -235,9 +211,6 @@ pub trait Trait: system::Trait { /// Handler for when a new account is created. type OnNewAccount: OnNewAccount; - /// Handler for the unbalanced reduction when taking transaction fees. - type TransactionPayment: OnUnbalanced>; - /// Handler for the unbalanced reduction when taking fees associated with balance /// transfer (which may also include account creation). type TransferPayment: OnUnbalanced>; @@ -256,15 +229,6 @@ pub trait Trait: system::Trait { /// The fee required to create an account. type CreationFee: Get; - - /// The fee to be paid for making a transaction; the base. - type TransactionBaseFee: Get; - - /// The fee to be paid for making a transaction; the per-byte portion. - type TransactionByteFee: Get; - - /// Convert a weight value into a deductible fee based on the currency type. - type WeightToFee: Convert; } impl, I: Instance> Subtrait for T { @@ -274,9 +238,6 @@ impl, I: Instance> Subtrait for T { type ExistentialDeposit = T::ExistentialDeposit; type TransferFee = T::TransferFee; type CreationFee = T::CreationFee; - type TransactionBaseFee = T::TransactionBaseFee; - type TransactionByteFee = T::TransactionByteFee; - type WeightToFee = T::WeightToFee; } decl_event!( @@ -414,12 +375,6 @@ decl_module! { /// The fee required to create an account. const CreationFee: T::Balance = T::CreationFee::get(); - /// The fee to be paid for making a transaction; the base. - const TransactionBaseFee: T::Balance = T::TransactionBaseFee::get(); - - /// The fee to be paid for making a transaction; the per-byte portion. - const TransactionByteFee: T::Balance = T::TransactionByteFee::get(); - fn deposit_event() = default; /// Transfer some liquid free balance to another account. @@ -776,7 +731,7 @@ mod imbalances { // This works as long as `increase_total_issuance_by` doesn't use the Imbalance // types (basically for charging fees). // This should eventually be refactored so that the three type items that do -// depend on the Imbalance type (TransactionPayment, TransferPayment, DustRemoval) +// depend on the Imbalance type (TransferPayment, DustRemoval) // are placed in their own SRML module. struct ElevatedTrait, I: Instance>(T, I); impl, I: Instance> Clone for ElevatedTrait { @@ -796,7 +751,6 @@ impl, I: Instance> system::Trait for ElevatedTrait { type AccountId = T::AccountId; type Lookup = T::Lookup; type Header = T::Header; - type WeightMultiplierUpdate = T::WeightMultiplierUpdate; type Event = (); type BlockHashCount = T::BlockHashCount; type MaximumBlockWeight = T::MaximumBlockWeight; @@ -809,15 +763,11 @@ impl, I: Instance> Trait for ElevatedTrait { type OnFreeBalanceZero = T::OnFreeBalanceZero; type OnNewAccount = T::OnNewAccount; type Event = (); - type TransactionPayment = (); type TransferPayment = (); type DustRemoval = (); type ExistentialDeposit = T::ExistentialDeposit; type TransferFee = T::TransferFee; type CreationFee = T::CreationFee; - type TransactionBaseFee = T::TransactionBaseFee; - type TransactionByteFee = T::TransactionByteFee; - type WeightToFee = T::WeightToFee; } impl, I: Instance> Currency for Module @@ -1194,91 +1144,6 @@ where } } -/// Require the transactor pay for themselves and maybe include a tip to gain additional priority -/// in the queue. -#[derive(Encode, Decode, Clone, Eq, PartialEq)] -pub struct TakeFees, I: Instance = DefaultInstance>(#[codec(compact)] T::Balance); - -impl, I: Instance> TakeFees { - /// utility constructor. Used only in client/factory code. - pub fn from(fee: T::Balance) -> Self { - Self(fee) - } - - /// Compute the final fee value for a particular transaction. - /// - /// The final fee is composed of: - /// - _length-fee_: This is the amount paid merely to pay for size of the transaction. - /// - _weight-fee_: This amount is computed based on the weight of the transaction. Unlike - /// size-fee, this is not input dependent and reflects the _complexity_ of the execution - /// and the time it consumes. - /// - (optional) _tip_: if included in the transaction, it will be added on top. Only signed - /// transactions can have a tip. - fn compute_fee(len: usize, info: DispatchInfo, tip: T::Balance) -> T::Balance { - let len_fee = if info.pay_length_fee() { - let len = T::Balance::from(len as u32); - let base = T::TransactionBaseFee::get(); - let per_byte = T::TransactionByteFee::get(); - base.saturating_add(per_byte.saturating_mul(len)) - } else { - Zero::zero() - }; - - let weight_fee = { - // cap the weight to the maximum defined in runtime, otherwise it will be the `Bounded` - // maximum of its data type, which is not desired. - let capped_weight = info.weight.min(::MaximumBlockWeight::get()); - let weight_update = >::next_weight_multiplier(); - let adjusted_weight = weight_update.apply_to(capped_weight); - T::WeightToFee::convert(adjusted_weight) - }; - - len_fee.saturating_add(weight_fee).saturating_add(tip) - } -} - -#[cfg(feature = "std")] -impl, I: Instance> rstd::fmt::Debug for TakeFees { - fn fmt(&self, f: &mut rstd::fmt::Formatter) -> rstd::fmt::Result { - self.0.fmt(f) - } -} - -impl, I: Instance + Clone + Eq> SignedExtension for TakeFees { - type AccountId = T::AccountId; - type Call = T::Call; - type AdditionalSigned = (); - type Pre = (); - fn additional_signed(&self) -> rstd::result::Result<(), TransactionValidityError> { Ok(()) } - - fn validate( - &self, - who: &Self::AccountId, - _call: &Self::Call, - info: DispatchInfo, - len: usize, - ) -> TransactionValidity { - // pay any fees. - let fee = Self::compute_fee(len, info, self.0); - let imbalance = match >::withdraw( - who, - fee, - WithdrawReason::TransactionPayment, - ExistenceRequirement::KeepAlive, - ) { - Ok(imbalance) => imbalance, - Err(_) => return InvalidTransaction::Payment.into(), - }; - T::TransactionPayment::on_unbalanced(imbalance); - - let mut r = ValidTransaction::default(); - // NOTE: we probably want to maximize the _fee (of any type) per weight unit_ here, which - // will be a bit more than setting the priority to tip. For now, this is enough. - r.priority = fee.saturated_into::(); - Ok(r) - } -} - impl, I: Instance> IsDeadAccount for Module where T::Balance: MaybeSerializeDebug diff --git a/srml/balances/src/mock.rs b/srml/balances/src/mock.rs index a909795178..600d0e6fb7 100644 --- a/srml/balances/src/mock.rs +++ b/srml/balances/src/mock.rs @@ -18,7 +18,7 @@ #![cfg(test)] -use sr_primitives::{Perbill, traits::{Convert, IdentityLookup}, testing::Header, +use sr_primitives::{Perbill, traits::{ConvertInto, IdentityLookup}, testing::Header, weights::{DispatchInfo, Weight}}; use primitives::H256; use runtime_io; @@ -35,10 +35,6 @@ thread_local! { static EXISTENTIAL_DEPOSIT: RefCell = RefCell::new(0); static TRANSFER_FEE: RefCell = RefCell::new(0); static CREATION_FEE: RefCell = RefCell::new(0); - static TRANSACTION_BASE_FEE: RefCell = RefCell::new(0); - static TRANSACTION_BYTE_FEE: RefCell = RefCell::new(1); - static TRANSACTION_WEIGHT_FEE: RefCell = RefCell::new(1); - static WEIGHT_TO_FEE: RefCell = RefCell::new(1); } pub struct ExistentialDeposit; @@ -56,23 +52,6 @@ impl Get for CreationFee { fn get() -> u64 { CREATION_FEE.with(|v| *v.borrow()) } } -pub struct TransactionBaseFee; -impl Get for TransactionBaseFee { - fn get() -> u64 { TRANSACTION_BASE_FEE.with(|v| *v.borrow()) } -} - -pub struct TransactionByteFee; -impl Get for TransactionByteFee { - fn get() -> u64 { TRANSACTION_BYTE_FEE.with(|v| *v.borrow()) } -} - -pub struct WeightToFee(u64); -impl Convert for WeightToFee { - fn convert(t: Weight) -> u64 { - WEIGHT_TO_FEE.with(|v| *v.borrow() * (t as u64)) - } -} - // Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted. #[derive(Clone, PartialEq, Eq, Debug)] pub struct Runtime; @@ -92,7 +71,6 @@ impl system::Trait for Runtime { type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type WeightMultiplierUpdate = (); type Event = (); type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; @@ -100,26 +78,31 @@ impl system::Trait for Runtime { type AvailableBlockRatio = AvailableBlockRatio; type Version = (); } +parameter_types! { + pub const TransactionBaseFee: u64 = 0; + pub const TransactionByteFee: u64 = 1; +} +impl transaction_payment::Trait for Runtime { + type Currency = Module; + type OnTransactionPayment = (); + type TransactionBaseFee = TransactionBaseFee; + type TransactionByteFee = TransactionByteFee; + type WeightToFee = ConvertInto; + type FeeMultiplierUpdate = (); +} impl Trait for Runtime { type Balance = u64; type OnFreeBalanceZero = (); type OnNewAccount = (); type Event = (); - type TransactionPayment = (); type DustRemoval = (); type TransferPayment = (); type ExistentialDeposit = ExistentialDeposit; type TransferFee = TransferFee; type CreationFee = CreationFee; - type TransactionBaseFee = TransactionBaseFee; - type TransactionByteFee = TransactionByteFee; - type WeightToFee = WeightToFee; } pub struct ExtBuilder { - transaction_base_fee: u64, - transaction_byte_fee: u64, - weight_to_fee: u64, existential_deposit: u64, transfer_fee: u64, creation_fee: u64, @@ -129,9 +112,6 @@ pub struct ExtBuilder { impl Default for ExtBuilder { fn default() -> Self { Self { - transaction_base_fee: 0, - transaction_byte_fee: 0, - weight_to_fee: 0, existential_deposit: 0, transfer_fee: 0, creation_fee: 0, @@ -141,12 +121,6 @@ impl Default for ExtBuilder { } } impl ExtBuilder { - pub fn transaction_fees(mut self, base_fee: u64, byte_fee: u64, weight_fee: u64) -> Self { - self.transaction_base_fee = base_fee; - self.transaction_byte_fee = byte_fee; - self.weight_to_fee = weight_fee; - self - } pub fn existential_deposit(mut self, existential_deposit: u64) -> Self { self.existential_deposit = existential_deposit; self @@ -175,9 +149,6 @@ impl ExtBuilder { EXISTENTIAL_DEPOSIT.with(|v| *v.borrow_mut() = self.existential_deposit); TRANSFER_FEE.with(|v| *v.borrow_mut() = self.transfer_fee); CREATION_FEE.with(|v| *v.borrow_mut() = self.creation_fee); - TRANSACTION_BASE_FEE.with(|v| *v.borrow_mut() = self.transaction_base_fee); - TRANSACTION_BYTE_FEE.with(|v| *v.borrow_mut() = self.transaction_byte_fee); - WEIGHT_TO_FEE.with(|v| *v.borrow_mut() = self.weight_to_fee); } pub fn build(self) -> runtime_io::TestExternalities { self.set_associated_consts(); @@ -211,7 +182,6 @@ impl ExtBuilder { pub type System = system::Module; pub type Balances = Module; - pub const CALL: &::Call = &(); /// create a transaction info struct from weight. Handy to avoid building the whole struct. diff --git a/srml/balances/src/tests.rs b/srml/balances/src/tests.rs index 0b119d3ae6..839ac67991 100644 --- a/srml/balances/src/tests.rs +++ b/srml/balances/src/tests.rs @@ -20,12 +20,13 @@ use super::*; use mock::{Balances, ExtBuilder, Runtime, System, info_from_weight, CALL}; +use sr_primitives::traits::SignedExtension; use support::{ assert_noop, assert_ok, assert_err, traits::{LockableCurrency, LockIdentifier, WithdrawReason, WithdrawReasons, Currency, ReservableCurrency} }; -use sr_primitives::weights::DispatchClass; +use transaction_payment::ChargeTransactionPayment; use system::RawOrigin; const ID_1: LockIdentifier = *b"1 "; @@ -115,7 +116,6 @@ fn lock_reasons_should_work() { ExtBuilder::default() .existential_deposit(1) .monied(true) - .transaction_fees(0, 1, 0) .build() .execute_with(|| { Balances::set_lock(ID_1, &1, 10, u64::max_value(), WithdrawReason::Transfer.into()); @@ -125,8 +125,8 @@ fn lock_reasons_should_work() { ); assert_ok!(>::reserve(&1, 1)); // NOTE: this causes a fee payment. - assert!( as SignedExtension>::pre_dispatch( - TakeFees::from(1), + assert!( as SignedExtension>::pre_dispatch( + ChargeTransactionPayment::from(1), &1, CALL, info_from_weight(1), @@ -139,8 +139,8 @@ fn lock_reasons_should_work() { >::reserve(&1, 1), "account liquidity restrictions prevent withdrawal" ); - assert!( as SignedExtension>::pre_dispatch( - TakeFees::from(1), + assert!( as SignedExtension>::pre_dispatch( + ChargeTransactionPayment::from(1), &1, CALL, info_from_weight(1), @@ -150,8 +150,8 @@ fn lock_reasons_should_work() { Balances::set_lock(ID_1, &1, 10, u64::max_value(), WithdrawReason::TransactionPayment.into()); assert_ok!(>::transfer(&1, &2, 1)); assert_ok!(>::reserve(&1, 1)); - assert!( as SignedExtension>::pre_dispatch( - TakeFees::from(1), + assert!( as SignedExtension>::pre_dispatch( + ChargeTransactionPayment::from(1), &1, CALL, info_from_weight(1), @@ -736,89 +736,6 @@ fn liquid_funds_should_transfer_with_delayed_vesting() { }); } -#[test] -fn signed_extension_take_fees_work() { - ExtBuilder::default() - .existential_deposit(10) - .transaction_fees(10, 1, 5) - .monied(true) - .build() - .execute_with(|| { - let len = 10; - assert!( - TakeFees::::from(0) - .pre_dispatch(&1, CALL, info_from_weight(5), len) - .is_ok() - ); - assert_eq!(Balances::free_balance(&1), 100 - 20 - 25); - assert!( - TakeFees::::from(5 /* tipped */) - .pre_dispatch(&1, CALL, info_from_weight(3), len) - .is_ok() - ); - assert_eq!(Balances::free_balance(&1), 100 - 20 - 25 - 20 - 5 - 15); - }); -} - -#[test] -fn signed_extension_take_fees_is_bounded() { - ExtBuilder::default() - .existential_deposit(1000) - .transaction_fees(0, 0, 1) - .monied(true) - .build() - .execute_with(|| { - use sr_primitives::weights::Weight; - - // maximum weight possible - assert!( - TakeFees::::from(0) - .pre_dispatch(&1, CALL, info_from_weight(Weight::max_value()), 10) - .is_ok() - ); - // fee will be proportional to what is the actual maximum weight in the runtime. - assert_eq!( - Balances::free_balance(&1), - (10000 - ::MaximumBlockWeight::get()) as u64 - ); - }); -} - -#[test] -fn signed_extension_allows_free_transactions() { - ExtBuilder::default() - .transaction_fees(100, 1, 1) - .monied(false) - .build() - .execute_with(|| { - // 1 ain't have a penny. - assert_eq!(Balances::free_balance(&1), 0); - - // like a FreeOperational - let operational_transaction = DispatchInfo { - weight: 0, - class: DispatchClass::Operational - }; - let len = 100; - assert!( - TakeFees::::from(0) - .validate(&1, CALL, operational_transaction , len) - .is_ok() - ); - - // like a FreeNormal - let free_transaction = DispatchInfo { - weight: 0, - class: DispatchClass::Normal - }; - assert!( - TakeFees::::from(0) - .validate(&1, CALL, free_transaction , len) - .is_err() - ); - }); -} - #[test] fn burn_must_work() { ExtBuilder::default().monied(true).build().execute_with(|| { diff --git a/srml/collective/src/lib.rs b/srml/collective/src/lib.rs index 2de6243dd6..edfc4bf46f 100644 --- a/srml/collective/src/lib.rs +++ b/srml/collective/src/lib.rs @@ -406,7 +406,6 @@ mod tests { type Lookup = IdentityLookup; type Header = Header; type Event = Event; - type WeightMultiplierUpdate = (); type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; type MaximumBlockLength = MaximumBlockLength; diff --git a/srml/contracts/src/lib.rs b/srml/contracts/src/lib.rs index 678fc65d76..3d8a455ad7 100644 --- a/srml/contracts/src/lib.rs +++ b/srml/contracts/src/lib.rs @@ -442,7 +442,7 @@ where } /// The default dispatch fee computor computes the fee in the same way that -/// the implementation of `TakeFees` for the Balances module does. Note that this only takes a fixed +/// the implementation of `ChargeTransactionPayment` for the Balances module does. Note that this only takes a fixed /// fee based on size. Unlike the balances module, weight-fee is applied. pub struct DefaultDispatchFeeComputor(PhantomData); impl ComputeDispatchFee<::Call, BalanceOf> for DefaultDispatchFeeComputor { diff --git a/srml/contracts/src/tests.rs b/srml/contracts/src/tests.rs index d6de2ce3bd..d3b52c334b 100644 --- a/srml/contracts/src/tests.rs +++ b/srml/contracts/src/tests.rs @@ -96,8 +96,6 @@ parameter_types! { pub const BlockHashCount: u64 = 250; pub const MaximumBlockWeight: u32 = 1024; pub const MaximumBlockLength: u32 = 2 * 1024; - pub const BalancesTransactionBaseFee: u64 = 0; - pub const BalancesTransactionByteFee: u64 = 0; pub const AvailableBlockRatio: Perbill = Perbill::one(); } impl system::Trait for Test { @@ -110,7 +108,6 @@ impl system::Trait for Test { type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type WeightMultiplierUpdate = (); type Event = MetaEvent; type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; @@ -123,15 +120,11 @@ impl balances::Trait for Test { type OnFreeBalanceZero = Contract; type OnNewAccount = (); type Event = MetaEvent; - type TransactionPayment = (); type DustRemoval = (); type TransferPayment = (); type ExistentialDeposit = ExistentialDeposit; type TransferFee = TransferFee; type CreationFee = CreationFee; - type TransactionBaseFee = BalancesTransactionBaseFee; - type TransactionByteFee = BalancesTransactionByteFee; - type WeightToFee = (); } parameter_types! { pub const MinimumPeriod: u64 = 1; diff --git a/srml/council/src/lib.rs b/srml/council/src/lib.rs index e65cf9ace1..195202c873 100644 --- a/srml/council/src/lib.rs +++ b/srml/council/src/lib.rs @@ -114,7 +114,6 @@ mod tests { type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type WeightMultiplierUpdate = (); type Event = Event; type Error = Error; type BlockHashCount = BlockHashCount; @@ -127,24 +126,18 @@ mod tests { pub const ExistentialDeposit: u64 = 0; pub const TransferFee: u64 = 0; pub const CreationFee: u64 = 0; - pub const TransactionBaseFee: u64 = 1; - pub const TransactionByteFee: u64 = 0; } impl balances::Trait for Test { type Balance = u64; type OnNewAccount = (); type OnFreeBalanceZero = (); type Event = Event; - type TransactionPayment = (); type TransferPayment = (); type DustRemoval = (); type Error = Error; type ExistentialDeposit = ExistentialDeposit; type TransferFee = TransferFee; type CreationFee = CreationFee; - type TransactionBaseFee = TransactionBaseFee; - type TransactionByteFee = TransactionByteFee; - type WeightToFee = (); } parameter_types! { pub const LaunchPeriod: u64 = 1; diff --git a/srml/democracy/src/lib.rs b/srml/democracy/src/lib.rs index 2af301df1c..b7e7dac6f9 100644 --- a/srml/democracy/src/lib.rs +++ b/srml/democracy/src/lib.rs @@ -1015,7 +1015,6 @@ mod tests { type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type WeightMultiplierUpdate = (); type Event = (); type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; @@ -1027,23 +1026,17 @@ mod tests { pub const ExistentialDeposit: u64 = 0; pub const TransferFee: u64 = 0; pub const CreationFee: u64 = 0; - pub const TransactionBaseFee: u64 = 0; - pub const TransactionByteFee: u64 = 0; } impl balances::Trait for Test { type Balance = u64; type OnFreeBalanceZero = (); type OnNewAccount = (); type Event = (); - type TransactionPayment = (); type TransferPayment = (); type DustRemoval = (); type ExistentialDeposit = ExistentialDeposit; type TransferFee = TransferFee; type CreationFee = CreationFee; - type TransactionBaseFee = TransactionBaseFee; - type TransactionByteFee = TransactionByteFee; - type WeightToFee = (); } parameter_types! { pub const LaunchPeriod: u64 = 2; diff --git a/srml/elections-phragmen/src/lib.rs b/srml/elections-phragmen/src/lib.rs index 6ec79a537c..fdc88ce9e0 100644 --- a/srml/elections-phragmen/src/lib.rs +++ b/srml/elections-phragmen/src/lib.rs @@ -616,7 +616,6 @@ mod tests { type Lookup = IdentityLookup; type Header = Header; type Event = Event; - type WeightMultiplierUpdate = (); type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; type MaximumBlockLength = MaximumBlockLength; @@ -628,8 +627,6 @@ mod tests { pub const ExistentialDeposit: u64 = 1; pub const TransferFee: u64 = 0; pub const CreationFee: u64 = 0; - pub const TransactionBaseFee: u64 = 0; - pub const TransactionByteFee: u64 = 0; } impl balances::Trait for Test { @@ -637,15 +634,11 @@ mod tests { type OnNewAccount = (); type OnFreeBalanceZero = (); type Event = Event; - type TransactionPayment = (); type TransferPayment = (); type DustRemoval = (); type ExistentialDeposit = ExistentialDeposit; type TransferFee = TransferFee; type CreationFee = CreationFee; - type TransactionBaseFee = TransactionBaseFee; - type TransactionByteFee = TransactionByteFee; - type WeightToFee = (); } parameter_types! { diff --git a/srml/elections/src/mock.rs b/srml/elections/src/mock.rs index d48a0fd3fd..77b13d74a1 100644 --- a/srml/elections/src/mock.rs +++ b/srml/elections/src/mock.rs @@ -47,7 +47,6 @@ impl system::Trait for Test { type Lookup = IdentityLookup; type Header = Header; type Event = Event; - type WeightMultiplierUpdate = (); type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; type MaximumBlockLength = MaximumBlockLength; @@ -59,23 +58,17 @@ parameter_types! { pub const ExistentialDeposit: u64 = 0; pub const TransferFee: u64 = 0; pub const CreationFee: u64 = 0; - pub const TransactionBaseFee: u64 = 0; - pub const TransactionByteFee: u64 = 0; } impl balances::Trait for Test { type Balance = u64; type OnNewAccount = (); type OnFreeBalanceZero = (); type Event = Event; - type TransactionPayment = (); type TransferPayment = (); type DustRemoval = (); type ExistentialDeposit = ExistentialDeposit; type TransferFee = TransferFee; type CreationFee = CreationFee; - type TransactionBaseFee = TransactionBaseFee; - type TransactionByteFee = TransactionByteFee; - type WeightToFee = (); } parameter_types! { diff --git a/srml/example/src/lib.rs b/srml/example/src/lib.rs index 0766468efa..a6a075d8cb 100644 --- a/srml/example/src/lib.rs +++ b/srml/example/src/lib.rs @@ -667,7 +667,6 @@ mod tests { type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type WeightMultiplierUpdate = (); type Event = (); type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; @@ -679,23 +678,17 @@ mod tests { pub const ExistentialDeposit: u64 = 0; pub const TransferFee: u64 = 0; pub const CreationFee: u64 = 0; - pub const TransactionBaseFee: u64 = 0; - pub const TransactionByteFee: u64 = 0; } impl balances::Trait for Test { type Balance = u64; type OnFreeBalanceZero = (); type OnNewAccount = (); type Event = (); - type TransactionPayment = (); type TransferPayment = (); type DustRemoval = (); type ExistentialDeposit = ExistentialDeposit; type TransferFee = TransferFee; type CreationFee = CreationFee; - type TransactionBaseFee = TransactionBaseFee; - type TransactionByteFee = TransactionByteFee; - type WeightToFee = (); } impl Trait for Test { type Event = (); diff --git a/srml/executive/Cargo.toml b/srml/executive/Cargo.toml index a87eed40b7..92191a7aac 100644 --- a/srml/executive/Cargo.toml +++ b/srml/executive/Cargo.toml @@ -18,6 +18,7 @@ hex-literal = "0.2.1" primitives = { package = "substrate-primitives", path = "../../core/primitives" } srml-indices = { path = "../indices" } balances = { package = "srml-balances", path = "../balances" } +transaction-payment = { package = "srml-transaction-payment", path = "../transaction-payment" } [features] default = ["std"] diff --git a/srml/executive/src/lib.rs b/srml/executive/src/lib.rs index 23c645f6ef..401f07d206 100644 --- a/srml/executive/src/lib.rs +++ b/srml/executive/src/lib.rs @@ -347,7 +347,6 @@ mod tests { type Header = Header; type Event = MetaEvent; type BlockHashCount = BlockHashCount; - type WeightMultiplierUpdate = (); type MaximumBlockWeight = MaximumBlockWeight; type AvailableBlockRatio = AvailableBlockRatio; type MaximumBlockLength = MaximumBlockLength; @@ -357,23 +356,30 @@ mod tests { pub const ExistentialDeposit: u64 = 0; pub const TransferFee: u64 = 0; pub const CreationFee: u64 = 0; - pub const TransactionBaseFee: u64 = 10; - pub const TransactionByteFee: u64 = 0; } impl balances::Trait for Runtime { type Balance = u64; type OnFreeBalanceZero = (); type OnNewAccount = (); type Event = MetaEvent; - type TransactionPayment = (); type DustRemoval = (); type TransferPayment = (); type ExistentialDeposit = ExistentialDeposit; type TransferFee = TransferFee; type CreationFee = CreationFee; + } + + parameter_types! { + pub const TransactionBaseFee: u64 = 10; + pub const TransactionByteFee: u64 = 0; + } + impl transaction_payment::Trait for Runtime { + type Currency = Balances; + type OnTransactionPayment = (); type TransactionBaseFee = TransactionBaseFee; type TransactionByteFee = TransactionByteFee; type WeightToFee = ConvertInto; + type FeeMultiplierUpdate = (); } impl ValidateUnsigned for Runtime { @@ -391,7 +397,7 @@ mod tests { system::CheckEra, system::CheckNonce, system::CheckWeight, - balances::TakeFees + transaction_payment::ChargeTransactionPayment ); type TestXt = sr_primitives::testing::TestXt; type Executive = super::Executive, system::ChainContext, Runtime, ()>; @@ -401,7 +407,7 @@ mod tests { system::CheckEra::from(Era::Immortal), system::CheckNonce::from(nonce), system::CheckWeight::new(), - balances::TakeFees::from(fee) + transaction_payment::ChargeTransactionPayment::from(fee) ) } @@ -450,7 +456,7 @@ mod tests { header: Header { parent_hash: [69u8; 32].into(), number: 1, - state_root: hex!("a6378d7fdd31029d13718d54bdff10a370e75cc624aaf94a90e7e7d4a24e0bcc").into(), + state_root: hex!("f0d1d66255c2e5b40580eb8b93ddbe732491478487f85e358e1d167d369e398e").into(), extrinsics_root: hex!("03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314").into(), digest: Digest { logs: vec![], }, }, diff --git a/srml/finality-tracker/src/lib.rs b/srml/finality-tracker/src/lib.rs index ba893c42d0..1106a17a58 100644 --- a/srml/finality-tracker/src/lib.rs +++ b/srml/finality-tracker/src/lib.rs @@ -298,7 +298,6 @@ mod tests { type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type WeightMultiplierUpdate = (); type Event = (); type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; diff --git a/srml/generic-asset/src/lib.rs b/srml/generic-asset/src/lib.rs index 6791ee5785..ca49e2f1cd 100644 --- a/srml/generic-asset/src/lib.rs +++ b/srml/generic-asset/src/lib.rs @@ -1056,7 +1056,6 @@ impl system::Trait for ElevatedTrait { type MaximumBlockWeight = T::MaximumBlockWeight; type MaximumBlockLength = T::MaximumBlockLength; type AvailableBlockRatio = T::AvailableBlockRatio; - type WeightMultiplierUpdate = (); type BlockHashCount = T::BlockHashCount; type Version = T::Version; } diff --git a/srml/generic-asset/src/mock.rs b/srml/generic-asset/src/mock.rs index c0f9f154b8..57b13760fa 100644 --- a/srml/generic-asset/src/mock.rs +++ b/srml/generic-asset/src/mock.rs @@ -56,7 +56,6 @@ impl system::Trait for Test { type Lookup = IdentityLookup; type Header = Header; type Event = TestEvent; - type WeightMultiplierUpdate = (); type MaximumBlockWeight = MaximumBlockWeight; type MaximumBlockLength = MaximumBlockLength; type AvailableBlockRatio = AvailableBlockRatio; diff --git a/srml/grandpa/src/mock.rs b/srml/grandpa/src/mock.rs index 8d585e4b46..fcacbade20 100644 --- a/srml/grandpa/src/mock.rs +++ b/srml/grandpa/src/mock.rs @@ -57,7 +57,6 @@ impl system::Trait for Test { type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type WeightMultiplierUpdate = (); type Event = TestEvent; type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; diff --git a/srml/im-online/src/mock.rs b/srml/im-online/src/mock.rs index c2869136dc..e50e7779e9 100644 --- a/srml/im-online/src/mock.rs +++ b/srml/im-online/src/mock.rs @@ -111,7 +111,6 @@ impl system::Trait for Runtime { type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type WeightMultiplierUpdate = (); type Event = (); type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; diff --git a/srml/indices/src/mock.rs b/srml/indices/src/mock.rs index 59d84279a9..427fd87c47 100644 --- a/srml/indices/src/mock.rs +++ b/srml/indices/src/mock.rs @@ -81,7 +81,6 @@ impl system::Trait for Runtime { type AccountId = u64; type Lookup = Indices; type Header = Header; - type WeightMultiplierUpdate = (); type Event = (); type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; diff --git a/srml/membership/src/lib.rs b/srml/membership/src/lib.rs index 0cd3b0af66..5d2001b32d 100644 --- a/srml/membership/src/lib.rs +++ b/srml/membership/src/lib.rs @@ -224,7 +224,6 @@ mod tests { type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type WeightMultiplierUpdate = (); type Event = (); type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; diff --git a/srml/offences/src/mock.rs b/srml/offences/src/mock.rs index 01891ce32b..f9c7939081 100644 --- a/srml/offences/src/mock.rs +++ b/srml/offences/src/mock.rs @@ -78,7 +78,6 @@ impl system::Trait for Runtime { type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type WeightMultiplierUpdate = (); type Event = TestEvent; type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; diff --git a/srml/randomness-collective-flip/src/lib.rs b/srml/randomness-collective-flip/src/lib.rs index 8dedf6f570..f6261b6a03 100644 --- a/srml/randomness-collective-flip/src/lib.rs +++ b/srml/randomness-collective-flip/src/lib.rs @@ -182,7 +182,6 @@ mod tests { type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type WeightMultiplierUpdate = (); type Event = (); type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; diff --git a/srml/scored-pool/src/mock.rs b/srml/scored-pool/src/mock.rs index 92a16bf25d..394f486a8b 100644 --- a/srml/scored-pool/src/mock.rs +++ b/srml/scored-pool/src/mock.rs @@ -52,8 +52,6 @@ parameter_types! { pub const ExistentialDeposit: u64 = 0; pub const TransferFee: u64 = 0; pub const CreationFee: u64 = 0; - pub const TransactionBaseFee: u64 = 0; - pub const TransactionByteFee: u64 = 0; } impl system::Trait for Test { @@ -66,7 +64,6 @@ impl system::Trait for Test { type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type WeightMultiplierUpdate = (); type Event = (); type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; @@ -80,15 +77,11 @@ impl balances::Trait for Test { type OnFreeBalanceZero = (); type OnNewAccount = (); type Event = (); - type TransactionPayment = (); type TransferPayment = (); type DustRemoval = (); type ExistentialDeposit = ExistentialDeposit; type TransferFee = TransferFee; type CreationFee = CreationFee; - type TransactionBaseFee = TransactionBaseFee; - type TransactionByteFee = TransactionByteFee; - type WeightToFee = (); } thread_local! { diff --git a/srml/session/src/mock.rs b/srml/session/src/mock.rs index 736d3fa4da..d680fdc96b 100644 --- a/srml/session/src/mock.rs +++ b/srml/session/src/mock.rs @@ -168,7 +168,6 @@ impl system::Trait for Test { type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type WeightMultiplierUpdate = (); type Event = (); type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; diff --git a/srml/staking/src/mock.rs b/srml/staking/src/mock.rs index 43bd00e3e0..41a2ad4802 100644 --- a/srml/staking/src/mock.rs +++ b/srml/staking/src/mock.rs @@ -118,7 +118,6 @@ impl system::Trait for Test { type AccountId = AccountId; type Lookup = IdentityLookup; type Header = Header; - type WeightMultiplierUpdate = (); type Event = (); type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; @@ -129,23 +128,17 @@ impl system::Trait for Test { parameter_types! { pub const TransferFee: Balance = 0; pub const CreationFee: Balance = 0; - pub const TransactionBaseFee: u64 = 0; - pub const TransactionByteFee: u64 = 0; } impl balances::Trait for Test { type Balance = Balance; type OnFreeBalanceZero = Staking; type OnNewAccount = (); type Event = (); - type TransactionPayment = (); type TransferPayment = (); type DustRemoval = (); type ExistentialDeposit = ExistentialDeposit; type TransferFee = TransferFee; type CreationFee = CreationFee; - type TransactionBaseFee = TransactionBaseFee; - type TransactionByteFee = TransactionByteFee; - type WeightToFee = (); } parameter_types! { pub const Period: BlockNumber = 1; diff --git a/srml/system/benches/bench.rs b/srml/system/benches/bench.rs index 1b18b55fd2..6da02cf9c8 100644 --- a/srml/system/benches/bench.rs +++ b/srml/system/benches/bench.rs @@ -68,7 +68,6 @@ impl system::Trait for Runtime { type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type WeightMultiplierUpdate = (); type Event = Event; type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; diff --git a/srml/system/src/lib.rs b/srml/system/src/lib.rs index 71c99af3b3..caa6d573b0 100644 --- a/srml/system/src/lib.rs +++ b/srml/system/src/lib.rs @@ -97,13 +97,13 @@ use rstd::marker::PhantomData; use sr_version::RuntimeVersion; use sr_primitives::{ generic::{self, Era}, Perbill, ApplyError, ApplyOutcome, DispatchError, - weights::{Weight, DispatchInfo, DispatchClass, WeightMultiplier, SimpleDispatchInfo}, + weights::{Weight, DispatchInfo, DispatchClass, SimpleDispatchInfo}, transaction_validity::{ ValidTransaction, TransactionPriority, TransactionLongevity, TransactionValidityError, InvalidTransaction, TransactionValidity, }, traits::{ - self, CheckEqual, SimpleArithmetic, Zero, SignedExtension, Convert, Lookup, LookupError, + self, CheckEqual, SimpleArithmetic, Zero, SignedExtension, Lookup, LookupError, SimpleBitOps, Hash, Member, MaybeDisplay, EnsureOrigin, SaturatedConversion, MaybeSerializeDebugButNotDeserialize, MaybeSerializeDebug, StaticLookup, One, Bounded, }, @@ -188,14 +188,6 @@ pub trait Trait: 'static + Eq + Clone { /// (e.g. Indices module) may provide more functional/efficient alternatives. type Lookup: StaticLookup; - /// Handler for updating the weight multiplier at the end of each block. - /// - /// It receives the current block's weight as input and returns the next weight multiplier for next - /// block. - /// - /// Note that passing `()` will keep the value constant. - type WeightMultiplierUpdate: Convert<(Weight, WeightMultiplier), WeightMultiplier>; - /// The block header. type Header: Parameter + traits::Header< Number = Self::BlockNumber, @@ -381,9 +373,6 @@ decl_storage! { AllExtrinsicsWeight: Option; /// Total length (in bytes) for all extrinsics put together, for the current block. AllExtrinsicsLen: Option; - /// The next weight multiplier. This should be updated at the end of each block based on the - /// saturation level (weight). - pub NextWeightMultiplier get(next_weight_multiplier): WeightMultiplier = Default::default(); /// Map of block numbers to block hashes. pub BlockHash get(block_hash) build(|_| vec![(T::BlockNumber::zero(), hash69())]): map T::BlockNumber => T::Hash; /// Extrinsics data for the current block (maps an extrinsic's index to its data). @@ -612,17 +601,6 @@ impl Module { AllExtrinsicsLen::get().unwrap_or_default() } - /// Update the next weight multiplier. - /// - /// This should be called at then end of each block, before `all_extrinsics_weight` is cleared. - pub fn update_weight_multiplier() { - // update the multiplier based on block weight. - let current_weight = Self::all_extrinsics_weight(); - NextWeightMultiplier::mutate(|fm| { - *fm = T::WeightMultiplierUpdate::convert((current_weight, *fm)) - }); - } - /// Start the execution of a particular block. pub fn initialize( number: &T::BlockNumber, @@ -645,7 +623,6 @@ impl Module { /// Remove temporary "environment" entries in storage. pub fn finalize() -> T::Header { ExtrinsicCount::kill(); - Self::update_weight_multiplier(); AllExtrinsicsWeight::kill(); AllExtrinsicsLen::kill(); @@ -1118,7 +1095,6 @@ mod tests { type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type WeightMultiplierUpdate = (); type Event = u16; type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; diff --git a/srml/timestamp/src/lib.rs b/srml/timestamp/src/lib.rs index cdacb8a391..35546575c5 100644 --- a/srml/timestamp/src/lib.rs +++ b/srml/timestamp/src/lib.rs @@ -348,7 +348,6 @@ mod tests { type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type WeightMultiplierUpdate = (); type Event = (); type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; diff --git a/srml/transaction-payment/Cargo.toml b/srml/transaction-payment/Cargo.toml new file mode 100644 index 0000000000..7f8eddab19 --- /dev/null +++ b/srml/transaction-payment/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "srml-transaction-payment" +version = "2.0.0" +authors = ["Parity Technologies "] +edition = "2018" + +[dependencies] +codec = { package = "parity-scale-codec", version = "1.0.0", default-features = false, features = ["derive"] } +rstd = { package = "sr-std", path = "../../core/sr-std", default-features = false } +sr-primitives = { path = "../../core/sr-primitives", default-features = false } +support = { package = "srml-support", path = "../support", default-features = false } +system = { package = "srml-system", path = "../system", default-features = false } + +[dev-dependencies] +runtime-io = { package = "sr-io", path = "../../core/sr-io" } +primitives = { package = "substrate-primitives", path = "../../core/primitives" } +balances = { package = "srml-balances", path = "../balances" } + +[features] +default = ["std"] +std = [ + "codec/std", + "rstd/std", + "sr-primitives/std", + "support/std", + "system/std", +] diff --git a/srml/transaction-payment/src/lib.rs b/srml/transaction-payment/src/lib.rs new file mode 100644 index 0000000000..f2e815fcd4 --- /dev/null +++ b/srml/transaction-payment/src/lib.rs @@ -0,0 +1,455 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +//! # Transaction Payment Module +//! +//! This module provides the basic logic needed to pay the absolute minimum amount needed for a +//! transaction to be included. This includes: +//! - _weight fee_: A fee proportional to amount of weight a transaction consumes. +//! - _length fee_: A fee proportional to the encoded length of the transaction. +//! - _tip_: An optional tip. Tip increases the priority of the transaction, giving it a higher +//! chance to be included by the transaction queue. +//! +//! Additionally, this module allows one to configure: +//! - The mapping between one unit of weight to one unit of fee via [`WeightToFee`]. +//! - A means of updating the fee for the next block, via defining a multiplier, based on the +//! final state of the chain at the end of the previous block. This can be configured via +//! [`FeeMultiplierUpdate`] + +#![cfg_attr(not(feature = "std"), no_std)] + +use rstd::prelude::*; +use codec::{Encode, Decode}; +use support::{ + decl_storage, decl_module, + traits::{Currency, Get, OnUnbalanced, ExistenceRequirement, WithdrawReason}, +}; +use sr_primitives::{ + Fixed64, + transaction_validity::{ + TransactionPriority, ValidTransaction, InvalidTransaction, TransactionValidityError, + TransactionValidity, + }, + traits::{Zero, Saturating, SignedExtension, SaturatedConversion, Convert}, + weights::{Weight, DispatchInfo}, +}; + +type Multiplier = Fixed64; +type BalanceOf = + <::Currency as Currency<::AccountId>>::Balance; +type NegativeImbalanceOf = + <::Currency as Currency<::AccountId>>::NegativeImbalance; + +pub trait Trait: system::Trait { + /// The currency type in which fees will be paid. + type Currency: Currency; + + /// Handler for the unbalanced reduction when taking transaction fees. + type OnTransactionPayment: OnUnbalanced>; + + /// The fee to be paid for making a transaction; the base. + type TransactionBaseFee: Get>; + + /// The fee to be paid for making a transaction; the per-byte portion. + type TransactionByteFee: Get>; + + /// Convert a weight value into a deductible fee based on the currency type. + type WeightToFee: Convert>; + + /// Update the multiplier of the next block, based on the previous block's weight. + // TODO: maybe this does not need previous weight and can just read it + type FeeMultiplierUpdate: Convert<(Weight, Multiplier), Multiplier>; +} + +decl_storage! { + trait Store for Module as Balances { + NextFeeMultiplier get(next_fee_multiplier): Multiplier = Multiplier::from_parts(0); + } +} + +decl_module! { + pub struct Module for enum Call where origin: T::Origin { + /// The fee to be paid for making a transaction; the base. + const TransactionBaseFee: BalanceOf = T::TransactionBaseFee::get(); + + /// The fee to be paid for making a transaction; the per-byte portion. + const TransactionByteFee: BalanceOf = T::TransactionByteFee::get(); + + fn on_finalize() { + let current_weight = >::all_extrinsics_weight(); + NextFeeMultiplier::mutate(|fm| { + *fm = T::FeeMultiplierUpdate::convert((current_weight, *fm)) + }); + } + } +} + +impl Module {} + +/// Require the transactor pay for themselves and maybe include a tip to gain additional priority +/// in the queue. +#[derive(Encode, Decode, Clone, Eq, PartialEq)] +pub struct ChargeTransactionPayment(#[codec(compact)] BalanceOf); + +impl ChargeTransactionPayment { + /// utility constructor. Used only in client/factory code. + pub fn from(fee: BalanceOf) -> Self { + Self(fee) + } + + /// Compute the final fee value for a particular transaction. + /// + /// The final fee is composed of: + /// - _length-fee_: This is the amount paid merely to pay for size of the transaction. + /// - _weight-fee_: This amount is computed based on the weight of the transaction. Unlike + /// size-fee, this is not input dependent and reflects the _complexity_ of the execution + /// and the time it consumes. + /// - (optional) _tip_: if included in the transaction, it will be added on top. Only signed + /// transactions can have a tip. + fn compute_fee(len: usize, info: DispatchInfo, tip: BalanceOf) -> BalanceOf { + let len_fee = if info.pay_length_fee() { + let len = >::from(len as u32); + let base = T::TransactionBaseFee::get(); + let per_byte = T::TransactionByteFee::get(); + base.saturating_add(per_byte.saturating_mul(len)) + } else { + Zero::zero() + }; + + let weight_fee = { + // cap the weight to the maximum defined in runtime, otherwise it will be the `Bounded` + // maximum of its data type, which is not desired. + let capped_weight = info.weight.min(::MaximumBlockWeight::get()); + T::WeightToFee::convert(capped_weight) + }; + + // everything except for tip + let basic_fee = len_fee.saturating_add(weight_fee); + let fee_update = NextFeeMultiplier::get(); + let adjusted_fee = fee_update.saturated_multiply_accumulate(basic_fee); + + adjusted_fee.saturating_add(tip) + } +} + +#[cfg(feature = "std")] +impl rstd::fmt::Debug for ChargeTransactionPayment { + fn fmt(&self, f: &mut rstd::fmt::Formatter) -> rstd::fmt::Result { + write!(f, "ChargeTransactionPayment<{:?}>", self.0) + } +} + +impl SignedExtension for ChargeTransactionPayment + where BalanceOf: Send + Sync +{ + type AccountId = T::AccountId; + type Call = T::Call; + type AdditionalSigned = (); + type Pre = (); + fn additional_signed(&self) -> rstd::result::Result<(), TransactionValidityError> { Ok(()) } + + fn validate( + &self, + who: &Self::AccountId, + _call: &Self::Call, + info: DispatchInfo, + len: usize, + ) -> TransactionValidity { + // pay any fees. + let fee = Self::compute_fee(len, info, self.0); + let imbalance = match T::Currency::withdraw( + who, + fee, + WithdrawReason::TransactionPayment, + ExistenceRequirement::KeepAlive, + ) { + Ok(imbalance) => imbalance, + Err(_) => return InvalidTransaction::Payment.into(), + }; + T::OnTransactionPayment::on_unbalanced(imbalance); + + let mut r = ValidTransaction::default(); + // NOTE: we probably want to maximize the _fee (of any type) per weight unit_ here, which + // will be a bit more than setting the priority to tip. For now, this is enough. + r.priority = fee.saturated_into::(); + Ok(r) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use support::{parameter_types, impl_outer_origin}; + use primitives::H256; + use sr_primitives::{ + Perbill, + testing::Header, + traits::{BlakeTwo256, IdentityLookup}, + weights::DispatchClass, + }; + use rstd::cell::RefCell; + + const CALL: &::Call = &(); + + #[derive(Clone, PartialEq, Eq, Debug)] + pub struct Runtime; + + impl_outer_origin!{ + pub enum Origin for Runtime {} + } + + parameter_types! { + pub const BlockHashCount: u64 = 250; + pub const MaximumBlockWeight: u32 = 1024; + pub const MaximumBlockLength: u32 = 2 * 1024; + pub const AvailableBlockRatio: Perbill = Perbill::one(); + } + + 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; + type Lookup = IdentityLookup; + type Header = Header; + type Event = (); + type BlockHashCount = BlockHashCount; + type MaximumBlockWeight = MaximumBlockWeight; + type MaximumBlockLength = MaximumBlockLength; + type AvailableBlockRatio = AvailableBlockRatio; + type Version = (); + } + + parameter_types! { + pub const TransferFee: u64 = 0; + pub const CreationFee: u64 = 0; + pub const ExistentialDeposit: u64 = 0; + } + + impl balances::Trait for Runtime { + type Balance = u64; + type OnFreeBalanceZero = (); + type OnNewAccount = (); + type Event = (); + type TransferPayment = (); + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type TransferFee = TransferFee; + type CreationFee = CreationFee; + } + + thread_local! { + static TRANSACTION_BASE_FEE: RefCell = RefCell::new(0); + static TRANSACTION_BYTE_FEE: RefCell = RefCell::new(1); + static WEIGHT_TO_FEE: RefCell = RefCell::new(1); + } + + pub struct TransactionBaseFee; + impl Get for TransactionBaseFee { + fn get() -> u64 { TRANSACTION_BASE_FEE.with(|v| *v.borrow()) } + } + + pub struct TransactionByteFee; + impl Get for TransactionByteFee { + fn get() -> u64 { TRANSACTION_BYTE_FEE.with(|v| *v.borrow()) } + } + + pub struct WeightToFee(u64); + impl Convert for WeightToFee { + fn convert(t: Weight) -> u64 { + WEIGHT_TO_FEE.with(|v| *v.borrow() * (t as u64)) + } + } + + impl Trait for Runtime { + type Currency = balances::Module; + type OnTransactionPayment = (); + type TransactionBaseFee = TransactionBaseFee; + type TransactionByteFee = TransactionByteFee; + type WeightToFee = WeightToFee; + type FeeMultiplierUpdate = (); + } + + type Balances = balances::Module; + + pub struct ExtBuilder { + balance_factor: u64, + base_fee: u64, + byte_fee: u64, + weight_to_fee: u64 + } + + impl Default for ExtBuilder { + fn default() -> Self { + Self { + balance_factor: 1, + base_fee: 0, + byte_fee: 1, + weight_to_fee: 1, + } + } + } + + impl ExtBuilder { + pub fn fees(mut self, base: u64, byte: u64, weight: u64) -> Self { + self.base_fee = base; + self.byte_fee = byte; + self.weight_to_fee = weight; + self + } + pub fn balance_factor(mut self, factor: u64) -> Self { + self.balance_factor = factor; + self + } + fn set_constants(&self) { + TRANSACTION_BASE_FEE.with(|v| *v.borrow_mut() = self.base_fee); + TRANSACTION_BYTE_FEE.with(|v| *v.borrow_mut() = self.byte_fee); + WEIGHT_TO_FEE.with(|v| *v.borrow_mut() = self.weight_to_fee); + } + pub fn build(self) -> runtime_io::TestExternalities { + self.set_constants(); + let mut t = system::GenesisConfig::default().build_storage::().unwrap(); + balances::GenesisConfig:: { + balances: vec![ + (1, 10 * self.balance_factor), + (2, 20 * self.balance_factor), + (3, 30 * self.balance_factor), + (4, 40 * self.balance_factor), + (5, 50 * self.balance_factor), + (6, 60 * self.balance_factor) + ], + vesting: vec![], + }.assimilate_storage(&mut t).unwrap(); + t.into() + } + } + + /// 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() } + } + + #[test] + fn signed_extension_transaction_payment_work() { + ExtBuilder::default() + .balance_factor(10) // 100 + .fees(5, 1, 1) // 5 fixed, 1 per byte, 1 per weight + .build() + .execute_with(|| + { + let len = 10; + assert!( + ChargeTransactionPayment::::from(0) + .pre_dispatch(&1, CALL, info_from_weight(5), len) + .is_ok() + ); + assert_eq!(Balances::free_balance(&1), 100 - 5 - 5 - 10); + + assert!( + ChargeTransactionPayment::::from(5 /* tipped */) + .pre_dispatch(&2, CALL, info_from_weight(3), len) + .is_ok() + ); + assert_eq!(Balances::free_balance(&2), 200 - 5 - 10 - 3 - 5); + }); + } + + #[test] + fn signed_extension_transaction_payment_is_bounded() { + ExtBuilder::default() + .balance_factor(1000) + .fees(0, 0, 1) + .build() + .execute_with(|| + { + use sr_primitives::weights::Weight; + + // maximum weight possible + assert!( + ChargeTransactionPayment::::from(0) + .pre_dispatch(&1, CALL, info_from_weight(Weight::max_value()), 10) + .is_ok() + ); + // fee will be proportional to what is the actual maximum weight in the runtime. + assert_eq!( + Balances::free_balance(&1), + (10000 - ::MaximumBlockWeight::get()) as u64 + ); + }); + } + + #[test] + fn signed_extension_allows_free_transactions() { + ExtBuilder::default() + .fees(100, 1, 1) + .balance_factor(0) + .build() + .execute_with(|| + { + // 1 ain't have a penny. + assert_eq!(Balances::free_balance(&1), 0); + + // like a FreeOperational + let operational_transaction = DispatchInfo { + weight: 0, + class: DispatchClass::Operational + }; + let len = 100; + assert!( + ChargeTransactionPayment::::from(0) + .validate(&1, CALL, operational_transaction , len) + .is_ok() + ); + + // like a FreeNormal + let free_transaction = DispatchInfo { + weight: 0, + class: DispatchClass::Normal + }; + assert!( + ChargeTransactionPayment::::from(0) + .validate(&1, CALL, free_transaction , len) + .is_err() + ); + }); + } + + #[test] + fn signed_ext_length_fee_is_also_updated_per_congestion() { + ExtBuilder::default() + .fees(5, 1, 1) + .balance_factor(10) + .build() + .execute_with(|| + { + // all fees should be x1.5 + NextFeeMultiplier::put(Fixed64::from_rational(1, 2)); + let len = 10; + + assert!( + ChargeTransactionPayment::::from(10) // tipped + .pre_dispatch(&1, CALL, info_from_weight(3), len) + .is_ok() + ); + assert_eq!(Balances::free_balance(&1), 100 - 10 - (5 + 10 + 3) * 3 / 2); + }) + } +} + + diff --git a/srml/treasury/src/lib.rs b/srml/treasury/src/lib.rs index d5b3e6e55f..936e4bd93d 100644 --- a/srml/treasury/src/lib.rs +++ b/srml/treasury/src/lib.rs @@ -383,7 +383,6 @@ mod tests { type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type WeightMultiplierUpdate = (); type Event = (); type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; @@ -395,23 +394,17 @@ mod tests { pub const ExistentialDeposit: u64 = 0; pub const TransferFee: u64 = 0; pub const CreationFee: u64 = 0; - pub const TransactionBaseFee: u64 = 0; - pub const TransactionByteFee: u64 = 0; } impl balances::Trait for Test { type Balance = u64; type OnNewAccount = (); type OnFreeBalanceZero = (); type Event = (); - type TransactionPayment = (); type TransferPayment = (); type DustRemoval = (); type ExistentialDeposit = ExistentialDeposit; type TransferFee = TransferFee; type CreationFee = CreationFee; - type TransactionBaseFee = TransactionBaseFee; - type TransactionByteFee = TransactionByteFee; - type WeightToFee = (); } parameter_types! { pub const ProposalBond: Permill = Permill::from_percent(5); diff --git a/srml/utility/src/lib.rs b/srml/utility/src/lib.rs index 52675d24fc..d69e260ff9 100644 --- a/srml/utility/src/lib.rs +++ b/srml/utility/src/lib.rs @@ -99,7 +99,6 @@ mod tests { type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type WeightMultiplierUpdate = (); type Event = (); type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; @@ -111,23 +110,17 @@ mod tests { pub const ExistentialDeposit: u64 = 0; pub const TransferFee: u64 = 0; pub const CreationFee: u64 = 0; - pub const TransactionBaseFee: u64 = 0; - pub const TransactionByteFee: u64 = 0; } impl balances::Trait for Test { type Balance = u64; type OnFreeBalanceZero = (); type OnNewAccount = (); type Event = (); - type TransactionPayment = (); type TransferPayment = (); type DustRemoval = (); type ExistentialDeposit = ExistentialDeposit; type TransferFee = TransferFee; type CreationFee = CreationFee; - type TransactionBaseFee = TransactionBaseFee; - type TransactionByteFee = TransactionByteFee; - type WeightToFee = (); } impl Trait for Test { type Event = (); diff --git a/subkey/Cargo.toml b/subkey/Cargo.toml index d901b59d0b..e1c3ef64d2 100644 --- a/subkey/Cargo.toml +++ b/subkey/Cargo.toml @@ -19,6 +19,7 @@ hex-literal = "0.2.1" codec = { package = "parity-scale-codec", version = "1.0.0" } system = { package = "srml-system", path = "../srml/system" } balances = { package = "srml-balances", path = "../srml/balances" } +transaction-payment = { package = "srml-transaction-payment", path = "../srml/transaction-payment" } [features] bench = [] diff --git a/subkey/src/main.rs b/subkey/src/main.rs index 973502b3d6..2596513ab2 100644 --- a/subkey/src/main.rs +++ b/subkey/src/main.rs @@ -363,7 +363,7 @@ fn create_extrinsic( system::CheckEra::::from(Era::Immortal), system::CheckNonce::::from(i), system::CheckWeight::::new(), - balances::TakeFees::::from(f), + transaction_payment::ChargeTransactionPayment::::from(f), Default::default(), ) }; -- GitLab From d0e68bf17e84102d50daa29365e8af4a2fc42cbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Thu, 17 Oct 2019 23:35:41 +0200 Subject: [PATCH 051/167] Don't panic when we try to register 2 global loggers (#3840) --- core/cli/src/lib.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/cli/src/lib.rs b/core/cli/src/lib.rs index c5af33b738..e891f90dc2 100644 --- a/core/cli/src/lib.rs +++ b/core/cli/src/lib.rs @@ -919,7 +919,9 @@ fn init_logger(pattern: &str) { writeln!(buf, "{}", output) }); - builder.init(); + if builder.try_init().is_err() { + info!("Not registering Substrate logger, as there is already a global logger registered!"); + } } fn kill_color(s: &str) -> String { -- GitLab From 734f1c3d066ba0c700d19aee5feb79869aae4228 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= Date: Fri, 18 Oct 2019 00:25:18 +0100 Subject: [PATCH 052/167] grandpa: don't expire next round messages (#3845) * grandpa: don't expire next round messages * grandpa: fix test * grandpa: first round in set is 1 * grandpa: fix test * grandpa: update doc --- .../src/communication/gossip.rs | 81 ++++++++++++++----- .../src/communication/tests.rs | 4 +- 2 files changed, 62 insertions(+), 23 deletions(-) diff --git a/core/finality-grandpa/src/communication/gossip.rs b/core/finality-grandpa/src/communication/gossip.rs index 831be7ad14..1f9d78c867 100644 --- a/core/finality-grandpa/src/communication/gossip.rs +++ b/core/finality-grandpa/src/communication/gossip.rs @@ -132,7 +132,7 @@ struct View { impl Default for View { fn default() -> Self { View { - round: Round(0), + round: Round(1), set_id: SetId(0), last_commit: None, } @@ -144,7 +144,7 @@ impl View { fn update_set(&mut self, set_id: SetId) { if set_id != self.set_id { self.set_id = set_id; - self.round = Round(0); + self.round = Round(1); } } @@ -194,21 +194,30 @@ impl KeepTopics { fn new() -> Self { KeepTopics { current_set: SetId(0), - rounds: VecDeque::with_capacity(KEEP_RECENT_ROUNDS + 1), + rounds: VecDeque::with_capacity(KEEP_RECENT_ROUNDS + 2), reverse_map: HashMap::new(), } } fn push(&mut self, round: Round, set_id: SetId) { self.current_set = std::cmp::max(self.current_set, set_id); - self.rounds.push_back((round, set_id)); - // the 1 is for the current round. - while self.rounds.len() > KEEP_RECENT_ROUNDS + 1 { + // under normal operation the given round is already tracked (since we + // track one round ahead). if we skip rounds (with a catch up) the given + // round topic might not be tracked yet. + if !self.rounds.contains(&(round, set_id)) { + self.rounds.push_back((round, set_id)); + } + + // we also accept messages for the next round + self.rounds.push_back((Round(round.0.saturating_add(1)), set_id)); + + // the 2 is for the current and next round. + while self.rounds.len() > KEEP_RECENT_ROUNDS + 2 { let _ = self.rounds.pop_front(); } - let mut map = HashMap::with_capacity(KEEP_RECENT_ROUNDS + 2); + let mut map = HashMap::with_capacity(KEEP_RECENT_ROUNDS + 3); map.insert(super::global_topic::(self.current_set.0), (None, self.current_set)); for &(round, set) in &self.rounds { @@ -554,7 +563,7 @@ impl Inner { { let local_view = match self.local_view { ref mut x @ None => x.get_or_insert(View { - round: Round(0), + round: Round(1), set_id, last_commit: None, }), @@ -566,7 +575,7 @@ impl Inner { }; local_view.update_set(set_id); - self.live_topics.push(Round(0), set_id); + self.live_topics.push(Round(1), set_id); self.authorities = authorities; } self.multicast_neighbor_packet() @@ -1466,11 +1475,11 @@ mod tests { let peer = PeerId::random(); val.note_set(SetId(set_id), vec![auth.clone()], |_, _| {}); - val.note_round(Round(0), |_, _| {}); + val.note_round(Round(1), |_, _| {}); let inner = val.inner.read(); let unknown_voter = inner.validate_round_message(&peer, &VoteOrPrecommitMessage { - round: Round(0), + round: Round(1), set_id: SetId(set_id), message: SignedMessage:: { message: grandpa::Message::Prevote(grandpa::Prevote { @@ -1483,7 +1492,7 @@ mod tests { }); let bad_sig = inner.validate_round_message(&peer, &VoteOrPrecommitMessage { - round: Round(0), + round: Round(1), set_id: SetId(set_id), message: SignedMessage:: { message: grandpa::Message::Prevote(grandpa::Prevote { @@ -1512,7 +1521,7 @@ mod tests { let peer = PeerId::random(); val.note_set(SetId(set_id), vec![auth.clone()], |_, _| {}); - val.note_round(Round(0), |_, _| {}); + val.note_round(Round(1), |_, _| {}); let validate_catch_up = || { let mut inner = val.inner.write(); @@ -1548,19 +1557,19 @@ mod tests { #[test] fn unanswerable_catch_up_requests_discarded() { - // create voter set state with round 1 completed + // create voter set state with round 2 completed let set_state: SharedVoterSetState = { let mut completed_rounds = voter_set_state().read().completed_rounds(); completed_rounds.push(environment::CompletedRound { - number: 1, + number: 2, state: grandpa::round::State::genesis(Default::default()), base: Default::default(), votes: Default::default(), }); let mut current_rounds = environment::CurrentRounds::new(); - current_rounds.insert(2, environment::HasVoted::No); + current_rounds.insert(3, environment::HasVoted::No); let set_state = environment::VoterSetState::::Live { completed_rounds, @@ -1581,7 +1590,7 @@ mod tests { let peer = PeerId::random(); val.note_set(SetId(set_id), vec![auth.clone()], |_, _| {}); - val.note_round(Round(2), |_, _| {}); + val.note_round(Round(3), |_, _| {}); // add the peer making the request to the validator, // otherwise it is discarded @@ -1597,7 +1606,7 @@ mod tests { &set_state, ); - // we're at round 2, a catch up request for round 10 is out of scope + // we're at round 3, a catch up request for round 10 is out of scope assert!(res.0.is_none()); assert_eq!(res.1, Action::Discard(cost::OUT_OF_SCOPE_MESSAGE)); @@ -1605,16 +1614,16 @@ mod tests { &peer, CatchUpRequestMessage { set_id: SetId(set_id), - round: Round(1), + round: Round(2), }, &set_state, ); - // a catch up request for round 1 should be answered successfully + // a catch up request for round 2 should be answered successfully match res.0.unwrap() { GossipMessage::CatchUp(catch_up) => { assert_eq!(catch_up.set_id, SetId(set_id)); - assert_eq!(catch_up.message.round_number, 1); + assert_eq!(catch_up.message.round_number, 2); assert_eq!(res.1, Action::Discard(cost::CATCH_UP_REPLY)); }, @@ -1849,4 +1858,34 @@ mod tests { _ => panic!("expected catch up message"), } } + + #[test] + fn doesnt_expire_next_round_messages() { + // NOTE: this is a regression test + let (val, _) = GossipValidator::::new( + config(), + voter_set_state(), + true, + ); + + // the validator starts at set id 1. + val.note_set(SetId(1), Vec::new(), |_, _| {}); + + // we are at round 10 + val.note_round(Round(9), |_, _| {}); + val.note_round(Round(10), |_, _| {}); + + let mut is_expired = val.message_expired(); + + // we accept messages from rounds 9, 10 and 11 + // therefore neither of those should be considered expired + for round in &[9, 10, 11] { + assert!( + !is_expired( + crate::communication::round_topic::(*round, 1), + &[], + ) + ) + } + } } diff --git a/core/finality-grandpa/src/communication/tests.rs b/core/finality-grandpa/src/communication/tests.rs index 6215e30b80..14e54511fb 100644 --- a/core/finality-grandpa/src/communication/tests.rs +++ b/core/finality-grandpa/src/communication/tests.rs @@ -217,7 +217,7 @@ fn good_commit_leads_to_relay() { let public = make_ids(&private[..]); let voter_set = Arc::new(public.iter().cloned().collect::>()); - let round = 0; + let round = 1; let set_id = 1; let commit = { @@ -332,7 +332,7 @@ fn bad_commit_leads_to_report() { let public = make_ids(&private[..]); let voter_set = Arc::new(public.iter().cloned().collect::>()); - let round = 0; + let round = 1; let set_id = 1; let commit = { -- GitLab From 48a5aaa921088ac8457a8c0510cedf88bace0ba2 Mon Sep 17 00:00:00 2001 From: kwingram25 Date: Fri, 18 Oct 2019 09:28:48 +0200 Subject: [PATCH 053/167] Use Bytes for contract rpc input_data (#3841) * Use Bytes for contract input_data * Update srml/contracts/rpc/src/lib.rs --- Cargo.lock | 1 + srml/contracts/rpc/Cargo.toml | 2 +- srml/contracts/rpc/src/lib.rs | 5 +++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c1aec02c00..bba0fc2f6f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4052,6 +4052,7 @@ dependencies = [ "sr-primitives 2.0.0", "srml-contracts-rpc-runtime-api 2.0.0", "substrate-client 2.0.0", + "substrate-primitives 2.0.0", "substrate-rpc-primitives 2.0.0", ] diff --git a/srml/contracts/rpc/Cargo.toml b/srml/contracts/rpc/Cargo.toml index 8ebb714e20..90bf34bec1 100644 --- a/srml/contracts/rpc/Cargo.toml +++ b/srml/contracts/rpc/Cargo.toml @@ -10,8 +10,8 @@ codec = { package = "parity-scale-codec", version = "1.0.0" } jsonrpc-core = "13.2.0" jsonrpc-core-client = "13.2.0" jsonrpc-derive = "13.2.0" +primitives = { package = "substrate-primitives", path = "../../../core/primitives" } rpc-primitives = { package = "substrate-rpc-primitives", path = "../../../core/rpc/primitives" } serde = { version = "1.0.101", features = ["derive"] } sr-primitives = { path = "../../../core/sr-primitives" } srml-contracts-rpc-runtime-api = { path = "./runtime-api" } - diff --git a/srml/contracts/rpc/src/lib.rs b/srml/contracts/rpc/src/lib.rs index 7e17aaaf17..ba50bd12f0 100644 --- a/srml/contracts/rpc/src/lib.rs +++ b/srml/contracts/rpc/src/lib.rs @@ -23,6 +23,7 @@ use client::blockchain::HeaderBackend; use codec::Codec; use jsonrpc_core::{Error, ErrorCode, Result}; use jsonrpc_derive::rpc; +use primitives::Bytes; use sr_primitives::{ generic::BlockId, traits::{Block as BlockT, ProvideRuntimeApi}, @@ -41,7 +42,7 @@ pub struct CallRequest { dest: AccountId, value: Balance, gas_limit: number::NumberOrHex, - input_data: Vec, + input_data: Bytes, } /// Contracts RPC methods. @@ -111,7 +112,7 @@ where })?; let exec_result = api - .call(&at, origin, dest, value, gas_limit, input_data) + .call(&at, origin, dest, value, gas_limit, input_data.to_vec()) .map_err(|e| Error { code: ErrorCode::ServerError(RUNTIME_ERROR), message: "Runtime trapped while executing a contract.".into(), -- GitLab From c2761470f79b2cd18727c223e1b9e9456b393496 Mon Sep 17 00:00:00 2001 From: cheme Date: Fri, 18 Oct 2019 09:52:25 +0200 Subject: [PATCH 054/167] Code redundancy between ext implementation and testing. (#3830) * fix child_storage_hash * extract common implementation for ext and testing * cleaning impl. * replace ExtBasisMut by actual Ext * remove extbasis. * Update tests to use Ext from test externalities. * use Ext constructor for getting ext from TestExternalities. * Add missing extensions from ext. * fix wasmi test * Fix merge error. --- core/executor/src/lib.rs | 1 + core/executor/src/sandbox.rs | 10 ++ core/executor/src/wasmi_execution.rs | 70 ++++++---- core/state-machine/src/ext.rs | 28 ++-- core/state-machine/src/testing.rs | 176 +++---------------------- core/state-machine/src/trie_backend.rs | 2 +- core/test-runtime/src/system.rs | 6 +- node/executor/src/lib.rs | 89 ++++++++----- 8 files changed, 151 insertions(+), 231 deletions(-) diff --git a/core/executor/src/lib.rs b/core/executor/src/lib.rs index 582ebbca34..ac98388cd7 100644 --- a/core/executor/src/lib.rs +++ b/core/executor/src/lib.rs @@ -98,6 +98,7 @@ mod tests { #[test] fn call_in_interpreted_wasm_works() { let mut ext = TestExternalities::default(); + let mut ext = ext.ext(); let res = call_in_wasm( "test_empty_return", &[], diff --git a/core/executor/src/sandbox.rs b/core/executor/src/sandbox.rs index c4122274a9..e1e9e0db95 100644 --- a/core/executor/src/sandbox.rs +++ b/core/executor/src/sandbox.rs @@ -610,6 +610,7 @@ mod tests { #[test] fn sandbox_should_work() { let mut ext = TestExternalities::default(); + let mut ext = ext.ext(); let test_code = WASM_BINARY; let code = wabt::wat2wasm(r#" @@ -642,6 +643,7 @@ mod tests { #[test] fn sandbox_trap() { let mut ext = TestExternalities::default(); + let mut ext = ext.ext(); let test_code = WASM_BINARY; let code = wabt::wat2wasm(r#" @@ -663,6 +665,7 @@ mod tests { #[test] fn sandbox_should_trap_when_heap_exhausted() { let mut ext = TestExternalities::default(); + let mut ext = ext.ext(); let test_code = WASM_BINARY; let code = wabt::wat2wasm(r#" @@ -691,6 +694,7 @@ mod tests { #[test] fn start_called() { let mut ext = TestExternalities::default(); + let mut ext = ext.ext(); let test_code = WASM_BINARY; let code = wabt::wat2wasm(r#" @@ -729,6 +733,7 @@ mod tests { #[test] fn invoke_args() { let mut ext = TestExternalities::default(); + let mut ext = ext.ext(); let test_code = WASM_BINARY; let code = wabt::wat2wasm(r#" @@ -763,6 +768,7 @@ mod tests { #[test] fn return_val() { let mut ext = TestExternalities::default(); + let mut ext = ext.ext(); let test_code = WASM_BINARY; let code = wabt::wat2wasm(r#" @@ -785,6 +791,7 @@ mod tests { #[test] fn unlinkable_module() { let mut ext = TestExternalities::default(); + let mut ext = ext.ext(); let test_code = WASM_BINARY; let code = wabt::wat2wasm(r#" @@ -805,6 +812,7 @@ mod tests { #[test] fn corrupted_module() { let mut ext = TestExternalities::default(); + let mut ext = ext.ext(); let test_code = WASM_BINARY; // Corrupted wasm file @@ -819,6 +827,7 @@ mod tests { #[test] fn start_fn_ok() { let mut ext = TestExternalities::default(); + let mut ext = ext.ext(); let test_code = WASM_BINARY; let code = wabt::wat2wasm(r#" @@ -842,6 +851,7 @@ mod tests { #[test] fn start_fn_traps() { let mut ext = TestExternalities::default(); + let mut ext = ext.ext(); let test_code = WASM_BINARY; let code = wabt::wat2wasm(r#" diff --git a/core/executor/src/wasmi_execution.rs b/core/executor/src/wasmi_execution.rs index ba7738a993..2b832b4906 100644 --- a/core/executor/src/wasmi_execution.rs +++ b/core/executor/src/wasmi_execution.rs @@ -681,6 +681,7 @@ mod tests { #[test] fn returning_should_work() { let mut ext = TestExternalities::default(); + let mut ext = ext.ext(); let test_code = WASM_BINARY; let output = call(&mut ext, 8, &test_code[..], "test_empty_return", &[]).unwrap(); @@ -690,6 +691,7 @@ mod tests { #[test] fn panicking_should_work() { let mut ext = TestExternalities::default(); + let mut ext = ext.ext(); let test_code = WASM_BINARY; let output = call(&mut ext, 8, &test_code[..], "test_panic", &[]); @@ -705,18 +707,22 @@ mod tests { #[test] fn storage_should_work() { let mut ext = TestExternalities::default(); - ext.set_storage(b"foo".to_vec(), b"bar".to_vec()); - let test_code = WASM_BINARY; - let output = call( - &mut ext, - 8, - &test_code[..], - "test_data_in", - &b"Hello world".to_vec().encode(), - ).unwrap(); + { + let mut ext = ext.ext(); + ext.set_storage(b"foo".to_vec(), b"bar".to_vec()); + let test_code = WASM_BINARY; + + let output = call( + &mut ext, + 8, + &test_code[..], + "test_data_in", + &b"Hello world".to_vec().encode(), + ).unwrap(); - assert_eq!(output, b"all ok!".to_vec().encode()); + assert_eq!(output, b"all ok!".to_vec().encode()); + } let expected = TestExternalities::new((map![ b"input".to_vec() => b"Hello world".to_vec(), @@ -729,23 +735,26 @@ mod tests { #[test] fn clear_prefix_should_work() { let mut ext = TestExternalities::default(); - ext.set_storage(b"aaa".to_vec(), b"1".to_vec()); - ext.set_storage(b"aab".to_vec(), b"2".to_vec()); - ext.set_storage(b"aba".to_vec(), b"3".to_vec()); - ext.set_storage(b"abb".to_vec(), b"4".to_vec()); - ext.set_storage(b"bbb".to_vec(), b"5".to_vec()); - let test_code = WASM_BINARY; - - // This will clear all entries which prefix is "ab". - let output = call( - &mut ext, - 8, - &test_code[..], - "test_clear_prefix", - &b"ab".to_vec().encode(), - ).unwrap(); + { + let mut ext = ext.ext(); + ext.set_storage(b"aaa".to_vec(), b"1".to_vec()); + ext.set_storage(b"aab".to_vec(), b"2".to_vec()); + ext.set_storage(b"aba".to_vec(), b"3".to_vec()); + ext.set_storage(b"abb".to_vec(), b"4".to_vec()); + ext.set_storage(b"bbb".to_vec(), b"5".to_vec()); + let test_code = WASM_BINARY; + + // This will clear all entries which prefix is "ab". + let output = call( + &mut ext, + 8, + &test_code[..], + "test_clear_prefix", + &b"ab".to_vec().encode(), + ).unwrap(); - assert_eq!(output, b"all ok!".to_vec().encode()); + assert_eq!(output, b"all ok!".to_vec().encode()); + } let expected = TestExternalities::new((map![ b"aaa".to_vec() => b"1".to_vec(), @@ -758,6 +767,7 @@ mod tests { #[test] fn blake2_256_should_work() { let mut ext = TestExternalities::default(); + let mut ext = ext.ext(); let test_code = WASM_BINARY; assert_eq!( call(&mut ext, 8, &test_code[..], "test_blake2_256", &[0]).unwrap(), @@ -778,6 +788,7 @@ mod tests { #[test] fn blake2_128_should_work() { let mut ext = TestExternalities::default(); + let mut ext = ext.ext(); let test_code = WASM_BINARY; assert_eq!( call(&mut ext, 8, &test_code[..], "test_blake2_128", &[0]).unwrap(), @@ -798,6 +809,7 @@ mod tests { #[test] fn twox_256_should_work() { let mut ext = TestExternalities::default(); + let mut ext = ext.ext(); let test_code = WASM_BINARY; assert_eq!( call(&mut ext, 8, &test_code[..], "test_twox_256", &[0]).unwrap(), @@ -822,6 +834,7 @@ mod tests { #[test] fn twox_128_should_work() { let mut ext = TestExternalities::default(); + let mut ext = ext.ext(); let test_code = WASM_BINARY; assert_eq!( call(&mut ext, 8, &test_code[..], "test_twox_128", &[0]).unwrap(), @@ -842,6 +855,7 @@ mod tests { #[test] fn ed25519_verify_should_work() { let mut ext = TestExternalities::default(); + let mut ext = ext.ext(); let test_code = WASM_BINARY; let key = ed25519::Pair::from_seed(&blake2_256(b"test")); let sig = key.sign(b"all ok!"); @@ -868,6 +882,7 @@ mod tests { #[test] fn sr25519_verify_should_work() { let mut ext = TestExternalities::default(); + let mut ext = ext.ext(); let test_code = WASM_BINARY; let key = sr25519::Pair::from_seed(&blake2_256(b"test")); let sig = key.sign(b"all ok!"); @@ -894,6 +909,7 @@ mod tests { #[test] fn ordered_trie_root_should_work() { let mut ext = TestExternalities::default(); + let mut ext = ext.ext(); let trie_input = vec![b"zero".to_vec(), b"one".to_vec(), b"two".to_vec()]; let test_code = WASM_BINARY; assert_eq!( @@ -910,6 +926,7 @@ mod tests { let (offchain, state) = testing::TestOffchainExt::new(); ext.register_extension(OffchainExt::new(offchain)); let test_code = WASM_BINARY; + let mut ext = ext.ext(); assert_eq!( call(&mut ext, 8, &test_code[..], "test_offchain_local_storage", &[0]).unwrap(), true.encode(), @@ -937,6 +954,7 @@ mod tests { ); let test_code = WASM_BINARY; + let mut ext = ext.ext(); assert_eq!( call(&mut ext, 8, &test_code[..], "test_offchain_http", &[0]).unwrap(), true.encode(), diff --git a/core/state-machine/src/ext.rs b/core/state-machine/src/ext.rs index 3433aee92c..0e93302a95 100644 --- a/core/state-machine/src/ext.rs +++ b/core/state-machine/src/ext.rs @@ -32,7 +32,6 @@ use trie::{trie_types::Layout, MemoryDB, default_child_trie_root}; use externalities::Extensions; use std::{error, fmt, any::{Any, TypeId}}; - use log::{warn, trace}; const EXT_NOT_ALLOWED_TO_FAIL: &str = "Externalities not allowed to fail within runtime"; @@ -99,6 +98,7 @@ where T: 'a + ChangesTrieStorage, N: crate::changes_trie::BlockNumber, { + /// Create a new `Ext` from overlayed changes and read-only backend pub fn new( overlay: &'a mut OverlayedChanges, @@ -467,16 +467,22 @@ where } else { let storage_key = storage_key.as_ref(); - let delta = self.overlay.committed.children.get(storage_key) - .into_iter() - .flat_map(|map| map.iter().map(|(k, v)| (k.clone(), v.value.clone()))) - .chain(self.overlay.prospective.children.get(storage_key) - .into_iter() - .flat_map(|map| map.clone().into_iter().map(|(k, v)| (k.clone(), v.value.clone())))); - - let root = self.backend.child_storage_root(storage_key, delta).0; - - self.overlay.set_storage(storage_key.to_vec(), Some(root.to_vec())); + let (root, is_empty, _) = { + let delta = self.overlay.committed.children.get(storage_key) + .into_iter() + .flat_map(|map| map.clone().into_iter().map(|(k, v)| (k, v.value))) + .chain(self.overlay.prospective.children.get(storage_key) + .into_iter() + .flat_map(|map| map.clone().into_iter().map(|(k, v)| (k, v.value)))); + + self.backend.child_storage_root(storage_key, delta) + }; + + if is_empty { + self.overlay.set_storage(storage_key.into(), None); + } else { + self.overlay.set_storage(storage_key.into(), Some(root.clone())); + } trace!(target: "state-trace", "{:04x}: ChildRoot({}) {}", self.id, diff --git a/core/state-machine/src/testing.rs b/core/state-machine/src/testing.rs index ca89921ff0..16ff62020b 100644 --- a/core/state-machine/src/testing.rs +++ b/core/state-machine/src/testing.rs @@ -21,22 +21,20 @@ use hash_db::Hasher; use crate::{ backend::{InMemory, Backend}, OverlayedChanges, changes_trie::{ - build_changes_trie, InMemoryStorage as ChangesTrieInMemoryStorage, + InMemoryStorage as ChangesTrieInMemoryStorage, BlockNumber as ChangesTrieBlockNumber, }, + ext::Ext, }; use primitives::{ storage::{ - ChildStorageKey, well_known_keys::{CHANGES_TRIE_CONFIG, CODE, HEAP_PAGES, is_child_storage_key} }, - traits::Externalities, hash::H256, Blake2Hasher, + hash::H256, Blake2Hasher, }; use codec::Encode; use externalities::{Extensions, Extension}; -const EXT_NOT_ALLOWED_TO_FAIL: &str = "Externalities not allowed to fail within runtime"; - type StorageTuple = (HashMap, Vec>, HashMap, HashMap, Vec>>); /// Simple HashMap-based Externalities impl. @@ -48,6 +46,17 @@ pub struct TestExternalities=Blake2Hasher, N: ChangesTrieBlo } impl, N: ChangesTrieBlockNumber> TestExternalities { + + /// Get externalities implementation. + pub fn ext(&mut self) -> Ext, ChangesTrieInMemoryStorage> { + Ext::new( + &mut self.overlay, + &self.backend, + Some(&self.changes_trie_storage), + Some(&mut self.extensions), + ) + } + /// Create a new instance of `TestExternalities` with storage. pub fn new(storage: StorageTuple) -> Self { Self::new_with_code(&[], storage) @@ -118,7 +127,8 @@ impl, N: ChangesTrieBlockNumber> TestExternalities { /// /// Returns the result of the given closure. pub fn execute_with(&mut self, execute: impl FnOnce() -> R) -> R { - externalities::set_and_run_with_externalities(self, execute) + let mut ext = self.ext(); + externalities::set_and_run_with_externalities(&mut ext, execute) } } @@ -146,156 +156,6 @@ impl, N: ChangesTrieBlockNumber> From for Test } } -impl Externalities for TestExternalities where - H: Hasher, - N: ChangesTrieBlockNumber, -{ - fn storage(&self, key: &[u8]) -> Option> { - self.overlay.storage(key).map(|x| x.map(|x| x.to_vec())).unwrap_or_else(|| - self.backend.storage(key).expect(EXT_NOT_ALLOWED_TO_FAIL)) - } - - fn storage_hash(&self, key: &[u8]) -> Option { - self.storage(key).map(|v| H::hash(&v)) - } - - fn original_storage(&self, key: &[u8]) -> Option> { - self.backend.storage(key).expect(EXT_NOT_ALLOWED_TO_FAIL) - } - - fn original_storage_hash(&self, key: &[u8]) -> Option { - self.storage_hash(key) - } - - fn child_storage(&self, storage_key: ChildStorageKey, key: &[u8]) -> Option> { - self.overlay - .child_storage(storage_key.as_ref(), key) - .map(|x| x.map(|x| x.to_vec())) - .unwrap_or_else(|| self.backend - .child_storage(storage_key.as_ref(), key) - .expect(EXT_NOT_ALLOWED_TO_FAIL) - ) - } - - fn child_storage_hash(&self, storage_key: ChildStorageKey, key: &[u8]) -> Option { - self.child_storage(storage_key, key).map(|v| H::hash(&v)) - } - - fn original_child_storage(&self, storage_key: ChildStorageKey, key: &[u8]) -> Option> { - self.backend - .child_storage(storage_key.as_ref(), key) - .map(|x| x.map(|x| x.to_vec())) - .expect(EXT_NOT_ALLOWED_TO_FAIL) - } - - fn original_child_storage_hash(&self, storage_key: ChildStorageKey, key: &[u8]) -> Option { - self.child_storage_hash(storage_key, key) - } - - fn place_storage(&mut self, key: Vec, maybe_value: Option>) { - if is_child_storage_key(&key) { - panic!("Refuse to directly set child storage key"); - } - - self.overlay.set_storage(key, maybe_value); - } - - fn place_child_storage( - &mut self, - storage_key: ChildStorageKey, - key: Vec, - value: Option>, - ) { - self.overlay.set_child_storage(storage_key.into_owned(), key, value); - } - - fn kill_child_storage(&mut self, storage_key: ChildStorageKey) { - let backend = &self.backend; - let overlay = &mut self.overlay; - - overlay.clear_child_storage(storage_key.as_ref()); - backend.for_keys_in_child_storage(storage_key.as_ref(), |key| { - overlay.set_child_storage(storage_key.as_ref().to_vec(), key.to_vec(), None); - }); - } - - fn clear_prefix(&mut self, prefix: &[u8]) { - if is_child_storage_key(prefix) { - panic!("Refuse to directly clear prefix that is part of child storage key"); - } - - self.overlay.clear_prefix(prefix); - - let backend = &self.backend; - let overlay = &mut self.overlay; - backend.for_keys_with_prefix(prefix, |key| { - overlay.set_storage(key.to_vec(), None); - }); - } - - fn clear_child_prefix(&mut self, storage_key: ChildStorageKey, prefix: &[u8]) { - self.overlay.clear_child_prefix(storage_key.as_ref(), prefix); - - let backend = &self.backend; - let overlay = &mut self.overlay; - backend.for_child_keys_with_prefix(storage_key.as_ref(), prefix, |key| { - overlay.set_child_storage(storage_key.as_ref().to_vec(), key.to_vec(), None); - }); - } - - fn chain_id(&self) -> u64 { 42 } - - fn storage_root(&mut self) -> H256 { - let child_storage_keys = - self.overlay.prospective.children.keys() - .chain(self.overlay.committed.children.keys()); - - let child_delta_iter = child_storage_keys.map(|storage_key| - (storage_key.clone(), self.overlay.committed.children.get(storage_key) - .into_iter() - .flat_map(|map| map.iter().map(|(k, v)| (k.clone(), v.value.clone()))) - .chain(self.overlay.prospective.children.get(storage_key) - .into_iter() - .flat_map(|map| map.iter().map(|(k, v)| (k.clone(), v.value.clone())))))); - - - // compute and memoize - let delta = self.overlay.committed.top.iter().map(|(k, v)| (k.clone(), v.value.clone())) - .chain(self.overlay.prospective.top.iter().map(|(k, v)| (k.clone(), v.value.clone()))); - self.backend.full_storage_root(delta, child_delta_iter).0 - } - - fn child_storage_root(&mut self, storage_key: ChildStorageKey) -> Vec { - let storage_key = storage_key.as_ref(); - - let (root, is_empty, _) = { - let delta = self.overlay.committed.children.get(storage_key) - .into_iter() - .flat_map(|map| map.clone().into_iter().map(|(k, v)| (k, v.value))) - .chain(self.overlay.prospective.children.get(storage_key) - .into_iter() - .flat_map(|map| map.clone().into_iter().map(|(k, v)| (k, v.value)))); - - self.backend.child_storage_root(storage_key, delta) - }; - if is_empty { - self.overlay.set_storage(storage_key.into(), None); - } else { - self.overlay.set_storage(storage_key.into(), Some(root.clone())); - } - root - } - - fn storage_changes_root(&mut self, parent: H256) -> Result, ()> { - Ok(build_changes_trie::<_, _, H, N>( - &self.backend, - Some(&self.changes_trie_storage), - &self.overlay, - parent, - )?.map(|(_, root, _)| root)) - } -} - impl externalities::ExtensionStore for TestExternalities where H: Hasher, N: ChangesTrieBlockNumber, @@ -308,12 +168,13 @@ impl externalities::ExtensionStore for TestExternalities where #[cfg(test)] mod tests { use super::*; - use primitives::{Blake2Hasher, H256}; + use primitives::traits::Externalities; use hex_literal::hex; #[test] fn commit_should_work() { let mut ext = TestExternalities::::default(); + let mut ext = ext.ext(); ext.set_storage(b"doe".to_vec(), b"reindeer".to_vec()); ext.set_storage(b"dog".to_vec(), b"puppy".to_vec()); ext.set_storage(b"dogglesworth".to_vec(), b"cat".to_vec()); @@ -324,6 +185,7 @@ mod tests { #[test] fn set_and_retrieve_code() { let mut ext = TestExternalities::::default(); + let mut ext = ext.ext(); let code = vec![1, 2, 3]; ext.set_storage(CODE.to_vec(), code.clone()); diff --git a/core/state-machine/src/trie_backend.rs b/core/state-machine/src/trie_backend.rs index ce5773c0b7..432ccf3e75 100644 --- a/core/state-machine/src/trie_backend.rs +++ b/core/state-machine/src/trie_backend.rs @@ -168,7 +168,7 @@ impl, H: Hasher> Backend for TrieBackend where let mut write_overlay = S::Overlay::default(); let mut root = match self.storage(storage_key) { - Ok(value) => value.unwrap_or(default_child_trie_root::>(storage_key)), + Ok(value) => value.unwrap_or(default_root.clone()), Err(e) => { warn!(target: "trie", "Failed to read child storage root: {}", e); default_root.clone() diff --git a/core/test-runtime/src/system.rs b/core/test-runtime/src/system.rs index d06bef5923..fc4de0ce4b 100644 --- a/core/test-runtime/src/system.rs +++ b/core/test-runtime/src/system.rs @@ -376,8 +376,9 @@ mod tests { #[test] fn block_import_works_wasm() { block_import_works(|b, ext| { + let mut ext = ext.ext(); executor().call::<_, NeverNativeValue, fn() -> _>( - ext, + &mut ext, "Core_execute_block", &b.encode(), false, @@ -468,8 +469,9 @@ mod tests { #[test] fn block_import_with_transaction_works_wasm() { block_import_with_transaction_works(|b, ext| { + let mut ext = ext.ext(); executor().call::<_, NeverNativeValue, fn() -> _>( - ext, + &mut ext, "Core_execute_block", &b.encode(), false, diff --git a/node/executor/src/lib.rs b/node/executor/src/lib.rs index 3558987716..3c97b3cd11 100644 --- a/node/executor/src/lib.rs +++ b/node/executor/src/lib.rs @@ -34,6 +34,7 @@ native_executor_instance!( #[cfg(test)] mod tests { + use substrate_executor::error::Result; use super::Executor; use {balances, contracts, indices, system, timestamp}; use codec::{Encode, Decode, Joiner}; @@ -122,6 +123,26 @@ mod tests { ext.place_storage(well_known_keys::HEAP_PAGES.to_vec(), Some(heap_pages.encode())); } + fn executor_call< + R:Decode + Encode + PartialEq, + NC: FnOnce() -> std::result::Result + std::panic::UnwindSafe + >( + t: &mut TestExternalities, + method: &str, + data: &[u8], + use_native: bool, + native_call: Option, + ) -> (Result>, bool) { + let mut t = t.ext(); + executor().call::<_, R, NC>( + &mut t, + method, + data, + use_native, + native_call, + ) + } + #[test] fn panic_execution_with_foreign_code_gives_error() { let mut t = TestExternalities::::new_with_code(BLOATY_CODE, (map![ @@ -139,7 +160,7 @@ mod tests { } ], map![])); - let r = executor().call::<_, NeverNativeValue, fn() -> _>( + let r = executor_call:: _>( &mut t, "Core_initialize_block", &vec![].and(&from_block_number(1u32)), @@ -147,7 +168,7 @@ mod tests { None, ).0; assert!(r.is_ok()); - let v = executor().call::<_, NeverNativeValue, fn() -> _>( + let v = executor_call:: _>( &mut t, "BlockBuilder_apply_extrinsic", &vec![].and(&xt()), @@ -175,7 +196,7 @@ mod tests { } ], map![])); - let r = executor().call::<_, NeverNativeValue, fn() -> _>( + let r = executor_call:: _>( &mut t, "Core_initialize_block", &vec![].and(&from_block_number(1u32)), @@ -183,7 +204,7 @@ mod tests { None, ).0; assert!(r.is_ok()); - let v = executor().call::<_, NeverNativeValue, fn() -> _>( + let v = executor_call:: _>( &mut t, "BlockBuilder_apply_extrinsic", &vec![].and(&xt()), @@ -207,7 +228,7 @@ mod tests { >::hashed_key_for(0) => vec![0u8; 32] ], map![])); - let r = executor().call::<_, NeverNativeValue, fn() -> _>( + let r = executor_call:: _>( &mut t, "Core_initialize_block", &vec![].and(&from_block_number(1u32)), @@ -218,7 +239,7 @@ mod tests { let fm = t.execute_with(TransactionPayment::next_fee_multiplier); - let r = executor().call::<_, NeverNativeValue, fn() -> _>( + let r = executor_call:: _>( &mut t, "BlockBuilder_apply_extrinsic", &vec![].and(&xt()), @@ -246,7 +267,7 @@ mod tests { >::hashed_key_for(0) => vec![0u8; 32] ], map![])); - let r = executor().call::<_, NeverNativeValue, fn() -> _>( + let r = executor_call:: _>( &mut t, "Core_initialize_block", &vec![].and(&from_block_number(1u32)), @@ -257,7 +278,7 @@ mod tests { let fm = t.execute_with(TransactionPayment::next_fee_multiplier); - let r = executor().call::<_, NeverNativeValue, fn() -> _>( + let r = executor_call:: _>( &mut t, "BlockBuilder_apply_extrinsic", &vec![].and(&xt()), @@ -307,7 +328,7 @@ mod tests { }; // execute the block to get the real header. - executor().call::<_, NeverNativeValue, fn() -> _>( + executor_call:: _>( env, "Core_initialize_block", &header.encode(), @@ -316,7 +337,7 @@ mod tests { ).0.unwrap(); for i in extrinsics.iter() { - executor().call::<_, NeverNativeValue, fn() -> _>( + executor_call:: _>( env, "BlockBuilder_apply_extrinsic", &i.encode(), @@ -325,7 +346,7 @@ mod tests { ).0.unwrap(); } - let header = match executor().call::<_, NeverNativeValue, fn() -> _>( + let header = match executor_call:: _>( env, "BlockBuilder_finalize_block", &[0u8;0], @@ -432,7 +453,7 @@ mod tests { let mut alice_last_known_balance: Balance = Default::default(); let mut fm = t.execute_with(TransactionPayment::next_fee_multiplier); - executor().call::<_, NeverNativeValue, fn() -> _>( + executor_call:: _>( &mut t, "Core_execute_block", &block1.0, @@ -471,7 +492,7 @@ mod tests { fm = t.execute_with(TransactionPayment::next_fee_multiplier); - executor().call::<_, NeverNativeValue, fn() -> _>( + executor_call:: _>( &mut t, "Core_execute_block", &block2.0, @@ -544,7 +565,7 @@ mod tests { let mut alice_last_known_balance: Balance = Default::default(); let mut fm = t.execute_with(TransactionPayment::next_fee_multiplier); - executor().call::<_, NeverNativeValue, fn() -> _>( + executor_call:: _>( &mut t, "Core_execute_block", &block1.0, @@ -560,7 +581,7 @@ mod tests { fm = t.execute_with(TransactionPayment::next_fee_multiplier); - executor().call::<_, NeverNativeValue, fn() -> _>( + executor_call:: _>( &mut t, "Core_execute_block", &block2.0, @@ -720,7 +741,7 @@ mod tests { let mut t = new_test_ext(COMPACT_CODE, false); - executor().call::<_, NeverNativeValue, fn() -> _>( + executor_call:: _>( &mut t, "Core_execute_block", &b.0, @@ -744,9 +765,9 @@ mod tests { fn wasm_big_block_import_fails() { let mut t = new_test_ext(COMPACT_CODE, false); - set_heap_pages(&mut t, 4); + set_heap_pages(&mut t.ext(), 4); - let result = executor().call::<_, NeverNativeValue, fn() -> _>( + let result = executor_call:: _>( &mut t, "Core_execute_block", &block_with_size(42, 0, 120_000).0, @@ -760,7 +781,7 @@ mod tests { fn native_big_block_import_succeeds() { let mut t = new_test_ext(COMPACT_CODE, false); - executor().call::<_, NeverNativeValue, fn() -> _>( + executor_call:: _>( &mut t, "Core_execute_block", &block_with_size(42, 0, 120_000).0, @@ -774,7 +795,7 @@ mod tests { let mut t = new_test_ext(COMPACT_CODE, false); assert!( - executor().call::<_, NeverNativeValue, fn() -> _>( + executor_call:: _>( &mut t, "Core_execute_block", &block_with_size(42, 0, 120_000).0, @@ -797,7 +818,7 @@ mod tests { >::hashed_key_for(0) => vec![0u8; 32] ], map![])); - let r = executor().call::<_, NeverNativeValue, fn() -> _>( + let r = executor_call:: _>( &mut t, "Core_initialize_block", &vec![].and(&from_block_number(1u32)), @@ -805,7 +826,7 @@ mod tests { None, ).0; assert!(r.is_ok()); - let r = executor().call::<_, NeverNativeValue, fn() -> _>( + let r = executor_call:: _>( &mut t, "BlockBuilder_apply_extrinsic", &vec![].and(&xt()), @@ -829,7 +850,7 @@ mod tests { >::hashed_key_for(0) => vec![0u8; 32] ], map![])); - let r = executor().call::<_, NeverNativeValue, fn() -> _>( + let r = executor_call:: _>( &mut t, "Core_initialize_block", &vec![].and(&from_block_number(1u32)), @@ -838,7 +859,7 @@ mod tests { ).0; assert!(r.is_ok()); let fm = t.execute_with(TransactionPayment::next_fee_multiplier); - let r = executor().call::<_, NeverNativeValue, fn() -> _>( + let r = executor_call:: _>( &mut t, "BlockBuilder_apply_extrinsic", &vec![].and(&xt()), @@ -863,7 +884,7 @@ mod tests { let block = Block::decode(&mut &block_data[..]).unwrap(); let mut t = new_test_ext(COMPACT_CODE, true); - executor().call::<_, NeverNativeValue, fn() -> _>( + executor_call:: _>( &mut t, "Core_execute_block", &block.encode(), @@ -871,7 +892,7 @@ mod tests { None, ).0.unwrap(); - assert!(t.storage_changes_root(GENESIS_HASH.into()).unwrap().is_some()); + assert!(t.ext().storage_changes_root(GENESIS_HASH.into()).unwrap().is_some()); } #[test] @@ -879,7 +900,7 @@ mod tests { let block1 = changes_trie_block(); let mut t = new_test_ext(COMPACT_CODE, true); - executor().call::<_, NeverNativeValue, fn() -> _>( + executor_call:: _>( &mut t, "Core_execute_block", &block1.0, @@ -887,7 +908,7 @@ mod tests { None, ).0.unwrap(); - assert!(t.storage_changes_root(GENESIS_HASH.into()).unwrap().is_some()); + assert!(t.ext().storage_changes_root(GENESIS_HASH.into()).unwrap().is_some()); } #[test] @@ -953,7 +974,7 @@ mod tests { println!("++ Block 1 size: {} / Block 2 size {}", block1.0.encode().len(), block2.0.encode().len()); // execute a big block. - executor().call::<_, NeverNativeValue, fn() -> _>( + executor_call:: _>( &mut t, "Core_execute_block", &block1.0, @@ -970,7 +991,7 @@ mod tests { }); // execute a big block. - executor().call::<_, NeverNativeValue, fn() -> _>( + executor_call:: _>( &mut t, "Core_execute_block", &block2.0, @@ -1015,7 +1036,7 @@ mod tests { function: Call::Balances(default_transfer_call()), }); - let r = executor().call::<_, NeverNativeValue, fn() -> _>( + let r = executor_call:: _>( &mut t, "Core_initialize_block", &vec![].and(&from_block_number(1u32)), @@ -1024,7 +1045,7 @@ mod tests { ).0; assert!(r.is_ok()); - let r = executor().call::<_, NeverNativeValue, fn() -> _>( + let r = executor_call:: _>( &mut t, "BlockBuilder_apply_extrinsic", &vec![].and(&xt.clone()), @@ -1109,7 +1130,7 @@ mod tests { len / 1024 / 1024, ); - let r = executor().call::<_, NeverNativeValue, fn() -> _>( + let r = executor_call:: _>( &mut t, "Core_execute_block", &block.0, @@ -1173,7 +1194,7 @@ mod tests { len / 1024 / 1024, ); - let r = executor().call::<_, NeverNativeValue, fn() -> _>( + let r = executor_call:: _>( &mut t, "Core_execute_block", &block.0, -- GitLab From 71c7b680790e634327b0c826c058a7ac30509aa9 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Fri, 18 Oct 2019 12:41:57 +0200 Subject: [PATCH 055/167] Update CONTRIBUTING.adoc (#3842) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update CONTRIBUTING.adoc * fix typos * Update CONTRIBUTING.adoc Co-Authored-By: André Silva --- CONTRIBUTING.adoc | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTING.adoc b/CONTRIBUTING.adoc index 1de4820a11..817e1d7489 100644 --- a/CONTRIBUTING.adoc +++ b/CONTRIBUTING.adoc @@ -26,6 +26,7 @@ Merging pull requests once CI is successful: - it is an urgent fix with no large change to logic, then it may be merged after a non-author contributor has approved the review once CI is complete. . Once a PR is ready for review please add the https://github.com/paritytech/substrate/pulls?q=is%3Apr+is%3Aopen+label%3AA0-pleasereview[`pleasereview`] label. Generally PRs should sit with this label for 48 hours in order to garner feedback. It may be merged before if all relevant parties had a look at it. +. If the first review is not an approval, swap `A0-pleasereview` to any label `[A3, A7]` to indicate that the PR has received some feedback, but needs further work. For example. https://github.com/paritytech/substrate/labels/A3-inprogress[`A3-inprogress`] is a general indicator that the PR is work in progress and https://github.com/paritytech/substrate/labels/A4-gotissues[`A4-gotissues`] means that it has significant problems that need fixing. Once the work is done, change the label back to `A0-pleasereview`. You might end up swapping a few times back and forth to climb up the A label group. Once a PR is https://github.com/paritytech/substrate/labels/A8-looksgood[`A8-looksgood`], it is ready to merge. . PRs that break the external API must be tagged with https://github.com/paritytech/substrate/labels/B2-breaksapi[`breaksapi`], when it changes the SRML or consensus of running system with https://github.com/paritytech/substrate/labels/B3-breaksconsensus[`breaksconsensus`] . No PR should be merged until all reviews' comments are addressed. -- GitLab From a2071c47c7f923407cc4ea0091db9eb3b5a42fbe Mon Sep 17 00:00:00 2001 From: Xiliang Chen Date: Fri, 18 Oct 2019 23:58:05 +1300 Subject: [PATCH 056/167] remove unused file (#3851) --- srml/council/src/lib.rs | 279 ---------------------------------------- 1 file changed, 279 deletions(-) delete mode 100644 srml/council/src/lib.rs diff --git a/srml/council/src/lib.rs b/srml/council/src/lib.rs deleted file mode 100644 index 195202c873..0000000000 --- a/srml/council/src/lib.rs +++ /dev/null @@ -1,279 +0,0 @@ -// Copyright 2017-2019 Parity Technologies (UK) Ltd. -// This file is part of Substrate. - -// Substrate is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Substrate is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Substrate. If not, see . - -//! Council system: Handles the voting in and maintenance of council members. - -#![cfg_attr(not(feature = "std"), no_std)] -#![recursion_limit="128"] - -pub mod motions; -pub mod seats; - -pub use crate::seats::{Trait, Module, RawEvent, Event, VoteIndex}; - -/// Trait for type that can handle incremental changes to a set of account IDs. -pub trait OnMembersChanged { - /// A number of members `new` just joined the set and replaced some `old` ones. - fn on_members_changed(new: &[AccountId], old: &[AccountId]); -} - -impl OnMembersChanged for () { - fn on_members_changed(_new: &[T], _old: &[T]) {} -} - -#[cfg(test)] -mod tests { - // These re-exports are here for a reason, edit with care - pub use super::*; - use support::{impl_outer_origin, impl_outer_event, impl_outer_dispatch, parameter_types}; - use support::traits::Get; - pub use primitives::{H256, Blake2Hasher, u32_trait::{_1, _2, _3, _4}}; - pub use sr_primitives::traits::{BlakeTwo256, IdentityLookup}; - pub use sr_primitives::testing::{Digest, DigestItem, Header}; - pub use sr_primitives::Perbill; - pub use {seats, motions}; - use std::cell::RefCell; - - impl_outer_origin! { - pub enum Origin for Test { - motions - } - } - - impl_outer_event! { - pub enum Event for Test { - balances, democracy, seats, motions, - } - } - - impl_outer_dispatch! { - pub enum Call for Test where origin: Origin { - type Error = Error; - - balances::Balances, - democracy::Democracy, - } - } - - thread_local! { - static VOTER_BOND: RefCell = RefCell::new(0); - static VOTING_FEE: RefCell = RefCell::new(0); - static PRESENT_SLASH_PER_VOTER: RefCell = RefCell::new(0); - static DECAY_RATIO: RefCell = RefCell::new(0); - } - - pub struct VotingBond; - impl Get for VotingBond { - fn get() -> u64 { VOTER_BOND.with(|v| *v.borrow()) } - } - - pub struct VotingFee; - impl Get for VotingFee { - fn get() -> u64 { VOTING_FEE.with(|v| *v.borrow()) } - } - - pub struct PresentSlashPerVoter; - impl Get for PresentSlashPerVoter { - fn get() -> u64 { PRESENT_SLASH_PER_VOTER.with(|v| *v.borrow()) } - } - - pub struct DecayRatio; - impl Get for DecayRatio { - fn get() -> u32 { DECAY_RATIO.with(|v| *v.borrow()) } - } - - // Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted. - #[derive(Clone, Eq, PartialEq, Debug)] - pub struct Test; - parameter_types! { - pub const BlockHashCount: u64 = 250; - pub const MaximumBlockWeight: u32 = 1024; - pub const MaximumBlockLength: u32 = 2 * 1024; - pub const AvailableBlockRatio: Perbill = Perbill::one(); - } - 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; - type Lookup = IdentityLookup; - type Header = Header; - type Event = Event; - type Error = Error; - type BlockHashCount = BlockHashCount; - type MaximumBlockWeight = MaximumBlockWeight; - type MaximumBlockLength = MaximumBlockLength; - type AvailableBlockRatio = AvailableBlockRatio; - type Version = (); - } - parameter_types! { - pub const ExistentialDeposit: u64 = 0; - pub const TransferFee: u64 = 0; - pub const CreationFee: u64 = 0; - } - impl balances::Trait for Test { - type Balance = u64; - type OnNewAccount = (); - type OnFreeBalanceZero = (); - type Event = Event; - type TransferPayment = (); - type DustRemoval = (); - type Error = Error; - type ExistentialDeposit = ExistentialDeposit; - type TransferFee = TransferFee; - type CreationFee = CreationFee; - } - parameter_types! { - pub const LaunchPeriod: u64 = 1; - pub const VotingPeriod: u64 = 3; - pub const MinimumDeposit: u64 = 1; - pub const EnactmentPeriod: u64 = 0; - pub const CooloffPeriod: u64 = 2; - } - impl democracy::Trait for Test { - type Proposal = Call; - type Event = Event; - type Currency = balances::Module; - type EnactmentPeriod = EnactmentPeriod; - type LaunchPeriod = LaunchPeriod; - type EmergencyVotingPeriod = VotingPeriod; - type VotingPeriod = VotingPeriod; - type MinimumDeposit = MinimumDeposit; - type ExternalOrigin = motions::EnsureProportionAtLeast<_1, _2, u64>; - type ExternalMajorityOrigin = motions::EnsureProportionAtLeast<_2, _3, u64>; - type EmergencyOrigin = motions::EnsureProportionAtLeast<_1, _1, u64>; - type CancellationOrigin = motions::EnsureProportionAtLeast<_2, _3, u64>; - type VetoOrigin = motions::EnsureMember; - type CooloffPeriod = CooloffPeriod; - } - parameter_types! { - pub const CandidacyBond: u64 = 3; - pub const CarryCount: u32 = 2; - pub const InactiveGracePeriod: u32 = 1; - pub const CouncilVotingPeriod: u64 = 4; - } - impl seats::Trait for Test { - type Event = Event; - type BadPresentation = (); - type BadReaper = (); - type BadVoterIndex = (); - type LoserCandidate = (); - type OnMembersChanged = CouncilMotions; - type CandidacyBond = CandidacyBond; - type VotingBond = VotingBond; - type VotingFee = VotingFee; - type PresentSlashPerVoter = PresentSlashPerVoter; - type CarryCount = CarryCount; - type InactiveGracePeriod = InactiveGracePeriod; - type CouncilVotingPeriod = CouncilVotingPeriod; - type DecayRatio = DecayRatio; - } - impl motions::Trait for Test { - type Origin = Origin; - type Proposal = Call; - type Event = Event; - } - - pub struct ExtBuilder { - balance_factor: u64, - decay_ratio: u32, - voting_fee: u64, - voter_bond: u64, - bad_presentation_punishment: u64, - with_council: bool, - } - - impl Default for ExtBuilder { - fn default() -> Self { - Self { - balance_factor: 1, - decay_ratio: 24, - voting_fee: 0, - voter_bond: 0, - bad_presentation_punishment: 1, - with_council: false, - } - } - } - - impl ExtBuilder { - pub fn with_council(mut self, council: bool) -> Self { - self.with_council = council; - self - } - pub fn balance_factor(mut self, factor: u64) -> Self { - self.balance_factor = factor; - self - } - pub fn decay_ratio(mut self, ratio: u32) -> Self { - self.decay_ratio = ratio; - self - } - pub fn voting_fee(mut self, fee: u64) -> Self { - self.voting_fee = fee; - self - } - pub fn bad_presentation_punishment(mut self, fee: u64) -> Self { - self.bad_presentation_punishment = fee; - self - } - pub fn voter_bond(mut self, fee: u64) -> Self { - self.voter_bond = fee; - self - } - pub fn set_associated_consts(&self) { - VOTER_BOND.with(|v| *v.borrow_mut() = self.voter_bond); - VOTING_FEE.with(|v| *v.borrow_mut() = self.voting_fee); - PRESENT_SLASH_PER_VOTER.with(|v| *v.borrow_mut() = self.bad_presentation_punishment); - DECAY_RATIO.with(|v| *v.borrow_mut() = self.decay_ratio); - } - pub fn build(self) -> runtime_io::TestExternalities { - self.set_associated_consts(); - let mut t = system::GenesisConfig::default().build_storage::().unwrap(); - balances::GenesisConfig::{ - balances: vec![ - (1, 10 * self.balance_factor), - (2, 20 * self.balance_factor), - (3, 30 * self.balance_factor), - (4, 40 * self.balance_factor), - (5, 50 * self.balance_factor), - (6, 60 * self.balance_factor) - ], - vesting: vec![], - }.assimilate_storage(&mut t).unwrap(); - seats::GenesisConfig:: { - active_council: if self.with_council { vec![ - (1, 10), - (2, 10), - (3, 10) - ] } else { vec![] }, - desired_seats: 2, - presentation_duration: 2, - term_duration: 5, - }.assimilate_storage(&mut t).unwrap(); - runtime_io::TestExternalities::new(t) - } - } - - pub type System = system::Module; - pub type Balances = balances::Module; - pub type Democracy = democracy::Module; - pub type Council = seats::Module; - pub type CouncilMotions = motions::Module; -} -- GitLab From 5e406b1c18babf2dd102f7f587b7959b277b6496 Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Fri, 18 Oct 2019 19:58:31 +0900 Subject: [PATCH 057/167] Switch node template to use AuRa (#3790) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Stuck on service * Make service compile * Remove Grandpa dependency * Update node-template/runtime/Cargo.toml Co-Authored-By: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Fix build * Update crypto import * Update node-template/src/service.rs Co-Authored-By: André Silva * Update node-template/src/service.rs Co-Authored-By: André Silva * Update node-template/src/service.rs Co-Authored-By: André Silva * Update node-template/src/service.rs Co-Authored-By: André Silva * Update node-template/runtime/src/lib.rs Co-Authored-By: André Silva * Fix macro dependency * Trying to add grandpa back * Update node-template/src/chain_spec.rs Co-Authored-By: André Silva * Update node-template/src/chain_spec.rs Co-Authored-By: André Silva * Update node-template/src/chain_spec.rs Co-Authored-By: André Silva * Update node-template/src/service.rs Co-Authored-By: André Silva * Update node-template/src/service.rs Co-Authored-By: André Silva * Unused import * Use grandpa block import --- Cargo.lock | 8 ++-- node-template/Cargo.toml | 4 +- node-template/README.md | 14 ++++-- node-template/runtime/Cargo.toml | 12 ++--- node-template/runtime/src/lib.rs | 73 +++++++++---------------------- node-template/src/chain_spec.rs | 22 +++++----- node-template/src/cli.rs | 1 + node-template/src/service.rs | 75 ++++++++++++-------------------- 8 files changed, 83 insertions(+), 126 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bba0fc2f6f..8cf8b42bd4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2519,8 +2519,8 @@ dependencies = [ "substrate-basic-authorship 2.0.0", "substrate-cli 2.0.0", "substrate-client 2.0.0", - "substrate-consensus-babe 2.0.0", - "substrate-consensus-babe-primitives 2.0.0", + "substrate-consensus-aura 2.0.0", + "substrate-consensus-aura-primitives 2.0.0", "substrate-executor 2.0.0", "substrate-finality-grandpa 2.0.0", "substrate-finality-grandpa-primitives 2.0.0", @@ -2545,7 +2545,7 @@ dependencies = [ "sr-primitives 2.0.0", "sr-std 2.0.0", "sr-version 2.0.0", - "srml-babe 2.0.0", + "srml-aura 2.0.0", "srml-balances 2.0.0", "srml-executive 2.0.0", "srml-grandpa 2.0.0", @@ -2557,7 +2557,7 @@ dependencies = [ "srml-timestamp 2.0.0", "srml-transaction-payment 2.0.0", "substrate-client 2.0.0", - "substrate-consensus-babe-primitives 2.0.0", + "substrate-consensus-aura-primitives 2.0.0", "substrate-offchain-primitives 2.0.0", "substrate-primitives 2.0.0", "substrate-session 2.0.0", diff --git a/node-template/Cargo.toml b/node-template/Cargo.toml index 2aa305486c..2c01655dc2 100644 --- a/node-template/Cargo.toml +++ b/node-template/Cargo.toml @@ -27,8 +27,8 @@ substrate-service = { path = "../core/service" } inherents = { package = "substrate-inherents", path = "../core/inherents" } transaction-pool = { package = "substrate-transaction-pool", path = "../core/transaction-pool" } network = { package = "substrate-network", path = "../core/network" } -babe = { package = "substrate-consensus-babe", path = "../core/consensus/babe" } -babe-primitives = { package = "substrate-consensus-babe-primitives", path = "../core/consensus/babe/primitives" } +aura = { package = "substrate-consensus-aura", path = "../core/consensus/aura" } +aura-primitives = { package = "substrate-consensus-aura-primitives", path = "../core/consensus/aura/primitives" } grandpa = { package = "substrate-finality-grandpa", path = "../core/finality-grandpa" } grandpa-primitives = { package = "substrate-finality-grandpa-primitives", path = "../core/finality-grandpa/primitives" } substrate-client = { path = "../core/client" } diff --git a/node-template/README.md b/node-template/README.md index 5a59652c1b..c411dbeef5 100644 --- a/node-template/README.md +++ b/node-template/README.md @@ -10,7 +10,7 @@ Install Rust: curl https://sh.rustup.rs -sSf | sh ``` -Install required tools: +Initialize your Wasm Build environment: ```bash ./scripts/init.sh @@ -19,17 +19,23 @@ Install required tools: Build Wasm and native code: ```bash -cargo build +cargo build --release ``` ## Run ### Single node development chain -You can start a development chain with: +Purge any existing developer chain state: ```bash -cargo run -- --dev +./target/release/node-template purge-chain --dev +``` + +Start a development chain with: + +```bash +./target/release/node-template --dev ``` Detailed logs may be shown by running the node with the following environment variables set: `RUST_LOG=debug RUST_BACKTRACE=1 cargo run -- --dev`. diff --git a/node-template/runtime/Cargo.toml b/node-template/runtime/Cargo.toml index 96484c16ae..df9dd9c77f 100644 --- a/node-template/runtime/Cargo.toml +++ b/node-template/runtime/Cargo.toml @@ -15,11 +15,11 @@ support = { package = "srml-support", path = "../../srml/support", default_featu primitives = { package = "substrate-primitives", path = "../../core/primitives", default_features = false } substrate-session = { path = "../../core/session", default-features = false } balances = { package = "srml-balances", path = "../../srml/balances", default_features = false } -babe = { package = "srml-babe", path = "../../srml/babe", default-features = false } -babe-primitives = { package = "substrate-consensus-babe-primitives", path = "../../core/consensus/babe/primitives", default-features = false } +aura = { package = "srml-aura", path = "../../srml/aura", default_features = false } +aura-primitives = { package = "substrate-consensus-aura-primitives", path = "../../core/consensus/aura/primitives", default_features = false } +grandpa = { package = "srml-grandpa", path = "../../srml/grandpa", default_features = false } executive = { package = "srml-executive", path = "../../srml/executive", default_features = false } indices = { package = "srml-indices", path = "../../srml/indices", default_features = false } -grandpa = { package = "srml-grandpa", path = "../../srml/grandpa", default-features = false } randomness-collective-flip = { package = "srml-randomness-collective-flip", path = "../../srml/randomness-collective-flip", default_features = false } system = { package = "srml-system", path = "../../srml/system", default_features = false } timestamp = { package = "srml-timestamp", path = "../../srml/timestamp", default_features = false } @@ -41,11 +41,11 @@ std = [ "runtime-io/std", "support/std", "balances/std", - "babe/std", - "babe-primitives/std", + "aura/std", + "aura-primitives/std", + 'grandpa/std', "executive/std", "indices/std", - "grandpa/std", "primitives/std", "sr-primitives/std", "randomness-collective-flip/std", diff --git a/node-template/runtime/src/lib.rs b/node-template/runtime/src/lib.rs index da49ad4474..acc5143ffe 100644 --- a/node-template/runtime/src/lib.rs +++ b/node-template/runtime/src/lib.rs @@ -16,13 +16,13 @@ use sr_primitives::{ }; use sr_primitives::traits::{NumberFor, BlakeTwo256, Block as BlockT, StaticLookup, Verify, ConvertInto}; use sr_primitives::weights::Weight; -use babe::{AuthorityId as BabeId}; -use grandpa::{AuthorityId as GrandpaId, AuthorityWeight as GrandpaWeight}; -use grandpa::fg_primitives; use client::{ block_builder::api::{CheckInherentsResult, InherentData, self as block_builder_api}, runtime_api as client_api, impl_runtime_apis }; +use aura_primitives::sr25519::AuthorityId as AuraId; +use grandpa::{AuthorityId as GrandpaId, AuthorityWeight as GrandpaWeight}; +use grandpa::fg_primitives; use version::RuntimeVersion; #[cfg(feature = "std")] use version::NativeVersion; @@ -80,14 +80,12 @@ pub mod opaque { /// Opaque block identifier type. pub type BlockId = generic::BlockId; - pub type SessionHandlers = (Grandpa, Babe); - impl_opaque_keys! { pub struct SessionKeys { + #[id(key_types::AURA)] + pub aura: AuraId, #[id(key_types::GRANDPA)] pub grandpa: GrandpaId, - #[id(key_types::BABE)] - pub babe: BabeId, } } } @@ -102,20 +100,6 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { apis: RUNTIME_API_VERSIONS, }; -/// Constants for Babe. - -/// Since BABE is probabilistic this is the average expected block time that -/// we are targetting. Blocks will be produced at a minimum duration defined -/// by `SLOT_DURATION`, but some slots will not be allocated to any -/// authority and hence no block will be produced. We expect to have this -/// block time on average following the defined slot duration and the value -/// of `c` configured for BABE (where `1 - c` represents the probability of -/// a slot being empty). -/// This value is only used indirectly to define the unit constants below -/// that are expressed in blocks. The rest of the code should use -/// `SLOT_DURATION` instead (like the timestamp module for calculating the -/// minimum period). -/// pub const MILLISECS_PER_BLOCK: u64 = 6000; pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK; @@ -180,15 +164,8 @@ impl system::Trait for Runtime { type Version = Version; } -parameter_types! { - pub const EpochDuration: u64 = EPOCH_DURATION_IN_BLOCKS as u64; - pub const ExpectedBlockTime: u64 = MILLISECS_PER_BLOCK; -} - -impl babe::Trait for Runtime { - type EpochDuration = EpochDuration; - type ExpectedBlockTime = ExpectedBlockTime; - type EpochChangeTrigger = babe::SameAuthoritiesForever; +impl aura::Trait for Runtime { + type AuthorityId = AuraId; } impl grandpa::Trait for Runtime { @@ -214,7 +191,7 @@ parameter_types! { impl timestamp::Trait for Runtime { /// A timestamp: milliseconds since the unix epoch. type Moment = u64; - type OnTimestampSet = Babe; + type OnTimestampSet = Aura; type MinimumPeriod = MinimumPeriod; } @@ -272,7 +249,7 @@ construct_runtime!( { System: system::{Module, Call, Storage, Config, Event}, Timestamp: timestamp::{Module, Call, Storage, Inherent}, - Babe: babe::{Module, Call, Storage, Config, Inherent(Timestamp)}, + Aura: aura::{Module, Config, Inherent(Timestamp)}, Grandpa: grandpa::{Module, Call, Storage, Config, Event}, Indices: indices::{default, Config}, Balances: balances::{default, Error}, @@ -365,27 +342,13 @@ impl_runtime_apis! { } } - impl fg_primitives::GrandpaApi for Runtime { - fn grandpa_authorities() -> Vec<(GrandpaId, GrandpaWeight)> { - Grandpa::grandpa_authorities() + impl aura_primitives::AuraApi for Runtime { + fn slot_duration() -> u64 { + Aura::slot_duration() } - } - - impl babe_primitives::BabeApi for Runtime { - fn configuration() -> babe_primitives::BabeConfiguration { - // The choice of `c` parameter (where `1 - c` represents the - // probability of a slot being empty), is done in accordance to the - // slot duration and expected target block time, for safely - // resisting network delays of maximum two seconds. - // - babe_primitives::BabeConfiguration { - slot_duration: Babe::slot_duration(), - epoch_length: EpochDuration::get(), - c: PRIMARY_PROBABILITY, - genesis_authorities: Babe::authorities(), - randomness: Babe::randomness(), - secondary_slots: true, - } + + fn authorities() -> Vec { + Aura::authorities() } } @@ -395,4 +358,10 @@ impl_runtime_apis! { opaque::SessionKeys::generate(seed) } } + + impl fg_primitives::GrandpaApi for Runtime { + fn grandpa_authorities() -> Vec<(GrandpaId, GrandpaWeight)> { + Grandpa::grandpa_authorities() + } + } } diff --git a/node-template/src/chain_spec.rs b/node-template/src/chain_spec.rs index 9fdc6ee2ca..2996f5414a 100644 --- a/node-template/src/chain_spec.rs +++ b/node-template/src/chain_spec.rs @@ -1,9 +1,9 @@ use primitives::{Pair, Public}; use node_template_runtime::{ - AccountId, BabeConfig, BalancesConfig, GenesisConfig, GrandpaConfig, + AccountId, AuraConfig, BalancesConfig, GenesisConfig, GrandpaConfig, SudoConfig, IndicesConfig, SystemConfig, WASM_BINARY, }; -use babe_primitives::{AuthorityId as BabeId}; +use aura_primitives::sr25519::{AuthorityId as AuraId}; use grandpa_primitives::{AuthorityId as GrandpaId}; use substrate_service; @@ -31,13 +31,11 @@ pub fn get_from_seed(seed: &str) -> ::Pu .public() } -/// Helper function to generate stash, controller and session key from seed -pub fn get_authority_keys_from_seed(seed: &str) -> (AccountId, AccountId, GrandpaId, BabeId) { +/// Helper function to generate an authority key for Aura +pub fn get_authority_keys_from_seed(s: &str) -> (AuraId, GrandpaId) { ( - get_from_seed::(&format!("{}//stash", seed)), - get_from_seed::(seed), - get_from_seed::(seed), - get_from_seed::(seed), + get_from_seed::(s), + get_from_seed::(s), ) } @@ -106,7 +104,7 @@ impl Alternative { } } -fn testnet_genesis(initial_authorities: Vec<(AccountId, AccountId, GrandpaId, BabeId)>, +fn testnet_genesis(initial_authorities: Vec<(AuraId, GrandpaId)>, root_key: AccountId, endowed_accounts: Vec, _enable_println: bool) -> GenesisConfig { @@ -125,11 +123,11 @@ fn testnet_genesis(initial_authorities: Vec<(AccountId, AccountId, GrandpaId, Ba sudo: Some(SudoConfig { key: root_key, }), - babe: Some(BabeConfig { - authorities: initial_authorities.iter().map(|x| (x.3.clone(), 1)).collect(), + aura: Some(AuraConfig { + authorities: initial_authorities.iter().map(|x| (x.0.clone())).collect(), }), grandpa: Some(GrandpaConfig { - authorities: initial_authorities.iter().map(|x| (x.2.clone(), 1)).collect(), + authorities: initial_authorities.iter().map(|x| (x.1.clone(), 1)).collect(), }), } } diff --git a/node-template/src/cli.rs b/node-template/src/cli.rs index 6a0b0dd706..f0b429e0fa 100644 --- a/node-template/src/cli.rs +++ b/node-template/src/cli.rs @@ -5,6 +5,7 @@ use tokio::runtime::Runtime; pub use substrate_cli::{VersionInfo, IntoExit, error}; use substrate_cli::{informant, parse_and_prepare, ParseAndPrepare, NoCustom}; use substrate_service::{AbstractService, Roles as ServiceRoles, Configuration}; +use aura_primitives::sr25519::{AuthorityPair as AuraPair}; use crate::chain_spec; use log::info; diff --git a/node-template/src/service.rs b/node-template/src/service.rs index 24b22082c5..64a453e298 100644 --- a/node-template/src/service.rs +++ b/node-template/src/service.rs @@ -3,16 +3,16 @@ use std::sync::Arc; use std::time::Duration; use substrate_client::LongestChain; -use babe; -use grandpa::{self, FinalityProofProvider as GrandpaFinalityProofProvider}; use futures::prelude::*; use node_template_runtime::{self, GenesisConfig, opaque::Block, RuntimeApi}; use substrate_service::{error::{Error as ServiceError}, AbstractService, Configuration, ServiceBuilder}; use transaction_pool::{self, txpool::{Pool as TransactionPool}}; use inherents::InherentDataProviders; -use network::construct_simple_protocol; +use network::{construct_simple_protocol}; use substrate_executor::native_executor_instance; pub use substrate_executor::NativeExecutor; +use aura_primitives::sr25519::{AuthorityPair as AuraPair}; +use grandpa::{self, FinalityProofProvider as GrandpaFinalityProofProvider}; // Our native executor instance. native_executor_instance!( @@ -44,33 +44,26 @@ macro_rules! new_full_start { .with_transaction_pool(|config, client| Ok(transaction_pool::txpool::Pool::new(config, transaction_pool::FullChainApi::new(client))) )? - .with_import_queue(|_config, client, mut select_chain, _transaction_pool| { + .with_import_queue(|_config, client, mut select_chain, transaction_pool| { let select_chain = select_chain.take() .ok_or_else(|| substrate_service::Error::SelectChainRequired)?; + let (grandpa_block_import, grandpa_link) = grandpa::block_import::<_, _, _, node_template_runtime::RuntimeApi, _, _>( client.clone(), &*client, select_chain )?; - let justification_import = grandpa_block_import.clone(); - - let (babe_block_import, babe_link) = babe::block_import( - babe::Config::get_or_compute(&*client)?, - grandpa_block_import, - client.clone(), - client.clone(), - )?; - let import_queue = babe::import_queue( - babe_link.clone(), - babe_block_import.clone(), - Some(Box::new(justification_import)), + let import_queue = aura::import_queue::<_, _, AuraPair, _>( + aura::SlotDuration::get_or_compute(&*client)?, + Box::new(grandpa_block_import.clone()), + Some(Box::new(grandpa_block_import.clone())), None, - client.clone(), client, inherent_data_providers.clone(), + Some(transaction_pool), )?; - import_setup = Some((babe_block_import, grandpa_link, babe_link)); + import_setup = Some((grandpa_block_import, grandpa_link)); Ok(import_queue) })?; @@ -83,24 +76,23 @@ macro_rules! new_full_start { pub fn new_full(config: Configuration) -> Result { - let is_authority = config.roles.is_authority(); + let force_authoring = config.force_authoring; let name = config.name.clone(); let disable_grandpa = config.disable_grandpa; - let force_authoring = config.force_authoring; let (builder, mut import_setup, inherent_data_providers) = new_full_start!(config); + let (block_import, grandpa_link) = + import_setup.take() + .expect("Link Half and Block Import are present for Full Services or setup failed before. qed"); + let service = builder.with_network_protocol(|_| Ok(NodeProtocol::new()))? .with_finality_proof_provider(|client, backend| Ok(Arc::new(GrandpaFinalityProofProvider::new(backend, client)) as _) )? .build()?; - let (block_import, grandpa_link, babe_link) = - import_setup.take() - .expect("Link Half and Block Import are present for Full Services or setup failed before. qed"); - if is_authority { let proposer = basic_authorship::ProposerFactory { client: service.client(), @@ -111,22 +103,21 @@ pub fn new_full(config: Configuration( + aura::SlotDuration::get_or_compute(&*client)?, client, select_chain, - env: proposer, block_import, - sync_oracle: service.network(), - inherent_data_providers: inherent_data_providers.clone(), + proposer, + service.network(), + inherent_data_providers.clone(), force_authoring, - babe_link, - }; + service.keystore(), + )?; - let babe = babe::start_babe(babe_config)?; - let select = babe.select(service.on_exit()).then(|_| Ok(())); + let select = aura.select(service.on_exit()).then(|_| Ok(())); - // the BABE authoring task is considered infallible, i.e. if it + // the AURA authoring task is considered essential, i.e. if it // fails we take down the service with it. service.spawn_essential_task(select); } @@ -196,26 +187,18 @@ pub fn new_light(config: Configuration( client.clone(), backend, Arc::new(fetch_checker), client.clone() )?; - let finality_proof_import = grandpa_block_import.clone(); let finality_proof_request_builder = finality_proof_import.create_finality_proof_request_builder(); - let (babe_block_import, babe_link) = babe::block_import( - babe::Config::get_or_compute(&*client)?, - grandpa_block_import, - client.clone(), - client.clone(), - )?; - - let import_queue = babe::import_queue( - babe_link.clone(), - babe_block_import, + let import_queue = aura::import_queue::<_, _, AuraPair, ()>( + aura::SlotDuration::get_or_compute(&*client)?, + Box::new(grandpa_block_import), None, Some(Box::new(finality_proof_import)), - client.clone(), client, inherent_data_providers.clone(), + None, )?; Ok((import_queue, finality_proof_request_builder)) -- GitLab From fb26c5605ff5a9fc2675e1cef4694ac53a9d86e9 Mon Sep 17 00:00:00 2001 From: h4x3rotab Date: Fri, 18 Oct 2019 21:00:45 +0800 Subject: [PATCH 058/167] Fix typo (#3853) In `core/client/src/client.rs`: "innacurate" -> "inaccurate" --- core/client/src/client.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/client/src/client.rs b/core/client/src/client.rs index 796520cb7f..d853d851c5 100644 --- a/core/client/src/client.rs +++ b/core/client/src/client.rs @@ -1125,7 +1125,7 @@ impl Client where // then some other block is the common ancestor. if route_from_best.common_block().hash != block { // NOTE: we're setting the finalized block as best block, this might - // be slightly innacurate since we might have a "better" block + // be slightly inaccurate since we might have a "better" block // further along this chain, but since best chain selection logic is // pluggable we cannot make a better choice here. usages that need // an accurate "best" block need to go through `SelectChain` -- GitLab From 6949b8e2862ed18f4f8d6be3f44d77e1e7097c98 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Fri, 18 Oct 2019 16:01:14 +0200 Subject: [PATCH 059/167] core/finality-grandpa: Minor refactorings (#3825) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * core/finality-grandpa: Improve code comments * core/finality-grandpa: Rename VoteOrPrecommit to PrevoteOrPrecommit According to the Grandpa paper [1]: > A vote is a block hash, together with some metadata such as round number and the type of vote, such as prevote or precommit, all signed with a voter’s private key. To reduce confusion this patch makes the code consistent with the research paper. [1] https://github.com/w3f/consensus/blob/master/pdf/grandpa.pdf * core/finality-grandpa: Add comment for NetworkStream concept * core/finality-grandpa: Improve round_communication doc comment * core/finality-grandpa: Rename PrevoteOrPrecommit to Vote * core/finality-grandpa: Represent NetworkStream state machine as enum * core/finality-grandpa: Improve KeepTopics comment --- core/finality-grandpa/primitives/src/lib.rs | 2 +- .../src/communication/gossip.rs | 24 ++++--- .../finality-grandpa/src/communication/mod.rs | 64 +++++++++++++------ 3 files changed, 59 insertions(+), 31 deletions(-) diff --git a/core/finality-grandpa/primitives/src/lib.rs b/core/finality-grandpa/primitives/src/lib.rs index 384319a298..a439953899 100644 --- a/core/finality-grandpa/primitives/src/lib.rs +++ b/core/finality-grandpa/primitives/src/lib.rs @@ -52,7 +52,7 @@ pub type AuthorityWeight = u64; /// The index of an authority. pub type AuthorityIndex = u64; -/// The identifier of a GRANDPA set. +/// The monotonic identifier of a GRANDPA set of authorities. pub type SetId = u64; /// The round indicator. diff --git a/core/finality-grandpa/src/communication/gossip.rs b/core/finality-grandpa/src/communication/gossip.rs index 1f9d78c867..24402c8a02 100644 --- a/core/finality-grandpa/src/communication/gossip.rs +++ b/core/finality-grandpa/src/communication/gossip.rs @@ -183,7 +183,13 @@ impl View { const KEEP_RECENT_ROUNDS: usize = 3; -/// Tracks topics we keep messages for. +/// Tracks gossip topics that we are keeping messages for. We keep topics of: +/// +/// - the last `KEEP_RECENT_ROUNDS` complete GRANDPA rounds, +/// +/// - the topic for the current and next round, +/// +/// - and a global topic for commit and catch-up messages. struct KeepTopics { current_set: SetId, rounds: VecDeque<(Round, SetId)>, @@ -256,7 +262,7 @@ fn neighbor_topics(view: &View>) -> Vec { #[derive(Debug, Encode, Decode)] pub(super) enum GossipMessage { /// Grandpa message with round and set info. - VoteOrPrecommit(VoteOrPrecommitMessage), + Vote(VoteMessage), /// Grandpa commit message with round and set info. Commit(FullCommitMessage), /// A neighbor packet. Not repropagated. @@ -273,9 +279,9 @@ impl From>> for GossipMessage { +pub(super) struct VoteMessage { /// The round this message is from. pub(super) round: Round, /// The voter set ID this message is from. @@ -612,7 +618,7 @@ impl Inner { cost::PAST_REJECTION } - fn validate_round_message(&self, who: &PeerId, full: &VoteOrPrecommitMessage) + fn validate_round_message(&self, who: &PeerId, full: &VoteMessage) -> Action { match self.consider_vote(full.round, full.set_id) { @@ -1003,7 +1009,7 @@ impl GossipValidator { let action = { match GossipMessage::::decode(&mut data) { - Ok(GossipMessage::VoteOrPrecommit(ref message)) + Ok(GossipMessage::Vote(ref message)) => self.inner.write().validate_round_message(who, message), Ok(GossipMessage::Commit(ref message)) => self.inner.write().validate_commit_message(who, message), Ok(GossipMessage::Neighbor(update)) => { @@ -1163,7 +1169,7 @@ impl network_gossip::Validator for GossipValidator Ok(GossipMessage::Neighbor(_)) => false, Ok(GossipMessage::CatchUpRequest(_)) => false, Ok(GossipMessage::CatchUp(_)) => false, - Ok(GossipMessage::VoteOrPrecommit(_)) => false, // should not be the case. + Ok(GossipMessage::Vote(_)) => false, // should not be the case. } }) } @@ -1478,7 +1484,7 @@ mod tests { val.note_round(Round(1), |_, _| {}); let inner = val.inner.read(); - let unknown_voter = inner.validate_round_message(&peer, &VoteOrPrecommitMessage { + let unknown_voter = inner.validate_round_message(&peer, &VoteMessage { round: Round(1), set_id: SetId(set_id), message: SignedMessage:: { @@ -1491,7 +1497,7 @@ mod tests { } }); - let bad_sig = inner.validate_round_message(&peer, &VoteOrPrecommitMessage { + let bad_sig = inner.validate_round_message(&peer, &VoteMessage { round: Round(1), set_id: SetId(set_id), message: SignedMessage:: { diff --git a/core/finality-grandpa/src/communication/mod.rs b/core/finality-grandpa/src/communication/mod.rs index 652c33c026..ba7bdce336 100644 --- a/core/finality-grandpa/src/communication/mod.rs +++ b/core/finality-grandpa/src/communication/mod.rs @@ -48,7 +48,7 @@ use crate::{ }; use crate::environment::HasVoted; use gossip::{ - GossipMessage, FullCatchUpMessage, FullCommitMessage, VoteOrPrecommitMessage, GossipValidator + GossipMessage, FullCatchUpMessage, FullCommitMessage, VoteMessage, GossipValidator }; use fg_primitives::{ AuthorityPair, AuthorityId, AuthoritySignature, SetId as SetIdNumber, RoundNumber, @@ -148,12 +148,21 @@ impl Network for Arc> where type In = NetworkStream; fn messages_for(&self, topic: B::Hash) -> Self::In { + // Given that one can only communicate with the Substrate network via the `NetworkService` via message-passing, + // and given that methods on the network consensus gossip are not exposed but only reachable by passing a + // closure into `with_gossip` on the `NetworkService` this function needs to make use of the `NetworkStream` + // construction. + // + // We create a oneshot channel and pass the sender within a closure to the network. At some point in the future + // the network passes the message channel back through the oneshot channel. But the consumer of this function + // expects a stream, not a stream within a oneshot. This complexity is abstracted within `NetworkStream`, + // waiting for the oneshot to resolve and from there on acting like a normal message channel. let (tx, rx) = oneshot::channel(); self.with_gossip(move |gossip, _| { let inner_rx = gossip.messages_for(GRANDPA_ENGINE_ID, topic); let _ = tx.send(inner_rx); }); - NetworkStream { outer: rx, inner: None } + NetworkStream::PollingOneshot(rx) } fn register_validator(&self, validator: Arc>) { @@ -202,10 +211,18 @@ impl Network for Arc> where } } -/// A stream used by NetworkBridge in its implementation of Network. -pub struct NetworkStream { - inner: Option>, - outer: oneshot::Receiver> +/// A stream used by NetworkBridge in its implementation of Network. Given a oneshot that eventually returns a channel +/// which eventually returns messages, instead of: +/// +/// 1. polling the oneshot until it returns a message channel +/// +/// 2. polling the message channel for messages +/// +/// `NetworkStream` combines the two steps into one, requiring a consumer to only poll `NetworkStream` to retrieve +/// messages directly. +pub enum NetworkStream { + PollingOneshot(oneshot::Receiver>), + PollingTopicNotifications(mpsc::UnboundedReceiver), } impl Stream for NetworkStream { @@ -213,17 +230,21 @@ impl Stream for NetworkStream { type Error = (); fn poll(&mut self) -> Poll, Self::Error> { - if let Some(ref mut inner) = self.inner { - return inner.poll(); - } - match self.outer.poll() { - Ok(futures::Async::Ready(mut inner)) => { - let poll_result = inner.poll(); - self.inner = Some(inner); - poll_result + match self { + NetworkStream::PollingOneshot(oneshot) => { + match oneshot.poll() { + Ok(futures::Async::Ready(mut stream)) => { + let poll_result = stream.poll(); + *self = NetworkStream::PollingTopicNotifications(stream); + poll_result + }, + Ok(futures::Async::NotReady) => Ok(futures::Async::NotReady), + Err(_) => Err(()) + } + }, + NetworkStream::PollingTopicNotifications(stream) => { + stream.poll() }, - Ok(futures::Async::NotReady) => Ok(futures::Async::NotReady), - Err(_) => Err(()) } } } @@ -275,8 +296,8 @@ impl> NetworkBridge { validator.note_round(Round(round.number), |_, _| {}); for signed in round.votes.iter() { - let message = gossip::GossipMessage::VoteOrPrecommit( - gossip::VoteOrPrecommitMessage:: { + let message = gossip::GossipMessage::Vote( + gossip::VoteMessage:: { message: signed.clone(), round: Round(round.number), set_id: SetId(set_id), @@ -341,7 +362,8 @@ impl> NetworkBridge { ); } - /// Get the round messages for a round in the current set ID. These are signature-checked. + /// Get a stream of signature-checked round messages from the network as well as a sink for round messages to the + /// network all within the current set. pub(crate) fn round_communication( &self, round: Round, @@ -379,7 +401,7 @@ impl> NetworkBridge { }) .and_then(move |msg| { match msg { - GossipMessage::VoteOrPrecommit(msg) => { + GossipMessage::Vote(msg) => { // check signature. if !voters.contains_key(&msg.message.id) { debug!(target: "afg", "Skipping message from unknown voter {}", msg.message.id); @@ -707,7 +729,7 @@ impl> Sink for OutgoingMessages id: local_id.clone(), }; - let message = GossipMessage::VoteOrPrecommit(VoteOrPrecommitMessage:: { + let message = GossipMessage::Vote(VoteMessage:: { message: signed.clone(), round: Round(self.round), set_id: SetId(self.set_id), -- GitLab From ac21a1b5804c350a995ece904440b0947d8a1f85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Fri, 18 Oct 2019 16:05:23 +0200 Subject: [PATCH 060/167] Don't make `ServiceBuilder` require to have a finality proof provider (#3831) specified --- core/service/src/builder.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/service/src/builder.rs b/core/service/src/builder.rs index e4b02150bf..6a286bf19d 100644 --- a/core/service/src/builder.rs +++ b/core/service/src/builder.rs @@ -149,7 +149,7 @@ where TGen: RuntimeGenesis, TCSExt: Extension { (), (), BoxFinalityProofRequestBuilder, - (), + Arc>, (), (), (), @@ -224,7 +224,7 @@ where TGen: RuntimeGenesis, TCSExt: Extension { (), (), BoxFinalityProofRequestBuilder, - (), + Arc>, (), (), (), -- GitLab From f5ea01efb14b6dcaa1a5e7aeef3c1341921c0538 Mon Sep 17 00:00:00 2001 From: Arkadiy Paronyan Date: Fri, 18 Oct 2019 16:44:40 +0200 Subject: [PATCH 061/167] Persist block announcements (#3826) * Persist block announcements * Renamed sync requests to fork targets * Fixed pruning detection condition --- core/network/src/protocol.rs | 11 +- core/network/src/protocol/sync.rs | 207 +++++++++++++----------------- core/network/src/test/mod.rs | 2 + core/network/src/test/sync.rs | 11 ++ 4 files changed, 104 insertions(+), 127 deletions(-) diff --git a/core/network/src/protocol.rs b/core/network/src/protocol.rs index dc9e6688e7..2e036cf118 100644 --- a/core/network/src/protocol.rs +++ b/core/network/src/protocol.rs @@ -1121,18 +1121,13 @@ impl, H: ExHashT> Protocol { }; match self.sync.on_block_announce(who.clone(), hash, &announce, is_their_best) { - sync::OnBlockAnnounce::Request(peer, req) => { - self.send_message(peer, GenericMessage::BlockRequest(req)); - return CustomMessageOutcome::None - } sync::OnBlockAnnounce::Nothing => { - // try_import is only true when we have all data required to import block + // `on_block_announce` returns `OnBlockAnnounce::ImportHeader` + // when we have all data required to import the block // in the BlockAnnounce message. This is only when: // 1) we're on light client; // AND - // - EITHER 2.1) announced block is stale; - // - OR 2.2) announced block is NEW and we normally only want to download this single block (i.e. - // there are no ascendants of this block scheduled for retrieval) + // 2) parent block is already imported and not pruned. return CustomMessageOutcome::None } sync::OnBlockAnnounce::ImportHeader => () // We proceed with the import. diff --git a/core/network/src/protocol/sync.rs b/core/network/src/protocol/sync.rs index 9f9db92289..bd8a9fe27f 100644 --- a/core/network/src/protocol/sync.rs +++ b/core/network/src/protocol/sync.rs @@ -69,9 +69,6 @@ const MAJOR_SYNC_BLOCKS: u8 = 5; /// Number of recently announced blocks to track for each peer. const ANNOUNCE_HISTORY_SIZE: usize = 64; -/// Max number of blocks to download for unknown forks. -const MAX_UNKNOWN_FORK_DOWNLOAD_LEN: u32 = 32; - /// Reputation change when a peer sent us a status message that led to a /// database read error. const BLOCKCHAIN_STATUS_READ_ERROR_REPUTATION_CHANGE: i32 = -(1 << 16); @@ -125,8 +122,8 @@ pub struct ChainSync { best_importing_number: NumberFor, /// Finality proof handler. request_builder: Option>, - /// Explicit sync requests. - sync_requests: HashMap>, + /// Fork sync targets. + fork_targets: HashMap>, /// A flag that caches idle state with no pending requests. is_idle: bool, /// A type to check incoming block announcements. @@ -160,8 +157,9 @@ pub struct PeerInfo { pub best_number: NumberFor } -struct SyncRequest { +struct ForkTarget { number: NumberFor, + parent_hash: Option, peers: HashSet, } @@ -242,13 +240,11 @@ pub enum OnBlockData { /// Result of [`ChainSync::on_block_announce`]. #[derive(Debug, Clone, PartialEq, Eq)] -pub enum OnBlockAnnounce { +pub enum OnBlockAnnounce { /// The announcement does not require further handling. Nothing, /// The announcement header should be imported. ImportHeader, - /// Another block request to the given peer is necessary. - Request(PeerId, BlockRequest) } /// Result of [`ChainSync::on_block_justification`]. @@ -307,7 +303,7 @@ impl ChainSync { queue_blocks: Default::default(), best_importing_number: Zero::zero(), request_builder, - sync_requests: Default::default(), + fork_targets: Default::default(), is_idle: false, block_announce_validator, } @@ -462,7 +458,7 @@ impl ChainSync { // The implementation is similar to on_block_announce with unknown parent hash. pub fn set_sync_fork_request(&mut self, peers: Vec, hash: &B::Hash, number: NumberFor) { if peers.is_empty() { - if let Some(_) = self.sync_requests.remove(hash) { + if let Some(_) = self.fork_targets.remove(hash) { debug!(target: "sync", "Cleared sync request for block {:?} with {:?}", hash, peers); } return; @@ -494,11 +490,12 @@ impl ChainSync { } } - self.sync_requests + self.fork_targets .entry(hash.clone()) - .or_insert_with(|| SyncRequest { + .or_insert_with(|| ForkTarget { number, peers: Default::default(), + parent_hash: None, }) .peers.extend(peers); } @@ -562,17 +559,30 @@ impl ChainSync { } let blocks = &mut self.blocks; let attrs = &self.required_block_attributes; - let sync_requests = &self.sync_requests; + let fork_targets = &self.fork_targets; let mut have_requests = false; let last_finalized = self.client.info().chain.finalized_number; let best_queued = self.best_queued_number; + let client = &self.client; + let queue = &self.queue_blocks; let iter = self.peers.iter_mut().filter_map(move |(id, peer)| { if !peer.state.is_available() { trace!(target: "sync", "Peer {} is busy", id); return None } - if let Some((hash, req)) = explicit_sync_request(id, sync_requests, best_queued, last_finalized, attrs) { - trace!(target: "sync", "Downloading explicitly requested block {:?} from {}", hash, id); + if let Some((hash, req)) = fork_sync_request( + id, + fork_targets, + best_queued, + last_finalized, + attrs, + |hash| if queue.contains(hash) { + BlockStatus::Queued + } else { + client.block_status(&BlockId::Hash(*hash)).unwrap_or(BlockStatus::Unknown) + }, + ) { + trace!(target: "sync", "Downloading fork {:?} from {}", hash, id); peer.state = PeerSyncState::DownloadingStale(hash); have_requests = true; Some((id.clone(), req)) @@ -665,6 +675,26 @@ impl ChainSync { peer.state = PeerSyncState::AncestorSearch(next_num, next_state); return Ok(OnBlockData::Request(who, ancestry_request::(next_num))) } else { + // Ancestry search is complete. Check if peer is on a stale fork unknown to us and + // add it to sync targets if necessary. + trace!(target: "sync", "Ancestry search complete. Ours={} ({}), Theirs={} ({}), Common={}", + self.best_queued_hash, + self.best_queued_number, + peer.best_hash, + peer.best_number, + peer.common_number + ); + if peer.common_number < peer.best_number && peer.best_number < self.best_queued_number { + trace!(target: "sync", "Added fork target {} for {}" , peer.best_hash, who); + self.fork_targets + .entry(peer.best_hash.clone()) + .or_insert_with(|| ForkTarget { + number: peer.best_number, + parent_hash: None, + peers: Default::default(), + }) + .peers.insert(who); + } peer.state = PeerSyncState::Available; Vec::new() } @@ -922,14 +952,14 @@ impl ChainSync { self.best_queued_number = number; self.best_queued_hash = *hash; } - if let Some(_) = self.sync_requests.remove(&hash) { - trace!(target: "sync", "Completed explicit sync request {:?}", hash); + if let Some(_) = self.fork_targets.remove(&hash) { + trace!(target: "sync", "Completed fork sync {:?}", hash); } // Update common blocks for (n, peer) in self.peers.iter_mut() { if let PeerSyncState::AncestorSearch(_, _) = peer.state { - // Abort search. - peer.state = PeerSyncState::Available; + // Wait for ancestry search to complete first. + continue; } let new_common_number = if peer.best_number >= number { number @@ -952,12 +982,12 @@ impl ChainSync { /// Call when a node announces a new block. /// - /// If true is returned, then the caller MUST try to import passed + /// If `OnBlockAnnounce::ImportHeader` is returned, then the caller MUST try to import passed /// header (call `on_block_data`). The network request isn't sent /// in this case. Both hash and header is passed as an optimization /// to avoid rehashing the header. pub fn on_block_announce(&mut self, who: PeerId, hash: B::Hash, announce: &BlockAnnounce, is_best: bool) - -> OnBlockAnnounce + -> OnBlockAnnounce { let header = &announce.header; let number = *header.number(); @@ -1001,6 +1031,9 @@ impl ChainSync { // known block case if known || self.is_already_downloading(&hash) { trace!(target: "sync", "Known block announce from {}: {}", who, hash); + if let Some(target) = self.fork_targets.get_mut(&hash) { + target.peers.insert(who); + } return OnBlockAnnounce::Nothing } @@ -1009,79 +1042,42 @@ impl ChainSync { match self.block_announce_validator.validate(&header, assoc_data) { Ok(Validation::Success) => (), Ok(Validation::Failure) => { - debug!(target: "sync", "block announcement validation of block {} from {} failed", hash, who); + debug!(target: "sync", "Block announcement validation of block {} from {} failed", hash, who); return OnBlockAnnounce::Nothing } Err(e) => { - error!(target: "sync", "block announcement validation errored: {}", e); + error!(target: "sync", "Block announcement validation errored: {}", e); return OnBlockAnnounce::Nothing } } - // stale block case - let requires_additional_data = !self.role.is_light(); - if number <= self.best_queued_number { - if !(known_parent || self.is_already_downloading(header.parent_hash())) { - let block_status = self.client.block_status(&BlockId::Number(*header.number())) - .unwrap_or(BlockStatus::Unknown); - if block_status == BlockStatus::InChainPruned { - trace!( - target: "sync", - "Ignored unknown ancient block announced from {}: {} {:?}", who, hash, header - ); - return OnBlockAnnounce::Nothing - } - trace!( - target: "sync", - "Considering new unknown stale block announced from {}: {} {:?}", who, hash, header - ); - if let Some(request) = self.download_unknown_stale(&who, &hash) { - if requires_additional_data { - return OnBlockAnnounce::Request(who, request) - } else { - return OnBlockAnnounce::ImportHeader - } - } else { - return OnBlockAnnounce::Nothing - } - } else { - if ancient_parent { - trace!(target: "sync", "Ignored ancient stale block announced from {}: {} {:?}", who, hash, header); - return OnBlockAnnounce::Nothing - } - if let Some(request) = self.download_stale(&who, &hash) { - if requires_additional_data { - return OnBlockAnnounce::Request(who, request) - } else { - return OnBlockAnnounce::ImportHeader - } - } else { - return OnBlockAnnounce::Nothing - } - } - } - if ancient_parent { trace!(target: "sync", "Ignored ancient block announced from {}: {} {:?}", who, hash, header); return OnBlockAnnounce::Nothing } - trace!(target: "sync", "Considering new block announced from {}: {} {:?}", who, hash, header); - - let (range, request) = match self.select_new_blocks(who.clone()) { - Some((range, request)) => (range, request), - None => return OnBlockAnnounce::Nothing - }; - - let is_required_data_available = !requires_additional_data - && range.end - range.start == One::one() - && range.start == *header.number(); + let requires_additional_data = !self.role.is_light() || !known_parent; + if !requires_additional_data { + trace!(target: "sync", "Importing new header announced from {}: {} {:?}", who, hash, header); + return OnBlockAnnounce::ImportHeader + } - if !is_required_data_available { - return OnBlockAnnounce::Request(who, request) + if number <= self.best_queued_number { + trace!( + target: "sync", + "Added sync target for block announced from {}: {} {:?}", who, hash, header + ); + self.fork_targets + .entry(hash.clone()) + .or_insert_with(|| ForkTarget { + number, + parent_hash: Some(header.parent_hash().clone()), + peers: Default::default(), + }) + .peers.insert(who); } - OnBlockAnnounce::ImportHeader + OnBlockAnnounce::Nothing } /// Call when a peer has disconnected. @@ -1117,40 +1113,6 @@ impl ChainSync { }) } - /// Download old block with known parent. - fn download_stale(&mut self, who: &PeerId, hash: &B::Hash) -> Option> { - let peer = self.peers.get_mut(who)?; - if !peer.state.is_available() { - return None - } - peer.state = PeerSyncState::DownloadingStale(*hash); - Some(message::generic::BlockRequest { - id: 0, - fields: self.required_block_attributes.clone(), - from: message::FromBlock::Hash(*hash), - to: None, - direction: message::Direction::Ascending, - max: Some(1), - }) - } - - /// Download old block with unknown parent. - fn download_unknown_stale(&mut self, who: &PeerId, hash: &B::Hash) -> Option> { - let peer = self.peers.get_mut(who)?; - if !peer.state.is_available() { - return None - } - peer.state = PeerSyncState::DownloadingStale(*hash); - Some(message::generic::BlockRequest { - id: 0, - fields: self.required_block_attributes.clone(), - from: message::FromBlock::Hash(*hash), - to: None, - direction: message::Direction::Descending, - max: Some(MAX_UNKNOWN_FORK_DOWNLOAD_LEN), - }) - } - /// Select a range of new blocks to download from the given peer. fn select_new_blocks(&mut self, who: PeerId) -> Option<(Range>, BlockRequest)> { // when there are too many blocks in the queue => do not try to download new blocks @@ -1298,28 +1260,35 @@ fn peer_block_request( } } -/// Get pending explicit sync request for a peer. -fn explicit_sync_request( +/// Get pending fork sync targets for a peer. +fn fork_sync_request( id: &PeerId, - requests: &HashMap>, + targets: &HashMap>, best_num: NumberFor, finalized: NumberFor, attributes: &message::BlockAttributes, + check_block: impl Fn(&B::Hash) -> BlockStatus, ) -> Option<(B::Hash, BlockRequest)> { - for (hash, r) in requests { + for (hash, r) in targets { if !r.peers.contains(id) { continue } if r.number <= best_num { trace!(target: "sync", "Downloading requested fork {:?} from {}", hash, id); + let parent_status = r.parent_hash.as_ref().map_or(BlockStatus::Unknown, check_block); + let mut count = (r.number - finalized).saturated_into::(); // up to the last finalized block + if parent_status != BlockStatus::Unknown { + // request only single block + count = 1; + } return Some((hash.clone(), message::generic::BlockRequest { id: 0, fields: attributes.clone(), from: message::FromBlock::Hash(hash.clone()), to: None, direction: message::Direction::Descending, - max: Some((r.number - finalized).saturated_into::()), // up to the last finalized block + max: Some(count), })) } } diff --git a/core/network/src/test/mod.rs b/core/network/src/test/mod.rs index 2c87ba1ac8..92e747280b 100644 --- a/core/network/src/test/mod.rs +++ b/core/network/src/test/mod.rs @@ -704,7 +704,9 @@ pub trait TestNetFactory: Sized { fn poll(&mut self) { self.mut_peers(|peers| { for peer in peers { + trace!(target: "sync", "-- Polling {}", peer.id()); peer.network.poll().unwrap(); + trace!(target: "sync", "-- Polling complete {}", peer.id()); // We poll `imported_blocks_stream`. while let Ok(Async::Ready(Some(notification))) = peer.imported_blocks_stream.poll() { diff --git a/core/network/src/test/sync.rs b/core/network/src/test/sync.rs index b5b137a31a..b1b2b9d407 100644 --- a/core/network/src/test/sync.rs +++ b/core/network/src/test/sync.rs @@ -457,6 +457,17 @@ fn can_sync_small_non_best_forks() { } Ok(Async::Ready(())) })).unwrap(); + net.block_until_sync(&mut runtime); + + let another_fork = net.peer(0).push_blocks_at(BlockId::Number(35), 2, true); + net.peer(0).announce_block(another_fork, Vec::new()); + runtime.block_on(futures::future::poll_fn::<(), (), _>(|| -> Result<_, ()> { + net.poll(); + if net.peer(1).client().header(&BlockId::Hash(another_fork)).unwrap().is_none() { + return Ok(Async::NotReady) + } + Ok(Async::Ready(())) + })).unwrap(); } #[test] -- GitLab From 5ad7a68fc7dc518b75734514d71dbaa64af74438 Mon Sep 17 00:00:00 2001 From: Ximin Luo Date: Fri, 18 Oct 2019 16:15:05 +0100 Subject: [PATCH 062/167] Make build work with rustc 1.37 stable and RUSTC_BOOTSTRAP=1 (#3844) * Make build work with rustc 1.37 stable and RUSTC_BOOTSTRAP=1 * Bump versions to run CI --- core/sr-std/without_std.rs | 1 - core/utils/wasm-builder/src/prerequisites.rs | 7 ++++++- node/runtime/src/lib.rs | 4 ++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/core/sr-std/without_std.rs b/core/sr-std/without_std.rs index ed9eea6c31..134cc25c94 100755 --- a/core/sr-std/without_std.rs +++ b/core/sr-std/without_std.rs @@ -14,7 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -#[cfg(feature = "nightly")] #[doc(hidden)] pub extern crate alloc; diff --git a/core/utils/wasm-builder/src/prerequisites.rs b/core/utils/wasm-builder/src/prerequisites.rs index eeac6df33e..0c41dff6c8 100644 --- a/core/utils/wasm-builder/src/prerequisites.rs +++ b/core/utils/wasm-builder/src/prerequisites.rs @@ -16,6 +16,7 @@ use std::{process::{Command, Stdio}, fs}; +use std::env; use tempfile::tempdir; /// Checks that all prerequisites are installed. @@ -23,7 +24,7 @@ use tempfile::tempdir; /// # Returns /// Returns `None` if everything was found and `Some(ERR_MSG)` if something could not be found. pub fn check() -> Option<&'static str> { - if !check_nightly_installed() { + if !rustc_stable_forced_to_nightly() && !check_nightly_installed(){ return Some("Rust nightly not installed, please install it!") } @@ -39,6 +40,10 @@ pub fn check() -> Option<&'static str> { check_wasm_toolchain_installed() } +fn rustc_stable_forced_to_nightly() -> bool { + env::var("RUSTC_BOOTSTRAP") == Ok("1".to_string()) +} + fn check_nightly_installed() -> bool { let command = crate::get_nightly_cargo(); command.is_nightly() diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index fdf0bfdc14..ac801fd39e 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -84,8 +84,8 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // and set impl_version to equal spec_version. If only runtime // implementation changes and behavior does not, then leave spec_version as // is and increment impl_version. - spec_version: 178, - impl_version: 178, + spec_version: 179, + impl_version: 179, apis: RUNTIME_API_VERSIONS, }; -- GitLab From c96f11a68ba8856ee97fbbc9e29bf667dd5fb0b8 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Fri, 18 Oct 2019 18:32:13 +0300 Subject: [PATCH 063/167] Support block revert operation in blockchain cache (#3401) * support block revert operation in cache * #[cfg(test)] -> fn unused_sink() * swap conditions * post-merge fix --- core/client/db/src/cache/list_cache.rs | 141 ++++++++++++++++++++++- core/client/db/src/cache/list_storage.rs | 8 ++ core/client/db/src/cache/mod.rs | 21 ++++ core/client/db/src/lib.rs | 6 + 4 files changed, 175 insertions(+), 1 deletion(-) diff --git a/core/client/db/src/cache/list_cache.rs b/core/client/db/src/cache/list_cache.rs index 9095b80fb6..7a4fcc448e 100644 --- a/core/client/db/src/cache/list_cache.rs +++ b/core/client/db/src/cache/list_cache.rs @@ -39,7 +39,7 @@ //! Finalized entry E1 is pruned when block B is finalized so that: //! EntryAt(B.number - prune_depth).points_to(E1) -use std::collections::BTreeSet; +use std::collections::{BTreeSet, BTreeMap}; use log::warn; @@ -89,6 +89,9 @@ pub enum CommitOperation { /// - new entry is finalized AND/OR /// - some forks are destroyed BlockFinalized(ComplexBlockId, Option>, BTreeSet), + /// When best block is reverted - contains the forks that have to be updated + /// (they're either destroyed, or their best entry is updated to earlier block). + BlockReverted(BTreeMap>>), } /// Single fork of list-based cache. @@ -333,6 +336,44 @@ impl> ListCache Ok(Some(operation)) } + /// When block is reverted. + pub fn on_block_revert>( + &self, + tx: &mut Tx, + reverted_block: &ComplexBlockId, + ) -> ClientResult> { + // can't revert finalized blocks + debug_assert!(self.best_finalized_block.number < reverted_block.number); + + // iterate all unfinalized forks and truncate/destroy if required + let mut updated = BTreeMap::new(); + for (index, fork) in self.unfinalized.iter().enumerate() { + // we only need to truncate fork if its head is ancestor of truncated block + if fork.head.valid_from.number < reverted_block.number { + continue; + } + + // we only need to truncate fork if its head is connected to truncated block + if !chain::is_connected_to_block(&self.storage, reverted_block, &fork.head.valid_from)? { + continue; + } + + let updated_fork = fork.truncate( + &self.storage, + tx, + reverted_block.number, + self.best_finalized_block.number, + )?; + updated.insert(index, updated_fork); + } + + // schedule commit operation and update meta + let operation = CommitOperation::BlockReverted(updated); + tx.update_meta(self.best_finalized_entry.as_ref(), &self.unfinalized, &operation); + + Ok(operation) + } + /// When transaction is committed. pub fn on_transaction_commit(&mut self, op: CommitOperation) { match op { @@ -366,6 +407,14 @@ impl> ListCache self.unfinalized.remove(*fork_index); } }, + CommitOperation::BlockReverted(forks) => { + for (fork_index, updated_fork) in forks.into_iter().rev() { + match updated_fork { + Some(updated_fork) => self.unfinalized[fork_index] = updated_fork, + None => { self.unfinalized.remove(fork_index); }, + } + } + }, } } @@ -533,6 +582,43 @@ impl Fork { best_finalized_block, ) } + + /// Truncate fork by deleting all entries that are descendants of given block. + pub fn truncate, Tx: StorageTransaction>( + &self, + storage: &S, + tx: &mut Tx, + reverting_block: NumberFor, + best_finalized_block: NumberFor, + ) -> ClientResult>> { + let mut current = self.head.valid_from.clone(); + loop { + // read pointer to previous entry + let entry = storage.require_entry(¤t)?; + + // truncation stops when we have reached the ancestor of truncated block + if current.number < reverting_block { + // if we have reached finalized block => destroy fork + if chain::is_finalized_block(storage, ¤t, best_finalized_block)? { + return Ok(None); + } + + // else fork needs to be updated + return Ok(Some(Fork { + best_block: None, + head: entry.into_entry(current), + })); + } + + tx.remove_storage_entry(¤t); + + // truncation also stops when there are no more entries in the list + current = match entry.prev_valid_from { + Some(prev_valid_from) => prev_valid_from, + None => return Ok(None), + }; + } + } } /// Destroy fork by deleting all unfinalized entries. @@ -1400,4 +1486,57 @@ pub mod tests { do_test(PruningStrategy::ByDepth(10)); do_test(PruningStrategy::NeverPrune) } + + #[test] + fn revert_block_works() { + // 1 -> (2) -> 3 -> 4 -> 5 + // \ + // -> 5'' + // \ + // -> (3') -> 4' -> 5' + let mut cache = ListCache::new( + DummyStorage::new() + .with_meta(Some(correct_id(1)), vec![correct_id(5), fork_id(1, 2, 5), fork_id(2, 4, 5)]) + .with_id(1, correct_id(1).hash) + .with_entry(correct_id(1), StorageEntry { prev_valid_from: None, value: 1 }) + .with_entry(correct_id(3), StorageEntry { prev_valid_from: Some(correct_id(1)), value: 3 }) + .with_entry(correct_id(4), StorageEntry { prev_valid_from: Some(correct_id(3)), value: 4 }) + .with_entry(correct_id(5), StorageEntry { prev_valid_from: Some(correct_id(4)), value: 5 }) + .with_entry(fork_id(1, 2, 4), StorageEntry { prev_valid_from: Some(correct_id(1)), value: 14 }) + .with_entry(fork_id(1, 2, 5), StorageEntry { prev_valid_from: Some(fork_id(1, 2, 4)), value: 15 }) + .with_entry(fork_id(2, 4, 5), StorageEntry { prev_valid_from: Some(correct_id(4)), value: 25 }) + .with_header(test_header(1)) + .with_header(test_header(2)) + .with_header(test_header(3)) + .with_header(test_header(4)) + .with_header(test_header(5)) + .with_header(fork_header(1, 2, 3)) + .with_header(fork_header(1, 2, 4)) + .with_header(fork_header(1, 2, 5)) + .with_header(fork_header(2, 4, 5)), + PruningStrategy::ByDepth(1024), correct_id(1) + ); + + // when 5 is reverted: entry 5 is truncated + let op = cache.on_block_revert(&mut DummyTransaction::new(), &correct_id(5)).unwrap(); + assert_eq!(op, CommitOperation::BlockReverted(vec![ + (0, Some(Fork { best_block: None, head: Entry { valid_from: correct_id(4), value: 4 } })), + ].into_iter().collect())); + cache.on_transaction_commit(op); + + // when 3 is reverted: entries 4+5' are truncated + let op = cache.on_block_revert(&mut DummyTransaction::new(), &correct_id(3)).unwrap(); + assert_eq!(op, CommitOperation::BlockReverted(vec![ + (0, None), + (2, None), + ].into_iter().collect())); + cache.on_transaction_commit(op); + + // when 2 is reverted: entries 4'+5' are truncated + let op = cache.on_block_revert(&mut DummyTransaction::new(), &correct_id(2)).unwrap(); + assert_eq!(op, CommitOperation::BlockReverted(vec![ + (0, None), + ].into_iter().collect())); + cache.on_transaction_commit(op); + } } diff --git a/core/client/db/src/cache/list_storage.rs b/core/client/db/src/cache/list_storage.rs index a7bfc4dd58..4fd9ecaced 100644 --- a/core/client/db/src/cache/list_storage.rs +++ b/core/client/db/src/cache/list_storage.rs @@ -227,6 +227,14 @@ mod meta { unfinalized.remove(*fork_index); } }, + CommitOperation::BlockReverted(ref forks) => { + for (fork_index, updated_fork) in forks.iter().rev() { + match updated_fork { + Some(updated_fork) => unfinalized[*fork_index] = &updated_fork.head().valid_from, + None => { unfinalized.remove(*fork_index); }, + } + } + }, } (finalized, unfinalized).encode() diff --git a/core/client/db/src/cache/mod.rs b/core/client/db/src/cache/mod.rs index 6f7d1bf47d..bfc496dd2f 100644 --- a/core/client/db/src/cache/mod.rs +++ b/core/client/db/src/cache/mod.rs @@ -268,6 +268,27 @@ impl<'a, Block: BlockT> DbCacheTransaction<'a, Block> { Ok(self) } + + /// When block is reverted. + pub fn on_block_revert( + mut self, + reverted_block: &ComplexBlockId, + ) -> ClientResult { + for (name, cache) in self.cache.cache_at.iter() { + let op = cache.on_block_revert( + &mut self::list_storage::DbStorageTransaction::new( + cache.storage(), + &mut self.tx + ), + reverted_block, + )?; + + assert!(!self.cache_at_op.contains_key(name)); + self.cache_at_op.insert(name.to_owned(), op); + } + + Ok(self) + } } /// Synchronous implementation of database-backed blockchain data cache. diff --git a/core/client/db/src/lib.rs b/core/client/db/src/lib.rs index 1f7fa604a4..0f765506a3 100644 --- a/core/client/db/src/lib.rs +++ b/core/client/db/src/lib.rs @@ -1518,6 +1518,12 @@ impl client::backend::Backend for Backend whe impl client::backend::LocalBackend for Backend where Block: BlockT {} +/// TODO: remove me in #3201 +pub fn unused_sink(cache_tx: crate::cache::DbCacheTransaction) { + cache_tx.on_block_revert(&crate::cache::ComplexBlockId::new(Default::default(), 0.into())).unwrap(); + unimplemented!() +} + #[cfg(test)] mod tests { use hash_db::{HashDB, EMPTY_PREFIX}; -- GitLab From 4f25b470dd682e7820e95322de35b914de6f65c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= Date: Fri, 18 Oct 2019 18:07:41 +0100 Subject: [PATCH 064/167] grandpa: pluggable voting rules (#3673) * grandpa: support pluggable custom voting rules * grandpa: add docs to grandpa voting rule * grandpa: make voting rule mandatory * grandpa: add test for voting rule * node: add GRANDPA voting rule * grandpa: pass backend to VotingRule * core: fix docs in SelectChain::finality_target * grandpa: implement 3/4 of unfinalized chain restriction as voting rule * grandpa: rename AlwaysBehindBestBlock voting rule * grandpa: fix tests * grandpa: remove useless test * grandpa: extend environemnt voting rule test * grandpa: add proofs to unreachable statements * grandpa: fix typo * grandpa: fix docs --- core/consensus/common/src/select_chain.rs | 5 +- core/finality-grandpa/src/environment.rs | 85 ++++--- core/finality-grandpa/src/lib.rs | 35 ++- core/finality-grandpa/src/tests.rs | 142 ++++++++++-- core/finality-grandpa/src/voting_rule.rs | 270 ++++++++++++++++++++++ node-template/src/service.rs | 1 + node/cli/src/service.rs | 1 + 7 files changed, 471 insertions(+), 68 deletions(-) create mode 100644 core/finality-grandpa/src/voting_rule.rs diff --git a/core/consensus/common/src/select_chain.rs b/core/consensus/common/src/select_chain.rs index cae28656a1..e696db6b87 100644 --- a/core/consensus/common/src/select_chain.rs +++ b/core/consensus/common/src/select_chain.rs @@ -42,8 +42,9 @@ pub trait SelectChain: Sync + Send + Clone { /// best chain to author new blocks upon and probably finalize. fn best_chain(&self) -> Result<::Header, Error>; - /// Get the best ancestor of `target_hash` that we should attempt - /// to finalize next. + /// Get the best descendent of `target_hash` that we should attempt to + /// finalize next, if any. It is valid to return the given `target_hash` + /// itself if no better descendent exists. fn finality_target( &self, target_hash: ::Hash, diff --git a/core/finality-grandpa/src/environment.rs b/core/finality-grandpa/src/environment.rs index 70e45848be..ee146c4608 100644 --- a/core/finality-grandpa/src/environment.rs +++ b/core/finality-grandpa/src/environment.rs @@ -52,6 +52,7 @@ use crate::authorities::{AuthoritySet, SharedAuthoritySet}; use crate::consensus_changes::SharedConsensusChanges; use crate::justification::GrandpaJustification; use crate::until_imported::UntilVoteTargetImported; +use crate::voting_rule::VotingRule; use fg_primitives::{AuthorityId, AuthoritySignature, SetId, RoundNumber}; type HistoricalVotes = grandpa::HistoricalVotes< @@ -368,7 +369,7 @@ impl SharedVoterSetState { } /// The environment we run GRANDPA in. -pub(crate) struct Environment, RA, SC> { +pub(crate) struct Environment, RA, SC, VR> { pub(crate) inner: Arc>, pub(crate) select_chain: SC, pub(crate) voters: Arc>, @@ -378,9 +379,10 @@ pub(crate) struct Environment, RA, SC> { pub(crate) network: crate::communication::NetworkBridge, pub(crate) set_id: SetId, pub(crate) voter_set_state: SharedVoterSetState, + pub(crate) voting_rule: VR, } -impl, RA, SC> Environment { +impl, RA, SC, VR> Environment { /// Updates the voter set state using the given closure. The write lock is /// held during evaluation of the closure and the environment's voter set /// state is set to its result if successful. @@ -396,16 +398,18 @@ impl, RA, SC> Environment, B, E, N, RA, SC> +impl, B, E, N, RA, SC, VR> grandpa::Chain> -for Environment +for Environment where Block: 'static, B: Backend + 'static, - E: CallExecutor + 'static, + E: CallExecutor + Send + Sync + 'static, N: Network + 'static, N::In: 'static, SC: SelectChain + 'static, + VR: VotingRule>, + RA: Send + Sync, NumberFor: BlockNumberOps, { fn ancestry(&self, base: Block::Hash, block: Block::Hash) -> Result, GrandpaError> { @@ -429,7 +433,7 @@ where debug!(target: "afg", "Finding best chain containing block {:?} with number limit {:?}", block, limit); match self.select_chain.finality_target(block, None) { - Ok(Some(mut best_hash)) => { + Ok(Some(best_hash)) => { let base_header = self.inner.header(&BlockId::Hash(block)).ok()? .expect("Header known to exist after `best_containing` call; qed"); @@ -445,35 +449,51 @@ where } } - let mut best_header = self.inner.header(&BlockId::Hash(best_hash)).ok()? + let best_header = self.inner.header(&BlockId::Hash(best_hash)).ok()? .expect("Header known to exist after `best_containing` call; qed"); - // we target a vote towards 3/4 of the unfinalized chain (rounding up) - let target = { - let two = NumberFor::::one() + One::one(); - let three = two + One::one(); - let four = three + One::one(); - - let diff = *best_header.number() - *base_header.number(); - let diff = ((diff * three) + two) / four; + // check if our vote is currently being limited due to a pending change + let limit = limit.filter(|limit| limit < best_header.number()); + let target; + + let target_header = if let Some(target_number) = limit { + let mut target_header = best_header.clone(); + + // walk backwards until we find the target block + loop { + if *target_header.number() < target_number { + unreachable!( + "we are traversing backwards from a known block; \ + blocks are stored contiguously; \ + qed" + ); + } + + if *target_header.number() == target_number { + break; + } + + target_header = self.inner.header(&BlockId::Hash(*target_header.parent_hash())).ok()? + .expect("Header known to exist after `best_containing` call; qed"); + } - *base_header.number() + diff + target = target_header; + &target + } else { + // otherwise just use the given best as the target + &best_header }; - // unless our vote is currently being limited due to a pending change - let target = limit.map(|limit| limit.min(target)).unwrap_or(target); - - // walk backwards until we find the target block - loop { - if *best_header.number() < target { unreachable!(); } - if *best_header.number() == target { - return Some((best_hash, *best_header.number())); - } - - best_hash = *best_header.parent_hash(); - best_header = self.inner.header(&BlockId::Hash(best_hash)).ok()? - .expect("Header known to exist after `best_containing` call; qed"); - } + // restrict vote according to the given voting rule, if the + // voting rule doesn't restrict the vote then we keep the + // previous target. + // + // note that we pass the original `best_header`, i.e. before the + // authority set limit filter, which can be considered a + // mandatory/implicit voting rule. + self.voting_rule + .restrict_vote(&*self.inner, &base_header, &best_header, target_header) + .or(Some((target_header.hash(), *target_header.number()))) }, Ok(None) => { debug!(target: "afg", "Encountered error finding best chain containing {:?}: couldn't find target block", block); @@ -519,9 +539,9 @@ pub(crate) fn ancestry, E, RA>( Ok(tree_route.retracted().iter().skip(1).map(|e| e.hash).collect()) } -impl, N, RA, SC> +impl, N, RA, SC, VR> voter::Environment> -for Environment +for Environment where Block: 'static, B: Backend + 'static, @@ -530,6 +550,7 @@ where N::In: 'static + Send, RA: 'static + Send + Sync, SC: SelectChain + 'static, + VR: VotingRule>, NumberFor: BlockNumberOps, { type Timer = Box + Send>; diff --git a/core/finality-grandpa/src/lib.rs b/core/finality-grandpa/src/lib.rs index e4b71acbec..3841084d11 100644 --- a/core/finality-grandpa/src/lib.rs +++ b/core/finality-grandpa/src/lib.rs @@ -92,11 +92,15 @@ mod justification; mod light_import; mod observer; mod until_imported; +mod voting_rule; pub use communication::Network; pub use finality_proof::FinalityProofProvider; pub use light_import::light_block_import; pub use observer::run_grandpa_observer; +pub use voting_rule::{ + BeforeBestBlock, ThreeQuartersOfTheUnfinalizedChain, VotingRule, VotingRulesBuilder +}; use aux_schema::PersistentData; use environment::{Environment, VoterSetState}; @@ -466,7 +470,7 @@ fn register_finality_tracker_inherent_data_provider, N, RA, SC, X> { +pub struct GrandpaParams, N, RA, SC, VR, X> { /// Configuration for the GRANDPA service. pub config: Config, /// A link to the block import worker. @@ -479,12 +483,14 @@ pub struct GrandpaParams, N, RA, SC, X> { pub on_exit: X, /// If supplied, can be used to hook on telemetry connection established events. pub telemetry_on_connect: Option>, + /// A voting rule used to potentially restrict target votes. + pub voting_rule: VR, } /// Run a GRANDPA voter as a task. Provide configuration and a link to a /// block import worker that has already been instantiated with `block_import`. -pub fn run_grandpa_voter, N, RA, SC, X>( - grandpa_params: GrandpaParams, +pub fn run_grandpa_voter, N, RA, SC, VR, X>( + grandpa_params: GrandpaParams, ) -> client::error::Result + Send + 'static> where Block::Hash: Ord, B: Backend + 'static, @@ -492,6 +498,7 @@ pub fn run_grandpa_voter, N, RA, SC, X>( N: Network + Send + Sync + 'static, N::In: Send + 'static, SC: SelectChain + 'static, + VR: VotingRule> + Clone + 'static, NumberFor: BlockNumberOps, DigestFor: Encode, RA: Send + Sync + 'static, @@ -504,6 +511,7 @@ pub fn run_grandpa_voter, N, RA, SC, X>( inherent_data_providers, on_exit, telemetry_on_connect, + voting_rule, } = grandpa_params; let LinkHalf { @@ -556,8 +564,9 @@ pub fn run_grandpa_voter, N, RA, SC, X>( config, network, select_chain, + voting_rule, persistent_data, - voter_commands_rx + voter_commands_rx, ); let voter_work = voter_work @@ -578,13 +587,13 @@ pub fn run_grandpa_voter, N, RA, SC, X>( /// Future that powers the voter. #[must_use] -struct VoterWork, RA, SC> { +struct VoterWork, RA, SC, VR> { voter: Box>> + Send>, - env: Arc>, + env: Arc>, voter_commands_rx: mpsc::UnboundedReceiver>>, } -impl VoterWork +impl VoterWork where Block: BlockT, N: Network + Sync, @@ -594,12 +603,14 @@ where E: CallExecutor + Send + Sync + 'static, B: Backend + 'static, SC: SelectChain + 'static, + VR: VotingRule> + Clone + 'static, { fn new( client: Arc>, config: Config, network: NetworkBridge, select_chain: SC, + voting_rule: VR, persistent_data: PersistentData, voter_commands_rx: mpsc::UnboundedReceiver>>, ) -> Self { @@ -608,6 +619,7 @@ where let env = Arc::new(Environment { inner: client, select_chain, + voting_rule, voters: Arc::new(voters), config, network, @@ -731,6 +743,7 @@ where authority_set: self.env.authority_set.clone(), consensus_changes: self.env.consensus_changes.clone(), network: self.env.network.clone(), + voting_rule: self.env.voting_rule.clone(), }); self.rebuild_voter(); @@ -755,7 +768,7 @@ where } } -impl Future for VoterWork +impl Future for VoterWork where Block: BlockT, N: Network + Sync, @@ -765,6 +778,7 @@ where E: CallExecutor + Send + Sync + 'static, B: Backend + 'static, SC: SelectChain + 'static, + VR: VotingRule> + Clone + 'static, { type Item = (); type Error = Error; @@ -809,8 +823,8 @@ where } #[deprecated(since = "1.1", note = "Please switch to run_grandpa_voter.")] -pub fn run_grandpa, N, RA, SC, X>( - grandpa_params: GrandpaParams, +pub fn run_grandpa, N, RA, SC, VR, X>( + grandpa_params: GrandpaParams, ) -> ::client::error::Result + Send + 'static> where Block::Hash: Ord, B: Backend + 'static, @@ -821,6 +835,7 @@ pub fn run_grandpa, N, RA, SC, X>( NumberFor: BlockNumberOps, DigestFor: Encode, RA: Send + Sync + 'static, + VR: VotingRule> + Clone + 'static, X: Future + Clone + Send + 'static, { run_grandpa_voter(grandpa_params) diff --git a/core/finality-grandpa/src/tests.rs b/core/finality-grandpa/src/tests.rs index 1957ab5c4f..7f4a0d053a 100644 --- a/core/finality-grandpa/src/tests.rs +++ b/core/finality-grandpa/src/tests.rs @@ -385,6 +385,7 @@ fn run_to_completion_with( inherent_data_providers: InherentDataProviders::new(), on_exit: Exit, telemetry_on_connect: None, + voting_rule: (), }; let voter = run_grandpa_voter(grandpa_params).expect("all in order with client and network"); @@ -516,6 +517,7 @@ fn finalize_3_voters_1_full_observer() { inherent_data_providers: InherentDataProviders::new(), on_exit: Exit, telemetry_on_connect: None, + voting_rule: (), }; let voter = run_grandpa_voter(grandpa_params).expect("all in order with client and network"); @@ -676,6 +678,7 @@ fn transition_3_voters_twice_1_full_observer() { inherent_data_providers: InherentDataProviders::new(), on_exit: Exit, telemetry_on_connect: None, + voting_rule: (), }; let voter = run_grandpa_voter(grandpa_params).expect("all in order with client and network"); @@ -861,30 +864,6 @@ fn finalizes_multiple_pending_changes_in_order() { run_to_completion(&mut runtime, 30, net.clone(), all_peers); } -#[test] -fn doesnt_vote_on_the_tip_of_the_chain() { - let mut runtime = current_thread::Runtime::new().unwrap(); - let peers_a = &[Ed25519Keyring::Alice, Ed25519Keyring::Bob, Ed25519Keyring::Charlie]; - let voters = make_ids(peers_a); - let api = TestApi::new(voters); - let mut net = GrandpaTestNet::new(api, 3); - - // add 100 blocks - net.peer(0).push_blocks(100, false); - net.block_until_sync(&mut runtime); - - for i in 0..3 { - assert_eq!(net.peer(i).client().info().chain.best_number, 100, - "Peer #{} failed to sync", i); - } - - let net = Arc::new(Mutex::new(net)); - let highest = run_to_completion(&mut runtime, 75, net.clone(), peers_a); - - // the highest block to be finalized will be 3/4 deep in the unfinalized chain - assert_eq!(highest, 75); -} - #[test] fn force_change_to_new_set() { let _ = env_logger::try_init(); @@ -1122,6 +1101,7 @@ fn voter_persists_its_votes() { inherent_data_providers: InherentDataProviders::new(), on_exit: Exit, telemetry_on_connect: None, + voting_rule: VotingRulesBuilder::default().build(), }; let voter = run_grandpa_voter(grandpa_params) @@ -1452,6 +1432,7 @@ fn voter_catches_up_to_latest_round_when_behind() { inherent_data_providers: InherentDataProviders::new(), on_exit: Exit, telemetry_on_connect: None, + voting_rule: (), }; Box::new(run_grandpa_voter(grandpa_params).expect("all in order with client and network")) @@ -1533,3 +1514,116 @@ fn voter_catches_up_to_latest_round_when_behind() { let drive_to_completion = futures::future::poll_fn(|| { net.lock().poll(); Ok(Async::NotReady) }); let _ = runtime.block_on(test.select(drive_to_completion).map_err(|_| ())).unwrap(); } + +#[test] +fn grandpa_environment_respects_voting_rules() { + use grandpa::Chain; + use network::test::TestClient; + + let peers = &[Ed25519Keyring::Alice]; + let voters = make_ids(peers); + + let mut net = GrandpaTestNet::new(TestApi::new(voters), 1); + let peer = net.peer(0); + let network_service = peer.network_service().clone(); + let link = peer.data.lock().take().unwrap(); + + // create a voter environment with a given voting rule + let environment = |voting_rule: Box>| { + let PersistentData { + ref authority_set, + ref consensus_changes, + ref set_state, + .. + } = link.persistent_data; + + let config = Config { + gossip_duration: TEST_GOSSIP_DURATION, + justification_period: 32, + keystore: None, + name: None, + }; + + let (network, _) = NetworkBridge::new( + network_service.clone(), + config.clone(), + set_state.clone(), + Exit, + true, + ); + + Environment { + authority_set: authority_set.clone(), + config: config.clone(), + consensus_changes: consensus_changes.clone(), + inner: link.client.clone(), + select_chain: link.select_chain.clone(), + set_id: authority_set.set_id(), + voter_set_state: set_state.clone(), + voters: Arc::new(authority_set.current_authorities()), + network, + voting_rule, + } + }; + + // add 20 blocks + peer.push_blocks(20, false); + + // create an environment with no voting rule restrictions + let unrestricted_env = environment(Box::new(())); + + // another with 3/4 unfinalized chain voting rule restriction + let three_quarters_env = environment(Box::new( + voting_rule::ThreeQuartersOfTheUnfinalizedChain + )); + + // and another restricted with the default voting rules: i.e. 3/4 rule and + // always below best block + let default_env = environment(Box::new( + VotingRulesBuilder::default().build() + )); + + // the unrestricted environment should just return the best block + assert_eq!( + unrestricted_env.best_chain_containing( + peer.client().info().chain.finalized_hash + ).unwrap().1, + 20, + ); + + // both the other environments should return block 15, which is 3/4 of the + // way in the unfinalized chain + assert_eq!( + three_quarters_env.best_chain_containing( + peer.client().info().chain.finalized_hash + ).unwrap().1, + 15, + ); + + assert_eq!( + default_env.best_chain_containing( + peer.client().info().chain.finalized_hash + ).unwrap().1, + 15, + ); + + // we finalize block 19 with block 20 being the best block + peer.client().finalize_block(BlockId::Number(19), None, false).unwrap(); + + // the 3/4 environment should propose block 20 for voting + assert_eq!( + three_quarters_env.best_chain_containing( + peer.client().info().chain.finalized_hash + ).unwrap().1, + 20, + ); + + // while the default environment will always still make sure we don't vote + // on the best block + assert_eq!( + default_env.best_chain_containing( + peer.client().info().chain.finalized_hash + ).unwrap().1, + 19, + ); +} diff --git a/core/finality-grandpa/src/voting_rule.rs b/core/finality-grandpa/src/voting_rule.rs new file mode 100644 index 0000000000..355fa0cd2d --- /dev/null +++ b/core/finality-grandpa/src/voting_rule.rs @@ -0,0 +1,270 @@ +// Copyright 2018-2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +//! Handling custom voting rules for GRANDPA. +//! +//! This exposes the `VotingRule` trait used to implement arbitrary voting +//! restrictions that are taken into account by the GRANDPA environment when +//! selecting a finality target to vote on. + +use std::sync::Arc; + +use client::blockchain::HeaderBackend; +use sr_primitives::generic::BlockId; +use sr_primitives::traits::{Block as BlockT, Header, NumberFor, One, Zero}; + +/// A trait for custom voting rules in GRANDPA. +pub trait VotingRule: Send + Sync where + Block: BlockT, + B: HeaderBackend, +{ + /// Restrict the given `current_target` vote, returning the block hash and + /// number of the block to vote on, and `None` in case the vote should not + /// be restricted. `base` is the block that we're basing our votes on in + /// order to pick our target (e.g. last round estimate), and `best_target` + /// is the initial best vote target before any vote rules were applied. When + /// applying multiple `VotingRule`s both `base` and `best_target` should + /// remain unchanged. + /// + /// The contract of this interface requires that when restricting a vote, the + /// returned value **must** be an ancestor of the given `current_target`, + /// this also means that a variant must be maintained throughout the + /// execution of voting rules wherein `current_target <= best_target`. + fn restrict_vote( + &self, + backend: &B, + base: &Block::Header, + best_target: &Block::Header, + current_target: &Block::Header, + ) -> Option<(Block::Hash, NumberFor)>; +} + +impl VotingRule for () where + Block: BlockT, + B: HeaderBackend, +{ + fn restrict_vote( + &self, + _backend: &B, + _base: &Block::Header, + _best_target: &Block::Header, + _current_target: &Block::Header, + ) -> Option<(Block::Hash, NumberFor)> { + None + } +} + +/// A custom voting rule that guarantees that our vote is always behind the best +/// block, in the best case exactly one block behind it. +#[derive(Clone)] +pub struct BeforeBestBlock; +impl VotingRule for BeforeBestBlock where + Block: BlockT, + B: HeaderBackend, +{ + fn restrict_vote( + &self, + _backend: &B, + _base: &Block::Header, + best_target: &Block::Header, + current_target: &Block::Header, + ) -> Option<(Block::Hash, NumberFor)> { + if current_target.number().is_zero() { + return None; + } + + if current_target.number() == best_target.number() { + return Some(( + current_target.parent_hash().clone(), + *current_target.number() - One::one(), + )); + } + + None + } +} + +/// A custom voting rule that limits votes towards 3/4 of the unfinalized chain, +/// using the given `base` and `best_target` to figure where the 3/4 target +/// should fall. +pub struct ThreeQuartersOfTheUnfinalizedChain; + +impl VotingRule for ThreeQuartersOfTheUnfinalizedChain where + Block: BlockT, + B: HeaderBackend, +{ + fn restrict_vote( + &self, + backend: &B, + base: &Block::Header, + best_target: &Block::Header, + current_target: &Block::Header, + ) -> Option<(Block::Hash, NumberFor)> { + // target a vote towards 3/4 of the unfinalized chain (rounding up) + let target_number = { + let two = NumberFor::::one() + One::one(); + let three = two + One::one(); + let four = three + One::one(); + + let diff = *best_target.number() - *base.number(); + let diff = ((diff * three) + two) / four; + + *base.number() + diff + }; + + // our current target is already lower than this rule would restrict + if target_number >= *current_target.number() { + return None; + } + + let mut target_header = current_target.clone(); + let mut target_hash = current_target.hash(); + + // walk backwards until we find the target block + loop { + if *target_header.number() < target_number { + unreachable!( + "we are traversing backwards from a known block; \ + blocks are stored contiguously; \ + qed" + ); + } + if *target_header.number() == target_number { + return Some((target_hash, target_number)); + } + + target_hash = *target_header.parent_hash(); + target_header = backend.header(BlockId::Hash(target_hash)).ok()? + .expect("Header known to exist due to the existence of one of its descendents; qed"); + } + } +} + +struct VotingRules { + rules: Arc>>>, +} + +impl Clone for VotingRules { + fn clone(&self) -> Self { + VotingRules { + rules: self.rules.clone(), + } + } +} + +impl VotingRule for VotingRules where + Block: BlockT, + B: HeaderBackend, +{ + fn restrict_vote( + &self, + backend: &B, + base: &Block::Header, + best_target: &Block::Header, + current_target: &Block::Header, + ) -> Option<(Block::Hash, NumberFor)> { + let restricted_target = self.rules.iter().fold( + current_target.clone(), + |current_target, rule| { + rule.restrict_vote( + backend, + base, + best_target, + ¤t_target, + ) + .and_then(|(hash, _)| backend.header(BlockId::Hash(hash)).ok()) + .and_then(std::convert::identity) + .unwrap_or(current_target) + }, + ); + + let restricted_hash = restricted_target.hash(); + + if restricted_hash != current_target.hash() { + Some((restricted_hash, *restricted_target.number())) + } else { + None + } + } +} + +/// A builder of a composite voting rule that applies a set of rules to +/// progressively restrict the vote. +pub struct VotingRulesBuilder { + rules: Vec>>, +} + +impl Default for VotingRulesBuilder where + Block: BlockT, + B: HeaderBackend, +{ + fn default() -> Self { + VotingRulesBuilder::new() + .add(BeforeBestBlock) + .add(ThreeQuartersOfTheUnfinalizedChain) + } +} + +impl VotingRulesBuilder where + Block: BlockT, + B: HeaderBackend, +{ + /// Return a new voting rule builder using the given backend. + pub fn new() -> Self { + VotingRulesBuilder { + rules: Vec::new(), + } + } + + /// Add a new voting rule to the builder. + pub fn add(mut self, rule: R) -> Self where + R: VotingRule + 'static, + { + self.rules.push(Box::new(rule)); + self + } + + /// Add all given voting rules to the builder. + pub fn add_all(mut self, rules: I) -> Self where + I: IntoIterator>>, + { + self.rules.extend(rules); + self + } + + /// Return a new `VotingRule` that applies all of the previously added + /// voting rules in-order. + pub fn build(self) -> impl VotingRule + Clone { + VotingRules { + rules: Arc::new(self.rules), + } + } +} + +impl VotingRule for Box> where + Block: BlockT, + B: HeaderBackend, +{ + fn restrict_vote( + &self, + backend: &B, + base: &Block::Header, + best_target: &Block::Header, + current_target: &Block::Header, + ) -> Option<(Block::Hash, NumberFor)> { + (**self).restrict_vote(backend, base, best_target, current_target) + } +} diff --git a/node-template/src/service.rs b/node-template/src/service.rs index 64a453e298..7934355812 100644 --- a/node-template/src/service.rs +++ b/node-template/src/service.rs @@ -149,6 +149,7 @@ pub fn new_full(config: Configuration Date: Sat, 19 Oct 2019 08:36:43 +0100 Subject: [PATCH 065/167] Move sr-arithmetic to a new crate and add in a fuzzer (#3799) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Split up sr_arithmetic.rs * Add some basic fuzzing * Add more tests * Add printing to fuzzing * Clean things up * Remove arbitrary * Remove comments * More cleaning, fix small error that was causing a panic * Add rational128 * Remove old random tests * introduce panic * fuzzing should panic properly * Bit of cleanup * Add a test uncovered via fuzzing that fails! * Few small changes * Move sr-arithmetic to its own crate * Fix fuzzing * Got rid of fuzzer Cargo.lock * Added no_std * re-export assert_eq_error_rate * bump impl and spec version * re add convert into * Add an ignore to the test * Enabled benchmarking * Reindent * Clean up biguint fuzzer * Clean up biguint more * shuffle sr-primitives/traits about * Remove unused dependencies * Apply clippy suggestions * upgrade primitive-types versions * Run tests against num-bigint * Get rid of allocation in assert_biguints_eq * Add an optimisation to multiply_by_rational * rename parts_per_x -> per_things * Change fuzzer cargo.toml * Remove allocation from BigUint PartialEq impl * Remove accidental indentation * Renmove Lazy and Convert traits * Copy assert_eq_error_rate macro back to sr-primitives * Add documentation to fuzzers * fix sr-primitives assert_eq_error_rate * add cfg(test) * Update core/sr-arithmetic/src/traits.rs Co-Authored-By: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update core/sr-arithmetic/src/traits.rs Co-Authored-By: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update core/sr-arithmetic/fuzzer/src/biguint.rs Co-Authored-By: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Allow rounding up in rational128 * Make changes to biguint.rs * Update core/sr-arithmetic/src/traits.rs Co-Authored-By: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Final touches * Convert to num_bigint::BigUint to compare * remove unused mut * more small changes * shuffle sr-primitives trait imports * more code review * move assert_eq_error_rate to lib.rs * Update core/sr-arithmetic/fuzzer/src/biguint.rs Co-Authored-By: Bastian Köcher * Get rid of S * Simplify rational128 honggfuzz link * Insignificantly change rational128 fuzzing code * Slightly tidy up some of the arithmetic logic * Get rid of sr_arithmetic again(?) and fix sr-primitives/weights * Apply updates to sr_arithmetic.rs to crate --- Cargo.lock | 78 +- Cargo.toml | 2 + core/sr-arithmetic/Cargo.toml | 26 + core/sr-arithmetic/fuzzer/.gitignore | 2 + core/sr-arithmetic/fuzzer/Cargo.toml | 20 + core/sr-arithmetic/fuzzer/src/biguint.rs | 181 ++ core/sr-arithmetic/fuzzer/src/rational128.rs | 77 + core/sr-arithmetic/src/biguint.rs | 809 +++++++ core/sr-arithmetic/src/fixed64.rs | 233 ++ core/sr-arithmetic/src/helpers_128bit.rs | 112 + core/sr-arithmetic/src/lib.rs | 48 + core/sr-arithmetic/src/per_things.rs | 519 +++++ core/sr-arithmetic/src/rational128.rs | 384 +++ core/sr-arithmetic/src/traits.rs | 143 ++ core/sr-primitives/Cargo.toml | 6 +- core/sr-primitives/src/lib.rs | 9 +- core/sr-primitives/src/sr_arithmetic.rs | 2203 ------------------ core/sr-primitives/src/traits.rs | 126 +- core/sr-primitives/src/weights.rs | 2 +- node/runtime/src/lib.rs | 2 +- 20 files changed, 2643 insertions(+), 2339 deletions(-) create mode 100644 core/sr-arithmetic/Cargo.toml create mode 100644 core/sr-arithmetic/fuzzer/.gitignore create mode 100644 core/sr-arithmetic/fuzzer/Cargo.toml create mode 100644 core/sr-arithmetic/fuzzer/src/biguint.rs create mode 100644 core/sr-arithmetic/fuzzer/src/rational128.rs create mode 100644 core/sr-arithmetic/src/biguint.rs create mode 100644 core/sr-arithmetic/src/fixed64.rs create mode 100644 core/sr-arithmetic/src/helpers_128bit.rs create mode 100644 core/sr-arithmetic/src/lib.rs create mode 100644 core/sr-arithmetic/src/per_things.rs create mode 100644 core/sr-arithmetic/src/rational128.rs create mode 100644 core/sr-arithmetic/src/traits.rs delete mode 100644 core/sr-primitives/src/sr_arithmetic.rs diff --git a/Cargo.lock b/Cargo.lock index 8cf8b42bd4..82a5ab2229 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -92,6 +92,11 @@ dependencies = [ "xdg 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "arbitrary" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "arc-swap" version = "0.3.11" @@ -890,6 +895,17 @@ dependencies = [ "static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "fixed-hash" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "fixedbitset" version = "0.1.9" @@ -1263,6 +1279,16 @@ dependencies = [ "hmac 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "honggfuzz" +version = "0.5.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "arbitrary 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "http" version = "0.1.18" @@ -2165,6 +2191,15 @@ dependencies = [ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "memmap" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "memoffset" version = "0.5.1" @@ -2995,6 +3030,16 @@ dependencies = [ "uint 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "primitive-types" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "fixed-hash 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "impl-codec 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "uint 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "proc-macro-crate" version = "0.1.4" @@ -3812,6 +3857,30 @@ dependencies = [ "trybuild 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "sr-arithmetic" +version = "2.0.0" +dependencies = [ + "integer-sqrt 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "primitive-types 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-std 2.0.0", +] + +[[package]] +name = "sr-arithmetic-fuzzer" +version = "2.0.0" +dependencies = [ + "honggfuzz 0.5.45 (registry+https://github.com/rust-lang/crates.io-index)", + "num-bigint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "primitive-types 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-arithmetic 2.0.0", +] + [[package]] name = "sr-io" version = "2.0.0" @@ -3833,15 +3902,13 @@ name = "sr-primitives" version = "2.0.0" dependencies = [ "impl-trait-for-tuples 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "integer-sqrt 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "paste 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "primitive-types 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-arithmetic 2.0.0", "sr-io 2.0.0", "sr-std 2.0.0", "substrate-application-crypto 2.0.0", @@ -6696,6 +6763,7 @@ dependencies = [ "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" "checksum ansi_term 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" "checksum app_dirs 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e73a24bad9bd6a94d6395382a6c69fe071708ae4409f763c5475e14ee896313d" +"checksum arbitrary 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "64cf76cb6e2222ed0ea86b2b0ee2f71c96ec6edd5af42e84d59160e91b836ec4" "checksum arc-swap 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "bc4662175ead9cd84451d5c35070517777949a2ed84551764129cedb88384841" "checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee" "checksum arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" @@ -6788,6 +6856,7 @@ dependencies = [ "checksum fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b1ee15a7050e5580b3712877157068ea713b245b080ff302ae2ca973cfcd9baa" "checksum finality-grandpa 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9681c1f75941ea47584573dd2bc10558b2067d460612945887e00744e43393be" "checksum fixed-hash 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "516877b7b9a1cc2d0293cbce23cd6203f0edbfd4090e6ca4489fecb5aa73050e" +"checksum fixed-hash 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6357b15872f8126e4ea7cf79d579473f132ccd2de239494ad1bf4aa892faea68" "checksum fixedbitset 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "86d4de0081402f5e88cdac65c8dcdcc73118c1a7a465e2a05f0da05843a8ea33" "checksum flate2 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)" = "ad3c5233c9a940c8719031b423d7e6c16af66e031cb0420b0896f5245bf181d3" "checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" @@ -6832,6 +6901,7 @@ dependencies = [ "checksum hmac 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5dcb5e64cda4c23119ab41ba960d1e170a774c8e4b9d9e6a9bc18aabf5e59695" "checksum hmac-drbg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4fe727d41d2eec0a6574d887914347e5ff96a3b87177817e2a9820c5c87fecc2" "checksum hmac-drbg 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c6e570451493f10f6581b48cdd530413b63ea9e780f544bfd3bdcaa0d89d1a7b" +"checksum honggfuzz 0.5.45 (registry+https://github.com/rust-lang/crates.io-index)" = "24c27b4aa3049d6d10d8e33d52c9d03ca9aec18f8a449b246f8c4a5b0c10fb34" "checksum http 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "372bcb56f939e449117fb0869c2e8fd8753a8223d92a172c6e808cf123a5b6e4" "checksum http-body 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6741c859c1b2463a423a1dbce98d418e6c3c3fc720fb0d45528657320920292d" "checksum httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" @@ -6908,6 +6978,7 @@ dependencies = [ "checksum malloc_size_of_derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "35adee9ed962cf7d07d62cb58bc45029f3227f5b5b86246caa8632f06c187bc3" "checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" "checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" +"checksum memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b" "checksum memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce6075db033bbbb7ee5a0bbd3a3186bbae616f57fb001c485c7ff77955f8177f" "checksum memory-db 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ef49315991403ba5fa225a70399df5e115f57b274cb0b1b4bcd6e734fa5bd783" "checksum memory_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "71d96e3f3c0b6325d8ccd83c33b28acb183edcb6c67938ba104ec546854b0882" @@ -6970,6 +7041,7 @@ dependencies = [ "checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b" "checksum pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f81e1644e1b54f5a68959a29aa86cde704219254669da328ecfdf6a1f09d427" "checksum primitive-types 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "83ef7b3b965c0eadcb6838f34f827e1dfb2939bdd5ebd43f9647e009b12b0371" +"checksum primitive-types 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97b5a08dda18910f056e5c2060c034e77cab18e0bd7d895e44f03207af4c71d5" "checksum proc-macro-crate 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e10d4b51f154c8a7fb96fd6dad097cb74b863943ec010ac94b9fd1be8861fe1e" "checksum proc-macro-error 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "aeccfe4d5d8ea175d5f0e4a2ad0637e0f4121d63bd99d356fb1f39ab2e7c6097" "checksum proc-macro-hack 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "114cdf1f426eb7f550f01af5f53a33c0946156f6814aec939b3bd77e844f9a9d" diff --git a/Cargo.toml b/Cargo.toml index 5b012be0e9..9d01fabc1e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -53,6 +53,8 @@ members = [ "core/service/test", "core/session", "core/sr-api-macros", + "core/sr-arithmetic", + "core/sr-arithmetic/fuzzer", "core/sr-io", "core/sr-primitives", "core/sr-staking-primitives", diff --git a/core/sr-arithmetic/Cargo.toml b/core/sr-arithmetic/Cargo.toml new file mode 100644 index 0000000000..d98404db94 --- /dev/null +++ b/core/sr-arithmetic/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "sr-arithmetic" +version = "2.0.0" +authors = ["Parity Technologies "] +edition = "2018" + +[dependencies] +num-traits = { version = "0.2.8", default-features = false } +serde = { version = "1.0.101", optional = true, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "1.0.0", default-features = false, features = ["derive"] } +rstd = { package = "sr-std", path = "../sr-std", default-features = false } +integer-sqrt = "0.1.2" + +[dev-dependencies] +primitive-types = "0.6.0" +rand = "0.7.2" + +[features] +bench = [] +default = ["std"] +std = [ + "serde", + "num-traits/std", + "rstd/std", + "codec/std", +] diff --git a/core/sr-arithmetic/fuzzer/.gitignore b/core/sr-arithmetic/fuzzer/.gitignore new file mode 100644 index 0000000000..3ebcb104d4 --- /dev/null +++ b/core/sr-arithmetic/fuzzer/.gitignore @@ -0,0 +1,2 @@ +hfuzz_target +hfuzz_workspace diff --git a/core/sr-arithmetic/fuzzer/Cargo.toml b/core/sr-arithmetic/fuzzer/Cargo.toml new file mode 100644 index 0000000000..8838e60436 --- /dev/null +++ b/core/sr-arithmetic/fuzzer/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "sr-arithmetic-fuzzer" +version = "2.0.0" +authors = ["Parity Technologies "] +edition = "2018" + +[dependencies] +sr-arithmetic = { path = ".." } +honggfuzz = "0.5" +primitive-types = "0.6" +num-bigint = "0.2" +num-traits = "0.2" + +[[bin]] +name = "biguint" +path = "src/biguint.rs" + +[[bin]] +name = "rational128" +path = "src/rational128.rs" diff --git a/core/sr-arithmetic/fuzzer/src/biguint.rs b/core/sr-arithmetic/fuzzer/src/biguint.rs new file mode 100644 index 0000000000..bd270a97ca --- /dev/null +++ b/core/sr-arithmetic/fuzzer/src/biguint.rs @@ -0,0 +1,181 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +//! # Running +//! Running this fuzzer can be done with `cargo hfuzz run biguint`. `honggfuzz` CLI options can +//! be used by setting `HFUZZ_RUN_ARGS`, such as `-n 4` to use 4 threads. +//! +//! # Debugging a panic +//! Once a panic is found, it can be debugged with +//! `cargo hfuzz run-debug biguint hfuzz_workspace/biguint/*.fuzz`. +//! +//! # More infomation +//! More information about `honggfuzz` can be found +//! [here](https://docs.rs/honggfuzz/). + +use honggfuzz::fuzz; +use sr_arithmetic::biguint::{BigUint, Single}; +use std::convert::TryFrom; + +fn main() { + loop { + fuzz!(|data: (Vec, Vec, bool)| { + let (mut digits_u, mut digits_v, return_remainder) = data; + + let mut u = BigUint::from_limbs(&digits_u); + let mut v = BigUint::from_limbs(&digits_v); + + u.lstrip(); + v.lstrip(); + + let ue = u128::try_from(u.clone()); + let ve = u128::try_from(v.clone()); + + digits_u.reverse(); + digits_v.reverse(); + + let num_u = num_bigint::BigUint::new(digits_u.clone()); + let num_v = num_bigint::BigUint::new(digits_v.clone()); + + if check_digit_lengths(&u, &v, 4) { + assert_eq!(u.cmp(&v), ue.cmp(&ve)); + assert_eq!(u.eq(&v), ue.eq(&ve)); + } + + if check_digit_lengths(&u, &v, 3) { + let expected = ue.unwrap() + ve.unwrap(); + let t = u.clone().add(&v); + assert_eq!( + u128::try_from(t.clone()).unwrap(), expected, + "{:?} + {:?} ===> {:?} != {:?}", u, v, t, expected, + ); + } + + if check_digit_lengths(&u, &v, 4) { + let expected = ue.unwrap().checked_sub(ve.unwrap()); + let t = u.clone().sub(&v); + if expected.is_none() { + assert!(t.is_err()) + } else { + let t = t.unwrap(); + let expected = expected.unwrap(); + assert_eq!( + u128::try_from(t.clone()).unwrap(), expected, + "{:?} - {:?} ===> {:?} != {:?}", u, v, t, expected, + ); + } + } + + if check_digit_lengths(&u, &v, 2) { + let expected = ue.unwrap() * ve.unwrap(); + let t = u.clone().mul(&v); + assert_eq!( + u128::try_from(t.clone()).unwrap(), expected, + "{:?} * {:?} ===> {:?} != {:?}", u, v, t, expected, + ); + } + + if check_digit_lengths(&u, &v, 4) { + let (ue, ve) = (ue.unwrap(), ve.unwrap()); + if ve == 0 { + return; + } + let (q, r) = (ue / ve, ue % ve); + if let Some((qq, rr)) = u.clone().div(&v, true) { + assert_eq!( + u128::try_from(qq.clone()).unwrap(), q, + "{:?} / {:?} ===> {:?} != {:?}", u, v, qq, q, + ); + assert_eq!( + u128::try_from(rr.clone()).unwrap(), r, + "{:?} % {:?} ===> {:?} != {:?}", u, v, rr, r, + ); + } else if v.len() == 1 { + let qq = u.clone().div_unit(ve as Single); + assert_eq!( + u128::try_from(qq.clone()).unwrap(), q, + "[single] {:?} / {:?} ===> {:?} != {:?}", u, v, qq, q, + ); + } else if v.msb() != 0 && u.msb() != 0 && u.len() > v.len() { + panic!("div returned none for an unexpected reason"); + } + } + + // Test against num_bigint + + // Equality + + assert_eq!(u.cmp(&v), num_u.cmp(&num_v)); + + // Addition + + let w = u.clone().add(&v); + let num_w = num_u.clone() + &num_v; + + assert_biguints_eq(&w, &num_w); + + // Subtraction + + if let Ok(w) = u.clone().sub(&v) { + let num_w = num_u.clone() - &num_v; + + assert_biguints_eq(&w, &num_w); + } + + // Multiplication + + let w = u.clone().mul(&v); + let num_w = num_u.clone() * &num_v; + + assert_biguints_eq(&w, &num_w); + + // Division + + if v.len() == 1 && v.get(0) != 0 { + let w = u.clone().div_unit(v.get(0)); + let num_w = num_u.clone() / &num_v; + assert_biguints_eq(&w, &num_w); + } else if u.len() > v.len() && v.len() > 0 { + let num_remainder = num_u.clone() % num_v.clone(); + + let (w, remainder) = u.clone().div(&v, return_remainder).unwrap(); + let num_w = num_u.clone() / &num_v; + + assert_biguints_eq(&w, &num_w); + + if return_remainder { + assert_biguints_eq(&remainder, &num_remainder); + } + } + }); + } +} + +fn check_digit_lengths(u: &BigUint, v: &BigUint, max_limbs: usize) -> bool { + 1 <= u.len() && u.len() <= max_limbs && 1 <= v.len() && v.len() <= max_limbs +} + +fn assert_biguints_eq(a: &BigUint, b: &num_bigint::BigUint) { + let mut a = a.clone(); + a.lstrip(); + + // `num_bigint::BigUint` doesn't expose it's internals, so we need to convert into that to + // compare. + let limbs = (0 .. a.len()).map(|i| a.get(i)).collect(); + let num_a = num_bigint::BigUint::new(limbs); + + assert!(&num_a == b, "\narithmetic: {:?}\nnum-bigint: {:?}", a, b); +} diff --git a/core/sr-arithmetic/fuzzer/src/rational128.rs b/core/sr-arithmetic/fuzzer/src/rational128.rs new file mode 100644 index 0000000000..b2a00d7545 --- /dev/null +++ b/core/sr-arithmetic/fuzzer/src/rational128.rs @@ -0,0 +1,77 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +//! # Running +//! Running this fuzzer can be done with `cargo hfuzz run rational128`. `honggfuzz` CLI options can +//! be used by setting `HFUZZ_RUN_ARGS`, such as `-n 4` to use 4 threads. +//! +//! # Debugging a panic +//! Once a panic is found, it can be debugged with +//! `cargo hfuzz run-debug rational128 hfuzz_workspace/rational128/*.fuzz`. +//! +//! # More infomation +//! More information about `honggfuzz` can be found +//! [here](https://docs.rs/honggfuzz/). + +use honggfuzz::fuzz; +use sr_arithmetic::{helpers_128bit::multiply_by_rational, traits::Zero}; + +fn main() { + loop { + fuzz!(|data: ([u8; 16], [u8; 16], [u8; 16])| { + let (a_bytes, b_bytes, c_bytes) = data; + let (a, b, c) = ( + u128::from_be_bytes(a_bytes), + u128::from_be_bytes(b_bytes), + u128::from_be_bytes(c_bytes), + ); + + println!("++ Equation: {} * {} / {}", a, b, c); + + // The point of this fuzzing is to make sure that `multiply_by_rational` is 100% + // accurate as long as the value fits in a u128. + if let Ok(result) = multiply_by_rational(a, b, c) { + let truth = mul_div(a, b, c); + + if result != truth && result != truth + 1 { + println!("++ Expected {}", truth); + println!("+++++++ Got {}", result); + panic!(); + } + } + }) + } +} + +fn mul_div(a: u128, b: u128, c: u128) -> u128 { + use primitive_types::U256; + if a.is_zero() { + return Zero::zero(); + } + let c = c.max(1); + + // e for extended + let ae: U256 = a.into(); + let be: U256 = b.into(); + let ce: U256 = c.into(); + + let r = ae * be / ce; + if r > u128::max_value().into() { + a + } else { + r.as_u128() + } +} diff --git a/core/sr-arithmetic/src/biguint.rs b/core/sr-arithmetic/src/biguint.rs new file mode 100644 index 0000000000..d90ad4862b --- /dev/null +++ b/core/sr-arithmetic/src/biguint.rs @@ -0,0 +1,809 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +//! Infinite precision unsigned integer for substrate runtime. + +use num_traits::Zero; +use rstd::{cmp::Ordering, ops, prelude::*, cell::RefCell, convert::TryFrom}; + +// A sensible value for this would be half of the dword size of the host machine. Since the +// runtime is compiled to 32bit webassembly, using 32 and 64 for single and double respectively +// should yield the most performance. TODO #3745 we could benchmark this and verify. +/// Representation of a single limb. +pub type Single = u32; +/// Representation of two limbs. +pub type Double = u64; +/// Difference in the number of bits of [`Single`] and [`Double`]. +const SHIFT: usize = 32; +/// short form of _Base_. Analogous to the value 10 in base-10 decimal numbers. +const B: Double = Single::max_value() as Double + 1; + +/// Splits a [`Double`] limb number into a tuple of two [`Single`] limb numbers. +pub fn split(a: Double) -> (Single, Single) { + let al = a as Single; + let ah = (a >> SHIFT) as Single; + (ah, al) +} + +/// Assumed as a given primitive. +/// +/// Multiplication of two singles, which at most yields 1 double. +pub fn mul_single(a: Single, b: Single) -> Double { + let a: Double = a.into(); + let b: Double = b.into(); + a * b +} + +/// Assumed as a given primitive. +/// +/// Addition of two singles, which at most takes a single limb of result and a carry, +/// returned as a tuple respectively. +pub fn add_single(a: Single, b: Single) -> (Single, Single) { + let a: Double = a.into(); + let b: Double = b.into(); + let q = a + b; + let (carry, r) = split(q); + (r, carry) +} + +/// Assumed as a given primitive. +/// +/// Division of double by a single limb. Always returns a double limb of quotient and a single +/// limb of remainder. +fn div_single(a: Double, b: Single) -> (Double, Single) { + let b: Double = b.into(); + let q = a / b; + let r = a % b; + // both conversions are trivially safe. + (q, r as Single) +} + +/// Simple wrapper around an infinitely large integer, represented as limbs of [`Single`]. +#[derive(Clone, Default)] +pub struct BigUint { + /// digits (limbs) of this number (sorted as msb -> lsd). + pub(crate) digits: Vec, +} + +impl BigUint { + /// Create a new instance with `size` limbs. This prevents any number with zero limbs to be + /// created. + /// + /// The behavior of the type is undefined with zero limbs. + pub fn with_capacity(size: usize) -> Self { + Self { digits: vec![0; size.max(1)] } + } + + /// Raw constructor from custom limbs. If `limbs` is empty, `Zero::zero()` implementation is + /// used. + pub fn from_limbs(limbs: &[Single]) -> Self { + if !limbs.is_empty() { + Self { digits: limbs.to_vec() } + } else { + Zero::zero() + } + } + + /// Number of limbs. + pub fn len(&self) -> usize { self.digits.len() } + + /// A naive getter for limb at `index`. Note that the order is lsb -> msb. + /// + /// #### Panics + /// + /// This panics if index is out of range. + pub fn get(&self, index: usize) -> Single { + self.digits[self.len() - 1 - index] + } + + /// A naive getter for limb at `index`. Note that the order is lsb -> msb. + pub fn checked_get(&self, index: usize) -> Option { + let i = self.len().checked_sub(1)?; + let j = i.checked_sub(index)?; + self.digits.get(j).cloned() + } + + /// A naive setter for limb at `index`. Note that the order is lsb -> msb. + /// + /// #### Panics + /// + /// This panics if index is out of range. + pub fn set(&mut self, index: usize, value: Single) { + let len = self.digits.len(); + self.digits[len - 1 - index] = value; + } + + /// returns the least significant limb of the number. + /// + /// #### Panics + /// + /// While the constructor of the type prevents this, this can panic if `self` has no digits. + pub fn lsb(&self) -> Single { + self.digits[self.len() - 1] + } + + /// returns the most significant limb of the number. + /// + /// #### Panics + /// + /// While the constructor of the type prevents this, this can panic if `self` has no digits. + pub fn msb(&self) -> Single { + self.digits[0] + } + + /// Strips zeros from the left side (the most significant limbs) of `self`, if any. + pub fn lstrip(&mut self) { + // by definition, a big-int number should never have leading zero limbs. This function + // has the ability to cause this. There is nothing to do if the number already has 1 + // limb only. call it a day and return. + if self.len().is_zero() { return; } + let index = self.digits.iter().position(|&elem| elem != 0).unwrap_or(0); + + if index > 0 { + self.digits = self.digits[index..].to_vec() + } + } + + /// Zero-pad `self` from left to reach `size` limbs. Will not make any difference if `self` + /// is already bigger than `size` limbs. + pub fn lpad(&mut self, size: usize) { + let n = self.len(); + if n >= size { return; } + let pad = size - n; + let mut new_digits = (0..pad).map(|_| 0).collect::>(); + new_digits.extend(self.digits.iter()); + self.digits = new_digits; + } + + /// Adds `self` with `other`. self and other do not have to have any particular size. Given + /// that the `n = max{size(self), size(other)}`, it will produce a number with `n + 1` + /// limbs. + /// + /// This function does not strip the output and returns the original allocated `n + 1` + /// limbs. The caller may strip the output if desired. + /// + /// Taken from "The Art of Computer Programming" by D.E. Knuth, vol 2, chapter 4. + pub fn add(self, other: &Self) -> Self { + let n = self.len().max(other.len()); + let mut k: Double = 0; + let mut w = Self::with_capacity(n + 1); + + for j in 0..n { + let u = Double::from(self.checked_get(j).unwrap_or(0)); + let v = Double::from(other.checked_get(j).unwrap_or(0)); + let s = u + v + k; + w.set(j, (s % B) as Single); + k = s / B; + } + // k is always 0 or 1. + w.set(n, k as Single); + w + } + + /// Subtracts `other` from `self`. self and other do not have to have any particular size. + /// Given that the `n = max{size(self), size(other)}`, it will produce a number of size `n`. + /// + /// If `other` is bigger than `self`, `Err(B - borrow)` is returned. + /// + /// Taken from "The Art of Computer Programming" by D.E. Knuth, vol 2, chapter 4. + pub fn sub(self, other: &Self) -> Result { + let n = self.len().max(other.len()); + let mut k = 0; + let mut w = Self::with_capacity(n); + for j in 0..n { + let s = { + let u = Double::from(self.checked_get(j).unwrap_or(0)); + let v = Double::from(other.checked_get(j).unwrap_or(0)); + let mut needs_borrow = false; + let mut t = 0; + + if let Some(v) = u.checked_sub(v) { + if let Some(v2) = v.checked_sub(k) { + t = v2 % B; + k = 0; + } else { + needs_borrow = true; + } + } else { + needs_borrow = true; + } + if needs_borrow { + t = u + B - v - k; + k = 1; + } + t + }; + // PROOF: t either comes from `v2 % B`, or from `u + B - v - k`. The former is + // trivial. The latter will not overflow this branch will only happen if the sum of + // `u - v - k` part has been negative, hence `u + B - v - k < b`. + w.set(j, s as Single); + } + + if k.is_zero() { + Ok(w) + } else { + Err(w) + } + } + + /// Multiplies n-limb number `self` with m-limb number `other`. + /// + /// The resulting number will always have `n + m` limbs. + /// + /// This function does not strip the output and returns the original allocated `n + m` + /// limbs. The caller may strip the output if desired. + /// + /// Taken from "The Art of Computer Programming" by D.E. Knuth, vol 2, chapter 4. + pub fn mul(self, other: &Self) -> Self { + let n = self.len(); + let m = other.len(); + let mut w = Self::with_capacity(m + n); + + for j in 0..n { + if self.get(j) == 0 { + // Note: `with_capacity` allocates with 0. Explicitly set j + m to zero if + // otherwise. + continue; + } + + let mut k = 0; + for i in 0..m { + // PROOF: (B−1) × (B−1) + (B−1) + (B−1) = B^2 −1 < B^2. addition is safe. + let t = + mul_single(self.get(j), other.get(i)) + + Double::from(w.get(i + j)) + + Double::from(k); + w.set(i + j, (t % B) as Single); + // PROOF: (B^2 - 1) / B < B. conversion is safe. + k = (t / B) as Single; + } + w.set(j + m, k); + } + w + } + + /// Divides `self` by a single limb `other`. This can be used in cases where the original + /// division cannot work due to the divisor (`other`) being just one limb. + /// + /// Invariant: `other` cannot be zero. + pub fn div_unit(self, mut other: Single) -> Self { + other = other.max(1); + let n = self.len(); + let mut out = Self::with_capacity(n); + let mut r: Single = 0; + // PROOF: (B-1) * B + (B-1) still fits in double + let with_r = |x: Double, r: Single| { Double::from(r) * B + x }; + for d in (0..n).rev() { + let (q, rr) = div_single(with_r(self.get(d).into(), r), other) ; + out.set(d, q as Single); + r = rr; + } + out + } + + /// Divides an `n + m` limb self by a `n` limb `other`. The result is a `m + 1` limb + /// quotient and a `n` limb remainder, if enabled by passing `true` in `rem` argument, both + /// in the form of an option's `Ok`. + /// + /// - requires `other` to be stripped and have no leading zeros. + /// - requires `self` to be stripped and have no leading zeros. + /// - requires `other` to have at least two limbs. + /// - requires `self` to have a greater length compared to `other`. + /// + /// All arguments are examined without being stripped for the above conditions. If any of + /// the above fails, `None` is returned.` + /// + /// Taken from "The Art of Computer Programming" by D.E. Knuth, vol 2, chapter 4. + pub fn div(self, other: &Self, rem: bool) -> Option<(Self, Self)> { + if other.len() <= 1 + || other.msb() == 0 + || self.msb() == 0 + || self.len() <= other.len() + { + return None + } + let n = other.len(); + let m = self.len() - n; + + let mut q = Self::with_capacity(m + 1); + let mut r = Self::with_capacity(n); + + // PROOF: 0 <= normalizer_bits < SHIFT 0 <= normalizer < B. all conversions are + // safe. + let normalizer_bits = other.msb().leading_zeros() as Single; + let normalizer = (2 as Single).pow(normalizer_bits as u32) as Single; + + // step D1. + let mut self_norm = self.mul(&Self::from(normalizer)); + let mut other_norm = other.clone().mul(&Self::from(normalizer)); + + // defensive only; the mul implementation should always create this. + self_norm.lpad(n + m + 1); + other_norm.lstrip(); + + // step D2. + for j in (0..=m).rev() { + // step D3.0 Find an estimate of q[j], named qhat. + let (qhat, rhat) = { + // PROOF: this always fits into `Double`. In the context of Single = u8, and + // Double = u16, think of 255 * 256 + 255 which is just u16::max_value(). + let dividend = + Double::from(self_norm.get(j + n)) + * B + + Double::from(self_norm.get(j + n - 1)); + let divisor = other_norm.get(n - 1); + div_single(dividend, divisor) + }; + + // D3.1 test qhat + // replace qhat and rhat with RefCells. This helps share state with the closure + let qhat = RefCell::new(qhat); + let rhat = RefCell::new(Double::from(rhat)); + + let test = || { + // decrease qhat if it is bigger than the base (B) + let qhat_local = *qhat.borrow(); + let rhat_local = *rhat.borrow(); + let predicate_1 = qhat_local >= B; + let predicate_2 = { + let lhs = qhat_local * Double::from(other_norm.get(n - 2)); + let rhs = B * rhat_local + Double::from(self_norm.get(j + n - 2)); + lhs > rhs + }; + if predicate_1 || predicate_2 { + *qhat.borrow_mut() -= 1; + *rhat.borrow_mut() += Double::from(other_norm.get(n - 1)); + true + } else { + false + } + }; + + test(); + while (*rhat.borrow() as Double) < B { + if !test() { break; } + } + + let qhat = qhat.into_inner(); + // we don't need rhat anymore. just let it go out of scope when it does. + + // step D4 + let lhs = Self { digits: (j..=j+n).rev().map(|d| self_norm.get(d)).collect() }; + let rhs = other_norm.clone().mul(&Self::from(qhat)); + + let maybe_sub = lhs.sub(&rhs); + let mut negative = false; + let sub = match maybe_sub { + Ok(t) => t, + Err(t) => { negative = true; t } + }; + (j..=j+n).for_each(|d| { self_norm.set(d, sub.get(d - j)); }); + + // step D5 + // PROOF: the `test()` specifically decreases qhat until it is below `B`. conversion + // is safe. + q.set(j, qhat as Single); + + // step D6: add back if negative happened. + if negative { + q.set(j, q.get(j) - 1); + let u = Self { digits: (j..=j+n).rev().map(|d| self_norm.get(d)).collect() }; + let r = other_norm.clone().add(&u); + (j..=j+n).rev().for_each(|d| { self_norm.set(d, r.get(d - j)); }) + } + } + + // if requested, calculate remainder. + if rem { + // undo the normalization. + if normalizer_bits > 0 { + let s = SHIFT as u32; + let nb = normalizer_bits; + for d in 0..n-1 { + let v = self_norm.get(d) >> nb + | self_norm.get(d + 1).overflowing_shl(s - nb).0; + r.set(d, v); + } + r.set(n - 1, self_norm.get(n - 1) >> normalizer_bits); + } else { + r = self_norm; + } + } + + Some((q, r)) + } +} + +#[cfg(feature = "std")] +impl rstd::fmt::Debug for BigUint { + fn fmt(&self, f: &mut rstd::fmt::Formatter<'_>) -> rstd::fmt::Result { + write!( + f, + "BigUint {{ {:?} ({:?})}}", + self.digits, + u128::try_from(self.clone()).unwrap_or(0), + ) + } +} + +impl PartialEq for BigUint { + fn eq(&self, other: &Self) -> bool { + self.cmp(other) == Ordering::Equal + } +} + +impl Eq for BigUint {} + +impl Ord for BigUint { + fn cmp(&self, other: &Self) -> Ordering { + let lhs_first = self.digits.iter().position(|&e| e != 0); + let rhs_first = other.digits.iter().position(|&e| e != 0); + + match (lhs_first, rhs_first) { + // edge cases that should not happen. This basically means that one or both were + // zero. + (None, None) => Ordering::Equal, + (Some(_), None) => Ordering::Greater, + (None, Some(_)) => Ordering::Less, + (Some(lhs_idx), Some(rhs_idx)) => { + let lhs = &self.digits[lhs_idx..]; + let rhs = &other.digits[rhs_idx..]; + let len_cmp = lhs.len().cmp(&rhs.len()); + match len_cmp { + Ordering::Equal => lhs.cmp(rhs), + _ => len_cmp, + } + } + } + } +} + +impl PartialOrd for BigUint { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl ops::Add for BigUint { + type Output = Self; + fn add(self, rhs: Self) -> Self::Output { + self.add(&rhs) + } +} + +impl ops::Sub for BigUint { + type Output = Self; + fn sub(self, rhs: Self) -> Self::Output { + self.sub(&rhs).unwrap_or_else(|e| e) + } +} + +impl ops::Mul for BigUint { + type Output = Self; + fn mul(self, rhs: Self) -> Self::Output { + self.mul(&rhs) + } +} + +impl Zero for BigUint { + fn zero() -> Self { + Self { digits: vec![Zero::zero()] } + } + + fn is_zero(&self) -> bool { + self.digits.iter().all(|d| d.is_zero()) + } +} + +macro_rules! impl_try_from_number_for { + ($([$type:ty, $len:expr]),+) => { + $( + impl TryFrom for $type { + type Error = &'static str; + fn try_from(mut value: BigUint) -> Result<$type, Self::Error> { + value.lstrip(); + let error_message = concat!("cannot fit a number into ", stringify!($type)); + if value.len() * SHIFT > $len { + Err(error_message) + } else { + let mut acc: $type = Zero::zero(); + for (i, d) in value.digits.iter().rev().cloned().enumerate() { + let d: $type = d.into(); + acc += d << (SHIFT * i); + } + Ok(acc) + } + } + } + )* + }; +} +// can only be implemented for sizes bigger than two limb. +impl_try_from_number_for!([u128, 128], [u64, 64]); + +macro_rules! impl_from_for_smaller_than_word { + ($($type:ty),+) => { + $(impl From<$type> for BigUint { + fn from(a: $type) -> Self { + Self { digits: vec! [a.into()] } + } + })* + } +} +impl_from_for_smaller_than_word!(u8, u16, Single); + +impl From for BigUint { + fn from(a: Double) -> Self { + let (ah, al) = split(a); + Self { digits: vec![ah, al] } + } +} + +#[cfg(test)] +pub mod tests { + use super::*; + #[cfg(feature = "bench")] + use test::Bencher; + + fn with_limbs(n: usize) -> BigUint { + BigUint { digits: vec![1; n] } + } + + #[test] + fn split_works() { + let a = SHIFT / 2; + let b = SHIFT * 3 / 2; + let num: Double = 1 << a | 1 << b; + // example when `Single = u8` + // assert_eq!(num, 0b_0001_0000_0001_0000) + assert_eq!(split(num), (1 << a, 1 << a)); + } + + #[test] + fn strip_works() { + let mut a = BigUint::from_limbs(&[0, 1, 0]); + a.lstrip(); + assert_eq!(a, BigUint { digits: vec![1, 0] }); + + let mut a = BigUint::from_limbs(&[0, 0, 1]); + a.lstrip(); + assert_eq!(a, BigUint { digits: vec![1] }); + + let mut a = BigUint::from_limbs(&[0, 0]); + a.lstrip(); + assert_eq!(a, BigUint { digits: vec![0] }); + + let mut a = BigUint::from_limbs(&[0, 0, 0]); + a.lstrip(); + assert_eq!(a, BigUint { digits: vec![0] }); + } + + #[test] + fn lpad_works() { + let mut a = BigUint::from_limbs(&[0, 1, 0]); + a.lpad(2); + assert_eq!(a.digits, vec![0, 1, 0]); + + let mut a = BigUint::from_limbs(&[0, 1, 0]); + a.lpad(3); + assert_eq!(a.digits, vec![0, 1, 0]); + + let mut a = BigUint::from_limbs(&[0, 1, 0]); + a.lpad(4); + assert_eq!(a.digits, vec![0, 0, 1, 0]); + } + + #[test] + fn equality_works() { + assert_eq!( + BigUint { digits: vec![1, 2, 3] } == BigUint { digits: vec![1, 2, 3] }, + true, + ); + assert_eq!( + BigUint { digits: vec![3, 2, 3] } == BigUint { digits: vec![1, 2, 3] }, + false, + ); + assert_eq!( + BigUint { digits: vec![0, 1, 2, 3] } == BigUint { digits: vec![1, 2, 3] }, + true, + ); + } + + #[test] + fn ordering_works() { + assert!(BigUint { digits: vec![0] } < BigUint { digits: vec![1] }); + assert!(BigUint { digits: vec![0] } == BigUint { digits: vec![0] }); + assert!(BigUint { digits: vec![] } == BigUint { digits: vec![0] }); + assert!(BigUint { digits: vec![] } == BigUint { digits: vec![] }); + assert!(BigUint { digits: vec![] } < BigUint { digits: vec![1] }); + + assert!(BigUint { digits: vec![1, 2, 3] } == BigUint { digits: vec![1, 2, 3] }); + assert!(BigUint { digits: vec![0, 1, 2, 3] } == BigUint { digits: vec![1, 2, 3] }); + + assert!(BigUint { digits: vec![1, 2, 4] } > BigUint { digits: vec![1, 2, 3] }); + assert!(BigUint { digits: vec![0, 1, 2, 4] } > BigUint { digits: vec![1, 2, 3] }); + assert!(BigUint { digits: vec![1, 2, 1, 0] } > BigUint { digits: vec![1, 2, 3] }); + + assert!(BigUint { digits: vec![0, 1, 2, 1] } < BigUint { digits: vec![1, 2, 3] }); + } + + #[test] + fn can_try_build_numbers_from_types() { + use rstd::convert::TryFrom; + assert_eq!(u64::try_from(with_limbs(1)).unwrap(), 1); + assert_eq!(u64::try_from(with_limbs(2)).unwrap(), u32::max_value() as u64 + 2); + assert_eq!( + u64::try_from(with_limbs(3)).unwrap_err(), + "cannot fit a number into u64", + ); + assert_eq!( + u128::try_from(with_limbs(3)).unwrap(), + u32::max_value() as u128 + u64::max_value() as u128 + 3 + ); + } + + #[test] + fn zero_works() { + assert_eq!(BigUint::zero(), BigUint { digits: vec![0] }); + assert_eq!(BigUint { digits: vec![0, 1, 0] }.is_zero(), false); + assert_eq!(BigUint { digits: vec![0, 0, 0] }.is_zero(), true); + + let a = BigUint::zero(); + let b = BigUint::zero(); + let c = a * b; + assert_eq!(c.digits, vec![0, 0]); + } + + #[test] + fn sub_negative_works() { + assert_eq!( + BigUint::from(10 as Single).sub(&BigUint::from(5 as Single)).unwrap(), + BigUint::from(5 as Single) + ); + assert_eq!( + BigUint::from(10 as Single).sub(&BigUint::from(10 as Single)).unwrap(), + BigUint::from(0 as Single) + ); + assert_eq!( + BigUint::from(10 as Single).sub(&BigUint::from(13 as Single)).unwrap_err(), + BigUint::from((B - 3) as Single), + ); + } + + #[test] + fn mul_always_appends_one_digit() { + let a = BigUint::from(10 as Single); + let b = BigUint::from(4 as Single); + assert_eq!(a.len(), 1); + assert_eq!(b.len(), 1); + + let n = a.mul(&b); + + assert_eq!(n.len(), 2); + assert_eq!(n.digits, vec![0, 40]); + } + + #[test] + fn div_conditions_work() { + let a = BigUint { digits: vec![2] }; + let b = BigUint { digits: vec![1, 2] }; + let c = BigUint { digits: vec![1, 1, 2] }; + let d = BigUint { digits: vec![0, 2] }; + let e = BigUint { digits: vec![0, 1, 1, 2] }; + + assert!(a.clone().div(&b, true).is_none()); + assert!(c.clone().div(&a, true).is_none()); + assert!(c.clone().div(&d, true).is_none()); + assert!(e.clone().div(&a, true).is_none()); + + assert!(c.clone().div(&b, true).is_some()); + } + + #[test] + fn div_unit_works() { + let a = BigUint { digits: vec![100] }; + let b = BigUint { digits: vec![1, 100] }; + + assert_eq!(a.clone().div_unit(1), a); + assert_eq!(a.clone().div_unit(0), a); + assert_eq!(a.clone().div_unit(2), BigUint::from(50 as Single)); + assert_eq!(a.clone().div_unit(7), BigUint::from(14 as Single)); + + assert_eq!(b.clone().div_unit(1), b); + assert_eq!(b.clone().div_unit(0), b); + assert_eq!(b.clone().div_unit(2), BigUint::from(((B + 100) / 2) as Single)); + assert_eq!(b.clone().div_unit(7), BigUint::from(((B + 100) / 7) as Single)); + + } + + #[cfg(feature = "bench")] + fn random_big_uint(size: usize) -> BigUint { + use rand::Rng; + let mut rng = rand::thread_rng(); + let digits = (0..size).map(|_| rng.gen_range(0, Single::max_value())).collect(); + BigUint { digits } + } + + #[cfg(feature = "bench")] + #[bench] + fn bench_addition_2_digit(bencher: &mut Bencher) { + let a = random_big_uint(2); + let b = random_big_uint(2); + bencher.iter(|| { + let _ = a.clone().add(&b); + }); + } + + #[cfg(feature = "bench")] + #[bench] + fn bench_addition_4_digit(bencher: &mut Bencher) { + let a = random_big_uint(4); + let b = random_big_uint(4); + bencher.iter(|| { + let _ = a.clone().add(&b); + }); + } + + #[cfg(feature = "bench")] + #[bench] + fn bench_subtraction_2_digit(bencher: &mut Bencher) { + let a = random_big_uint(2); + let b = random_big_uint(2); + bencher.iter(|| { + let _ = a.clone().sub(&b); + }); + } + + #[cfg(feature = "bench")] + #[bench] + fn bench_subtraction_4_digit(bencher: &mut Bencher) { + let a = random_big_uint(4); + let b = random_big_uint(4); + bencher.iter(|| { + let _ = a.clone().sub(&b); + }); + } + + #[cfg(feature = "bench")] + #[bench] + fn bench_multiplication_2_digit(bencher: &mut Bencher) { + let a = random_big_uint(2); + let b = random_big_uint(2); + bencher.iter(|| { + let _ = a.clone().mul(&b); + }); + } + + #[cfg(feature = "bench")] + #[bench] + fn bench_multiplication_4_digit(bencher: &mut Bencher) { + let a = random_big_uint(4); + let b = random_big_uint(4); + bencher.iter(|| { + let _ = a.clone().mul(&b); + }); + } + + #[cfg(feature = "bench")] + #[bench] + fn bench_division_4_digit(bencher: &mut Bencher) { + let a = random_big_uint(4); + let b = random_big_uint(2); + bencher.iter(|| { + let _ = a.clone().div(&b, true); + }); + } +} diff --git a/core/sr-arithmetic/src/fixed64.rs b/core/sr-arithmetic/src/fixed64.rs new file mode 100644 index 0000000000..7dfc8414d2 --- /dev/null +++ b/core/sr-arithmetic/src/fixed64.rs @@ -0,0 +1,233 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +use rstd::{ + ops, prelude::*, + convert::{TryFrom, TryInto}, +}; +use codec::{Encode, Decode}; +use crate::{ + Perbill, + traits::{ + SaturatedConversion, CheckedSub, CheckedAdd, Bounded, UniqueSaturatedInto, Saturating + } +}; + +/// An unsigned fixed point number. Can hold any value in the range [-9_223_372_036, 9_223_372_036] +/// with fixed point accuracy of one billion. +#[derive(Encode, Decode, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct Fixed64(i64); + +/// The accuracy of the `Fixed64` type. +const DIV: i64 = 1_000_000_000; + +impl Fixed64 { + /// creates self from a natural number. + /// + /// Note that this might be lossy. + pub fn from_natural(int: i64) -> Self { + Self(int.saturating_mul(DIV)) + } + + /// Return the accuracy of the type. Given that this function returns the value `X`, it means + /// that an instance composed of `X` parts (`Fixed64::from_parts(X)`) is equal to `1`. + pub fn accuracy() -> i64 { + DIV + } + + /// Raw constructor. Equal to `parts / 1_000_000_000`. + pub fn from_parts(parts: i64) -> Self { + Self(parts) + } + + /// creates self from a rational number. Equal to `n/d`. + /// + /// Note that this might be lossy. + pub fn from_rational(n: i64, d: u64) -> Self { + Self( + (i128::from(n).saturating_mul(i128::from(DIV)) / i128::from(d).max(1)) + .try_into() + .unwrap_or_else(|_| Bounded::max_value()) + ) + } + + /// Performs a saturated multiply and accumulate by unsigned number. + /// + /// Returns a saturated `int + (self * int)`. + pub fn saturated_multiply_accumulate(self, int: N) -> N + where + N: TryFrom + From + UniqueSaturatedInto + Bounded + Clone + Saturating + + ops::Rem + ops::Div + ops::Mul + + ops::Add, + { + let div = DIV as u64; + let positive = self.0 > 0; + // safe to convert as absolute value. + let parts = self.0.checked_abs().map(|v| v as u64).unwrap_or(i64::max_value() as u64 + 1); + + + // will always fit. + let natural_parts = parts / div; + // might saturate. + let natural_parts: N = natural_parts.saturated_into(); + // fractional parts can always fit into u32. + let perbill_parts = (parts % div) as u32; + + let n = int.clone().saturating_mul(natural_parts); + let p = Perbill::from_parts(perbill_parts) * int.clone(); + + // everything that needs to be either added or subtracted from the original weight. + let excess = n.saturating_add(p); + + if positive { + int.saturating_add(excess) + } else { + int.saturating_sub(excess) + } + } +} + +impl Saturating for Fixed64 { + fn saturating_add(self, rhs: Self) -> Self { + Self(self.0.saturating_add(rhs.0)) + } + fn saturating_mul(self, rhs: Self) -> Self { + Self(self.0.saturating_mul(rhs.0) / DIV) + } + fn saturating_sub(self, rhs: Self) -> Self { + Self(self.0.saturating_sub(rhs.0)) + } +} + +/// Note that this is a standard, _potentially-panicking_, implementation. Use `Saturating` trait +/// for safe addition. +impl ops::Add for Fixed64 { + type Output = Self; + + fn add(self, rhs: Self) -> Self::Output { + Self(self.0 + rhs.0) + } +} + +/// Note that this is a standard, _potentially-panicking_, implementation. Use `Saturating` trait +/// for safe subtraction. +impl ops::Sub for Fixed64 { + type Output = Self; + + fn sub(self, rhs: Self) -> Self::Output { + Self(self.0 - rhs.0) + } +} + +impl CheckedSub for Fixed64 { + fn checked_sub(&self, rhs: &Self) -> Option { + self.0.checked_sub(rhs.0).map(Self) + } +} + +impl CheckedAdd for Fixed64 { + fn checked_add(&self, rhs: &Self) -> Option { + self.0.checked_add(rhs.0).map(Self) + } +} + +#[cfg(feature = "std")] +impl rstd::fmt::Debug for Fixed64 { + fn fmt(&self, f: &mut rstd::fmt::Formatter<'_>) -> rstd::fmt::Result { + write!(f, "Fixed64({},{})", self.0 / DIV, (self.0 % DIV) / 1000) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn max() -> Fixed64 { + Fixed64::from_parts(i64::max_value()) + } + + #[test] + fn fixed64_semantics() { + assert_eq!(Fixed64::from_rational(5, 2).0, 5 * 1_000_000_000 / 2); + assert_eq!(Fixed64::from_rational(5, 2), Fixed64::from_rational(10, 4)); + assert_eq!(Fixed64::from_rational(5, 0), Fixed64::from_rational(5, 1)); + + // biggest value that can be created. + assert_ne!(max(), Fixed64::from_natural(9_223_372_036)); + assert_eq!(max(), Fixed64::from_natural(9_223_372_037)); + } + + #[test] + fn fixed_64_growth_decrease_curve() { + let test_set = vec![0u32, 1, 10, 1000, 1_000_000_000]; + + // negative (1/2) + let mut fm = Fixed64::from_rational(-1, 2); + test_set.clone().into_iter().for_each(|i| { + assert_eq!(fm.saturated_multiply_accumulate(i) as i32, i as i32 - i as i32 / 2); + }); + + // unit (1) multiplier + fm = Fixed64::from_parts(0); + test_set.clone().into_iter().for_each(|i| { + assert_eq!(fm.saturated_multiply_accumulate(i), i); + }); + + // i.5 multiplier + fm = Fixed64::from_rational(1, 2); + test_set.clone().into_iter().for_each(|i| { + assert_eq!(fm.saturated_multiply_accumulate(i), i * 3 / 2); + }); + + // dual multiplier + fm = Fixed64::from_rational(1, 1); + test_set.clone().into_iter().for_each(|i| { + assert_eq!(fm.saturated_multiply_accumulate(i), i * 2); + }); + } + + macro_rules! saturating_mul_acc_test { + ($num_type:tt) => { + assert_eq!( + Fixed64::from_rational(100, 1).saturated_multiply_accumulate(10 as $num_type), + 1010, + ); + assert_eq!( + Fixed64::from_rational(100, 2).saturated_multiply_accumulate(10 as $num_type), + 510, + ); + assert_eq!( + Fixed64::from_rational(100, 3).saturated_multiply_accumulate(0 as $num_type), + 0, + ); + assert_eq!( + Fixed64::from_rational(5, 1).saturated_multiply_accumulate($num_type::max_value()), + $num_type::max_value() + ); + assert_eq!( + max().saturated_multiply_accumulate($num_type::max_value()), + $num_type::max_value() + ); + } + } + + #[test] + fn fixed64_multiply_accumulate_works() { + saturating_mul_acc_test!(u32); + saturating_mul_acc_test!(u64); + saturating_mul_acc_test!(u128); + } +} diff --git a/core/sr-arithmetic/src/helpers_128bit.rs b/core/sr-arithmetic/src/helpers_128bit.rs new file mode 100644 index 0000000000..10cc94ae77 --- /dev/null +++ b/core/sr-arithmetic/src/helpers_128bit.rs @@ -0,0 +1,112 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +//! Some helper functions to work with 128bit numbers. Note that the functionality provided here is +//! only sensible to use with 128bit numbers because for smaller sizes, you can always rely on +//! assumptions of a bigger type (u128) being available, or simply create a per-thing and use the +//! multiplication implementation provided there. + +use crate::biguint; +use num_traits::Zero; +use rstd::{cmp::{min, max}, convert::TryInto, mem}; + +/// Helper gcd function used in Rational128 implementation. +pub fn gcd(a: u128, b: u128) -> u128 { + match ((a, b), (a & 1, b & 1)) { + ((x, y), _) if x == y => y, + ((0, x), _) | ((x, 0), _) => x, + ((x, y), (0, 1)) | ((y, x), (1, 0)) => gcd(x >> 1, y), + ((x, y), (0, 0)) => gcd(x >> 1, y >> 1) << 1, + ((x, y), (1, 1)) => { + let (x, y) = (min(x, y), max(x, y)); + gcd((y - x) >> 1, x) + }, + _ => unreachable!(), + } +} + +/// split a u128 into two u64 limbs +pub fn split(a: u128) -> (u64, u64) { + let al = a as u64; + let ah = (a >> 64) as u64; + (ah, al) +} + +/// Convert a u128 to a u32 based biguint. +pub fn to_big_uint(x: u128) -> biguint::BigUint { + let (xh, xl) = split(x); + let (xhh, xhl) = biguint::split(xh); + let (xlh, xll) = biguint::split(xl); + let mut n = biguint::BigUint::from_limbs(&[xhh, xhl, xlh, xll]); + n.lstrip(); + n +} + +/// Safely and accurately compute `a * b / c`. The approach is: +/// - Simply try `a * b / c`. +/// - Else, convert them both into big numbers and re-try. `Err` is returned if the result +/// cannot be safely casted back to u128. +/// +/// Invariant: c must be greater than or equal to 1. +pub fn multiply_by_rational(mut a: u128, mut b: u128, mut c: u128) -> Result { + if a.is_zero() || b.is_zero() { return Ok(Zero::zero()); } + c = c.max(1); + + // a and b are interchangeable by definition in this function. It always helps to assume the + // bigger of which is being multiplied by a `0 < b/c < 1`. Hence, a should be the bigger and + // b the smaller one. + if b > a { + mem::swap(&mut a, &mut b); + } + + // Attempt to perform the division first + if a % c == 0 { + a /= c; + c = 1; + } else if b % c == 0 { + b /= c; + c = 1; + } + + if let Some(x) = a.checked_mul(b) { + // This is the safest way to go. Try it. + Ok(x / c) + } else { + let a_num = to_big_uint(a); + let b_num = to_big_uint(b); + let c_num = to_big_uint(c); + + let mut ab = a_num * b_num; + ab.lstrip(); + let mut q = if c_num.len() == 1 { + // PROOF: if `c_num.len() == 1` then `c` fits in one limb. + ab.div_unit(c as biguint::Single) + } else { + // PROOF: both `ab` and `c` cannot have leading zero limbs; if length of `c` is 1, + // the previous branch would handle. Also, if ab for sure has a bigger size than + // c, because `a.checked_mul(b)` has failed, hence ab must be at least one limb + // bigger than c. In this case, returning zero is defensive-only and div should + // always return Some. + let (mut q, r) = ab.div(&c_num, true).unwrap_or((Zero::zero(), Zero::zero())); + let r: u128 = r.try_into() + .expect("reminder of div by c is always less than c; qed"); + if r > (c / 2) { q = q.add(&to_big_uint(1)); } + q + }; + q.lstrip(); + q.try_into().map_err(|_| "result cannot fit in u128") + } +} diff --git a/core/sr-arithmetic/src/lib.rs b/core/sr-arithmetic/src/lib.rs new file mode 100644 index 0000000000..847ca9e797 --- /dev/null +++ b/core/sr-arithmetic/src/lib.rs @@ -0,0 +1,48 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +//! Minimal fixed point arithmetic primitives and types for runtime. + +#![cfg_attr(not(feature = "std"), no_std)] + +// to allow benchmarking +#![cfg_attr(feature = "bench", feature(test))] +#[cfg(feature = "bench")] extern crate test; + +/// Copied from `sr-primitives` and documented there. +#[cfg(test)] +macro_rules! assert_eq_error_rate { + ($x:expr, $y:expr, $error:expr $(,)?) => { + assert!( + ($x) >= (($y) - ($error)) && ($x) <= (($y) + ($error)), + "{:?} != {:?} (with error rate {:?})", + $x, + $y, + $error, + ); + }; +} + +pub mod biguint; +pub mod helpers_128bit; +pub mod traits; +mod per_things; +mod fixed64; +mod rational128; + +pub use fixed64::Fixed64; +pub use per_things::{Percent, Permill, Perbill, Perquintill}; +pub use rational128::Rational128; diff --git a/core/sr-arithmetic/src/per_things.rs b/core/sr-arithmetic/src/per_things.rs new file mode 100644 index 0000000000..afd8100a84 --- /dev/null +++ b/core/sr-arithmetic/src/per_things.rs @@ -0,0 +1,519 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +#[cfg(feature = "std")] +use serde::{Serialize, Deserialize}; + +use rstd::{ops, prelude::*, convert::TryInto}; +use codec::{Encode, Decode, CompactAs}; +use crate::traits::{SaturatedConversion, UniqueSaturatedInto, Saturating}; + +macro_rules! implement_per_thing { + ($name:ident, $test_mod:ident, [$($test_units:tt),+], $max:tt, $type:ty, $upper_type:ty, $title:expr $(,)?) => { + /// A fixed point representation of a number between in the range [0, 1]. + /// + #[doc = $title] + #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug, Ord, PartialOrd))] + #[derive(Encode, Decode, Default, Copy, Clone, PartialEq, Eq, CompactAs)] + pub struct $name($type); + + impl $name { + /// Nothing. + pub fn zero() -> Self { Self(0) } + + /// `true` if this is nothing. + pub fn is_zero(&self) -> bool { self.0 == 0 } + + /// Everything. + pub fn one() -> Self { Self($max) } + + /// Consume self and deconstruct into a raw numeric type. + pub fn deconstruct(self) -> $type { self.0 } + + /// Return the scale at which this per-thing is working. + pub const fn accuracy() -> $type { $max } + + /// From an explicitly defined number of parts per maximum of the type. + /// + /// This can be called at compile time. + pub const fn from_parts(parts: $type) -> Self { + Self([parts, $max][(parts > $max) as usize]) + } + + /// Converts from a percent. Equal to `x / 100`. + /// + /// This can be created at compile time. + pub const fn from_percent(x: $type) -> Self { + Self([x, 100][(x > 100) as usize] * ($max / 100)) + } + + /// Return the product of multiplication of this value by itself. + pub fn square(self) -> Self { + // both can be safely casted and multiplied. + let p: $upper_type = self.0 as $upper_type * self.0 as $upper_type; + let q: $upper_type = <$upper_type>::from($max) * <$upper_type>::from($max); + Self::from_rational_approximation(p, q) + } + + /// Converts a fraction into `Permill`. + #[cfg(feature = "std")] + pub fn from_fraction(x: f64) -> Self { Self((x * ($max as f64)) as $type) } + + /// Approximate the fraction `p/q` into a per-thing fraction. This will never overflow. + /// + /// The computation of this approximation is performed in the generic type `N`. Given + /// `M` as the data type that can hold the maximum value of this per-thing (e.g. u32 for + /// perbill), this can only work if `N == M` or `N: From + TryInto`. + pub fn from_rational_approximation(p: N, q: N) -> Self + where N: Clone + Ord + From<$type> + TryInto<$type> + ops::Div + { + // q cannot be zero. + let q = q.max((1 as $type).into()); + // p should not be bigger than q. + let p = p.min(q.clone()); + + let factor = (q.clone() / $max.into()).max((1 as $type).into()); + + // q cannot overflow: (q / (q/$max)) < 2 * $max. p < q hence p also cannot overflow. + // this implies that $type must be able to fit 2 * $max. + let q_reduce: $type = (q / factor.clone()) + .try_into() + .map_err(|_| "Failed to convert") + .expect( + "q / (q/$max) < (2 * $max). Macro prevents any type being created that \ + does not satisfy this; qed" + ); + let p_reduce: $type = (p / factor.clone()) + .try_into() + .map_err(|_| "Failed to convert") + .expect( + "q / (q/$max) < (2 * $max). Macro prevents any type being created that \ + does not satisfy this; qed" + ); + + // `p_reduced` and `q_reduced` are withing $type. Mul by another $max will always + // fit in $upper_type. This is guaranteed by the macro tests. + let part = + p_reduce as $upper_type + * <$upper_type>::from($max) + / q_reduce as $upper_type; + + $name(part as $type) + } + } + + impl Saturating for $name { + fn saturating_add(self, rhs: Self) -> Self { + // defensive-only: since `$max * 2 < $type::max_value()`, this can never overflow. + Self::from_parts(self.0.saturating_add(rhs.0)) + } + fn saturating_sub(self, rhs: Self) -> Self { + Self::from_parts(self.0.saturating_sub(rhs.0)) + } + fn saturating_mul(self, rhs: Self) -> Self { + let a = self.0 as $upper_type; + let b = rhs.0 as $upper_type; + let m = <$upper_type>::from($max); + let parts = a * b / m; + // This will always fit into $type. + Self::from_parts(parts as $type) + } + } + + impl ops::Div for $name { + type Output = Self; + + fn div(self, rhs: Self) -> Self::Output { + let p = self.0; + let q = rhs.0; + Self::from_rational_approximation(p, q) + } + } + + /// Overflow-prune multiplication. + /// + /// tailored to be used with a balance type. + impl ops::Mul for $name + where + N: Clone + From<$type> + UniqueSaturatedInto<$type> + ops::Rem + + ops::Div + ops::Mul + ops::Add, + { + type Output = N; + fn mul(self, b: N) -> Self::Output { + let maximum: N = $max.into(); + let upper_max: $upper_type = $max.into(); + let part: N = self.0.into(); + + let rem_multiplied_divided = { + let rem = b.clone().rem(maximum.clone()); + + // `rem_sized` is inferior to $max, thus it fits into $type. This is assured by + // a test. + let rem_sized = rem.saturated_into::<$type>(); + + // `self` and `rem_sized` are inferior to $max, thus the product is less than + // $max^2 and fits into $upper_type. This is assured by a test. + let rem_multiplied_upper = rem_sized as $upper_type * self.0 as $upper_type; + + // `rem_multiplied_upper` is less than $max^2 therefore divided by $max it fits + // in $type. remember that $type always fits $max. + let mut rem_multiplied_divided_sized = + (rem_multiplied_upper / upper_max) as $type; + // fix a tiny rounding error + if rem_multiplied_upper % upper_max > upper_max / 2 { + rem_multiplied_divided_sized += 1; + } + + // `rem_multiplied_divided_sized` is inferior to b, thus it can be converted + // back to N type + rem_multiplied_divided_sized.into() + }; + + (b / maximum) * part + rem_multiplied_divided + } + } + + #[cfg(test)] + mod $test_mod { + use codec::{Encode, Decode}; + use super::{$name, Saturating}; + use crate::traits::Zero; + + + #[test] + fn macro_expanded_correctly() { + // needed for the `from_percent` to work. + assert!($max >= 100); + assert!($max % 100 == 0); + + // needed for `from_rational_approximation` + assert!(2 * $max < <$type>::max_value()); + assert!(<$upper_type>::from($max) < <$upper_type>::max_value()); + + // for something like percent they can be the same. + assert!((<$type>::max_value() as $upper_type) <= <$upper_type>::max_value()); + assert!(<$upper_type>::from($max).checked_mul($max.into()).is_some()); + } + + #[derive(Encode, Decode, PartialEq, Eq, Debug)] + struct WithCompact { + data: T, + } + + #[test] + fn has_compact() { + let data = WithCompact { data: $name(1) }; + let encoded = data.encode(); + assert_eq!(data, WithCompact::<$name>::decode(&mut &encoded[..]).unwrap()); + } + + #[test] + fn compact_encoding() { + let tests = [ + // assume all per_things have the size u8 at least. + (0 as $type, 1usize), + (1 as $type, 1usize), + (63, 1), + (64, 2), + (65, 2), + (<$type>::max_value(), <$type>::max_value().encode().len() + 1) + ]; + for &(n, l) in &tests { + let compact: codec::Compact<$name> = $name(n).into(); + let encoded = compact.encode(); + assert_eq!(encoded.len(), l); + let decoded = >::decode(&mut & encoded[..]) + .unwrap(); + let per_thingy: $name = decoded.into(); + assert_eq!(per_thingy, $name(n)); + } + } + + #[test] + fn per_thing_api_works() { + // some really basic stuff + assert_eq!($name::zero(), $name::from_parts(Zero::zero())); + assert_eq!($name::one(), $name::from_parts($max)); + assert_eq!($name::accuracy(), $max); + assert_eq!($name::from_percent(0), $name::from_parts(Zero::zero())); + assert_eq!($name::from_percent(10), $name::from_parts($max / 10)); + assert_eq!($name::from_percent(100), $name::from_parts($max)); + } + + macro_rules! per_thing_mul_test { + ($num_type:tt) => { + // multiplication from all sort of from_percent + assert_eq!( + $name::from_percent(100) * $num_type::max_value(), + $num_type::max_value() + ); + assert_eq_error_rate!( + $name::from_percent(99) * $num_type::max_value(), + ((Into::::into($num_type::max_value()) * 99u32) / 100u32).as_u128() as $num_type, + 1, + ); + assert_eq!( + $name::from_percent(50) * $num_type::max_value(), + $num_type::max_value() / 2, + ); + assert_eq_error_rate!( + $name::from_percent(1) * $num_type::max_value(), + $num_type::max_value() / 100, + 1, + ); + assert_eq!($name::from_percent(0) * $num_type::max_value(), 0); + + // // multiplication with bounds + assert_eq!($name::one() * $num_type::max_value(), $num_type::max_value()); + assert_eq!($name::zero() * $num_type::max_value(), 0); + } + } + + #[test] + fn per_thing_mul_works() { + use primitive_types::U256; + + // accuracy test + assert_eq!($name::from_rational_approximation(1 as $type, 3) * 30 as $type, 10); + + $(per_thing_mul_test!($test_units);)* + } + + #[test] + fn per_thing_mul_rounds_to_nearest_number() { + assert_eq!($name::from_percent(33) * 10u64, 3); + assert_eq!($name::from_percent(34) * 10u64, 3); + assert_eq!($name::from_percent(35) * 10u64, 3); + assert_eq!($name::from_percent(36) * 10u64, 4); + assert_eq!($name::from_percent(36) * 10u64, 4); + } + + #[test] + fn per_thing_multiplication_with_large_number() { + use primitive_types::U256; + let max_minus_one = $max - 1; + assert_eq_error_rate!( + $name::from_parts(max_minus_one) * std::u128::MAX, + ((Into::::into(std::u128::MAX) * max_minus_one) / $max).as_u128(), + 1, + ); + } + + macro_rules! per_thing_from_rationale_approx_test { + ($num_type:tt) => { + // within accuracy boundary + assert_eq!( + $name::from_rational_approximation(1 as $num_type, 0), + $name::one(), + ); + assert_eq!( + $name::from_rational_approximation(1 as $num_type, 1), + $name::one(), + ); + assert_eq_error_rate!( + $name::from_rational_approximation(1 as $num_type, 3).0, + $name::from_parts($max / 3).0, + 2 + ); + assert_eq!( + $name::from_rational_approximation(1 as $num_type, 10), + $name::from_percent(10), + ); + assert_eq!( + $name::from_rational_approximation(1 as $num_type, 4), + $name::from_percent(25), + ); + assert_eq!( + $name::from_rational_approximation(1 as $num_type, 4), + $name::from_rational_approximation(2 as $num_type, 8), + ); + // no accurate anymore but won't overflow. + assert_eq!( + $name::from_rational_approximation( + $num_type::max_value() - 1, + $num_type::max_value() + ), + $name::one(), + ); + assert_eq_error_rate!( + $name::from_rational_approximation( + $num_type::max_value() / 3, + $num_type::max_value() + ).0, + $name::from_parts($max / 3).0, + 2 + ); + assert_eq!( + $name::from_rational_approximation(1, $num_type::max_value()), + $name::zero(), + ); + }; + } + + #[test] + fn per_thing_from_rationale_approx_works() { + // This is just to make sure something like Percent which _might_ get built from a + // u8 does not overflow in the context of this test. + let max_value = <$upper_type>::from($max); + // almost at the edge + assert_eq!( + $name::from_rational_approximation($max - 1, $max + 1), + $name::from_parts($max - 2), + ); + assert_eq!( + $name::from_rational_approximation(1, $max-1), + $name::from_parts(1), + ); + assert_eq!( + $name::from_rational_approximation(1, $max), + $name::from_parts(1), + ); + assert_eq!( + $name::from_rational_approximation(2, 2 * $max - 1), + $name::from_parts(1), + ); + assert_eq!( + $name::from_rational_approximation(1, $max+1), + $name::zero(), + ); + assert_eq!( + $name::from_rational_approximation(3 * max_value / 2, 3 * max_value), + $name::from_percent(50), + ); + $(per_thing_from_rationale_approx_test!($test_units);)* + } + + #[test] + fn per_things_mul_operates_in_output_type() { + // assert_eq!($name::from_percent(50) * 100u32, 50u32); + assert_eq!($name::from_percent(50) * 100u64, 50u64); + assert_eq!($name::from_percent(50) * 100u128, 50u128); + } + + #[test] + fn per_thing_saturating_op_works() { + assert_eq!( + $name::from_percent(50).saturating_add($name::from_percent(40)), + $name::from_percent(90) + ); + assert_eq!( + $name::from_percent(50).saturating_add($name::from_percent(50)), + $name::from_percent(100) + ); + assert_eq!( + $name::from_percent(60).saturating_add($name::from_percent(50)), + $name::from_percent(100) + ); + + assert_eq!( + $name::from_percent(60).saturating_sub($name::from_percent(50)), + $name::from_percent(10) + ); + assert_eq!( + $name::from_percent(60).saturating_sub($name::from_percent(60)), + $name::from_percent(0) + ); + assert_eq!( + $name::from_percent(60).saturating_sub($name::from_percent(70)), + $name::from_percent(0) + ); + + assert_eq!( + $name::from_percent(50).saturating_mul($name::from_percent(50)), + $name::from_percent(25) + ); + assert_eq!( + $name::from_percent(20).saturating_mul($name::from_percent(20)), + $name::from_percent(4) + ); + assert_eq!( + $name::from_percent(10).saturating_mul($name::from_percent(10)), + $name::from_percent(1) + ); + } + + #[test] + fn per_thing_square_works() { + assert_eq!($name::from_percent(100).square(), $name::from_percent(100)); + assert_eq!($name::from_percent(50).square(), $name::from_percent(25)); + assert_eq!($name::from_percent(10).square(), $name::from_percent(1)); + assert_eq!( + $name::from_percent(2).square(), + $name::from_parts((4 * <$upper_type>::from($max) / 100 / 100) as $type) + ); + } + + #[test] + fn per_things_div_works() { + // normal + assert_eq!($name::from_percent(10) / $name::from_percent(20), + $name::from_percent(50) + ); + assert_eq!($name::from_percent(10) / $name::from_percent(10), + $name::from_percent(100) + ); + assert_eq!($name::from_percent(10) / $name::from_percent(0), + $name::from_percent(100) + ); + + // will not overflow + assert_eq!($name::from_percent(10) / $name::from_percent(5), + $name::from_percent(100) + ); + assert_eq!($name::from_percent(100) / $name::from_percent(50), + $name::from_percent(100) + ); + } + } + }; +} + +implement_per_thing!( + Percent, + test_per_cent, + [u32, u64, u128], + 100u8, + u8, + u16, + "_Percent_", +); +implement_per_thing!( + Permill, + test_permill, + [u32, u64, u128], + 1_000_000u32, + u32, + u64, + "_Parts per Million_", +); +implement_per_thing!( + Perbill, + test_perbill, + [u32, u64, u128], + 1_000_000_000u32, + u32, + u64, + "_Parts per Billion_", +); +implement_per_thing!( + Perquintill, + test_perquintill, + [u64, u128], + 1_000_000_000_000_000_000u64, + u64, + u128, + "_Parts per Quintillion_", +); diff --git a/core/sr-arithmetic/src/rational128.rs b/core/sr-arithmetic/src/rational128.rs new file mode 100644 index 0000000000..706d6a5eba --- /dev/null +++ b/core/sr-arithmetic/src/rational128.rs @@ -0,0 +1,384 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +use rstd::{cmp::Ordering, prelude::*}; +use crate::helpers_128bit; +use num_traits::Zero; + +/// A wrapper for any rational number with a 128 bit numerator and denominator. +#[derive(Clone, Copy, Default, Eq)] +#[cfg_attr(feature = "std", derive(Debug))] +pub struct Rational128(u128, u128); + +impl Rational128 { + /// Nothing. + pub fn zero() -> Self { + Self(0, 1) + } + + /// If it is zero or not + pub fn is_zero(&self) -> bool { + self.0.is_zero() + } + + /// Build from a raw `n/d`. + pub fn from(n: u128, d: u128) -> Self { + Self(n, d.max(1)) + } + + /// Build from a raw `n/d`. This could lead to / 0 if not properly handled. + pub fn from_unchecked(n: u128, d: u128) -> Self { + Self(n, d) + } + + /// Return the numerator. + pub fn n(&self) -> u128 { + self.0 + } + + /// Return the denominator. + pub fn d(&self) -> u128 { + self.1 + } + + /// Convert `self` to a similar rational number where denominator is the given `den`. + // + /// This only returns if the result is accurate. `Err` is returned if the result cannot be + /// accurately calculated. + pub fn to_den(self, den: u128) -> Result { + if den == self.1 { + Ok(self) + } else { + helpers_128bit::multiply_by_rational(self.0, den, self.1).map(|n| Self(n, den)) + } + } + + /// Get the least common divisor of `self` and `other`. + /// + /// This only returns if the result is accurate. `Err` is returned if the result cannot be + /// accurately calculated. + pub fn lcm(&self, other: &Self) -> Result { + // this should be tested better: two large numbers that are almost the same. + if self.1 == other.1 { return Ok(self.1) } + let g = helpers_128bit::gcd(self.1, other.1); + helpers_128bit::multiply_by_rational(self.1 , other.1, g) + } + + /// A saturating add that assumes `self` and `other` have the same denominator. + pub fn lazy_saturating_add(self, other: Self) -> Self { + if other.is_zero() { + self + } else { + Self(self.0.saturating_add(other.0) ,self.1) + } + } + + /// A saturating subtraction that assumes `self` and `other` have the same denominator. + pub fn lazy_saturating_sub(self, other: Self) -> Self { + if other.is_zero() { + self + } else { + Self(self.0.saturating_sub(other.0) ,self.1) + } + } + + /// Addition. Simply tries to unify the denominators and add the numerators. + /// + /// Overflow might happen during any of the steps. Error is returned in such cases. + pub fn checked_add(self, other: Self) -> Result { + let lcm = self.lcm(&other).map_err(|_| "failed to scale to denominator")?; + let self_scaled = self.to_den(lcm).map_err(|_| "failed to scale to denominator")?; + let other_scaled = other.to_den(lcm).map_err(|_| "failed to scale to denominator")?; + let n = self_scaled.0.checked_add(other_scaled.0) + .ok_or("overflow while adding numerators")?; + Ok(Self(n, self_scaled.1)) + } + + /// Subtraction. Simply tries to unify the denominators and subtract the numerators. + /// + /// Overflow might happen during any of the steps. None is returned in such cases. + pub fn checked_sub(self, other: Self) -> Result { + let lcm = self.lcm(&other).map_err(|_| "failed to scale to denominator")?; + let self_scaled = self.to_den(lcm).map_err(|_| "failed to scale to denominator")?; + let other_scaled = other.to_den(lcm).map_err(|_| "failed to scale to denominator")?; + + let n = self_scaled.0.checked_sub(other_scaled.0) + .ok_or("overflow while subtracting numerators")?; + Ok(Self(n, self_scaled.1)) + } +} + +impl PartialOrd for Rational128 { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for Rational128 { + fn cmp(&self, other: &Self) -> Ordering { + // handle some edge cases. + if self.1 == other.1 { + self.0.cmp(&other.0) + } else if self.1.is_zero() { + Ordering::Greater + } else if other.1.is_zero() { + Ordering::Less + } else { + // Don't even compute gcd. + let self_n = helpers_128bit::to_big_uint(self.0) * helpers_128bit::to_big_uint(other.1); + let other_n = helpers_128bit::to_big_uint(other.0) * helpers_128bit::to_big_uint(self.1); + self_n.cmp(&other_n) + } + } +} + +impl PartialEq for Rational128 { + fn eq(&self, other: &Self) -> bool { + // handle some edge cases. + if self.1 == other.1 { + self.0.eq(&other.0) + } else { + let self_n = helpers_128bit::to_big_uint(self.0) * helpers_128bit::to_big_uint(other.1); + let other_n = helpers_128bit::to_big_uint(other.0) * helpers_128bit::to_big_uint(self.1); + self_n.eq(&other_n) + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use super::helpers_128bit::*; + + const MAX128: u128 = u128::max_value(); + const MAX64: u128 = u64::max_value() as u128; + const MAX64_2: u128 = 2 * u64::max_value() as u128; + + fn r(p: u128, q: u128) -> Rational128 { + Rational128(p, q) + } + + fn mul_div(a: u128, b: u128, c: u128) -> u128 { + use primitive_types::U256; + if a.is_zero() { return Zero::zero(); } + let c = c.max(1); + + // e for extended + let ae: U256 = a.into(); + let be: U256 = b.into(); + let ce: U256 = c.into(); + + let r = ae * be / ce; + if r > u128::max_value().into() { + a + } else { + r.as_u128() + } + } + + #[test] + fn truth_value_function_works() { + assert_eq!( + mul_div(2u128.pow(100), 8, 4), + 2u128.pow(101) + ); + assert_eq!( + mul_div(2u128.pow(100), 4, 8), + 2u128.pow(99) + ); + + // and it returns a if result cannot fit + assert_eq!(mul_div(MAX128 - 10, 2, 1), MAX128 - 10); + } + + #[test] + fn to_denom_works() { + // simple up and down + assert_eq!(r(1, 5).to_den(10), Ok(r(2, 10))); + assert_eq!(r(4, 10).to_den(5), Ok(r(2, 5))); + + // up and down with large numbers + assert_eq!(r(MAX128 - 10, MAX128).to_den(10), Ok(r(10, 10))); + assert_eq!(r(MAX128 / 2, MAX128).to_den(10), Ok(r(5, 10))); + + // large to perbill. This is very well needed for phragmen. + assert_eq!( + r(MAX128 / 2, MAX128).to_den(1000_000_000), + Ok(r(500_000_000, 1000_000_000)) + ); + + // large to large + assert_eq!(r(MAX128 / 2, MAX128).to_den(MAX128/2), Ok(r(MAX128/4, MAX128/2))); + } + + #[test] + fn gdc_works() { + assert_eq!(gcd(10, 5), 5); + assert_eq!(gcd(7, 22), 1); + } + + #[test] + fn lcm_works() { + // simple stuff + assert_eq!(r(3, 10).lcm(&r(4, 15)).unwrap(), 30); + assert_eq!(r(5, 30).lcm(&r(1, 7)).unwrap(), 210); + assert_eq!(r(5, 30).lcm(&r(1, 10)).unwrap(), 30); + + // large numbers + assert_eq!( + r(1_000_000_000, MAX128).lcm(&r(7_000_000_000, MAX128-1)), + Err("result cannot fit in u128"), + ); + assert_eq!( + r(1_000_000_000, MAX64).lcm(&r(7_000_000_000, MAX64-1)), + Ok(340282366920938463408034375210639556610), + ); + assert!(340282366920938463408034375210639556610 < MAX128); + assert!(340282366920938463408034375210639556610 == MAX64 * (MAX64 - 1)); + } + + #[test] + fn add_works() { + // works + assert_eq!(r(3, 10).checked_add(r(1, 10)).unwrap(), r(2, 5)); + assert_eq!(r(3, 10).checked_add(r(3, 7)).unwrap(), r(51, 70)); + + // errors + assert_eq!( + r(1, MAX128).checked_add(r(1, MAX128-1)), + Err("failed to scale to denominator"), + ); + assert_eq!( + r(7, MAX128).checked_add(r(MAX128, MAX128)), + Err("overflow while adding numerators"), + ); + assert_eq!( + r(MAX128, MAX128).checked_add(r(MAX128, MAX128)), + Err("overflow while adding numerators"), + ); + } + + #[test] + fn sub_works() { + // works + assert_eq!(r(3, 10).checked_sub(r(1, 10)).unwrap(), r(1, 5)); + assert_eq!(r(6, 10).checked_sub(r(3, 7)).unwrap(), r(12, 70)); + + // errors + assert_eq!( + r(2, MAX128).checked_sub(r(1, MAX128-1)), + Err("failed to scale to denominator"), + ); + assert_eq!( + r(7, MAX128).checked_sub(r(MAX128, MAX128)), + Err("overflow while subtracting numerators"), + ); + assert_eq!( + r(1, 10).checked_sub(r(2,10)), + Err("overflow while subtracting numerators"), + ); + } + + #[test] + fn ordering_and_eq_works() { + assert!(r(1, 2) > r(1, 3)); + assert!(r(1, 2) > r(2, 6)); + + assert!(r(1, 2) < r(6, 6)); + assert!(r(2, 1) > r(2, 6)); + + assert!(r(5, 10) == r(1, 2)); + assert!(r(1, 2) == r(1, 2)); + + assert!(r(1, 1490000000000200000) > r(1, 1490000000000200001)); + } + + #[test] + fn multiply_by_rational_works() { + assert_eq!(multiply_by_rational(7, 2, 3).unwrap(), 7 * 2 / 3); + assert_eq!(multiply_by_rational(7, 20, 30).unwrap(), 7 * 2 / 3); + assert_eq!(multiply_by_rational(20, 7, 30).unwrap(), 7 * 2 / 3); + + assert_eq!( + // MAX128 % 3 == 0 + multiply_by_rational(MAX128, 2, 3).unwrap(), + MAX128 / 3 * 2, + ); + assert_eq!( + // MAX128 % 7 == 3 + multiply_by_rational(MAX128, 5, 7).unwrap(), + (MAX128 / 7 * 5) + (3 * 5 / 7), + ); + assert_eq!( + // MAX128 % 7 == 3 + multiply_by_rational(MAX128, 11 , 13).unwrap(), + (MAX128 / 13 * 11) + (8 * 11 / 13), + ); + assert_eq!( + // MAX128 % 1000 == 455 + multiply_by_rational(MAX128, 555, 1000).unwrap(), + (MAX128 / 1000 * 555) + (455 * 555 / 1000), + ); + + assert_eq!( + multiply_by_rational(2 * MAX64 - 1, MAX64, MAX64).unwrap(), + 2 * MAX64 - 1, + ); + assert_eq!( + multiply_by_rational(2 * MAX64 - 1, MAX64 - 1, MAX64).unwrap(), + 2 * MAX64 - 3, + ); + + assert_eq!( + multiply_by_rational(MAX64 + 100, MAX64_2, MAX64_2 / 2).unwrap(), + (MAX64 + 100) * 2, + ); + assert_eq!( + multiply_by_rational(MAX64 + 100, MAX64_2 / 100, MAX64_2 / 200).unwrap(), + (MAX64 + 100) * 2, + ); + + assert_eq!( + multiply_by_rational(2u128.pow(66) - 1, 2u128.pow(65) - 1, 2u128.pow(65)).unwrap(), + 73786976294838206461, + ); + assert_eq!( + multiply_by_rational(1_000_000_000, MAX128 / 8, MAX128 / 2).unwrap(), + 250000000, + ); + } + + #[test] + fn multiply_by_rational_a_b_are_interchangeable() { + assert_eq!( + multiply_by_rational(10, MAX128, MAX128 / 2), + Ok(20), + ); + assert_eq!( + multiply_by_rational(MAX128, 10, MAX128 / 2), + Ok(20), + ); + } + + #[test] + #[ignore] + fn multiply_by_rational_fuzzed_equation() { + assert_eq!( + multiply_by_rational(154742576605164960401588224, 9223376310179529214, 549756068598), + Ok(2596149632101417846585204209223679) + ); + } +} diff --git a/core/sr-arithmetic/src/traits.rs b/core/sr-arithmetic/src/traits.rs new file mode 100644 index 0000000000..d02425066f --- /dev/null +++ b/core/sr-arithmetic/src/traits.rs @@ -0,0 +1,143 @@ +// Copyright 2017-2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +//! Primitives for the runtime modules. + +use rstd::{self, convert::{TryFrom, TryInto}}; +use codec::HasCompact; +pub use integer_sqrt::IntegerSquareRoot; +pub use num_traits::{ + Zero, One, Bounded, CheckedAdd, CheckedSub, CheckedMul, CheckedDiv, + CheckedShl, CheckedShr +}; +use rstd::ops::{ + Add, Sub, Mul, Div, Rem, AddAssign, SubAssign, MulAssign, DivAssign, + RemAssign, Shl, Shr +}; + +/// A meta trait for arithmetic. +/// +/// Arithmetic types do all the usual stuff you'd expect numbers to do. They are guaranteed to +/// be able to represent at least `u32` values without loss, hence the trait implies `From` +/// and smaller ints. All other conversions are fallible. +pub trait SimpleArithmetic: + Zero + One + IntegerSquareRoot + + From + From + From + TryInto + TryInto + TryInto + + TryFrom + TryInto + TryFrom + TryInto + TryFrom + TryInto + + UniqueSaturatedInto + UniqueSaturatedInto + UniqueSaturatedInto + + UniqueSaturatedFrom + UniqueSaturatedInto + UniqueSaturatedFrom + UniqueSaturatedInto + + Add + AddAssign + + Sub + SubAssign + + Mul + MulAssign + + Div + DivAssign + + Rem + RemAssign + + Shl + Shr + + CheckedShl + CheckedShr + CheckedAdd + CheckedSub + CheckedMul + CheckedDiv + + Saturating + PartialOrd + Ord + Bounded + + HasCompact + Sized +{} +impl + From + From + TryInto + TryInto + TryInto + + TryFrom + TryInto + TryFrom + TryInto + TryFrom + TryInto + + UniqueSaturatedInto + UniqueSaturatedInto + UniqueSaturatedInto + + UniqueSaturatedFrom + UniqueSaturatedInto + UniqueSaturatedFrom + + UniqueSaturatedInto + UniqueSaturatedFrom + UniqueSaturatedInto + + Add + AddAssign + + Sub + SubAssign + + Mul + MulAssign + + Div + DivAssign + + Rem + RemAssign + + Shl + Shr + + CheckedShl + CheckedShr + CheckedAdd + CheckedSub + CheckedMul + CheckedDiv + + Saturating + PartialOrd + Ord + Bounded + + HasCompact + Sized +> SimpleArithmetic for T {} + +/// Just like `From` except that if the source value is too big to fit into the destination type +/// then it'll saturate the destination. +pub trait UniqueSaturatedFrom: Sized { + /// Convert from a value of `T` into an equivalent instance of `Self`. + fn unique_saturated_from(t: T) -> Self; +} + +/// Just like `Into` except that if the source value is too big to fit into the destination type +/// then it'll saturate the destination. +pub trait UniqueSaturatedInto: Sized { + /// Consume self to return an equivalent value of `T`. + fn unique_saturated_into(self) -> T; +} + +impl + Bounded + Sized> UniqueSaturatedFrom for S { + fn unique_saturated_from(t: T) -> Self { + S::try_from(t).unwrap_or_else(|_| Bounded::max_value()) + } +} + +impl + Sized> UniqueSaturatedInto for S { + fn unique_saturated_into(self) -> T { + self.try_into().unwrap_or_else(|_| Bounded::max_value()) + } +} + +/// Simple trait to use checked mul and max value to give a saturated mul operation over +/// supported types. +pub trait Saturating { + /// Saturated addition - if the product can't fit in the type then just use max-value. + fn saturating_add(self, o: Self) -> Self; + + /// Saturated subtraction - if the product can't fit in the type then just use max-value. + fn saturating_sub(self, o: Self) -> Self; + + /// Saturated multiply - if the product can't fit in the type then just use max-value. + fn saturating_mul(self, o: Self) -> Self; +} + +impl Saturating for T { + fn saturating_add(self, o: Self) -> Self { + ::saturating_add(self, o) + } + fn saturating_sub(self, o: Self) -> Self { + ::saturating_sub(self, o) + } + fn saturating_mul(self, o: Self) -> Self { + self.checked_mul(&o).unwrap_or_else(Bounded::max_value) + } +} + +/// Convenience type to work around the highly unergonomic syntax needed +/// to invoke the functions of overloaded generic traits, in this case +/// `SaturatedFrom` and `SaturatedInto`. +pub trait SaturatedConversion { + /// Convert from a value of `T` into an equivalent instance of `Self`. + /// + /// This just uses `UniqueSaturatedFrom` internally but with this + /// variant you can provide the destination type using turbofish syntax + /// in case Rust happens not to assume the correct type. + fn saturated_from(t: T) -> Self where Self: UniqueSaturatedFrom { + >::unique_saturated_from(t) + } + + /// Consume self to return an equivalent value of `T`. + /// + /// This just uses `UniqueSaturatedInto` internally but with this + /// variant you can provide the destination type using turbofish syntax + /// in case Rust happens not to assume the correct type. + fn saturated_into(self) -> T where Self: UniqueSaturatedInto { + >::unique_saturated_into(self) + } +} +impl SaturatedConversion for T {} diff --git a/core/sr-primitives/Cargo.toml b/core/sr-primitives/Cargo.toml index ac6e8685e2..249b89acee 100644 --- a/core/sr-primitives/Cargo.toml +++ b/core/sr-primitives/Cargo.toml @@ -5,12 +5,11 @@ authors = ["Parity Technologies "] edition = "2018" [dependencies] -num-traits = { version = "0.2.8", default-features = false } -integer-sqrt = "0.1.2" serde = { version = "1.0.101", optional = true, features = ["derive"] } codec = { package = "parity-scale-codec", version = "1.0.0", default-features = false, features = ["derive"] } primitives = { package = "substrate-primitives", path = "../primitives", default-features = false } app-crypto = { package = "substrate-application-crypto", path = "../application-crypto", default-features = false } +arithmetic = { package = "sr-arithmetic", path = "../sr-arithmetic", default-features = false } rstd = { package = "sr-std", path = "../sr-std", default-features = false } runtime_io = { package = "sr-io", path = "../sr-io", default-features = false } log = { version = "0.4.8", optional = true } @@ -20,7 +19,6 @@ impl-trait-for-tuples = "0.1.2" [dev-dependencies] serde_json = "1.0.41" -primitive-types = "0.5.1" rand = "0.7.2" substrate-offchain = { path = "../offchain" } @@ -28,7 +26,6 @@ substrate-offchain = { path = "../offchain" } bench = [] default = ["std"] std = [ - "num-traits/std", "serde", "log", "rstd/std", @@ -36,5 +33,6 @@ std = [ "codec/std", "primitives/std", "app-crypto/std", + "arithmetic/std", "rand", ] diff --git a/core/sr-primitives/src/lib.rs b/core/sr-primitives/src/lib.rs index 7032560d0f..590b6fedd7 100644 --- a/core/sr-primitives/src/lib.rs +++ b/core/sr-primitives/src/lib.rs @@ -51,7 +51,6 @@ pub mod testing; pub mod curve; pub mod generic; pub mod offchain; -pub mod sr_arithmetic; pub mod traits; pub mod transaction_validity; pub mod weights; @@ -64,14 +63,14 @@ pub use primitives::{TypeId, crypto::{key_types, KeyTypeId, CryptoType}}; pub use app_crypto::RuntimeAppPublic; /// Re-export top-level arithmetic stuff. -pub use sr_arithmetic::{ +pub use arithmetic::{ Perquintill, Perbill, Permill, Percent, Rational128, Fixed64 }; /// Re-export 128 bit helpers. -pub use sr_arithmetic::helpers_128bit; -/// Re-export big_uint stiff. -pub use sr_arithmetic::biguint; +pub use arithmetic::helpers_128bit; +/// Re-export big_uint stuff. +pub use arithmetic::biguint; /// An abstraction over justification for a block's validity under a consensus algorithm. /// diff --git a/core/sr-primitives/src/sr_arithmetic.rs b/core/sr-primitives/src/sr_arithmetic.rs deleted file mode 100644 index 5f5b5dc1e5..0000000000 --- a/core/sr-primitives/src/sr_arithmetic.rs +++ /dev/null @@ -1,2203 +0,0 @@ -// Copyright 2019 Parity Technologies (UK) Ltd. -// This file is part of Substrate. - -// Substrate is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Substrate is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Substrate. If not, see . - -//! Minimal fixed point arithmetic primitives and types for runtime. - -#[cfg(feature = "std")] -use crate::serde::{Serialize, Deserialize}; - -use rstd::{ - ops, cmp::Ordering, prelude::*, - convert::{TryFrom, TryInto}, -}; -use codec::{Encode, Decode}; -use crate::traits::{ - SaturatedConversion, CheckedSub, CheckedAdd, Bounded, UniqueSaturatedInto, Saturating, Zero, -}; - -macro_rules! implement_per_thing { - ($name:ident, $test_mod:ident, [$($test_units:tt),+], $max:tt, $type:ty, $upper_type:ty, $title:expr $(,)?) => { - /// A fixed point representation of a number between in the range [0, 1]. - /// - #[doc = $title] - #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug, Ord, PartialOrd))] - #[derive(Encode, Decode, Default, Copy, Clone, PartialEq, Eq)] - pub struct $name($type); - - impl $name { - /// Nothing. - pub fn zero() -> Self { Self(0) } - - /// `true` if this is nothing. - pub fn is_zero(&self) -> bool { self.0 == 0 } - - /// Everything. - pub fn one() -> Self { Self($max) } - - /// Consume self and deconstruct into a raw numeric type. - pub fn deconstruct(self) -> $type { self.0 } - - /// Return the scale at which this per-thing is working. - pub const fn accuracy() -> $type { $max } - - /// From an explicitly defined number of parts per maximum of the type. - /// - /// This can be called at compile time. - pub const fn from_parts(parts: $type) -> Self { - Self([parts, $max][(parts > $max) as usize]) - } - - /// Converts from a percent. Equal to `x / 100`. - /// - /// This can be created at compile time. - pub const fn from_percent(x: $type) -> Self { - Self([x, 100][(x > 100) as usize] * ($max / 100)) - } - - /// Return the product of multiplication of this value by itself. - pub fn square(self) -> Self { - // both can be safely casted and multiplied. - let p: $upper_type = self.0 as $upper_type * self.0 as $upper_type; - let q: $upper_type = $max as $upper_type * $max as $upper_type; - Self::from_rational_approximation(p, q) - } - - /// Converts a fraction into `Permill`. - #[cfg(feature = "std")] - pub fn from_fraction(x: f64) -> Self { Self((x * ($max as f64)) as $type) } - - /// Approximate the fraction `p/q` into a per-thing fraction. This will never overflow. - /// - /// The computation of this approximation is performed in the generic type `N`. Given - /// `M` as the data type that can hold the maximum value of this per-thing (e.g. u32 for - /// perbill), this can only work if `N == M` or `N: From + TryInto`. - pub fn from_rational_approximation(p: N, q: N) -> Self - where N: Clone + Ord + From<$type> + TryInto<$type> + ops::Div - { - // q cannot be zero. - let q = q.max((1 as $type).into()); - // p should not be bigger than q. - let p = p.min(q.clone()); - - let factor = (q.clone() / $max.into()).max((1 as $type).into()); - - // q cannot overflow: (q / (q/$max)) < 2 * $max. p < q hence p also cannot overflow. - // this implies that $type must be able to fit 2 * $max. - let q_reduce: $type = (q / factor.clone()) - .try_into() - .map_err(|_| "Failed to convert") - .expect( - "q / (q/$max) < (2 * $max). Macro prevents any type being created that \ - does not satisfy this; qed" - ); - let p_reduce: $type = (p / factor.clone()) - .try_into() - .map_err(|_| "Failed to convert") - .expect( - "q / (q/$max) < (2 * $max). Macro prevents any type being created that \ - does not satisfy this; qed" - ); - - // `p_reduced` and `q_reduced` are withing $type. Mul by another $max will always - // fit in $upper_type. This is guaranteed by the macro tests. - let part = - p_reduce as $upper_type - * ($max as $upper_type) - / q_reduce as $upper_type; - - $name(part as $type) - } - } - - impl Saturating for $name { - fn saturating_add(self, rhs: Self) -> Self { - // defensive-only: since `$max * 2 < $type::max_value()`, this can never overflow. - Self::from_parts(self.0.saturating_add(rhs.0)) - } - fn saturating_sub(self, rhs: Self) -> Self { - Self::from_parts(self.0.saturating_sub(rhs.0)) - } - fn saturating_mul(self, rhs: Self) -> Self { - let a = self.0 as $upper_type; - let b = rhs.0 as $upper_type; - let m = $max as $upper_type; - let parts = a * b / m; - // This will always fit into $type. - Self::from_parts(parts as $type) - } - } - - impl ops::Div for $name { - type Output = Self; - - fn div(self, rhs: Self) -> Self::Output { - let p = self.0; - let q = rhs.0; - Self::from_rational_approximation(p, q) - } - } - - /// Overflow-prune multiplication. - /// - /// tailored to be used with a balance type. - impl ops::Mul for $name - where - N: Clone + From<$type> + UniqueSaturatedInto<$type> + ops::Rem - + ops::Div + ops::Mul + ops::Add, - { - type Output = N; - fn mul(self, b: N) -> Self::Output { - let maximum: N = $max.into(); - let upper_max: $upper_type = $max.into(); - let part: N = self.0.into(); - - let rem_multiplied_divided = { - let rem = b.clone().rem(maximum.clone()); - - // `rem_sized` is inferior to $max, thus it fits into $type. This is assured by - // a test. - let rem_sized = rem.saturated_into::<$type>(); - - // `self` and `rem_sized` are inferior to $max, thus the product is less than - // $max^2 and fits into $upper_type. This is assured by a test. - let rem_multiplied_upper = rem_sized as $upper_type * self.0 as $upper_type; - - // `rem_multiplied_upper` is less than $max^2 therefore divided by $max it fits - // in $type. remember that $type always fits $max. - let mut rem_multiplied_divided_sized = - (rem_multiplied_upper / upper_max) as $type; - // fix a tiny rounding error - if rem_multiplied_upper % upper_max > upper_max / 2 { - rem_multiplied_divided_sized += 1; - } - - // `rem_multiplied_divided_sized` is inferior to b, thus it can be converted - // back to N type - rem_multiplied_divided_sized.into() - }; - - (b / maximum) * part + rem_multiplied_divided - } - } - - impl codec::CompactAs for $name { - type As = $type; - fn encode_as(&self) -> &$type { - &self.0 - } - fn decode_from(x: $type) -> Self { - Self(x) - } - } - - impl From> for $name { - fn from(x: codec::Compact<$name>) -> Self { - x.0 - } - } - - #[cfg(test)] - mod $test_mod { - use codec::{Encode, Decode}; - use super::{$name, Saturating}; - use crate::{assert_eq_error_rate, traits::Zero}; - - - #[test] - fn macro_expanded_correctly() { - // needed for the `from_percent` to work. - assert!($max >= 100); - assert!($max % 100 == 0); - - // needed for `from_rational_approximation` - assert!(2 * $max < <$type>::max_value()); - assert!(($max as $upper_type) < <$upper_type>::max_value()); - - // for something like percent they can be the same. - assert!((<$type>::max_value() as $upper_type) <= <$upper_type>::max_value()); - assert!(($max as $upper_type).checked_mul($max.into()).is_some()); - } - - #[derive(Encode, Decode, PartialEq, Eq, Debug)] - struct WithCompact { - data: T, - } - - #[test] - fn has_compact() { - let data = WithCompact { data: $name(1) }; - let encoded = data.encode(); - assert_eq!(data, WithCompact::<$name>::decode(&mut &encoded[..]).unwrap()); - } - - #[test] - fn compact_encoding() { - let tests = [ - // assume all per_things have the size u8 at least. - (0 as $type, 1usize), - (1 as $type, 1usize), - (63, 1), - (64, 2), - (65, 2), - (<$type>::max_value(), <$type>::max_value().encode().len() + 1) - ]; - for &(n, l) in &tests { - let compact: crate::codec::Compact<$name> = $name(n).into(); - let encoded = compact.encode(); - assert_eq!(encoded.len(), l); - let decoded = >::decode(&mut & encoded[..]) - .unwrap(); - let per_thingy: $name = decoded.into(); - assert_eq!(per_thingy, $name(n)); - } - } - - #[test] - fn per_thing_api_works() { - // some really basic stuff - assert_eq!($name::zero(), $name::from_parts(Zero::zero())); - assert_eq!($name::one(), $name::from_parts($max)); - assert_eq!($name::accuracy(), $max); - assert_eq!($name::from_percent(0), $name::from_parts(Zero::zero())); - assert_eq!($name::from_percent(10), $name::from_parts($max / 10)); - assert_eq!($name::from_percent(100), $name::from_parts($max)); - } - - macro_rules! per_thing_mul_test { - ($num_type:tt) => { - // multiplication from all sort of from_percent - assert_eq!( - $name::from_percent(100) * $num_type::max_value(), - $num_type::max_value() - ); - assert_eq_error_rate!( - $name::from_percent(99) * $num_type::max_value(), - ((Into::::into($num_type::max_value()) * 99u32) / 100u32).as_u128() as $num_type, - 1, - ); - assert_eq!( - $name::from_percent(50) * $num_type::max_value(), - $num_type::max_value() / 2, - ); - assert_eq_error_rate!( - $name::from_percent(1) * $num_type::max_value(), - $num_type::max_value() / 100, - 1, - ); - assert_eq!($name::from_percent(0) * $num_type::max_value(), 0); - - // // multiplication with bounds - assert_eq!($name::one() * $num_type::max_value(), $num_type::max_value()); - assert_eq!($name::zero() * $num_type::max_value(), 0); - } - } - - #[test] - fn per_thing_mul_works() { - use primitive_types::U256; - - // accuracy test - assert_eq!($name::from_rational_approximation(1 as $type, 3) * 30 as $type, 10); - - $(per_thing_mul_test!($test_units);)* - } - - #[test] - fn per_thing_mul_rounds_to_nearest_number() { - assert_eq!($name::from_percent(33) * 10u64, 3); - assert_eq!($name::from_percent(34) * 10u64, 3); - assert_eq!($name::from_percent(35) * 10u64, 3); - assert_eq!($name::from_percent(36) * 10u64, 4); - assert_eq!($name::from_percent(36) * 10u64, 4); - } - - #[test] - fn per_thing_multiplication_with_large_number() { - use primitive_types::U256; - let max_minus_one = $max - 1; - assert_eq_error_rate!( - $name::from_parts(max_minus_one) * std::u128::MAX, - ((Into::::into(std::u128::MAX) * max_minus_one) / $max).as_u128(), - 1, - ); - } - - macro_rules! per_thing_from_rationale_approx_test { - ($num_type:tt) => { - // within accuracy boundary - assert_eq!( - $name::from_rational_approximation(1 as $num_type, 0), - $name::one(), - ); - assert_eq!( - $name::from_rational_approximation(1 as $num_type, 1), - $name::one(), - ); - assert_eq_error_rate!( - $name::from_rational_approximation(1 as $num_type, 3).0, - $name::from_parts($max / 3).0, - 2 - ); - assert_eq!( - $name::from_rational_approximation(1 as $num_type, 10), - $name::from_percent(10), - ); - assert_eq!( - $name::from_rational_approximation(1 as $num_type, 4), - $name::from_percent(25), - ); - assert_eq!( - $name::from_rational_approximation(1 as $num_type, 4), - $name::from_rational_approximation(2 as $num_type, 8), - ); - // no accurate anymore but won't overflow. - assert_eq!( - $name::from_rational_approximation( - $num_type::max_value() - 1, - $num_type::max_value() - ), - $name::one(), - ); - assert_eq_error_rate!( - $name::from_rational_approximation( - $num_type::max_value() / 3, - $num_type::max_value() - ).0, - $name::from_parts($max / 3).0, - 2 - ); - assert_eq!( - $name::from_rational_approximation(1, $num_type::max_value()), - $name::zero(), - ); - }; - } - - #[test] - fn per_thing_from_rationale_approx_works() { - // This is just to make sure something like Percent which _might_ get built from a - // u8 does not overflow in the context of this test. - let max_value = $max as $upper_type; - // almost at the edge - assert_eq!( - $name::from_rational_approximation($max - 1, $max + 1), - $name::from_parts($max - 2), - ); - assert_eq!( - $name::from_rational_approximation(1, $max-1), - $name::from_parts(1), - ); - assert_eq!( - $name::from_rational_approximation(1, $max), - $name::from_parts(1), - ); - assert_eq!( - $name::from_rational_approximation(2, 2 * $max - 1), - $name::from_parts(1), - ); - assert_eq!( - $name::from_rational_approximation(1, $max+1), - $name::zero(), - ); - assert_eq!( - $name::from_rational_approximation(3 * max_value / 2, 3 * max_value), - $name::from_percent(50), - ); - $(per_thing_from_rationale_approx_test!($test_units);)* - } - - #[test] - fn per_things_mul_operates_in_output_type() { - // assert_eq!($name::from_percent(50) * 100u32, 50u32); - assert_eq!($name::from_percent(50) * 100u64, 50u64); - assert_eq!($name::from_percent(50) * 100u128, 50u128); - } - - #[test] - fn per_thing_saturating_op_works() { - assert_eq!( - $name::from_percent(50).saturating_add($name::from_percent(40)), - $name::from_percent(90) - ); - assert_eq!( - $name::from_percent(50).saturating_add($name::from_percent(50)), - $name::from_percent(100) - ); - assert_eq!( - $name::from_percent(60).saturating_add($name::from_percent(50)), - $name::from_percent(100) - ); - - assert_eq!( - $name::from_percent(60).saturating_sub($name::from_percent(50)), - $name::from_percent(10) - ); - assert_eq!( - $name::from_percent(60).saturating_sub($name::from_percent(60)), - $name::from_percent(0) - ); - assert_eq!( - $name::from_percent(60).saturating_sub($name::from_percent(70)), - $name::from_percent(0) - ); - - assert_eq!( - $name::from_percent(50).saturating_mul($name::from_percent(50)), - $name::from_percent(25) - ); - assert_eq!( - $name::from_percent(20).saturating_mul($name::from_percent(20)), - $name::from_percent(4) - ); - assert_eq!( - $name::from_percent(10).saturating_mul($name::from_percent(10)), - $name::from_percent(1) - ); - } - - #[test] - fn per_thing_square_works() { - assert_eq!($name::from_percent(100).square(), $name::from_percent(100)); - assert_eq!($name::from_percent(50).square(), $name::from_percent(25)); - assert_eq!($name::from_percent(10).square(), $name::from_percent(1)); - assert_eq!( - $name::from_percent(2).square(), - $name::from_parts((4 * ($max as $upper_type) / 100 / 100) as $type) - ); - } - - #[test] - fn per_things_div_works() { - // normal - assert_eq!($name::from_percent(10) / $name::from_percent(20), - $name::from_percent(50) - ); - assert_eq!($name::from_percent(10) / $name::from_percent(10), - $name::from_percent(100) - ); - assert_eq!($name::from_percent(10) / $name::from_percent(0), - $name::from_percent(100) - ); - - // will not overflow - assert_eq!($name::from_percent(10) / $name::from_percent(5), - $name::from_percent(100) - ); - assert_eq!($name::from_percent(100) / $name::from_percent(50), - $name::from_percent(100) - ); - } - } - }; -} - -implement_per_thing!( - Percent, - test_per_cent, - [u32, u64, u128], - 100u8, - u8, - u16, - "_Percent_", -); -implement_per_thing!( - Permill, - test_permill, - [u32, u64, u128], - 1_000_000u32, - u32, - u64, - "_Parts per Million_", -); -implement_per_thing!( - Perbill, - test_perbill, - [u32, u64, u128], - 1_000_000_000u32, - u32, - u64, - "_Parts per Billion_", -); -implement_per_thing!( - Perquintill, - test_perquintill, - [u64, u128], - 1_000_000_000_000_000_000u64, - u64, - u128, - "_Parts per Quintillion_", -); - -/// An unsigned fixed point number. Can hold any value in the range [-9_223_372_036, 9_223_372_036] -/// with fixed point accuracy of one billion. -#[derive(Encode, Decode, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] -pub struct Fixed64(i64); - -/// The accuracy of the `Fixed64` type. -const DIV: i64 = 1_000_000_000; - -impl Fixed64 { - /// creates self from a natural number. - /// - /// Note that this might be lossy. - pub fn from_natural(int: i64) -> Self { - Self(int.saturating_mul(DIV)) - } - - /// Return the accuracy of the type. Given that this function returns the value `X`, it means - /// that an instance composed of `X` parts (`Fixed64::from_parts(X)`) is equal to `1`. - pub fn accuracy() -> i64 { - DIV - } - - /// Raw constructor. Equal to `parts / 1_000_000_000`. - pub fn from_parts(parts: i64) -> Self { - Self(parts) - } - - /// creates self from a rational number. Equal to `n/d`. - /// - /// Note that this might be lossy. - pub fn from_rational(n: i64, d: u64) -> Self { - Self( - ((n as i128).saturating_mul(DIV as i128) / (d as i128).max(1)) - .try_into() - .unwrap_or(Bounded::max_value()) - ) - } - - /// Performs a saturated multiply and accumulate by unsigned number. - /// - /// Returns a saturated `int + (self * int)`. - pub fn saturated_multiply_accumulate(&self, int: N) -> N - where - N: TryFrom + From + UniqueSaturatedInto + Bounded + Clone + Saturating + - ops::Rem + ops::Div + ops::Mul + - ops::Add, - { - let div = DIV as u64; - let positive = self.0 > 0; - // safe to convert as absolute value. - let parts = self.0.checked_abs().map(|v| v as u64).unwrap_or(i64::max_value() as u64 + 1); - - - // will always fit. - let natural_parts = parts / div; - // might saturate. - let natural_parts: N = natural_parts.saturated_into(); - // fractional parts can always fit into u32. - let perbill_parts = (parts % div) as u32; - - let n = int.clone().saturating_mul(natural_parts); - let p = Perbill::from_parts(perbill_parts) * int.clone(); - - // everything that needs to be either added or subtracted from the original weight. - let excess = n.saturating_add(p); - - if positive { - int.saturating_add(excess) - } else { - int.saturating_sub(excess) - } - } -} - -impl Saturating for Fixed64 { - fn saturating_add(self, rhs: Self) -> Self { - Self(self.0.saturating_add(rhs.0)) - } - fn saturating_mul(self, rhs: Self) -> Self { - Self(self.0.saturating_mul(rhs.0) / DIV) - } - fn saturating_sub(self, rhs: Self) -> Self { - Self(self.0.saturating_sub(rhs.0)) - } -} - -/// Note that this is a standard, _potentially-panicking_, implementation. Use `Saturating` trait -/// for safe addition. -impl ops::Add for Fixed64 { - type Output = Self; - - fn add(self, rhs: Self) -> Self::Output { - Self(self.0 + rhs.0) - } -} - -/// Note that this is a standard, _potentially-panicking_, implementation. Use `Saturating` trait -/// for safe subtraction. -impl ops::Sub for Fixed64 { - type Output = Self; - - fn sub(self, rhs: Self) -> Self::Output { - Self(self.0 - rhs.0) - } -} - -impl CheckedSub for Fixed64 { - fn checked_sub(&self, rhs: &Self) -> Option { - if let Some(v) = self.0.checked_sub(rhs.0) { - Some(Self(v)) - } else { - None - } - } -} - -impl CheckedAdd for Fixed64 { - fn checked_add(&self, rhs: &Self) -> Option { - if let Some(v) = self.0.checked_add(rhs.0) { - Some(Self(v)) - } else { - None - } - } -} - -#[cfg(feature = "std")] -impl rstd::fmt::Debug for Fixed64 { - fn fmt(&self, f: &mut rstd::fmt::Formatter<'_>) -> rstd::fmt::Result { - write!(f, "Fixed64({},{})", self.0 / DIV, (self.0 % DIV) / 1000) - } -} - -/// Infinite precision unsigned integer for substrate runtime. -pub mod biguint { - use super::Zero; - use rstd::{cmp::Ordering, ops, prelude::*, cell::RefCell, convert::TryFrom}; - - // A sensible value for this would be half of the dword size of the host machine. Since the - // runtime is compiled to 32bit webassembly, using 32 and 64 for single and double respectively - // should yield the most performance. TODO #3745 we could benchmark this and verify. - /// Representation of a single limb. - pub type Single = u32; - /// Representation of two limbs. - pub type Double = u64; - /// Difference in the number of bits of [`Single`] and [`Double`]. - const SHIFT: usize = 32; - /// short form of _Base_. Analogous to the value 10 in base-10 decimal numbers. - const B: Double = Single::max_value() as Double + 1; - - /// Splits a [`Double`] limb number into a tuple of two [`Single`] limb numbers. - pub fn split(a: Double) -> (Single, Single) { - let al = a as Single; - let ah = (a >> SHIFT) as Single; - (ah, al) - } - - /// Assumed as a given primitive. - /// - /// Multiplication of two singles, which at most yields 1 double. - pub fn mul_single(a: Single, b: Single) -> Double { - let a: Double = a.into(); - let b: Double = b.into(); - let r = a * b; - r - } - - /// Assumed as a given primitive. - /// - /// Addition of two singles, which at most takes a single limb of result and a carry, - /// returned as a tuple respectively. - pub fn add_single(a: Single, b: Single) -> (Single, Single) { - let a: Double = a.into(); - let b: Double = b.into(); - let q = a + b; - let (carry, r) = split(q); - (r, carry) - } - - /// Assumed as a given primitive. - /// - /// Division of double by a single limb. Always returns a double limb of quotient and a single - /// limb of remainder. - fn div_single(a: Double, b: Single) -> (Double, Single) { - let b: Double = b.into(); - let q = a / b; - let r = a % b; - // both conversions are trivially safe. - (q, r as Single) - } - - /// Simple wrapper around an infinitely large integer, represented as limbs of [`Single`]. - #[derive(Clone, Default)] - pub struct BigUint { - /// digits (limbs) of this number (sorted as msb -> lsd). - pub(crate) digits: Vec, - } - - impl BigUint { - /// Create a new instance with `size` limbs. This prevents any number with zero limbs to be - /// created. - /// - /// The behavior of the type is undefined with zero limbs. - pub fn with_capacity(size: usize) -> Self { - Self { digits: vec![0; size.max(1)] } - } - - /// Raw constructor from custom limbs. If `limbs` is empty, `Zero::zero()` implementation is - /// used. - pub fn from_limbs(limbs: &[Single]) -> Self { - if limbs.len() > 0 { - Self { digits: limbs.to_vec() } - } else { - Zero::zero() - } - } - - /// Number of limbs. - pub fn len(&self) -> usize { self.digits.len() } - - /// A naive getter for limb at `index`. Note that the order is lsb -> msb. - /// - /// #### Panics - /// - /// This panics if index is out of range. - pub fn get(&self, index: usize) -> Single { - self.digits[self.len() - 1 - index] - } - - /// A naive getter for limb at `index`. Note that the order is lsb -> msb. - pub fn checked_get(&self, index: usize) -> Option { - if let Some(i) = self.len().checked_sub(1) { - if let Some(j) = i.checked_sub(index) { - return self.digits.get(j).cloned(); - } - } - return None; - } - - /// A naive setter for limb at `index`. Note that the order is lsb -> msb. - /// - /// #### Panics - /// - /// This panics if index is out of range. - pub fn set(&mut self, index: usize, value: Single) { - let len = self.digits.len(); - self.digits[len - 1 - index] = value; - } - - /// returns the least significant limb of the number. - /// - /// #### Panics - /// - /// While the constructor of the type prevents this, this can panic if `self` has no digits. - pub fn lsb(&self) -> Single { - self.digits[self.len() - 1] - } - - /// returns the most significant limb of the number. - /// - /// #### Panics - /// - /// While the constructor of the type prevents this, this can panic if `self` has no digits. - pub fn msb(&self) -> Single { - self.digits[0] - } - - /// Strips zeros from the left side of `self`, if any. - pub fn lstrip(&mut self) { - // by definition, a big-int number should never have leading zero limbs. This function - // has the ability to cause this. There is nothing to do if the number already has 1 - // limb only. call it a day and return. - if self.len().is_zero() { return; } - let mut index = 0; - for elem in self.digits.iter() { - if *elem != 0 { break } else { index += 1 } - } - if index > 0 { - self.digits = self.digits[index..].to_vec() - } - } - - /// Zero-pad `self` from left to reach `size` limbs. Will not make any difference if `self` - /// is already bigger than `size` limbs. - pub fn lpad(&mut self, size: usize) { - let n = self.len(); - if n >= size { return; } - let pad = size - n; - let mut new_digits = (0..pad).map(|_| 0).collect::>(); - new_digits.extend(self.digits.iter()); - self.digits = new_digits; - } - - /// Adds `self` with `other`. self and other do not have to have any particular size. Given - /// that the `n = max{size(self), size(other)}`, it will produce a number with `n + 1` - /// limbs. - /// - /// This function does not strip the output and returns the original allocated `n + 1` - /// limbs. The caller may strip the output if desired. - /// - /// Taken from "The Art of Computer Programming" by D.E. Knuth, vol 2, chapter 4. - pub fn add(self, other: &Self) -> Self { - let n = self.len().max(other.len()); - let mut k: Double = 0; - let mut w = Self::with_capacity(n + 1); - - for j in 0..n { - let u = Double::from(self.checked_get(j).unwrap_or(0)); - let v = Double::from(other.checked_get(j).unwrap_or(0)); - let s = u + v + k; - w.set(j, (s % B) as Single); - k = s / B; - } - // k is always 0 or 1. - w.set(n, k as Single); - w - } - - /// Subtracts `other` from `self`. self and other do not have to have any particular size. - /// Given that the `n = max{size(self), size(other)}`, it will produce a number of size `n`. - /// - /// If `other` is bigger than `self`, `Err(B - borrow)` is returned. - /// - /// Taken from "The Art of Computer Programming" by D.E. Knuth, vol 2, chapter 4. - pub fn sub(self, other: &Self) -> Result { - let n = self.len().max(other.len()); - let mut k = 0; - let mut w = Self::with_capacity(n); - for j in 0..n { - let s = { - let u = Double::from(self.checked_get(j).unwrap_or(0)); - let v = Double::from(other.checked_get(j).unwrap_or(0)); - let mut needs_borrow = false; - let mut t = 0; - - if let Some(v) = u.checked_sub(v) { - if let Some(v2) = v.checked_sub(k) { - t = v2 % B; - k = 0; - } else { - needs_borrow = true; - } - } else { - needs_borrow = true; - } - if needs_borrow { - t = u + B - v - k; - k = 1; - } - t - }; - // PROOF: t either comes from `v2 % B`, or from `u + B - v - k`. The former is - // trivial. The latter will not overflow this branch will only happen if the sum of - // `u - v - k` part has been negative, hence `u + B - v - k < b`. - w.set(j, s as Single); - } - - if k.is_zero() { - Ok(w) - } else { - Err(w) - } - } - - /// Multiplies n-limb number `self` with m-limb number `other`. - /// - /// The resulting number will always have `n + m` limbs. - /// - /// This function does not strip the output and returns the original allocated `n + m` - /// limbs. The caller may strip the output if desired. - /// - /// Taken from "The Art of Computer Programming" by D.E. Knuth, vol 2, chapter 4. - pub fn mul(self, other: &Self) -> Self { - let n = self.len(); - let m = other.len(); - let mut w = Self::with_capacity(m + n); - - for j in 0..n { - if self.get(j) == 0 { - // Note: `with_capacity` allocates with 0. Explicitly set j + m to zero if - // otherwise. - continue; - } - - let mut k = 0; - for i in 0..m { - // PROOF: (B−1) × (B−1) + (B−1) + (B−1) = B^2 −1 < B^2. addition is safe. - let t = - mul_single(self.get(j), other.get(i)) - + Double::from(w.get(i + j)) - + Double::from(k); - w.set(i + j, (t % B) as Single); - // PROOF: (B^2 - 1) / B < B. conversion is safe. - k = (t / B) as Single; - } - w.set(j + m, k); - } - w - } - - /// Divides `self` by a single limb `other`. This can be used in cases where the original - /// division cannot work due to the divisor (`other`) being just one limb. - /// - /// Invariant: `other` cannot be zero. - pub fn div_unit(self, mut other: Single) -> Self { - other = other.max(1); - let n = self.len(); - let mut out = Self::with_capacity(n); - let mut r: Single = 0; - // PROOF: (B-1) * B + (B-1) still fits in double - let with_r = |x: Double, r: Single| { r as Double * B + x }; - for d in (0..=n-1).rev() { - let (q, rr) = div_single(with_r(self.get(d).into(), r), other) ; - out.set(d, q as Single); - r = rr; - } - out - } - - /// Divides an `n + m` limb self by a `n` limb `other`. The result is a `m + 1` limb - /// quotient and a `n` limb remainder, if enabled by passing `true` in `rem` argument, both - /// in the form of an option's `Ok`. - /// - /// - requires `other` to be stripped and have no leading zeros. - /// - requires `self` to be stripped and have no leading zeros. - /// - requires `other` to have at least two limbs. - /// - requires `self` to have a greater length compared to `other`. - /// - /// All arguments are examined without being stripped for the above conditions. If any of - /// the above fails, `None` is returned.` - /// - /// Taken from "The Art of Computer Programming" by D.E. Knuth, vol 2, chapter 4. - pub fn div(self, other: &Self, rem: bool) -> Option<(Self, Self)> { - if other.len() <= 1 - || other.msb() == 0 - || self.msb() == 0 - || self.len() <= other.len() - { - return None - } - let n = other.len(); - let m = self.len() - n; - - let mut q = Self::with_capacity(m + 1); - let mut r = Self::with_capacity(n); - - // PROOF: 0 <= normalizer_bits < SHIFT 0 <= normalizer < B. all conversions are - // safe. - let normalizer_bits = other.msb().leading_zeros() as Single; - let normalizer = (2 as Single).pow(normalizer_bits as u32) as Single; - - // step D1. - let mut self_norm = self.mul(&Self::from(normalizer)); - let mut other_norm = other.clone().mul(&Self::from(normalizer)); - - // defensive only; the mul implementation should always create this. - self_norm.lpad(n + m + 1); - other_norm.lstrip(); - - // step D2. - for j in (0..=m).rev() { - // step D3.0 Find an estimate of q[j], named qhat. - let (qhat, rhat) = { - // PROOF: this always fits into `Double`. In the context of Single = u8, and - // Double = u16, think of 255 * 256 + 255 which is just u16::max_value(). - let dividend = - Double::from(self_norm.get(j + n)) - * B - + Double::from(self_norm.get(j + n - 1)); - let divisor = other_norm.get(n - 1); - div_single(dividend, divisor.into()) - }; - - // D3.1 test qhat - // replace qhat and rhat with RefCells. This helps share state with the closure - let qhat = RefCell::new(qhat); - let rhat = RefCell::new(rhat as Double); - - let test = || { - // decrease qhat if it is bigger than the base (B) - let qhat_local = *qhat.borrow(); - let rhat_local = *rhat.borrow(); - let predicate_1 = qhat_local >= B; - let predicate_2 = { - let lhs = qhat_local * other_norm.get(n - 2) as Double; - let rhs = B * rhat_local + self_norm.get(j + n - 2) as Double; - lhs > rhs - }; - if predicate_1 || predicate_2 { - *qhat.borrow_mut() -= 1; - *rhat.borrow_mut() += other_norm.get(n - 1) as Double; - true - } else { - false - } - }; - - test(); - while (*rhat.borrow() as Double) < B { - if !test() { break; } - } - - let qhat = qhat.into_inner(); - // we don't need rhat anymore. just let it go out of scope when it does. - - // step D4 - let lhs = Self { digits: (j..=j+n).rev().map(|d| self_norm.get(d)).collect() }; - let rhs = other_norm.clone().mul(&Self::from(qhat)); - - let maybe_sub = lhs.sub(&rhs); - let mut negative = false; - let sub = match maybe_sub { - Ok(t) => t, - Err(t) => { negative = true; t } - }; - (j..=j+n).for_each(|d| { self_norm.set(d, sub.get(d - j)); }); - - // step D5 - // PROOF: the `test()` specifically decreases qhat until it is below `B`. conversion - // is safe. - q.set(j, qhat as Single); - - // step D6: add back if negative happened. - if negative { - q.set(j, q.get(j) - 1); - let u = Self { digits: (j..=j+n).rev().map(|d| self_norm.get(d)).collect() }; - let r = other_norm.clone().add(&u); - (j..=j+n).rev().for_each(|d| { self_norm.set(d, r.get(d - j)); }) - } - } - - // if requested, calculate remainder. - if rem { - // undo the normalization. - if normalizer_bits > 0 { - let s = SHIFT as u32; - let nb = normalizer_bits; - for d in 0..n-1 { - let v = self_norm.get(d) >> nb - | self_norm.get(d + 1).overflowing_shl(s - nb).0; - r.set(d, v); - } - r.set(n - 1, self_norm.get(n - 1) >> normalizer_bits); - } else { - r = self_norm; - } - } - - Some((q, r)) - } - } - - #[cfg(feature = "std")] - impl rstd::fmt::Debug for BigUint { - fn fmt(&self, f: &mut rstd::fmt::Formatter<'_>) -> rstd::fmt::Result { - write!( - f, - "BigUint {{ {:?} ({:?})}}", - self.digits, - u128::try_from(self.clone()).unwrap_or_else(|_| 0), - ) - } - } - - impl PartialEq for BigUint { - fn eq(&self, other: &Self) -> bool { - // sadly, we have to reallocate here as strip mutably uses self. - let mut lhs = self.clone(); - let mut rhs = other.clone(); - lhs.lstrip(); - rhs.lstrip(); - lhs.digits.eq(&rhs.digits) - } - } - - impl Eq for BigUint {} - - impl Ord for BigUint { - fn cmp(&self, other: &Self) -> Ordering { - let lhs_first = self.digits.iter().position(|&e| e != 0); - let rhs_first = other.digits.iter().position(|&e| e != 0); - - match (lhs_first, rhs_first) { - // edge cases that should not happen. This basically means that one or both were - // zero. - (None, None) => Ordering::Equal, - (Some(_), None) => Ordering::Greater, - (None, Some(_)) => Ordering::Less, - (Some(lhs_idx), Some(rhs_idx)) => { - let lhs = &self.digits[lhs_idx..]; - let rhs = &other.digits[rhs_idx..]; - let len_cmp = lhs.len().cmp(&rhs.len()); - match len_cmp { - Ordering::Equal => lhs.cmp(rhs), - _ => len_cmp, - } - } - } - } - } - - impl PartialOrd for BigUint { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } - } - - impl ops::Add for BigUint { - type Output = Self; - fn add(self, rhs: Self) -> Self::Output { - self.add(&rhs) - } - } - - impl ops::Sub for BigUint { - type Output = Self; - fn sub(self, rhs: Self) -> Self::Output { - self.sub(&rhs).unwrap_or_else(|e| e) - } - } - - impl ops::Mul for BigUint { - type Output = Self; - fn mul(self, rhs: Self) -> Self::Output { - self.mul(&rhs) - } - } - - impl Zero for BigUint { - fn zero() -> Self { - Self { digits: vec![Zero::zero()] } - } - - fn is_zero(&self) -> bool { - self.digits.iter().all(|d| d.is_zero()) - } - } - - macro_rules! impl_try_from_number_for { - ($([$type:ty, $len:expr]),+) => { - $( - impl TryFrom for $type { - type Error = &'static str; - fn try_from(mut value: BigUint) -> Result<$type, Self::Error> { - value.lstrip(); - let error_message = concat!("cannot fit a number into ", stringify!($type)); - if value.len() * SHIFT > $len { - Err(error_message) - } else { - let mut acc: $type = Zero::zero(); - for (i, d) in value.digits.iter().rev().cloned().enumerate() { - let d: $type = d.into(); - acc += d << (SHIFT * i); - } - Ok(acc) - } - } - } - )* - }; - } - // can only be implemented for sizes bigger than two limb. - impl_try_from_number_for!([u128, 128], [u64, 64]); - - macro_rules! impl_from_for_smaller_than_word { - ($($type:ty),+) => { - $(impl From<$type> for BigUint { - fn from(a: $type) -> Self { - Self { digits: vec! [a.into()] } - } - })* - } - } - impl_from_for_smaller_than_word!(u8, u16, Single); - - impl From for BigUint { - fn from(a: Double) -> Self { - let (ah, al) = split(a); - Self { digits: vec![ah, al] } - } - } - - #[cfg(test)] - pub mod tests_biguint { - use super::*; - use rand::Rng; - #[cfg(feature = "bench")] - use test::Bencher; - - // TODO move into a proper fuzzer #3745 - const FUZZ_COUNT: usize = 100_000; - - pub fn random_big_uint(size: usize) -> BigUint { - let mut rng = rand::thread_rng(); - let digits = (0..size).map(|_| rng.gen_range(0, Single::max_value())).collect(); - BigUint { digits } - } - - fn run_with_data_set( - count: usize, - limbs_ub_1: usize, - limbs_ub_2: usize, - exact: bool, - assertion: F, - ) where - F: Fn(BigUint, BigUint) -> () - { - let mut rng = rand::thread_rng(); - for _ in 0..count { - let digits_len_1 = if exact { limbs_ub_1 } else { rng.gen_range(1, limbs_ub_1) }; - let digits_len_2 = if exact { limbs_ub_2 } else { rng.gen_range(1, limbs_ub_2) }; - - let u = random_big_uint(digits_len_1); - let v = random_big_uint(digits_len_2); - assertion(u, v); - } - } - - fn with_limbs(n: usize) -> BigUint { - BigUint { digits: vec![1; n] } - } - - #[test] - fn split_works() { - let a = SHIFT / 2; - let b = SHIFT * 3 / 2; - let num: Double = 1 << a | 1 << b; - // example when `Single = u8` - // assert_eq!(num, 0b_0001_0000_0001_0000) - assert_eq!(split(num), (1 << a, 1 << a)); - } - - #[test] - fn strip_works() { - let mut a = BigUint::from_limbs(&[0, 1, 0]); - a.lstrip(); - assert_eq!(a, BigUint { digits: vec![1, 0] }); - - let mut a = BigUint::from_limbs(&[0, 0, 1]); - a.lstrip(); - assert_eq!(a, BigUint { digits: vec![1] }); - - let mut a = BigUint::from_limbs(&[0, 0]); - a.lstrip(); - assert_eq!(a, BigUint { digits: vec![0] }); - - let mut a = BigUint::from_limbs(&[0, 0, 0]); - a.lstrip(); - assert_eq!(a, BigUint { digits: vec![0] }); - } - - #[test] - fn lpad_works() { - let mut a = BigUint::from_limbs(&[0, 1, 0]); - a.lpad(2); - assert_eq!(a.digits, vec![0, 1, 0]); - - let mut a = BigUint::from_limbs(&[0, 1, 0]); - a.lpad(3); - assert_eq!(a.digits, vec![0, 1, 0]); - - let mut a = BigUint::from_limbs(&[0, 1, 0]); - a.lpad(4); - assert_eq!(a.digits, vec![0, 0, 1, 0]); - } - - #[test] - fn equality_works() { - assert_eq!( - BigUint { digits: vec![1, 2, 3] } == BigUint { digits: vec![1, 2, 3] }, - true, - ); - assert_eq!( - BigUint { digits: vec![3, 2, 3] } == BigUint { digits: vec![1, 2, 3] }, - false, - ); - assert_eq!( - BigUint { digits: vec![0, 1, 2, 3] } == BigUint { digits: vec![1, 2, 3] }, - true, - ); - } - - #[test] - fn ordering_works() { - assert!(BigUint { digits: vec![0] } < BigUint { digits: vec![1] }); - assert!(BigUint { digits: vec![0] } == BigUint { digits: vec![0] }); - assert!(BigUint { digits: vec![] } == BigUint { digits: vec![0] }); - assert!(BigUint { digits: vec![] } == BigUint { digits: vec![] }); - assert!(BigUint { digits: vec![] } < BigUint { digits: vec![1] }); - - assert!(BigUint { digits: vec![1, 2, 3] } == BigUint { digits: vec![1, 2, 3] }); - assert!(BigUint { digits: vec![0, 1, 2, 3] } == BigUint { digits: vec![1, 2, 3] }); - - assert!(BigUint { digits: vec![1, 2, 4] } > BigUint { digits: vec![1, 2, 3] }); - assert!(BigUint { digits: vec![0, 1, 2, 4] } > BigUint { digits: vec![1, 2, 3] }); - assert!(BigUint { digits: vec![1, 2, 1, 0] } > BigUint { digits: vec![1, 2, 3] }); - - assert!(BigUint { digits: vec![0, 1, 2, 1] } < BigUint { digits: vec![1, 2, 3] }); - } - - #[test] - fn basic_random_ord_eq_works() { - type S = u128; - run_with_data_set(FUZZ_COUNT, 4, 4, false, |u, v| { - let ue = S::try_from(u.clone()).unwrap(); - let ve = S::try_from(v.clone()).unwrap(); - assert_eq!(u.cmp(&v), ue.cmp(&ve)); - assert_eq!(u.eq(&v), ue.eq(&ve)); - }) - } - - #[test] - fn can_try_build_numbers_from_types() { - use rstd::convert::TryFrom; - assert_eq!(u64::try_from(with_limbs(1)).unwrap(), 1); - assert_eq!(u64::try_from(with_limbs(2)).unwrap(), u32::max_value() as u64 + 2); - assert_eq!( - u64::try_from(with_limbs(3)).unwrap_err(), - "cannot fit a number into u64", - ); - assert_eq!( - u128::try_from(with_limbs(3)).unwrap(), - u32::max_value() as u128 + u64::max_value() as u128 + 3 - ); - } - - #[test] - fn zero_works() { - assert_eq!(BigUint::zero(), BigUint { digits: vec![0] }); - assert_eq!(BigUint { digits: vec![0, 1, 0] }.is_zero(), false); - assert_eq!(BigUint { digits: vec![0, 0, 0] }.is_zero(), true); - - let a = BigUint::zero(); - let b = BigUint::zero(); - let c = a * b; - assert_eq!(c.digits, vec![0, 0]); - } - - #[test] - fn basic_random_add_works() { - type S = u128; - run_with_data_set(FUZZ_COUNT, 3, 3, false, |u, v| { - let expected = S::try_from(u.clone()).unwrap() + S::try_from(v.clone()).unwrap(); - let t = u.clone().add(&v); - assert_eq!( - S::try_from(t.clone()).unwrap(), expected, - "{:?} + {:?} ===> {:?} != {:?}", u, v, t, expected, - ); - }) - } - - #[test] - fn sub_negative_works() { - assert_eq!( - BigUint::from(10 as Single).sub(&BigUint::from(5 as Single)).unwrap(), - BigUint::from(5 as Single) - ); - assert_eq!( - BigUint::from(10 as Single).sub(&BigUint::from(10 as Single)).unwrap(), - BigUint::from(0 as Single) - ); - assert_eq!( - BigUint::from(10 as Single).sub(&BigUint::from(13 as Single)).unwrap_err(), - BigUint::from((B - 3) as Single), - ); - } - - #[test] - fn basic_random_sub_works() { - type S = u128; - run_with_data_set(FUZZ_COUNT, 4, 4, false, |u, v| { - let expected = S::try_from(u.clone()).unwrap() - .checked_sub(S::try_from(v.clone()).unwrap()); - let t = u.clone().sub(&v); - if expected.is_none() { - assert!(t.is_err()) - } else { - let t = t.unwrap(); - let expected = expected.unwrap(); - assert_eq!( - S::try_from(t.clone()).unwrap(), expected, - "{:?} - {:?} ===> {:?} != {:?}", u, v, t, expected, - ); - } - }) - } - - #[test] - fn basic_random_mul_works() { - type S = u128; - run_with_data_set(FUZZ_COUNT, 2, 2, false, |u, v| { - let expected = S::try_from(u.clone()).unwrap() * S::try_from(v.clone()).unwrap(); - let t = u.clone().mul(&v); - assert_eq!( - S::try_from(t.clone()).unwrap(), expected, - "{:?} * {:?} ===> {:?} != {:?}", u, v, t, expected, - ); - }) - } - - #[test] - fn mul_always_appends_one_digit() { - let a = BigUint::from(10 as Single); - let b = BigUint::from(4 as Single); - assert_eq!(a.len(), 1); - assert_eq!(b.len(), 1); - - let n = a.mul(&b); - - assert_eq!(n.len(), 2); - assert_eq!(n.digits, vec![0, 40]); - } - - #[test] - fn div_conditions_work() { - let a = BigUint { digits: vec![2] }; - let b = BigUint { digits: vec![1, 2] }; - let c = BigUint { digits: vec![1, 1, 2] }; - let d = BigUint { digits: vec![0, 2] }; - let e = BigUint { digits: vec![0, 1, 1, 2] }; - - assert!(a.clone().div(&b, true).is_none()); - assert!(c.clone().div(&a, true).is_none()); - assert!(c.clone().div(&d, true).is_none()); - assert!(e.clone().div(&a, true).is_none()); - - assert!(c.clone().div(&b, true).is_some()); - } - - #[test] - fn div_unit_works() { - let a = BigUint { digits: vec![100] }; - let b = BigUint { digits: vec![1, 100] }; - - assert_eq!(a.clone().div_unit(1), a); - assert_eq!(a.clone().div_unit(0), a); - assert_eq!(a.clone().div_unit(2), BigUint::from(50 as Single)); - assert_eq!(a.clone().div_unit(7), BigUint::from(14 as Single)); - - assert_eq!(b.clone().div_unit(1), b); - assert_eq!(b.clone().div_unit(0), b); - assert_eq!(b.clone().div_unit(2), BigUint::from(((B + 100) / 2) as Single)); - assert_eq!(b.clone().div_unit(7), BigUint::from(((B + 100) / 7) as Single)); - - } - - #[test] - fn basic_random_div_works() { - type S = u128; - run_with_data_set(FUZZ_COUNT, 4, 4, false, |u, v| { - let ue = S::try_from(u.clone()).unwrap(); - let ve = S::try_from(v.clone()).unwrap(); - let (q, r) = (ue / ve, ue % ve); - if let Some((qq, rr)) = u.clone().div(&v, true) { - assert_eq!( - S::try_from(qq.clone()).unwrap(), q, - "{:?} / {:?} ===> {:?} != {:?}", u, v, qq, q, - ); - assert_eq!( - S::try_from(rr.clone()).unwrap(), r, - "{:?} % {:?} ===> {:?} != {:?}", u, v, rr, r, - ); - } else if v.len() == 1 { - let qq = u.clone().div_unit(ve as Single); - assert_eq!( - S::try_from(qq.clone()).unwrap(), q, - "[single] {:?} / {:?} ===> {:?} != {:?}", u, v, qq, q, - ); - } else { - if v.msb() == 0 || v.msb() == 0 || u.len() <= v.len() {} // nada - else { panic!("div returned none for an unexpected reason"); } - } - }) - } - - #[cfg(feature = "bench")] - #[bench] - fn bench_addition_2_digit(bencher: &mut Bencher) { - let a = random_big_uint(2); - let b = random_big_uint(2); - bencher.iter(|| { - let _ = a.clone().add(&b); - }); - } - - #[cfg(feature = "bench")] - #[bench] - fn bench_addition_4_digit(bencher: &mut Bencher) { - let a = random_big_uint(4); - let b = random_big_uint(4); - bencher.iter(|| { - let _ = a.clone().add(&b); - }); - } - - #[cfg(feature = "bench")] - #[bench] - fn bench_subtraction_2_digit(bencher: &mut Bencher) { - let a = random_big_uint(2); - let b = random_big_uint(2); - bencher.iter(|| { - let _ = a.clone().sub(&b); - }); - } - - #[cfg(feature = "bench")] - #[bench] - fn bench_subtraction_4_digit(bencher: &mut Bencher) { - let a = random_big_uint(4); - let b = random_big_uint(4); - bencher.iter(|| { - let _ = a.clone().sub(&b); - }); - } - - #[cfg(feature = "bench")] - #[bench] - fn bench_multiplication_2_digit(bencher: &mut Bencher) { - let a = random_big_uint(2); - let b = random_big_uint(2); - bencher.iter(|| { - let _ = a.clone().mul(&b); - }); - } - - #[cfg(feature = "bench")] - #[bench] - fn bench_multiplication_4_digit(bencher: &mut Bencher) { - let a = random_big_uint(4); - let b = random_big_uint(4); - bencher.iter(|| { - let _ = a.clone().mul(&b); - }); - } - - #[cfg(feature = "bench")] - #[bench] - fn bench_division_4_digit(bencher: &mut Bencher) { - let a = random_big_uint(4); - let b = random_big_uint(2); - bencher.iter(|| { - let _ = a.clone().div(&b, true); - }); - } - } -} - -/// Some helper functions to work with 128bit numbers. Note that the functionality provided here is -/// only sensible to use with 128bit numbers because for smaller sizes, you can always rely on -/// assumptions of a bigger type (u128) being available, or simply create a per-thing and use the -/// multiplication implementation provided there. -pub mod helpers_128bit { - use crate::biguint; - use crate::traits::Zero; - use rstd::{cmp::{min, max}, convert::TryInto}; - - /// Helper gcd function used in Rational128 implementation. - pub fn gcd(a: u128, b: u128) -> u128 { - match ((a, b), (a & 1, b & 1)) { - ((x, y), _) if x == y => y, - ((0, x), _) | ((x, 0), _) => x, - ((x, y), (0, 1)) | ((y, x), (1, 0)) => gcd(x >> 1, y), - ((x, y), (0, 0)) => gcd(x >> 1, y >> 1) << 1, - ((x, y), (1, 1)) => { - let (x, y) = (min(x, y), max(x, y)); - gcd((y - x) >> 1, x) - }, - _ => unreachable!(), - } - } - - /// split a u128 into two u64 limbs - pub fn split(a: u128) -> (u64, u64) { - let al = a as u64; - let ah = (a >> 64) as u64; - (ah, al) - } - - /// Convert a u128 to a u32 based biguint. - pub fn to_big_uint(x: u128) -> biguint::BigUint { - let (xh, xl) = split(x); - let (xhh, xhl) = biguint::split(xh); - let (xlh, xll) = biguint::split(xl); - let mut n = biguint::BigUint::from_limbs(&[xhh, xhl, xlh, xll]); - n.lstrip(); - n - } - - /// Safely and accurately compute `a * b / c`. The approach is: - /// - Simply try `a * b / c`. - /// - Else, convert them both into big numbers and re-try. `Err` is returned if the result - /// cannot be safely casted back to u128. - /// - /// Invariant: c must be greater than or equal to 1. - pub fn multiply_by_rational(a: u128, b: u128, c: u128) -> Result { - if a.is_zero() || b.is_zero() { return Ok(Zero::zero()); } - let c = c.max(1); - - // a and b are interchangeable by definition in this function. It always helps to assume the - // bigger of which is being multiplied by a `0 < b/c < 1`. Hence, a should be the bigger and - // b the smaller one. - let t = a; - let a = a.max(b); - let b = t.min(b); - - if let Some(x) = a.checked_mul(b) { - // This is the safest way to go. Try it. - Ok(x / c) - } else { - let a_num = to_big_uint(a); - let b_num = to_big_uint(b); - let c_num = to_big_uint(c); - - let mut ab = a_num * b_num; - ab.lstrip(); - let mut q = if c_num.len() == 1 { - // PROOF: if `c_num.len() == 1` then `c` fits in one limb. - ab.div_unit(c as biguint::Single) - } else { - // PROOF: both `ab` and `c` cannot have leading zero limbs; if length of `c` is 1, - // the previous branch would handle. Also, if ab for sure has a bigger size than - // c, because `a.checked_mul(b)` has failed, hence ab must be at least one limb - // bigger than c. In this case, returning zero is defensive-only and div should - // always return Some. - let (mut q, r) = ab.div(&c_num, true).unwrap_or((Zero::zero(), Zero::zero())); - let r: u128 = r.try_into() - .expect("reminder of div by c is always less than c; qed"); - if r > (c / 2) { q = q.add(&to_big_uint(1)); } - q - }; - q.lstrip(); - q.try_into().map_err(|_| "result cannot fit in u128") - } - } -} - -/// A wrapper for any rational number with a 128 bit numerator and denominator. -#[derive(Clone, Copy, Default, Eq)] -#[cfg_attr(feature = "std", derive(Debug))] -pub struct Rational128(u128, u128); - -impl Rational128 { - /// Nothing. - pub fn zero() -> Self { - Self(0, 1) - } - - /// If it is zero or not - pub fn is_zero(&self) -> bool { - self.0.is_zero() - } - - /// Build from a raw `n/d`. - pub fn from(n: u128, d: u128) -> Self { - Self(n, d.max(1)) - } - - /// Build from a raw `n/d`. This could lead to / 0 if not properly handled. - pub fn from_unchecked(n: u128, d: u128) -> Self { - Self(n, d) - } - - /// Return the numerator. - pub fn n(&self) -> u128 { - self.0 - } - - /// Return the denominator. - pub fn d(&self) -> u128 { - self.1 - } - - /// Convert `self` to a similar rational number where denominator is the given `den`. - // - /// This only returns if the result is accurate. `Err` is returned if the result cannot be - /// accurately calculated. - pub fn to_den(self, den: u128) -> Result { - if den == self.1 { - Ok(self) - } else { - helpers_128bit::multiply_by_rational(self.0, den, self.1).map(|n| Self(n, den)) - } - } - - /// Get the least common divisor of `self` and `other`. - /// - /// This only returns if the result is accurate. `Err` is returned if the result cannot be - /// accurately calculated. - pub fn lcm(&self, other: &Self) -> Result { - // this should be tested better: two large numbers that are almost the same. - if self.1 == other.1 { return Ok(self.1) } - let g = helpers_128bit::gcd(self.1, other.1); - helpers_128bit::multiply_by_rational(self.1 , other.1, g) - } - - /// A saturating add that assumes `self` and `other` have the same denominator. - pub fn lazy_saturating_add(self, other: Self) -> Self { - if other.is_zero() { - self - } else { - Self(self.0.saturating_add(other.0) ,self.1) - } - } - - /// A saturating subtraction that assumes `self` and `other` have the same denominator. - pub fn lazy_saturating_sub(self, other: Self) -> Self { - if other.is_zero() { - self - } else { - Self(self.0.saturating_sub(other.0) ,self.1) - } - } - - /// Addition. Simply tries to unify the denominators and add the numerators. - /// - /// Overflow might happen during any of the steps. Error is returned in such cases. - pub fn checked_add(self, other: Self) -> Result { - let lcm = self.lcm(&other).map_err(|_| "failed to scale to denominator")?; - let self_scaled = self.to_den(lcm).map_err(|_| "failed to scale to denominator")?; - let other_scaled = other.to_den(lcm).map_err(|_| "failed to scale to denominator")?; - let n = self_scaled.0.checked_add(other_scaled.0) - .ok_or("overflow while adding numerators")?; - Ok(Self(n, self_scaled.1)) - } - - /// Subtraction. Simply tries to unify the denominators and subtract the numerators. - /// - /// Overflow might happen during any of the steps. None is returned in such cases. - pub fn checked_sub(self, other: Self) -> Result { - let lcm = self.lcm(&other).map_err(|_| "failed to scale to denominator")?; - let self_scaled = self.to_den(lcm).map_err(|_| "failed to scale to denominator")?; - let other_scaled = other.to_den(lcm).map_err(|_| "failed to scale to denominator")?; - - let n = self_scaled.0.checked_sub(other_scaled.0) - .ok_or("overflow while subtracting numerators")?; - Ok(Self(n, self_scaled.1)) - } -} - -impl PartialOrd for Rational128 { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for Rational128 { - fn cmp(&self, other: &Self) -> Ordering { - // handle some edge cases. - if self.1 == other.1 { - self.0.cmp(&other.0) - } else if self.1.is_zero() { - Ordering::Greater - } else if other.1.is_zero() { - Ordering::Less - } else { - // Don't even compute gcd. - let self_n = helpers_128bit::to_big_uint(self.0) * helpers_128bit::to_big_uint(other.1); - let other_n = helpers_128bit::to_big_uint(other.0) * helpers_128bit::to_big_uint(self.1); - self_n.cmp(&other_n) - } - } -} - -impl PartialEq for Rational128 { - fn eq(&self, other: &Self) -> bool { - // handle some edge cases. - if self.1 == other.1 { - self.0.eq(&other.0) - } else { - let self_n = helpers_128bit::to_big_uint(self.0) * helpers_128bit::to_big_uint(other.1); - let other_n = helpers_128bit::to_big_uint(other.0) * helpers_128bit::to_big_uint(self.1); - self_n.eq(&other_n) - } - } -} - -#[cfg(test)] -mod test_rational128 { - use super::*; - use super::helpers_128bit::*; - use rand::Rng; - - const MAX128: u128 = u128::max_value(); - const MAX64: u128 = u64::max_value() as u128; - const MAX64_2: u128 = 2 * u64::max_value() as u128; - - fn r(p: u128, q: u128) -> Rational128 { - Rational128(p, q) - } - - fn mul_div(a: u128, b: u128, c: u128) -> u128 { - use primitive_types::U256; - if a.is_zero() { return Zero::zero(); } - let c = c.max(1); - - // e for extended - let ae: U256 = a.into(); - let be: U256 = b.into(); - let ce: U256 = c.into(); - - let r = ae * be / ce; - if r > u128::max_value().into() { - a - } else { - r.as_u128() - } - } - - #[test] - fn truth_value_function_works() { - assert_eq!( - mul_div(2u128.pow(100), 8, 4), - 2u128.pow(101) - ); - assert_eq!( - mul_div(2u128.pow(100), 4, 8), - 2u128.pow(99) - ); - - // and it returns a if result cannot fit - assert_eq!(mul_div(MAX128 - 10, 2, 1), MAX128 - 10); - } - - #[test] - fn to_denom_works() { - // simple up and down - assert_eq!(r(1, 5).to_den(10), Ok(r(2, 10))); - assert_eq!(r(4, 10).to_den(5), Ok(r(2, 5))); - - // up and down with large numbers - assert_eq!(r(MAX128 - 10, MAX128).to_den(10), Ok(r(10, 10))); - assert_eq!(r(MAX128 / 2, MAX128).to_den(10), Ok(r(5, 10))); - - // large to perbill. This is very well needed for phragmen. - assert_eq!( - r(MAX128 / 2, MAX128).to_den(1000_000_000), - Ok(r(500_000_000, 1000_000_000)) - ); - - // large to large - assert_eq!(r(MAX128 / 2, MAX128).to_den(MAX128/2), Ok(r(MAX128/4, MAX128/2))); - } - - #[test] - fn gdc_works() { - assert_eq!(gcd(10, 5), 5); - assert_eq!(gcd(7, 22), 1); - } - - #[test] - fn lcm_works() { - // simple stuff - assert_eq!(r(3, 10).lcm(&r(4, 15)).unwrap(), 30); - assert_eq!(r(5, 30).lcm(&r(1, 7)).unwrap(), 210); - assert_eq!(r(5, 30).lcm(&r(1, 10)).unwrap(), 30); - - // large numbers - assert_eq!( - r(1_000_000_000, MAX128).lcm(&r(7_000_000_000, MAX128-1)), - Err("result cannot fit in u128"), - ); - assert_eq!( - r(1_000_000_000, MAX64).lcm(&r(7_000_000_000, MAX64-1)), - Ok(340282366920938463408034375210639556610), - ); - assert!(340282366920938463408034375210639556610 < MAX128); - assert!(340282366920938463408034375210639556610 == MAX64 * (MAX64 - 1)); - } - - #[test] - fn add_works() { - // works - assert_eq!(r(3, 10).checked_add(r(1, 10)).unwrap(), r(2, 5)); - assert_eq!(r(3, 10).checked_add(r(3, 7)).unwrap(), r(51, 70)); - - // errors - assert_eq!( - r(1, MAX128).checked_add(r(1, MAX128-1)), - Err("failed to scale to denominator"), - ); - assert_eq!( - r(7, MAX128).checked_add(r(MAX128, MAX128)), - Err("overflow while adding numerators"), - ); - assert_eq!( - r(MAX128, MAX128).checked_add(r(MAX128, MAX128)), - Err("overflow while adding numerators"), - ); - } - - #[test] - fn sub_works() { - // works - assert_eq!(r(3, 10).checked_sub(r(1, 10)).unwrap(), r(1, 5)); - assert_eq!(r(6, 10).checked_sub(r(3, 7)).unwrap(), r(12, 70)); - - // errors - assert_eq!( - r(2, MAX128).checked_sub(r(1, MAX128-1)), - Err("failed to scale to denominator"), - ); - assert_eq!( - r(7, MAX128).checked_sub(r(MAX128, MAX128)), - Err("overflow while subtracting numerators"), - ); - assert_eq!( - r(1, 10).checked_sub(r(2,10)), - Err("overflow while subtracting numerators"), - ); - } - - #[test] - fn ordering_and_eq_works() { - assert!(r(1, 2) > r(1, 3)); - assert!(r(1, 2) > r(2, 6)); - - assert!(r(1, 2) < r(6, 6)); - assert!(r(2, 1) > r(2, 6)); - - assert!(r(5, 10) == r(1, 2)); - assert!(r(1, 2) == r(1, 2)); - - assert!(r(1, 1490000000000200000) > r(1, 1490000000000200001)); - } - - #[test] - fn multiply_by_rational_works() { - assert_eq!(multiply_by_rational(7, 2, 3).unwrap(), 7 * 2 / 3); - assert_eq!(multiply_by_rational(7, 20, 30).unwrap(), 7 * 2 / 3); - assert_eq!(multiply_by_rational(20, 7, 30).unwrap(), 7 * 2 / 3); - - assert_eq!( - // MAX128 % 3 == 0 - multiply_by_rational(MAX128, 2, 3).unwrap(), - MAX128 / 3 * 2, - ); - assert_eq!( - // MAX128 % 7 == 3 - multiply_by_rational(MAX128, 5, 7).unwrap(), - (MAX128 / 7 * 5) + (3 * 5 / 7), - ); - assert_eq!( - // MAX128 % 7 == 3 - multiply_by_rational(MAX128, 11 , 13).unwrap(), - (MAX128 / 13 * 11) + (8 * 11 / 13), - ); - assert_eq!( - // MAX128 % 1000 == 455 - multiply_by_rational(MAX128, 555, 1000).unwrap(), - (MAX128 / 1000 * 555) + (455 * 555 / 1000), - ); - - assert_eq!( - multiply_by_rational(2 * MAX64 - 1, MAX64, MAX64).unwrap(), - 2 * MAX64 - 1, - ); - assert_eq!( - multiply_by_rational(2 * MAX64 - 1, MAX64 - 1, MAX64).unwrap(), - 2 * MAX64 - 3, - ); - - assert_eq!( - multiply_by_rational(MAX64 + 100, MAX64_2, MAX64_2 / 2).unwrap(), - (MAX64 + 100) * 2, - ); - assert_eq!( - multiply_by_rational(MAX64 + 100, MAX64_2 / 100, MAX64_2 / 200).unwrap(), - (MAX64 + 100) * 2, - ); - - assert_eq!( - multiply_by_rational(2u128.pow(66) - 1, 2u128.pow(65) - 1, 2u128.pow(65)).unwrap(), - 73786976294838206461, - ); - assert_eq!( - multiply_by_rational(1_000_000_000, MAX128 / 8, MAX128 / 2).unwrap(), - 250000000, - ); - } - - #[test] - fn multiply_by_rational_a_b_are_interchangeable() { - assert_eq!( - multiply_by_rational(10, MAX128, MAX128 / 2), - Ok(20), - ); - assert_eq!( - multiply_by_rational(MAX128, 10, MAX128 / 2), - Ok(20), - ); - } - - fn do_fuzz_multiply_by_rational( - iters: usize, - bits: u32, - maximum_error: u128, - do_print: bool, - bounded: bool, - mul_fn: F, - ) where F: Fn(u128, u128, u128) -> u128 { - let mut rng = rand::thread_rng(); - let mut average_diff = 0.0; - let upper_bound = 2u128.pow(bits); - - for _ in 0..iters { - let a = rng.gen_range(0u128, upper_bound); - let c = rng.gen_range(0u128, upper_bound); - let b = rng.gen_range( - 0u128, - if bounded { c } else { upper_bound } - ); - - let a: u128 = a.into(); - let b: u128 = b.into(); - let c: u128 = c.into(); - - let truth = mul_div(a, b, c); - let result = mul_fn(a, b, c); - let diff = truth.max(result) - truth.min(result); - let loss_ratio = diff as f64 / truth as f64; - average_diff += loss_ratio; - - if do_print && diff > maximum_error { - println!("++ Computed with more loss than expected: {} * {} / {}", a, b, c); - println!("++ Expected {}", truth); - println!("+++++++ Got {}", result); - } - } - - // print report - println!( - "## Fuzzed with {} numbers. Average error was {}", - iters, - average_diff / (iters as f64), - ); - } - - // TODO $# move into a proper fuzzer #3745 - const FUZZ_COUNT: usize = 100_000; - - #[test] - fn fuzz_multiply_by_rational_32() { - // if Err just return the truth value. We don't care about such cases. The point of this - // fuzzing is to make sure: if `multiply_by_rational` returns `Ok`, it must be 100% accurate - // returning `Err` is fine. - let f = |a, b, c| multiply_by_rational(a, b, c).unwrap_or(mul_div(a, b, c)); - println!("\nInvariant: b < c"); - do_fuzz_multiply_by_rational(FUZZ_COUNT, 32, 0, false, true, f); - println!("every possibility"); - do_fuzz_multiply_by_rational(FUZZ_COUNT, 32, 0, false, false, f); - } - - #[test] - fn fuzz_multiply_by_rational_64() { - let f = |a, b, c| multiply_by_rational(a, b, c).unwrap_or(mul_div(a, b, c)); - println!("\nInvariant: b < c"); - do_fuzz_multiply_by_rational(FUZZ_COUNT, 64, 0, false, true, f); - println!("every possibility"); - do_fuzz_multiply_by_rational(FUZZ_COUNT, 64, 0, false, false, f); - } - - #[test] - fn fuzz_multiply_by_rational_96() { - let f = |a, b, c| multiply_by_rational(a, b, c).unwrap_or(mul_div(a, b, c)); - println!("\nInvariant: b < c"); - do_fuzz_multiply_by_rational(FUZZ_COUNT, 96, 0, false, true, f); - println!("every possibility"); - do_fuzz_multiply_by_rational(FUZZ_COUNT, 96, 0, false, false, f); - } - - #[test] - fn fuzz_multiply_by_rational_128() { - let f = |a, b, c| multiply_by_rational(a, b, c).unwrap_or(mul_div(a, b, c)); - println!("\nInvariant: b < c"); - do_fuzz_multiply_by_rational(FUZZ_COUNT, 127, 0, false, true, f); - println!("every possibility"); - do_fuzz_multiply_by_rational(FUZZ_COUNT, 127, 0, false, false, f); - } -} - -#[cfg(test)] -mod tests_fixed64 { - use super::*; - - fn max() -> Fixed64 { - Fixed64::from_parts(i64::max_value()) - } - - #[test] - fn fixed64_semantics() { - assert_eq!(Fixed64::from_rational(5, 2).0, 5 * 1_000_000_000 / 2); - assert_eq!(Fixed64::from_rational(5, 2), Fixed64::from_rational(10, 4)); - assert_eq!(Fixed64::from_rational(5, 0), Fixed64::from_rational(5, 1)); - - // biggest value that can be created. - assert_ne!(max(), Fixed64::from_natural(9_223_372_036)); - assert_eq!(max(), Fixed64::from_natural(9_223_372_037)); - } - - #[test] - fn fixed_64_growth_decrease_curve() { - let test_set = vec![0u32, 1, 10, 1000, 1_000_000_000]; - - // negative (1/2) - let mut fm = Fixed64::from_rational(-1, 2); - test_set.clone().into_iter().for_each(|i| { - assert_eq!(fm.saturated_multiply_accumulate(i) as i32, i as i32 - i as i32 / 2); - }); - - // unit (1) multiplier - fm = Fixed64::from_parts(0); - test_set.clone().into_iter().for_each(|i| { - assert_eq!(fm.saturated_multiply_accumulate(i), i); - }); - - // i.5 multiplier - fm = Fixed64::from_rational(1, 2); - test_set.clone().into_iter().for_each(|i| { - assert_eq!(fm.saturated_multiply_accumulate(i), i * 3 / 2); - }); - - // dual multiplier - fm = Fixed64::from_rational(1, 1); - test_set.clone().into_iter().for_each(|i| { - assert_eq!(fm.saturated_multiply_accumulate(i), i * 2); - }); - } - - macro_rules! saturating_mul_acc_test { - ($num_type:tt) => { - assert_eq!( - Fixed64::from_rational(100, 1).saturated_multiply_accumulate(10 as $num_type), - 1010, - ); - assert_eq!( - Fixed64::from_rational(100, 2).saturated_multiply_accumulate(10 as $num_type), - 510, - ); - assert_eq!( - Fixed64::from_rational(100, 3).saturated_multiply_accumulate(0 as $num_type), - 0, - ); - assert_eq!( - Fixed64::from_rational(5, 1).saturated_multiply_accumulate($num_type::max_value()), - $num_type::max_value() - ); - assert_eq!( - max().saturated_multiply_accumulate($num_type::max_value()), - $num_type::max_value() - ); - } - } - - #[test] - fn fixed64_multiply_accumulate_works() { - saturating_mul_acc_test!(u32); - saturating_mul_acc_test!(u64); - saturating_mul_acc_test!(u128); - } -} diff --git a/core/sr-primitives/src/traits.rs b/core/sr-primitives/src/traits.rs index a589f5f389..a384c95e19 100644 --- a/core/sr-primitives/src/traits.rs +++ b/core/sr-primitives/src/traits.rs @@ -24,20 +24,16 @@ use std::fmt::{Debug, Display}; #[cfg(feature = "std")] use serde::{Serialize, Deserialize, de::DeserializeOwned}; use primitives::{self, Hasher, Blake2Hasher, TypeId}; -use crate::codec::{Codec, Encode, Decode, HasCompact}; +use crate::codec::{Codec, Encode, Decode}; use crate::transaction_validity::{ ValidTransaction, TransactionValidity, TransactionValidityError, UnknownTransaction, }; use crate::generic::{Digest, DigestItem}; use crate::weights::DispatchInfo; -pub use integer_sqrt::IntegerSquareRoot; -pub use num_traits::{ +pub use arithmetic::traits::{ + SimpleArithmetic, UniqueSaturatedInto, UniqueSaturatedFrom, Saturating, SaturatedConversion, Zero, One, Bounded, CheckedAdd, CheckedSub, CheckedMul, CheckedDiv, - CheckedShl, CheckedShr -}; -use rstd::ops::{ - Add, Sub, Mul, Div, Rem, AddAssign, SubAssign, MulAssign, DivAssign, - RemAssign, Shl, Shr + CheckedShl, CheckedShr, IntegerSquareRoot }; use app_crypto::AppKey; use impl_trait_for_tuples::impl_for_tuples; @@ -198,120 +194,6 @@ impl> Convert for ConvertInto { fn convert(a: A) -> B { a.into() } } -/// A meta trait for arithmetic. -/// -/// Arithmetic types do all the usual stuff you'd expect numbers to do. They are guaranteed to -/// be able to represent at least `u32` values without loss, hence the trait implies `From` -/// and smaller ints. All other conversions are fallible. -pub trait SimpleArithmetic: - Zero + One + IntegerSquareRoot + - From + From + From + TryInto + TryInto + TryInto + - TryFrom + TryInto + TryFrom + TryInto + TryFrom + TryInto + - UniqueSaturatedInto + UniqueSaturatedInto + UniqueSaturatedInto + - UniqueSaturatedFrom + UniqueSaturatedInto + UniqueSaturatedFrom + UniqueSaturatedInto + - Add + AddAssign + - Sub + SubAssign + - Mul + MulAssign + - Div + DivAssign + - Rem + RemAssign + - Shl + Shr + - CheckedShl + CheckedShr + CheckedAdd + CheckedSub + CheckedMul + CheckedDiv + - Saturating + PartialOrd + Ord + Bounded + - HasCompact + Sized -{} -impl + From + From + TryInto + TryInto + TryInto + - TryFrom + TryInto + TryFrom + TryInto + TryFrom + TryInto + - UniqueSaturatedInto + UniqueSaturatedInto + UniqueSaturatedInto + - UniqueSaturatedFrom + UniqueSaturatedInto + UniqueSaturatedFrom + - UniqueSaturatedInto + UniqueSaturatedFrom + UniqueSaturatedInto + - Add + AddAssign + - Sub + SubAssign + - Mul + MulAssign + - Div + DivAssign + - Rem + RemAssign + - Shl + Shr + - CheckedShl + CheckedShr + CheckedAdd + CheckedSub + CheckedMul + CheckedDiv + - Saturating + PartialOrd + Ord + Bounded + - HasCompact + Sized -> SimpleArithmetic for T {} - -/// Just like `From` except that if the source value is too big to fit into the destination type -/// then it'll saturate the destination. -pub trait UniqueSaturatedFrom: Sized { - /// Convert from a value of `T` into an equivalent instance of `Self`. - fn unique_saturated_from(t: T) -> Self; -} - -/// Just like `Into` except that if the source value is too big to fit into the destination type -/// then it'll saturate the destination. -pub trait UniqueSaturatedInto: Sized { - /// Consume self to return an equivalent value of `T`. - fn unique_saturated_into(self) -> T; -} - -impl + Bounded + Sized> UniqueSaturatedFrom for S { - fn unique_saturated_from(t: T) -> Self { - S::try_from(t).unwrap_or_else(|_| Bounded::max_value()) - } -} - -impl + Sized> UniqueSaturatedInto for S { - fn unique_saturated_into(self) -> T { - self.try_into().unwrap_or_else(|_| Bounded::max_value()) - } -} - -/// Simple trait to use checked mul and max value to give a saturated mul operation over -/// supported types. -pub trait Saturating { - /// Saturated addition - if the product can't fit in the type then just use max-value. - fn saturating_add(self, o: Self) -> Self; - - /// Saturated subtraction - if the product can't fit in the type then just use max-value. - fn saturating_sub(self, o: Self) -> Self; - - /// Saturated multiply - if the product can't fit in the type then just use max-value. - fn saturating_mul(self, o: Self) -> Self; -} - -impl Saturating for T { - fn saturating_add(self, o: Self) -> Self { - ::saturating_add(self, o) - } - fn saturating_sub(self, o: Self) -> Self { - ::saturating_sub(self, o) - } - fn saturating_mul(self, o: Self) -> Self { - self.checked_mul(&o).unwrap_or_else(Bounded::max_value) - } -} - -/// Convenience type to work around the highly unergonomic syntax needed -/// to invoke the functions of overloaded generic traits, in this case -/// `SaturatedFrom` and `SaturatedInto`. -pub trait SaturatedConversion { - /// Convert from a value of `T` into an equivalent instance of `Self`. - /// - /// This just uses `UniqueSaturatedFrom` internally but with this - /// variant you can provide the destination type using turbofish syntax - /// in case Rust happens not to assume the correct type. - fn saturated_from(t: T) -> Self where Self: UniqueSaturatedFrom { - >::unique_saturated_from(t) - } - - /// Consume self to return an equivalent value of `T`. - /// - /// This just uses `UniqueSaturatedInto` internally but with this - /// variant you can provide the destination type using turbofish syntax - /// in case Rust happens not to assume the correct type. - fn saturated_into(self) -> T where Self: UniqueSaturatedInto { - >::unique_saturated_into(self) - } -} -impl SaturatedConversion for T {} - /// Convenience type to work around the highly unergonomic syntax needed /// to invoke the functions of overloaded generic traits, in this case /// `TryFrom` and `TryInto`. diff --git a/core/sr-primitives/src/weights.rs b/core/sr-primitives/src/weights.rs index 2ffd4ee391..b1cce0f77f 100644 --- a/core/sr-primitives/src/weights.rs +++ b/core/sr-primitives/src/weights.rs @@ -24,7 +24,7 @@ //! (something that does not implement `Weighable`) is passed in. pub use crate::transaction_validity::TransactionPriority; -use crate::traits::Bounded; +use arithmetic::traits::Bounded; /// Numeric range of a transaction weight. pub type Weight = u32; diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index ac801fd39e..69f812ce32 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -85,7 +85,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // implementation changes and behavior does not, then leave spec_version as // is and increment impl_version. spec_version: 179, - impl_version: 179, + impl_version: 180, apis: RUNTIME_API_VERSIONS, }; -- GitLab From e479a512f104e77747a2bb3e98f57ebc59faad8d Mon Sep 17 00:00:00 2001 From: Andrew Dirksen Date: Sat, 19 Oct 2019 01:38:19 -0700 Subject: [PATCH 066/167] Change manual dependency on wasm-gc executable to an automatic cargo dependency. (#3854) Improves user experience. --- Cargo.lock | 21 ++++++++++++++++++++ Dockerfile | 1 - README.adoc | 13 ++++-------- core/utils/wasm-builder/Cargo.toml | 1 + core/utils/wasm-builder/README.md | 1 - core/utils/wasm-builder/src/lib.rs | 1 - core/utils/wasm-builder/src/prerequisites.rs | 13 +----------- core/utils/wasm-builder/src/wasm_project.rs | 13 +++--------- node-template/scripts/init.sh | 4 ---- scripts/init.sh | 4 ---- 10 files changed, 30 insertions(+), 42 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 82a5ab2229..d9bfc40409 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2840,6 +2840,14 @@ dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "parity-wasm" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "parity-wasm" version = "0.40.3" @@ -5759,6 +5767,7 @@ dependencies = [ "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-gc-api 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -6516,6 +6525,16 @@ dependencies = [ "weedle 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "wasm-gc-api" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-wasm 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "wasm-timer" version = "0.1.3" @@ -7019,6 +7038,7 @@ dependencies = [ "checksum parity-scale-codec-derive 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "42af752f59119656fa3cb31e8852ed24e895b968c0bdb41847da7f0cea6d155f" "checksum parity-send-wrapper 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aa9777aa91b8ad9dd5aaa04a9b6bcb02c7f1deb952fca5a66034d5e63afc5c6f" "checksum parity-util-mem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2005637ccf93dbb60c85081ccaaf3f945f573da48dcc79f27f9646caa3ec1dc" +"checksum parity-wasm 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "16ad52817c4d343339b3bc2e26861bd21478eda0b7509acf83505727000512ac" "checksum parity-wasm 0.40.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1e39faaa292a687ea15120b1ac31899b13586446521df6c149e46f1584671e0f" "checksum parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f0802bff09003b291ba756dc7e79313e51cc31667e94afbe847def490424cde5" "checksum parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337" @@ -7219,6 +7239,7 @@ dependencies = [ "checksum wasm-bindgen-macro-support 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)" = "9c075d27b7991c68ca0f77fe628c3513e64f8c477d422b859e03f28751b46fc5" "checksum wasm-bindgen-shared 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)" = "83d61fe986a7af038dd8b5ec660e5849cbd9f38e7492b9404cc48b2b4df731d1" "checksum wasm-bindgen-webidl 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)" = "9b979afb0535fe4749906a674082db1211de8aef466331d43232f63accb7c07c" +"checksum wasm-gc-api 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d0c32691b6c7e6c14e7f8fd55361a9088b507aa49620fcd06c09b3a1082186b9" "checksum wasm-timer 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "aa3e01d234bb71760e685cfafa5e2c96f8ad877c161a721646356651069e26ac" "checksum wasmi 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f31d26deb2d9a37e6cfed420edce3ed604eab49735ba89035e13c98f9a528313" "checksum wasmi-validation 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6bc0356e3df56e639fc7f7d8a99741915531e27ed735d911ed83d7e1339c8188" diff --git a/Dockerfile b/Dockerfile index 1ebc7b04aa..7cba85c544 100644 --- a/Dockerfile +++ b/Dockerfile @@ -20,7 +20,6 @@ RUN curl https://sh.rustup.rs -sSf | sh -s -- -y && \ export PATH="$PATH:$HOME/.cargo/bin" && \ rustup toolchain install nightly && \ rustup target add wasm32-unknown-unknown --toolchain nightly && \ - cargo install --git https://github.com/alexcrichton/wasm-gc && \ rustup default nightly && \ rustup default stable && \ cargo build "--$PROFILE" diff --git a/README.adoc b/README.adoc index f5d7f95713..6563340cc6 100644 --- a/README.adoc +++ b/README.adoc @@ -184,7 +184,6 @@ curl https://sh.rustup.rs -sSf | sh rustup update nightly rustup target add wasm32-unknown-unknown --toolchain nightly rustup update stable -cargo install --git https://github.com/alexcrichton/wasm-gc ---- You will also need to install the following packages: @@ -231,13 +230,9 @@ If you are trying to set up Substrate on Windows, you should do the following: rustup update stable rustup target add wasm32-unknown-unknown --toolchain nightly -4. Next, you install wasm-gc, which is used to slim down Wasm files: +4. Then, you need to install LLVM: https://releases.llvm.org/download.html - cargo install --git https://github.com/alexcrichton/wasm-gc --force - -5. Then, you need to install LLVM: https://releases.llvm.org/download.html - -6. Next, you need to install OpenSSL, which we will do with `vcpkg`: +5. Next, you need to install OpenSSL, which we will do with `vcpkg`: mkdir \Tools cd \Tools @@ -246,14 +241,14 @@ If you are trying to set up Substrate on Windows, you should do the following: .\bootstrap-vcpkg.bat .\vcpkg.exe install openssl:x64-windows-static -7. After, you need to add OpenSSL to your System Variables. Note that in order for the following commands to work, you need to use Windows Powershell: +6. After, you need to add OpenSSL to your System Variables. Note that in order for the following commands to work, you need to use Windows Powershell: $env:OPENSSL_DIR = 'C:\Tools\vcpkg\installed\x64-windows-static' $env:OPENSSL_STATIC = 'Yes' [System.Environment]::SetEnvironmentVariable('OPENSSL_DIR', $env:OPENSSL_DIR, [System.EnvironmentVariableTarget]::User) [System.Environment]::SetEnvironmentVariable('OPENSSL_STATIC', $env:OPENSSL_STATIC, [System.EnvironmentVariableTarget]::User) -8. Finally, you need to install `cmake`: https://cmake.org/download/ +7. Finally, you need to install `cmake`: https://cmake.org/download/ ==== Shared Steps diff --git a/core/utils/wasm-builder/Cargo.toml b/core/utils/wasm-builder/Cargo.toml index bbcfe2ff52..7fcdd6c4e1 100644 --- a/core/utils/wasm-builder/Cargo.toml +++ b/core/utils/wasm-builder/Cargo.toml @@ -15,3 +15,4 @@ tempfile = "3.1.0" toml = "0.5.3" walkdir = "2.2.9" fs2 = "0.4.3" +wasm-gc-api = "0.1.11" diff --git a/core/utils/wasm-builder/README.md b/core/utils/wasm-builder/README.md index 0f3d933a2f..b15d2ebfab 100644 --- a/core/utils/wasm-builder/README.md +++ b/core/utils/wasm-builder/README.md @@ -57,7 +57,6 @@ be `NODE_RUNTIME`. WASM builder requires the following prerequisities for building the WASM binary: - rust nightly + `wasm32-unknown-unknown` toolchain -- wasm-gc License: GPL-3.0 diff --git a/core/utils/wasm-builder/src/lib.rs b/core/utils/wasm-builder/src/lib.rs index 6f7687f446..b97559c076 100644 --- a/core/utils/wasm-builder/src/lib.rs +++ b/core/utils/wasm-builder/src/lib.rs @@ -75,7 +75,6 @@ //! WASM builder requires the following prerequisities for building the WASM binary: //! //! - rust nightly + `wasm32-unknown-unknown` toolchain -//! - wasm-gc //! use std::{env, fs, path::PathBuf, process::{Command, Stdio, self}}; diff --git a/core/utils/wasm-builder/src/prerequisites.rs b/core/utils/wasm-builder/src/prerequisites.rs index 0c41dff6c8..73e356f0c2 100644 --- a/core/utils/wasm-builder/src/prerequisites.rs +++ b/core/utils/wasm-builder/src/prerequisites.rs @@ -14,9 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -use std::{process::{Command, Stdio}, fs}; - -use std::env; +use std::{env, fs}; use tempfile::tempdir; /// Checks that all prerequisites are installed. @@ -28,15 +26,6 @@ pub fn check() -> Option<&'static str> { return Some("Rust nightly not installed, please install it!") } - if Command::new("wasm-gc") - .stdout(Stdio::null()) - .stderr(Stdio::null()) - .status() - .map(|s| !s.success()).unwrap_or(true) - { - return Some("`wasm-gc` not installed, please install it!") - } - check_wasm_toolchain_installed() } diff --git a/core/utils/wasm-builder/src/wasm_project.rs b/core/utils/wasm-builder/src/wasm_project.rs index afe6faa070..1651642ee0 100644 --- a/core/utils/wasm-builder/src/wasm_project.rs +++ b/core/utils/wasm-builder/src/wasm_project.rs @@ -16,7 +16,7 @@ use crate::write_file_if_changed; -use std::{fs, path::{Path, PathBuf}, borrow::ToOwned, process::{Command, self}, env}; +use std::{fs, path::{Path, PathBuf}, borrow::ToOwned, process, env}; use toml::value::Table; @@ -352,15 +352,8 @@ fn compact_wasm_file( .join(format!("{}.wasm", wasm_binary)); let wasm_compact_file = project.join(format!("{}.compact.wasm", wasm_binary)); - let res = Command::new("wasm-gc") - .arg(&wasm_file) - .arg(&wasm_compact_file) - .status() - .map(|s| s.success()); - - if !res.unwrap_or(false) { - panic!("Failed to compact generated WASM binary."); - } + wasm_gc::garbage_collect_file(&wasm_file, &wasm_compact_file) + .expect("Failed to compact generated WASM binary."); (WasmBinary(wasm_compact_file), WasmBinaryBloaty(wasm_file)) } diff --git a/node-template/scripts/init.sh b/node-template/scripts/init.sh index cf5ecf9792..1405a41ef3 100755 --- a/node-template/scripts/init.sh +++ b/node-template/scripts/init.sh @@ -10,7 +10,3 @@ if [ -z $CI_PROJECT_NAME ] ; then fi rustup target add wasm32-unknown-unknown --toolchain nightly - -# Install wasm-gc. It's useful for stripping slimming down wasm binaries. -command -v wasm-gc || \ - cargo +nightly install --git https://github.com/alexcrichton/wasm-gc --force diff --git a/scripts/init.sh b/scripts/init.sh index cf5ecf9792..1405a41ef3 100755 --- a/scripts/init.sh +++ b/scripts/init.sh @@ -10,7 +10,3 @@ if [ -z $CI_PROJECT_NAME ] ; then fi rustup target add wasm32-unknown-unknown --toolchain nightly - -# Install wasm-gc. It's useful for stripping slimming down wasm binaries. -command -v wasm-gc || \ - cargo +nightly install --git https://github.com/alexcrichton/wasm-gc --force -- GitLab From 5fde6d0882bd9943da28df6d40dc78714672dcca Mon Sep 17 00:00:00 2001 From: Caio Date: Sat, 19 Oct 2019 08:01:51 -0300 Subject: [PATCH 067/167] It's Clippy time (#3806) Fix some Clippy issues --- core/client/db/src/cache/mod.rs | 2 +- core/consensus/babe/primitives/src/digest.rs | 2 +- core/consensus/babe/src/aux_schema.rs | 2 +- core/consensus/slots/src/aux_schema.rs | 2 +- core/consensus/slots/src/lib.rs | 11 +++++------ core/finality-grandpa/src/lib.rs | 2 +- core/primitives/src/ed25519.rs | 8 +------- core/primitives/src/sr25519.rs | 8 +------- core/rpc-servers/src/lib.rs | 2 +- core/service/src/chain_ops.rs | 4 ++-- srml/support/src/hash.rs | 2 +- srml/support/src/traits.rs | 2 +- srml/system/src/lib.rs | 2 +- 13 files changed, 18 insertions(+), 31 deletions(-) diff --git a/core/client/db/src/cache/mod.rs b/core/client/db/src/cache/mod.rs index bfc496dd2f..9aaea57b0c 100644 --- a/core/client/db/src/cache/mod.rs +++ b/core/client/db/src/cache/mod.rs @@ -207,7 +207,7 @@ impl<'a, Block: BlockT> DbCacheTransaction<'a, Block> { // prepare list of caches that are not update // (we might still need to do some cache maintenance in this case) let missed_caches = self.cache.cache_at.keys() - .filter(|cache| !data_at.contains_key(cache.clone())) + .filter(|cache| !data_at.contains_key(*cache)) .cloned() .collect::>(); diff --git a/core/consensus/babe/primitives/src/digest.rs b/core/consensus/babe/primitives/src/digest.rs index 3f275ecdb6..ff62ae29c5 100644 --- a/core/consensus/babe/primitives/src/digest.rs +++ b/core/consensus/babe/primitives/src/digest.rs @@ -91,7 +91,7 @@ impl BabePreDigest { } /// The prefix used by BABE for its VRF keys. -pub const BABE_VRF_PREFIX: &'static [u8] = b"substrate-babe-vrf"; +pub const BABE_VRF_PREFIX: &[u8] = b"substrate-babe-vrf"; /// A raw version of `BabePreDigest`, usable on `no_std`. #[derive(Copy, Clone, Encode, Decode)] diff --git a/core/consensus/babe/src/aux_schema.rs b/core/consensus/babe/src/aux_schema.rs index 67f61050fa..6290d5cf31 100644 --- a/core/consensus/babe/src/aux_schema.rs +++ b/core/consensus/babe/src/aux_schema.rs @@ -38,7 +38,7 @@ fn load_decode(backend: &B, key: &[u8]) -> ClientResult> T: Decode, { let corrupt = |e: codec::Error| { - ClientError::Backend(format!("BABE DB is corrupted. Decode error: {}", e.what())).into() + ClientError::Backend(format!("BABE DB is corrupted. Decode error: {}", e.what())) }; match backend.get_aux(key)? { None => Ok(None), diff --git a/core/consensus/slots/src/aux_schema.rs b/core/consensus/slots/src/aux_schema.rs index 1d54cb5c2e..186288c174 100644 --- a/core/consensus/slots/src/aux_schema.rs +++ b/core/consensus/slots/src/aux_schema.rs @@ -38,7 +38,7 @@ fn load_decode(backend: &C, key: &[u8]) -> ClientResult> None => Ok(None), Some(t) => T::decode(&mut &t[..]) .map_err( - |e| ClientError::Backend(format!("Slots DB is corrupted. Decode error: {}", e.what())).into(), + |e| ClientError::Backend(format!("Slots DB is corrupted. Decode error: {}", e.what())), ) .map(Some) } diff --git a/core/consensus/slots/src/lib.rs b/core/consensus/slots/src/lib.rs index fd86a0f277..e33d00d255 100644 --- a/core/consensus/slots/src/lib.rs +++ b/core/consensus/slots/src/lib.rs @@ -189,9 +189,9 @@ pub trait SimpleSlotWorker { logs, }, remaining_duration, - ).map_err(|e| consensus_common::Error::ClientImport(format!("{:?}", e)).into()), + ).map_err(|e| consensus_common::Error::ClientImport(format!("{:?}", e))), Delay::new(remaining_duration) - .map_err(|err| consensus_common::Error::FaultyTimer(err).into()) + .map_err(consensus_common::Error::FaultyTimer) ).map(|v| match v { futures::future::Either::Left((b, _)) => b.map(|b| (b, claim)), futures::future::Either::Right((Ok(_), _)) => @@ -220,9 +220,9 @@ pub trait SimpleSlotWorker { } let (header, body) = block.deconstruct(); - let header_num = header.number().clone(); + let header_num = *header.number(); let header_hash = header.hash(); - let parent_hash = header.parent_hash().clone(); + let parent_hash = *header.parent_hash(); let block_import_params = block_import_params_maker( header, @@ -401,9 +401,8 @@ impl SlotDuration { .map_err(|_| { client::error::Error::Backend({ error!(target: "slots", "slot duration kept in invalid format"); - format!("slot duration kept in invalid format") + "slot duration kept in invalid format".to_string() }) - .into() }), None => { use sr_primitives::traits::Zero; diff --git a/core/finality-grandpa/src/lib.rs b/core/finality-grandpa/src/lib.rs index 3841084d11..9d1e3f563f 100644 --- a/core/finality-grandpa/src/lib.rs +++ b/core/finality-grandpa/src/lib.rs @@ -822,7 +822,7 @@ where } } -#[deprecated(since = "1.1", note = "Please switch to run_grandpa_voter.")] +#[deprecated(since = "1.1.0", note = "Please switch to run_grandpa_voter.")] pub fn run_grandpa, N, RA, SC, VR, X>( grandpa_params: GrandpaParams, ) -> ::client::error::Result + Send + 'static> where diff --git a/core/primitives/src/ed25519.rs b/core/primitives/src/ed25519.rs index c40499a3a1..b674a150c4 100644 --- a/core/primitives/src/ed25519.rs +++ b/core/primitives/src/ed25519.rs @@ -41,6 +41,7 @@ use crate::{crypto::{Public as TraitPublic, UncheckedFrom, CryptoType, Derive}}; type Seed = [u8; 32]; /// A public key. +#[cfg_attr(feature = "std", derive(Hash))] #[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Decode, Default)] pub struct Public(pub [u8; 32]); @@ -152,13 +153,6 @@ impl<'de> Deserialize<'de> for Public { } } -#[cfg(feature = "std")] -impl std::hash::Hash for Public { - fn hash(&self, state: &mut H) { - self.0.hash(state); - } -} - /// A signature (a 512-bit value). #[derive(Encode, Decode)] pub struct Signature(pub [u8; 64]); diff --git a/core/primitives/src/sr25519.rs b/core/primitives/src/sr25519.rs index 0e573f49ce..ed8bb72c9e 100644 --- a/core/primitives/src/sr25519.rs +++ b/core/primitives/src/sr25519.rs @@ -47,6 +47,7 @@ use schnorrkel::keys::{MINI_SECRET_KEY_LENGTH, SECRET_KEY_LENGTH}; const SIGNING_CTX: &[u8] = b"substrate"; /// An Schnorrkel/Ristretto x25519 ("sr25519") public key. +#[cfg_attr(feature = "std", derive(Hash))] #[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Decode, Default)] pub struct Public(pub [u8; 32]); @@ -151,13 +152,6 @@ impl<'de> Deserialize<'de> for Public { } } -#[cfg(feature = "std")] -impl std::hash::Hash for Public { - fn hash(&self, state: &mut H) { - self.0.hash(state); - } -} - /// An Schnorrkel/Ristretto x25519 ("sr25519") signature. /// /// Instead of importing it for the local module, alias it to be available as a public type diff --git a/core/rpc-servers/src/lib.rs b/core/rpc-servers/src/lib.rs index a23b4a0899..3f408f6684 100644 --- a/core/rpc-servers/src/lib.rs +++ b/core/rpc-servers/src/lib.rs @@ -16,7 +16,7 @@ //! Substrate RPC servers. -#[warn(missing_docs)] +#![warn(missing_docs)] use std::io; use jsonrpc_core::IoHandlerExtension; diff --git a/core/service/src/chain_ops.rs b/core/service/src/chain_ops.rs index 0858534482..e6d7df33c2 100644 --- a/core/service/src/chain_ops.rs +++ b/core/service/src/chain_ops.rs @@ -46,7 +46,7 @@ macro_rules! export_blocks { let last_: u64 = last.saturated_into::(); let block_: u64 = block.saturated_into::(); let len: u64 = last_ - block_ + 1; - $output.write(&len.encode())?; + $output.write_all(&len.encode())?; } loop { @@ -59,7 +59,7 @@ macro_rules! export_blocks { serde_json::to_writer(&mut $output, &block) .map_err(|e| format!("Error writing JSON: {}", e))?; } else { - $output.write(&block.encode())?; + $output.write_all(&block.encode())?; } }, None => break, diff --git a/srml/support/src/hash.rs b/srml/support/src/hash.rs index 3775ebc26b..cbd78f6032 100644 --- a/srml/support/src/hash.rs +++ b/srml/support/src/hash.rs @@ -59,7 +59,7 @@ impl StorageHasher for Twox64Concat { type Output = Vec; fn hash(x: &[u8]) -> Vec { twox_64(x) - .into_iter() + .iter() .chain(x.into_iter()) .cloned() .collect::>() diff --git a/srml/support/src/traits.rs b/srml/support/src/traits.rs index cd11b56612..05f3cd070c 100644 --- a/srml/support/src/traits.rs +++ b/srml/support/src/traits.rs @@ -148,7 +148,7 @@ pub trait OnUnbalanced { fn on_unbalanced(amount: Imbalance); } -impl OnUnbalanced for () { +impl OnUnbalanced for () { fn on_unbalanced(amount: Imbalance) { drop(amount); } } diff --git a/srml/system/src/lib.rs b/srml/system/src/lib.rs index caa6d573b0..76cbe7cbab 100644 --- a/srml/system/src/lib.rs +++ b/srml/system/src/lib.rs @@ -567,7 +567,7 @@ impl Module { // We perform early return if we've reached the maximum capacity of the event list, // so `Events` seems to be corrupted. Also, this has happened after the start of execution // (since the event list is cleared at the block initialization). - if >::append([event].into_iter()).is_err() { + if >::append([event].iter()).is_err() { // The most sensible thing to do here is to just ignore this event and wait until the // new block. return; -- GitLab From d1cd01c74e8d5550396cb654f9a3f1b641efdf4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Sun, 20 Oct 2019 13:02:21 +0200 Subject: [PATCH 068/167] Clean up the wasm-builder and release 1.0.8 (#3858) --- Cargo.lock | 2 +- core/executor/runtime-test/build.rs | 2 +- core/test-runtime/build.rs | 2 +- core/utils/wasm-builder/Cargo.toml | 2 +- core/utils/wasm-builder/src/lib.rs | 23 +++++++++++--------- core/utils/wasm-builder/src/prerequisites.rs | 12 ++++------ node-template/runtime/build.rs | 2 +- node/runtime/build.rs | 2 +- 8 files changed, 23 insertions(+), 24 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d9bfc40409..aab1866999 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5759,7 +5759,7 @@ dependencies = [ [[package]] name = "substrate-wasm-builder" -version = "1.0.7" +version = "1.0.8" dependencies = [ "build-helper 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "cargo_metadata 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/core/executor/runtime-test/build.rs b/core/executor/runtime-test/build.rs index 136dc79398..68e5205f0c 100644 --- a/core/executor/runtime-test/build.rs +++ b/core/executor/runtime-test/build.rs @@ -21,7 +21,7 @@ fn main() { "wasm_binary.rs", WasmBuilderSource::CratesOrPath { path: "../../utils/wasm-builder", - version: "1.0.7", + version: "1.0.8", }, // This instructs LLD to export __heap_base as a global variable, which is used by the // external memory allocator. diff --git a/core/test-runtime/build.rs b/core/test-runtime/build.rs index 2e2d1fc93e..200cd6d42c 100644 --- a/core/test-runtime/build.rs +++ b/core/test-runtime/build.rs @@ -21,7 +21,7 @@ fn main() { "wasm_binary.rs", WasmBuilderSource::CratesOrPath { path: "../utils/wasm-builder", - version: "1.0.7", + version: "1.0.8", }, // Note that we set the stack-size to 1MB explicitly even though it is set // to this value by default. This is because some of our tests (`restoration_of_globals`) diff --git a/core/utils/wasm-builder/Cargo.toml b/core/utils/wasm-builder/Cargo.toml index 7fcdd6c4e1..e9d38f2bd2 100644 --- a/core/utils/wasm-builder/Cargo.toml +++ b/core/utils/wasm-builder/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "substrate-wasm-builder" -version = "1.0.7" +version = "1.0.8" authors = ["Parity Technologies "] description = "Utility for building WASM binaries" edition = "2018" diff --git a/core/utils/wasm-builder/src/lib.rs b/core/utils/wasm-builder/src/lib.rs index b97559c076..93e1700792 100644 --- a/core/utils/wasm-builder/src/lib.rs +++ b/core/utils/wasm-builder/src/lib.rs @@ -205,9 +205,7 @@ impl CargoCommand { } fn args(&mut self, args: &[&str]) -> &mut Self { - for arg in args { - self.arg(arg); - } + args.into_iter().for_each(|a| { self.arg(a); }); self } @@ -227,12 +225,17 @@ impl CargoCommand { /// Check if the supplied cargo command is a nightly version fn is_nightly(&self) -> bool { - self.command() - .arg("--version") - .output() - .map_err(|_| ()) - .and_then(|o| String::from_utf8(o.stdout).map_err(|_| ())) - .unwrap_or_default() - .contains("-nightly") + // `RUSTC_BOOTSTRAP` tells a stable compiler to behave like a nightly. So, when this env + // variable is set, we can assume that whatever rust compiler we have, it is a nightly compiler. + // For "more" information, see: + // https://github.com/rust-lang/rust/blob/fa0f7d0080d8e7e9eb20aa9cbf8013f96c81287f/src/libsyntax/feature_gate/check.rs#L891 + env::var("RUSTC_BOOTSTRAP").is_ok() || + self.command() + .arg("--version") + .output() + .map_err(|_| ()) + .and_then(|o| String::from_utf8(o.stdout).map_err(|_| ())) + .unwrap_or_default() + .contains("-nightly") } } diff --git a/core/utils/wasm-builder/src/prerequisites.rs b/core/utils/wasm-builder/src/prerequisites.rs index 73e356f0c2..3a7f8387dc 100644 --- a/core/utils/wasm-builder/src/prerequisites.rs +++ b/core/utils/wasm-builder/src/prerequisites.rs @@ -14,7 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -use std::{env, fs}; +use std::fs; + use tempfile::tempdir; /// Checks that all prerequisites are installed. @@ -22,20 +23,15 @@ use tempfile::tempdir; /// # Returns /// Returns `None` if everything was found and `Some(ERR_MSG)` if something could not be found. pub fn check() -> Option<&'static str> { - if !rustc_stable_forced_to_nightly() && !check_nightly_installed(){ + if !check_nightly_installed(){ return Some("Rust nightly not installed, please install it!") } check_wasm_toolchain_installed() } -fn rustc_stable_forced_to_nightly() -> bool { - env::var("RUSTC_BOOTSTRAP") == Ok("1".to_string()) -} - fn check_nightly_installed() -> bool { - let command = crate::get_nightly_cargo(); - command.is_nightly() + crate::get_nightly_cargo().is_nightly() } fn check_wasm_toolchain_installed() -> Option<&'static str> { diff --git a/node-template/runtime/build.rs b/node-template/runtime/build.rs index ddbeefa112..c5e798c6ef 100644 --- a/node-template/runtime/build.rs +++ b/node-template/runtime/build.rs @@ -19,7 +19,7 @@ use wasm_builder_runner::{build_current_project_with_rustflags, WasmBuilderSourc fn main() { build_current_project_with_rustflags( "wasm_binary.rs", - WasmBuilderSource::Crates("1.0.7"), + WasmBuilderSource::Crates("1.0.8"), // This instructs LLD to export __heap_base as a global variable, which is used by the // external memory allocator. "-Clink-arg=--export=__heap_base", diff --git a/node/runtime/build.rs b/node/runtime/build.rs index 7311fb90ce..f5c2f98a75 100644 --- a/node/runtime/build.rs +++ b/node/runtime/build.rs @@ -21,7 +21,7 @@ fn main() { "wasm_binary.rs", WasmBuilderSource::CratesOrPath { path: "../../core/utils/wasm-builder", - version: "1.0.7", + version: "1.0.8", }, // This instructs LLD to export __heap_base as a global variable, which is used by the // external memory allocator. -- GitLab From c497fcb150002be1b34cc90d31d196e9766cd37a Mon Sep 17 00:00:00 2001 From: Ashley Date: Mon, 21 Oct 2019 07:46:23 +0100 Subject: [PATCH 069/167] Change Contracts::DefaultMaxDepth from 1024 to 32 (#3855) * Change DefaultMaxDepth from 1024 to 32 * bump impl and spec version --- node/runtime/src/lib.rs | 2 +- srml/contracts/src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index 69f812ce32..d11897845b 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -84,7 +84,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // and set impl_version to equal spec_version. If only runtime // implementation changes and behavior does not, then leave spec_version as // is and increment impl_version. - spec_version: 179, + spec_version: 180, impl_version: 180, apis: RUNTIME_API_VERSIONS, }; diff --git a/srml/contracts/src/lib.rs b/srml/contracts/src/lib.rs index 3d8a455ad7..e52d059992 100644 --- a/srml/contracts/src/lib.rs +++ b/srml/contracts/src/lib.rs @@ -325,7 +325,7 @@ parameter_types! { /// A reasonable default value for [`Trait::InstantiateBaseFee`]. pub const DefaultInstantiateBaseFee: u32 = 1000; /// A reasonable default value for [`Trait::MaxDepth`]. - pub const DefaultMaxDepth: u32 = 1024; + pub const DefaultMaxDepth: u32 = 32; /// A reasonable default value for [`Trait::MaxValueSize`]. pub const DefaultMaxValueSize: u32 = 16_384; /// A reasonable default value for [`Trait::BlockGasLimit`]. -- GitLab From b7627c4cf8e109dfc80095c5c58f4cf082b56e4d Mon Sep 17 00:00:00 2001 From: CrocdileChan <1576710154@qq.com> Date: Mon, 21 Oct 2019 15:25:50 +0800 Subject: [PATCH 070/167] use ThreadPool to execute spawn_worker(fn) (#3836) * use ThreadPool to spawn_worker() * use ThreadPool to implement spawn_worker(fn) * use ThreadPool to implement spawn_worker(f) * update [dependencies] threadpool and num_cpus version * rm 'extern crate num_cpus' * cargo.lock update * merge the newest cargo.lock * Update Cargo.lock * use Mutex to wrap OffchainWorkers.thread_pool * format use crate * use parking_lot::Mutex instead of std::sync::Mutex --- Cargo.lock | 11 +++++++++++ core/offchain/Cargo.toml | 2 ++ core/offchain/src/lib.rs | 29 ++++++++++++++++------------- 3 files changed, 29 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index aab1866999..2e30793e47 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5316,6 +5316,7 @@ dependencies = [ "hyper 0.12.35 (registry+https://github.com/rust-lang/crates.io-index)", "hyper-tls 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -5328,6 +5329,7 @@ dependencies = [ "substrate-primitives 2.0.0", "substrate-test-runtime-client 2.0.0", "substrate-transaction-pool 2.0.0", + "threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -5906,6 +5908,14 @@ dependencies = [ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "threadpool" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "time" version = "0.1.42" @@ -7176,6 +7186,7 @@ dependencies = [ "checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e" "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" +"checksum threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e2f0c90a5f3459330ac8bc0d2f879c693bb7a2f59689c1083fc4ef83834da865" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" "checksum tiny-bip39 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c1c5676413eaeb1ea35300a0224416f57abc3bd251657e0fafc12c47ff98c060" "checksum tiny-keccak 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d8a021c69bb74a44ccedb824a046447e2c84a01df9e5c20779750acb38e11b2" diff --git a/core/offchain/Cargo.toml b/core/offchain/Cargo.toml index ca9b27eee2..678d943c59 100644 --- a/core/offchain/Cargo.toml +++ b/core/offchain/Cargo.toml @@ -16,6 +16,8 @@ futures-timer = "0.4.0" hyper = "0.12.35" hyper-tls = "0.3.2" log = "0.4.8" +threadpool = "1.7" +num_cpus = "1.10" offchain-primitives = { package = "substrate-offchain-primitives", path = "./primitives" } codec = { package = "parity-scale-codec", version = "1.0.0", features = ["derive"] } parking_lot = "0.9.0" diff --git a/core/offchain/src/lib.rs b/core/offchain/src/lib.rs index 79c6df04ea..a335ca5380 100644 --- a/core/offchain/src/lib.rs +++ b/core/offchain/src/lib.rs @@ -39,6 +39,8 @@ use std::{ sync::Arc, }; +use parking_lot::Mutex; +use threadpool::ThreadPool; use client::runtime_api::ApiExt; use futures::future::Future; use log::{debug, warn}; @@ -58,6 +60,7 @@ pub struct OffchainWorkers { client: Arc, db: Storage, _block: PhantomData, + thread_pool: Mutex, } impl OffchainWorkers { @@ -67,6 +70,7 @@ impl OffchainWorkers OffchainWorkers< debug!("Spawning offchain workers at {:?}", at); let number = *number; let client = self.client.clone(); - spawn_worker(move || { + self.spawn_worker(move || { let runtime = client.runtime_api(); let api = Box::new(api); debug!("Running offchain workers at {:?}", at); @@ -134,19 +138,18 @@ impl OffchainWorkers< futures::future::Either::Right(futures::future::ready(())) } } -} -/// Spawns a new offchain worker. -/// -/// We spawn offchain workers for each block in a separate thread, -/// since they can run for a significant amount of time -/// in a blocking fashion and we don't want to block the runtime. -/// -/// Note that we should avoid that if we switch to future-based runtime in the future, -/// alternatively: -/// TODO [ToDr] (#1458) we can consider using a thread pool instead. -fn spawn_worker(f: impl FnOnce() -> () + Send + 'static) { - std::thread::spawn(f); + /// Spawns a new offchain worker. + /// + /// We spawn offchain workers for each block in a separate thread, + /// since they can run for a significant amount of time + /// in a blocking fashion and we don't want to block the runtime. + /// + /// Note that we should avoid that if we switch to future-based runtime in the future, + /// alternatively: + fn spawn_worker(&self, f: impl FnOnce() -> () + Send + 'static) { + self.thread_pool.lock().execute(f); + } } #[cfg(test)] -- GitLab From 44a9482bdac1ebbb5c820530b25eb4554739bf84 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Mon, 21 Oct 2019 23:40:22 +0300 Subject: [PATCH 071/167] Use uniform quotes (#3867) --- node-template/runtime/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node-template/runtime/Cargo.toml b/node-template/runtime/Cargo.toml index df9dd9c77f..5ebf3af6cf 100644 --- a/node-template/runtime/Cargo.toml +++ b/node-template/runtime/Cargo.toml @@ -43,7 +43,7 @@ std = [ "balances/std", "aura/std", "aura-primitives/std", - 'grandpa/std', + "grandpa/std", "executive/std", "indices/std", "primitives/std", -- GitLab From 271f4cfd523061abfd3ec7724fb1064caecc939d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Tue, 22 Oct 2019 03:09:39 +0200 Subject: [PATCH 072/167] Fix deserialization of `Bytes` (#3866) * Update impl-serde to patch RPC. * Add test. * Fix long line. --- Cargo.lock | 12 ++++++------ core/rpc/src/state/tests.rs | 8 ++++++++ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2e30793e47..d77ba65cbd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1412,7 +1412,7 @@ dependencies = [ [[package]] name = "impl-serde" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3034,7 +3034,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "fixed-hash 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "impl-codec 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "impl-serde 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "impl-serde 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "uint 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3957,7 +3957,7 @@ dependencies = [ name = "sr-version" version = "2.0.0" dependencies = [ - "impl-serde 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "impl-serde 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", @@ -5386,7 +5386,7 @@ dependencies = [ "hash256-std-hasher 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "hex-literal 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "impl-serde 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "impl-serde 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -5415,7 +5415,7 @@ dependencies = [ name = "substrate-primitives-storage" version = "2.0.0" dependencies = [ - "impl-serde 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "impl-serde 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "sr-std 2.0.0", ] @@ -6941,7 +6941,7 @@ dependencies = [ "checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" "checksum idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9" "checksum impl-codec 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3fa0086251524c50fd53b32e7b05eb6d79e2f97221eaf0c53c0ca9c3096f21d3" -"checksum impl-serde 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bbb1ea6188aca47a0eaeeb330d8a82f16cd500f30b897062d23922568727333a" +"checksum impl-serde 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a263dc95daa6c3788c8f7133d86dc2ad89ec5a0c56167f9e3441c5f7f33358c4" "checksum impl-trait-for-tuples 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6947b372790f8948f439bb6aaa6baabdf80be1a207a477ff072f83fb793e428f" "checksum indexmap 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a61202fbe46c4a951e9404a720a0180bcf3212c750d735cb5c4ba4dc551299f3" "checksum integer-sqrt 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ea155abb3ba6f382a75f1418988c05fe82959ed9ce727de427f9cfd425b0c903" diff --git a/core/rpc/src/state/tests.rs b/core/rpc/src/state/tests.rs index 3790b3ea11..5dfa234337 100644 --- a/core/rpc/src/state/tests.rs +++ b/core/rpc/src/state/tests.rs @@ -313,3 +313,11 @@ fn should_notify_on_runtime_version_initially() { // no more notifications on this channel assert_eq!(core.block_on(next.into_future()).unwrap().0, None); } + +#[test] +fn should_deserialize_storage_key() { + let k = "\"0x7f864e18e3dd8b58386310d2fe0919eef27c6e558564b7f67f22d99d20f587b\""; + let k: StorageKey = serde_json::from_str(k).unwrap(); + + assert_eq!(k.0.len(), 32); +} -- GitLab From 0b972942392db1042ae67300f37f4accaa8304cf Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Tue, 22 Oct 2019 03:53:58 -0400 Subject: [PATCH 073/167] Explicitly declare decl_storage! getters as functions (#3870) * parse decl_storage getters with fn keyword * test for get in decl_storage * update all decl_storage! getters * bump version * adjust missed doc line --- node-template/runtime/src/template.rs | 4 +-- node/runtime/src/lib.rs | 4 +-- srml/assets/src/lib.rs | 2 +- srml/aura/src/lib.rs | 4 +-- srml/authority-discovery/src/lib.rs | 2 +- srml/babe/src/lib.rs | 12 +++---- srml/balances/src/lib.rs | 10 +++--- srml/collective/src/lib.rs | 10 +++--- srml/contracts/src/lib.rs | 6 ++-- srml/democracy/src/lib.rs | 24 ++++++------- srml/elections-phragmen/src/lib.rs | 18 +++++----- srml/elections/src/lib.rs | 32 ++++++++--------- srml/example/src/lib.rs | 10 +++--- srml/finality-tracker/src/lib.rs | 8 ++--- srml/generic-asset/src/lib.rs | 12 +++---- srml/grandpa/src/lib.rs | 12 +++---- srml/im-online/src/lib.rs | 6 ++-- srml/indices/src/lib.rs | 4 +-- srml/membership/src/lib.rs | 2 +- srml/offences/src/lib.rs | 2 +- srml/randomness-collective-flip/src/lib.rs | 2 +- srml/scored-pool/src/lib.rs | 8 ++--- srml/session/src/historical.rs | 4 +-- srml/session/src/lib.rs | 8 ++--- srml/staking/src/lib.rs | 36 ++++++++++---------- srml/sudo/src/lib.rs | 2 +- srml/support/procedural/src/lib.rs | 6 ++-- srml/support/procedural/src/storage/parse.rs | 15 +++++--- srml/support/src/lib.rs | 16 +++++++-- srml/support/src/storage/storage_items.rs | 32 ++++++++--------- srml/support/test/tests/final_keys.rs | 8 ++--- srml/support/test/tests/issue2219.rs | 14 ++++---- srml/system/src/lib.rs | 20 +++++------ srml/timestamp/src/lib.rs | 2 +- srml/transaction-payment/src/lib.rs | 2 +- srml/treasury/src/lib.rs | 6 ++-- 36 files changed, 190 insertions(+), 175 deletions(-) diff --git a/node-template/runtime/src/template.rs b/node-template/runtime/src/template.rs index 8c6c35edc4..db7bd24b0e 100644 --- a/node-template/runtime/src/template.rs +++ b/node-template/runtime/src/template.rs @@ -24,8 +24,8 @@ decl_storage! { trait Store for Module as TemplateModule { // Just a dummy storage item. // Here we are declaring a StorageValue, `Something` as a Option - // `get(something)` is the default getter which returns either the stored `u32` or `None` if nothing stored - Something get(something): Option; + // `get(fn something)` is the default getter which returns either the stored `u32` or `None` if nothing stored + Something get(fn something): Option; } } diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index d11897845b..75e1c9eefd 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -84,8 +84,8 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // and set impl_version to equal spec_version. If only runtime // implementation changes and behavior does not, then leave spec_version as // is and increment impl_version. - spec_version: 180, - impl_version: 180, + spec_version: 181, + impl_version: 181, apis: RUNTIME_API_VERSIONS, }; diff --git a/srml/assets/src/lib.rs b/srml/assets/src/lib.rs index 37845c3a14..528428000e 100644 --- a/srml/assets/src/lib.rs +++ b/srml/assets/src/lib.rs @@ -215,7 +215,7 @@ decl_storage! { /// The number of units of assets held by any given account. Balances: map (T::AssetId, T::AccountId) => T::Balance; /// The next asset identifier up for grabs. - NextAssetId get(next_asset_id): T::AssetId; + NextAssetId get(fn next_asset_id): T::AssetId; /// The total unit supply of an asset. TotalSupply: map T::AssetId => T::Balance; } diff --git a/srml/aura/src/lib.rs b/srml/aura/src/lib.rs index 834d6b0a14..f9034c7ca0 100644 --- a/srml/aura/src/lib.rs +++ b/srml/aura/src/lib.rs @@ -148,10 +148,10 @@ pub trait Trait: timestamp::Trait { decl_storage! { trait Store for Module as Aura { /// The last timestamp. - LastTimestamp get(last) build(|_| 0.into()): T::Moment; + LastTimestamp get(fn last) build(|_| 0.into()): T::Moment; /// The current authorities - pub Authorities get(authorities): Vec; + pub Authorities get(fn authorities): Vec; } add_extra_genesis { config(authorities): Vec; diff --git a/srml/authority-discovery/src/lib.rs b/srml/authority-discovery/src/lib.rs index 2c923103a8..c82d580fd9 100644 --- a/srml/authority-discovery/src/lib.rs +++ b/srml/authority-discovery/src/lib.rs @@ -41,7 +41,7 @@ pub trait Trait: system::Trait + session::Trait { decl_storage! { trait Store for Module as AuthorityDiscovery { /// The current set of keys that may issue a heartbeat. - Keys get(keys): Vec; + Keys get(fn keys): Vec; } add_extra_genesis { config(keys): Vec; diff --git a/srml/babe/src/lib.rs b/srml/babe/src/lib.rs index e69877d783..ee2d66fbe6 100644 --- a/srml/babe/src/lib.rs +++ b/srml/babe/src/lib.rs @@ -180,17 +180,17 @@ type MaybeVrf = Option<[u8; 32 /* VRF_OUTPUT_LENGTH */]>; decl_storage! { trait Store for Module as Babe { /// Current epoch index. - pub EpochIndex get(epoch_index): u64; + pub EpochIndex get(fn epoch_index): u64; /// Current epoch authorities. - pub Authorities get(authorities): Vec<(AuthorityId, BabeAuthorityWeight)>; + pub Authorities get(fn authorities): Vec<(AuthorityId, BabeAuthorityWeight)>; /// The slot at which the first epoch actually started. This is 0 /// until the first block of the chain. - pub GenesisSlot get(genesis_slot): u64; + pub GenesisSlot get(fn genesis_slot): u64; /// Current slot number. - pub CurrentSlot get(current_slot): u64; + pub CurrentSlot get(fn current_slot): u64; /// The epoch randomness for the *current* epoch. /// @@ -205,7 +205,7 @@ decl_storage! { // NOTE: the following fields don't use the constants to define the // array size because the metadata API currently doesn't resolve the // variable to its underlying value. - pub Randomness get(randomness): [u8; 32 /* RANDOMNESS_LENGTH */]; + pub Randomness get(fn randomness): [u8; 32 /* RANDOMNESS_LENGTH */]; /// Next epoch randomness. NextRandomness: [u8; 32 /* RANDOMNESS_LENGTH */]; @@ -224,7 +224,7 @@ decl_storage! { /// Temporary value (cleared at block finalization) which is `Some` /// if per-block initialization has already been called for current block. - Initialized get(initialized): Option; + Initialized get(fn initialized): Option; } add_extra_genesis { config(authorities): Vec<(AuthorityId, BabeAuthorityWeight)>; diff --git a/srml/balances/src/lib.rs b/srml/balances/src/lib.rs index 4f8edc5428..b0b0a60efa 100644 --- a/srml/balances/src/lib.rs +++ b/srml/balances/src/lib.rs @@ -295,12 +295,12 @@ pub struct BalanceLock { decl_storage! { trait Store for Module, I: Instance=DefaultInstance> as Balances { /// The total units issued in the system. - pub TotalIssuance get(total_issuance) build(|config: &GenesisConfig| { + pub TotalIssuance get(fn total_issuance) build(|config: &GenesisConfig| { config.balances.iter().fold(Zero::zero(), |acc: T::Balance, &(_, n)| acc + n) }): T::Balance; /// Information regarding the vesting of a given account. - pub Vesting get(vesting) build(|config: &GenesisConfig| { + pub Vesting get(fn vesting) build(|config: &GenesisConfig| { // Generate initial vesting configuration // * who - Account which we are generating vesting configuration for // * begin - Block when the account will start to vest @@ -337,7 +337,7 @@ decl_storage! { /// /// `system::AccountNonce` is also deleted if `ReservedBalance` is also zero (it also gets /// collapsed to zero if it ever becomes less than `ExistentialDeposit`. - pub FreeBalance get(free_balance) + pub FreeBalance get(fn free_balance) build(|config: &GenesisConfig| config.balances.clone()): map T::AccountId => T::Balance; @@ -352,10 +352,10 @@ decl_storage! { /// /// `system::AccountNonce` is also deleted if `FreeBalance` is also zero (it also gets /// collapsed to zero if it ever becomes less than `ExistentialDeposit`.) - pub ReservedBalance get(reserved_balance): map T::AccountId => T::Balance; + pub ReservedBalance get(fn reserved_balance): map T::AccountId => T::Balance; /// Any liquidity locks on some account balances. - pub Locks get(locks): map T::AccountId => Vec>; + pub Locks get(fn locks): map T::AccountId => Vec>; } add_extra_genesis { config(balances): Vec<(T::AccountId, T::Balance)>; diff --git a/srml/collective/src/lib.rs b/srml/collective/src/lib.rs index edfc4bf46f..a965230246 100644 --- a/srml/collective/src/lib.rs +++ b/srml/collective/src/lib.rs @@ -86,15 +86,15 @@ pub struct Votes { decl_storage! { trait Store for Module, I: Instance=DefaultInstance> as Collective { /// The hashes of the active proposals. - pub Proposals get(proposals): Vec; + pub Proposals get(fn proposals): Vec; /// Actual proposal for a given hash, if it's current. - pub ProposalOf get(proposal_of): map T::Hash => Option<>::Proposal>; + pub ProposalOf get(fn proposal_of): map T::Hash => Option<>::Proposal>; /// Votes on a given proposal, if it is ongoing. - pub Voting get(voting): map T::Hash => Option>; + pub Voting get(fn voting): map T::Hash => Option>; /// Proposals so far. - pub ProposalCount get(proposal_count): u32; + pub ProposalCount get(fn proposal_count): u32; /// The current members of the collective. This is stored sorted (just by value). - pub Members get(members): Vec; + pub Members get(fn members): Vec; } add_extra_genesis { config(phantom): rstd::marker::PhantomData; diff --git a/srml/contracts/src/lib.rs b/srml/contracts/src/lib.rs index e52d059992..b3c8c9b764 100644 --- a/srml/contracts/src/lib.rs +++ b/srml/contracts/src/lib.rs @@ -838,9 +838,9 @@ decl_event! { decl_storage! { trait Store for Module as Contract { /// Gas spent so far in this block. - GasSpent get(gas_spent): Gas; + GasSpent get(fn gas_spent): Gas; /// Current cost schedule for contracts. - CurrentSchedule get(current_schedule) config(): Schedule = Schedule::default(); + CurrentSchedule get(fn current_schedule) config(): Schedule = Schedule::default(); /// A mapping from an original code hash to the original code, untouched by instrumentation. pub PristineCode: map CodeHash => Option>; /// A mapping between an original code hash and instrumented wasm code, ready for execution. @@ -850,7 +850,7 @@ decl_storage! { /// The code associated with a given account. pub ContractInfoOf: map T::AccountId => Option>; /// The price of one unit of gas. - GasPrice get(gas_price) config(): BalanceOf = 1.into(); + GasPrice get(fn gas_price) config(): BalanceOf = 1.into(); } } diff --git a/srml/democracy/src/lib.rs b/srml/democracy/src/lib.rs index b7e7dac6f9..af145828ab 100644 --- a/srml/democracy/src/lib.rs +++ b/srml/democracy/src/lib.rs @@ -259,38 +259,38 @@ impl ReferendumInfo as Democracy { /// The number of (public) proposals that have been made so far. - pub PublicPropCount get(public_prop_count) build(|_| 0 as PropIndex) : PropIndex; + pub PublicPropCount get(fn public_prop_count) build(|_| 0 as PropIndex) : PropIndex; /// The public proposals. Unsorted. - pub PublicProps get(public_props): Vec<(PropIndex, T::Proposal, T::AccountId)>; + pub PublicProps get(fn public_props): Vec<(PropIndex, T::Proposal, T::AccountId)>; /// Those who have locked a deposit. - pub DepositOf get(deposit_of): map PropIndex => Option<(BalanceOf, Vec)>; + pub DepositOf get(fn deposit_of): map PropIndex => Option<(BalanceOf, Vec)>; /// The next free referendum index, aka the number of referenda started so far. - pub ReferendumCount get(referendum_count) build(|_| 0 as ReferendumIndex): ReferendumIndex; + pub ReferendumCount get(fn referendum_count) build(|_| 0 as ReferendumIndex): ReferendumIndex; /// The next referendum index that should be tallied. - pub NextTally get(next_tally) build(|_| 0 as ReferendumIndex): ReferendumIndex; + pub NextTally get(fn next_tally) build(|_| 0 as ReferendumIndex): ReferendumIndex; /// Information concerning any given referendum. - pub ReferendumInfoOf get(referendum_info): + pub ReferendumInfoOf get(fn referendum_info): map ReferendumIndex => Option<(ReferendumInfo)>; /// Queue of successful referenda to be dispatched. - pub DispatchQueue get(dispatch_queue): + pub DispatchQueue get(fn dispatch_queue): map T::BlockNumber => Vec>; /// Get the voters for the current proposal. - pub VotersFor get(voters_for): map ReferendumIndex => Vec; + pub VotersFor get(fn voters_for): map ReferendumIndex => Vec; /// Get the vote in a given referendum of a particular voter. The result is meaningful only /// if `voters_for` includes the voter when called with the referendum (you'll get the /// default `Vote` value otherwise). If you don't want to check `voters_for`, then you can /// also check for simple existence with `VoteOf::exists` first. - pub VoteOf get(vote_of): map (ReferendumIndex, T::AccountId) => Vote; + pub VoteOf get(fn vote_of): map (ReferendumIndex, T::AccountId) => Vote; /// Who is able to vote for whom. Value is the fund-holding account, key is the /// vote-transaction-sending account. - pub Proxy get(proxy): map T::AccountId => Option; + pub Proxy get(fn proxy): map T::AccountId => Option; /// Get the account (and lock periods) to which another account is delegating vote. - pub Delegations get(delegations): linked_map T::AccountId => (T::AccountId, Conviction); + pub Delegations get(fn delegations): linked_map T::AccountId => (T::AccountId, Conviction); /// True if the last referendum tabled was submitted externally. False if it was a public /// proposal. @@ -304,7 +304,7 @@ decl_storage! { /// A record of who vetoed what. Maps proposal hash to a possible existent block number /// (until when it may not be resubmitted) and who vetoed it. - pub Blacklist get(blacklist): map T::Hash => Option<(T::BlockNumber, Vec)>; + pub Blacklist get(fn blacklist): map T::Hash => Option<(T::BlockNumber, Vec)>; /// Record of all proposals that have been subject to emergency cancellation. pub Cancellations: map T::Hash => bool; diff --git a/srml/elections-phragmen/src/lib.rs b/srml/elections-phragmen/src/lib.rs index fdc88ce9e0..781d506bd6 100644 --- a/srml/elections-phragmen/src/lib.rs +++ b/srml/elections-phragmen/src/lib.rs @@ -132,29 +132,29 @@ decl_storage! { trait Store for Module as PhragmenElection { // ---- parameters /// Number of members to elect. - pub DesiredMembers get(desired_members) config(): u32; + pub DesiredMembers get(fn desired_members) config(): u32; /// Number of runners_up to keep. - pub DesiredRunnersUp get(desired_runners_up) config(): u32; + pub DesiredRunnersUp get(fn desired_runners_up) config(): u32; /// How long each seat is kept. This defines the next block number at which an election /// round will happen. - pub TermDuration get(term_duration) config(): T::BlockNumber; + pub TermDuration get(fn term_duration) config(): T::BlockNumber; // ---- State /// The current elected membership. Sorted based on account id. - pub Members get(members) config(): Vec; + pub Members get(fn members) config(): Vec; /// The current runners_up. Sorted based on low to high merit (worse to best runner). - pub RunnersUp get(runners_up): Vec; + pub RunnersUp get(fn runners_up): Vec; /// The total number of vote rounds that have happened, excluding the upcoming one. - pub ElectionRounds get(election_rounds): u32 = Zero::zero(); + pub ElectionRounds get(fn election_rounds): u32 = Zero::zero(); /// Votes of a particular voter, with the round index of the votes. - pub VotesOf get(votes_of): linked_map T::AccountId => Vec; + pub VotesOf get(fn votes_of): linked_map T::AccountId => Vec; /// Locked stake of a voter. - pub StakeOf get(stake_of): map T::AccountId => BalanceOf; + pub StakeOf get(fn stake_of): map T::AccountId => BalanceOf; /// The present candidate list. Sorted based on account id. A current member can never enter /// this vector and is always implicitly assumed to be a candidate. - pub Candidates get(candidates): Vec; + pub Candidates get(fn candidates): Vec; } } diff --git a/srml/elections/src/lib.rs b/srml/elections/src/lib.rs index 8c90090349..439be7e76c 100644 --- a/srml/elections/src/lib.rs +++ b/srml/elections/src/lib.rs @@ -213,11 +213,11 @@ decl_storage! { // ---- parameters /// How long to give each top candidate to present themselves after the vote ends. - pub PresentationDuration get(presentation_duration) config(): T::BlockNumber; + pub PresentationDuration get(fn presentation_duration) config(): T::BlockNumber; /// How long each position is active for. - pub TermDuration get(term_duration) config(): T::BlockNumber; + pub TermDuration get(fn term_duration) config(): T::BlockNumber; /// Number of accounts that should constitute the collective. - pub DesiredSeats get(desired_seats) config(): u32; + pub DesiredSeats get(fn desired_seats) config(): u32; // ---- permanent state (always relevant, changes only at the finalization of voting) @@ -225,9 +225,9 @@ decl_storage! { /// executive matters. The block number (second element in the tuple) is the block that /// their position is active until (calculated by the sum of the block number when the /// member was elected and their term duration). - pub Members get(members) config(): Vec<(T::AccountId, T::BlockNumber)>; + pub Members get(fn members) config(): Vec<(T::AccountId, T::BlockNumber)>; /// The total number of vote rounds that have happened or are in progress. - pub VoteCount get(vote_index): VoteIndex; + pub VoteCount get(fn vote_index): VoteIndex; // ---- persistent state (always relevant, changes constantly) @@ -235,35 +235,35 @@ decl_storage! { // bit-wise manner. In order to get a human-readable representation (`Vec`), use // [`all_approvals_of`]. Furthermore, each vector of scalars is chunked with the cap of // `APPROVAL_SET_SIZE`. - pub ApprovalsOf get(approvals_of): map (T::AccountId, SetIndex) => Vec; + pub ApprovalsOf get(fn approvals_of): map (T::AccountId, SetIndex) => Vec; /// The vote index and list slot that the candidate `who` was registered or `None` if they /// are not currently registered. - pub RegisterInfoOf get(candidate_reg_info): map T::AccountId => Option<(VoteIndex, u32)>; + pub RegisterInfoOf get(fn candidate_reg_info): map T::AccountId => Option<(VoteIndex, u32)>; /// Basic information about a voter. - pub VoterInfoOf get(voter_info): map T::AccountId => Option>>; + pub VoterInfoOf get(fn voter_info): map T::AccountId => Option>>; /// The present voter list (chunked and capped at [`VOTER_SET_SIZE`]). - pub Voters get(voters): map SetIndex => Vec>; + pub Voters get(fn voters): map SetIndex => Vec>; /// the next free set to store a voter in. This will keep growing. - pub NextVoterSet get(next_nonfull_voter_set): SetIndex = 0; + pub NextVoterSet get(fn next_nonfull_voter_set): SetIndex = 0; /// Current number of Voters. - pub VoterCount get(voter_count): SetIndex = 0; + pub VoterCount get(fn voter_count): SetIndex = 0; /// The present candidate list. - pub Candidates get(candidates): Vec; // has holes + pub Candidates get(fn candidates): Vec; // has holes /// Current number of active candidates - pub CandidateCount get(candidate_count): u32; + pub CandidateCount get(fn candidate_count): u32; // ---- temporary state (only relevant during finalization/presentation) /// The accounts holding the seats that will become free on the next tally. - pub NextFinalize get(next_finalize): Option<(T::BlockNumber, u32, Vec)>; + pub NextFinalize get(fn next_finalize): Option<(T::BlockNumber, u32, Vec)>; /// Get the leaderboard if we're in the presentation phase. The first element is the weight /// of each entry; It may be the direct summed approval stakes, or a weighted version of it. /// Sorted from low to high. - pub Leaderboard get(leaderboard): Option, T::AccountId)> >; + pub Leaderboard get(fn leaderboard): Option, T::AccountId)> >; /// Who is able to vote for whom. Value is the fund-holding account, key is the /// vote-transaction-sending account. - pub Proxy get(proxy): map T::AccountId => Option; + pub Proxy get(fn proxy): map T::AccountId => Option; } } diff --git a/srml/example/src/lib.rs b/srml/example/src/lib.rs index a6a075d8cb..bc85241456 100644 --- a/srml/example/src/lib.rs +++ b/srml/example/src/lib.rs @@ -318,7 +318,7 @@ decl_storage! { // keep things around between blocks. trait Store for Module as Example { // Any storage declarations of the form: - // `pub? Name get(getter_name)? [config()|config(myname)] [build(|_| {...})] : (= )?;` + // `pub? Name get(fn getter_name)? [config()|config(myname)] [build(|_| {...})] : (= )?;` // where `` is either: // - `Type` (a basic value item); or // - `map KeyType => ValueType` (a map item). @@ -331,7 +331,7 @@ decl_storage! { // - `Foo::put(1); Foo::get()` returns `1`; // - `Foo::kill(); Foo::get()` returns `0` (u32::default()). // e.g. Foo: u32; - // e.g. pub Bar get(bar): map T::AccountId => Vec<(T::Balance, u64)>; + // e.g. pub Bar get(fn bar): map T::AccountId => Vec<(T::Balance, u64)>; // // For basic value items, you'll get a type which implements // `support::StorageValue`. For map items, you'll get a type which @@ -340,13 +340,13 @@ decl_storage! { // If they have a getter (`get(getter_name)`), then your module will come // equipped with `fn getter_name() -> Type` for basic value items or // `fn getter_name(key: KeyType) -> ValueType` for map items. - Dummy get(dummy) config(): Option; + Dummy get(fn dummy) config(): Option; // A map that has enumerable entries. - Bar get(bar) config(): linked_map T::AccountId => T::Balance; + Bar get(fn bar) config(): linked_map T::AccountId => T::Balance; // this one uses the default, we'll demonstrate the usage of 'mutate' API. - Foo get(foo) config(): T::Balance; + Foo get(fn foo) config(): T::Balance; } } diff --git a/srml/finality-tracker/src/lib.rs b/srml/finality-tracker/src/lib.rs index 1106a17a58..5e973cd432 100644 --- a/srml/finality-tracker/src/lib.rs +++ b/srml/finality-tracker/src/lib.rs @@ -96,17 +96,17 @@ pub trait Trait: SystemTrait { decl_storage! { trait Store for Module as Timestamp { /// Recent hints. - RecentHints get(recent_hints) build(|_| vec![T::BlockNumber::zero()]): Vec; + RecentHints get(fn recent_hints) build(|_| vec![T::BlockNumber::zero()]): Vec; /// Ordered recent hints. - OrderedHints get(ordered_hints) build(|_| vec![T::BlockNumber::zero()]): Vec; + OrderedHints get(fn ordered_hints) build(|_| vec![T::BlockNumber::zero()]): Vec; /// The median. - Median get(median) build(|_| T::BlockNumber::zero()): T::BlockNumber; + Median get(fn median) build(|_| T::BlockNumber::zero()): T::BlockNumber; /// Final hint to apply in the block. `None` means "same as parent". Update: Option; // when initialized through config this is set in the beginning. - Initialized get(initialized) build(|_| false): bool; + Initialized get(fn initialized) build(|_| false): bool; } } diff --git a/srml/generic-asset/src/lib.rs b/srml/generic-asset/src/lib.rs index ca49e2f1cd..12e9d2cbf6 100644 --- a/srml/generic-asset/src/lib.rs +++ b/srml/generic-asset/src/lib.rs @@ -447,7 +447,7 @@ pub struct BalanceLock { decl_storage! { trait Store for Module as GenericAsset { /// Total issuance of a given asset. - pub TotalIssuance get(total_issuance) build(|config: &GenesisConfig| { + pub TotalIssuance get(fn total_issuance) build(|config: &GenesisConfig| { let issuance = config.initial_balance * (config.endowed_accounts.len() as u32).into(); config.assets.iter().map(|id| (id.clone(), issuance)).collect::>() }): map T::AssetId => T::Balance; @@ -459,19 +459,19 @@ decl_storage! { pub ReservedBalance: double_map T::AssetId, twox_128(T::AccountId) => T::Balance; /// Next available ID for user-created asset. - pub NextAssetId get(next_asset_id) config(): T::AssetId; + pub NextAssetId get(fn next_asset_id) config(): T::AssetId; /// Permission options for a given asset. - pub Permissions get(get_permission): map T::AssetId => PermissionVersions; + pub Permissions get(fn get_permission): map T::AssetId => PermissionVersions; /// Any liquidity locks on some account balances. - pub Locks get(locks): map T::AccountId => Vec>; + pub Locks get(fn locks): map T::AccountId => Vec>; /// The identity of the asset which is the one that is designated for the chain's staking system. - pub StakingAssetId get(staking_asset_id) config(): T::AssetId; + pub StakingAssetId get(fn staking_asset_id) config(): T::AssetId; /// The identity of the asset which is the one that is designated for paying the chain's transaction fee. - pub SpendingAssetId get(spending_asset_id) config(): T::AssetId; + pub SpendingAssetId get(fn spending_asset_id) config(): T::AssetId; } add_extra_genesis { config(assets): Vec; diff --git a/srml/grandpa/src/lib.rs b/srml/grandpa/src/lib.rs index 610bd18fb3..0fc0df382a 100644 --- a/srml/grandpa/src/lib.rs +++ b/srml/grandpa/src/lib.rs @@ -138,26 +138,26 @@ decl_event!( decl_storage! { trait Store for Module as GrandpaFinality { /// The current authority set. - Authorities get(authorities): Vec<(AuthorityId, AuthorityWeight)>; + Authorities get(fn authorities): Vec<(AuthorityId, AuthorityWeight)>; /// State of the current authority set. - State get(state): StoredState = StoredState::Live; + State get(fn state): StoredState = StoredState::Live; /// Pending change: (signaled at, scheduled change). PendingChange: Option>; /// next block number where we can force a change. - NextForced get(next_forced): Option; + NextForced get(fn next_forced): Option; /// `true` if we are currently stalled. - Stalled get(stalled): Option<(T::BlockNumber, T::BlockNumber)>; + Stalled get(fn stalled): Option<(T::BlockNumber, T::BlockNumber)>; /// The number of changes (both in terms of keys and underlying economic responsibilities) /// in the "set" of Grandpa validators from genesis. - CurrentSetId get(current_set_id) build(|_| fg_primitives::SetId::default()): SetId; + CurrentSetId get(fn current_set_id) build(|_| fg_primitives::SetId::default()): SetId; /// A mapping from grandpa set ID to the index of the *most recent* session for which its members were responsible. - SetIdSession get(session_for_set): map SetId => Option; + SetIdSession get(fn session_for_set): map SetId => Option; } add_extra_genesis { config(authorities): Vec<(AuthorityId, AuthorityWeight)>; diff --git a/srml/im-online/src/lib.rs b/srml/im-online/src/lib.rs index 84c95fee47..1a75cebd2e 100644 --- a/srml/im-online/src/lib.rs +++ b/srml/im-online/src/lib.rs @@ -221,14 +221,14 @@ decl_event!( decl_storage! { trait Store for Module as ImOnline { /// The block number when we should gossip. - GossipAt get(gossip_at): T::BlockNumber; + GossipAt get(fn gossip_at): T::BlockNumber; /// The current set of keys that may issue a heartbeat. - Keys get(keys): Vec; + Keys get(fn keys): Vec; /// For each session index we keep a mapping of `AuthorityId` /// to `offchain::OpaqueNetworkState`. - ReceivedHeartbeats get(received_heartbeats): double_map SessionIndex, + ReceivedHeartbeats get(fn received_heartbeats): double_map SessionIndex, blake2_256(AuthIndex) => Vec; } add_extra_genesis { diff --git a/srml/indices/src/lib.rs b/srml/indices/src/lib.rs index be5016c40e..31aa57276b 100644 --- a/srml/indices/src/lib.rs +++ b/srml/indices/src/lib.rs @@ -93,12 +93,12 @@ decl_event!( decl_storage! { trait Store for Module as Indices { /// The next free enumeration set. - pub NextEnumSet get(next_enum_set) build(|config: &GenesisConfig| { + pub NextEnumSet get(fn next_enum_set) build(|config: &GenesisConfig| { (config.ids.len() as u32 / ENUM_SET_SIZE).into() }): T::AccountIndex; /// The enumeration sets. - pub EnumSet get(enum_set) build(|config: &GenesisConfig| { + pub EnumSet get(fn enum_set) build(|config: &GenesisConfig| { (0..((config.ids.len() as u32) + ENUM_SET_SIZE - 1) / ENUM_SET_SIZE) .map(|i| ( i.into(), diff --git a/srml/membership/src/lib.rs b/srml/membership/src/lib.rs index 5d2001b32d..6cd2a914e6 100644 --- a/srml/membership/src/lib.rs +++ b/srml/membership/src/lib.rs @@ -57,7 +57,7 @@ pub trait Trait: system::Trait { decl_storage! { trait Store for Module, I: Instance=DefaultInstance> as Membership { /// The current membership, stored as an ordered Vec. - Members get(members): Vec; + Members get(fn members): Vec; } add_extra_genesis { config(members): Vec; diff --git a/srml/offences/src/lib.rs b/srml/offences/src/lib.rs index 801b8b5fca..a6cf4d7956 100644 --- a/srml/offences/src/lib.rs +++ b/srml/offences/src/lib.rs @@ -59,7 +59,7 @@ pub trait Trait: system::Trait { decl_storage! { trait Store for Module as Offences { /// The primary structure that holds all offence records keyed by report identifiers. - Reports get(reports): map ReportIdOf => Option>; + Reports get(fn reports): map ReportIdOf => Option>; /// A vector of reports of the same kind that happened at the same time slot. ConcurrentReportsIndex: double_map Kind, blake2_256(OpaqueTimeSlot) => Vec>; diff --git a/srml/randomness-collective-flip/src/lib.rs b/srml/randomness-collective-flip/src/lib.rs index f6261b6a03..3644b8898c 100644 --- a/srml/randomness-collective-flip/src/lib.rs +++ b/srml/randomness-collective-flip/src/lib.rs @@ -87,7 +87,7 @@ decl_storage! { /// Series of block headers from the last 81 blocks that acts as random seed material. This /// is arranged as a ring buffer with `block_number % 81` being the index into the `Vec` of /// the oldest hash. - RandomMaterial get(random_material): Vec; + RandomMaterial get(fn random_material): Vec; } } diff --git a/srml/scored-pool/src/lib.rs b/srml/scored-pool/src/lib.rs index 609f17b457..fa18d899e2 100644 --- a/srml/scored-pool/src/lib.rs +++ b/srml/scored-pool/src/lib.rs @@ -154,20 +154,20 @@ decl_storage! { trait Store for Module, I: Instance=DefaultInstance> as ScoredPool { /// The current pool of candidates, stored as an ordered Vec /// (ordered descending by score, `None` last, highest first). - Pool get(pool) config(): PoolT; + Pool get(fn pool) config(): PoolT; /// A Map of the candidates. The information in this Map is redundant /// to the information in the `Pool`. But the Map enables us to easily /// check if a candidate is already in the pool, without having to /// iterate over the entire pool (the `Pool` is not sorted by /// `T::AccountId`, but by `T::Score` instead). - CandidateExists get(candidate_exists): map T::AccountId => bool; + CandidateExists get(fn candidate_exists): map T::AccountId => bool; /// The current membership, stored as an ordered Vec. - Members get(members): Vec; + Members get(fn members): Vec; /// Size of the `Members` set. - MemberCount get(member_count) config(): u32; + MemberCount get(fn member_count) config(): u32; } add_extra_genesis { config(members): Vec; diff --git a/srml/session/src/historical.rs b/srml/session/src/historical.rs index 08e4a6ce31..d3fbc67b95 100644 --- a/srml/session/src/historical.rs +++ b/srml/session/src/historical.rs @@ -56,9 +56,9 @@ pub trait Trait: super::Trait { decl_storage! { trait Store for Module as Session { /// Mapping from historical session indices to session-data root hash and validator count. - HistoricalSessions get(historical_root): map SessionIndex => Option<(T::Hash, ValidatorCount)>; + HistoricalSessions get(fn historical_root): map SessionIndex => Option<(T::Hash, ValidatorCount)>; /// Queued full identifications for queued sessions whose validators have become obsolete. - CachedObsolete get(cached_obsolete): map SessionIndex + CachedObsolete get(fn cached_obsolete): map SessionIndex => Option>; /// The range of historical sessions we store. [first, last) StoredRange: Option<(SessionIndex, SessionIndex)>; diff --git a/srml/session/src/lib.rs b/srml/session/src/lib.rs index bb14b0d8f4..76cc6d0663 100644 --- a/srml/session/src/lib.rs +++ b/srml/session/src/lib.rs @@ -349,10 +349,10 @@ const DEDUP_KEY_PREFIX: &[u8] = b":session:keys"; decl_storage! { trait Store for Module as Session { /// The current set of validators. - Validators get(validators): Vec; + Validators get(fn validators): Vec; /// Current index of the session. - CurrentIndex get(current_index): SessionIndex; + CurrentIndex get(fn current_index): SessionIndex; /// True if the underlying economic identities or weighting behind the validators /// has changed in the queued validator set. @@ -360,12 +360,12 @@ decl_storage! { /// The queued keys for the next session. When the next session begins, these keys /// will be used to determine the validator's session keys. - QueuedKeys get(queued_keys): Vec<(T::ValidatorId, T::Keys)>; + QueuedKeys get(fn queued_keys): Vec<(T::ValidatorId, T::Keys)>; /// Indices of disabled validators. /// /// The set is cleared when `on_session_ending` returns a new set of identities. - DisabledValidators get(disabled_validators): Vec; + DisabledValidators get(fn disabled_validators): Vec; /// The next session keys for a validator. /// diff --git a/srml/staking/src/lib.rs b/srml/staking/src/lib.rs index 0a2f37ccc4..013aed2729 100644 --- a/srml/staking/src/lib.rs +++ b/srml/staking/src/lib.rs @@ -551,72 +551,72 @@ decl_storage! { trait Store for Module as Staking { /// The ideal number of staking participants. - pub ValidatorCount get(validator_count) config(): u32; + pub ValidatorCount get(fn validator_count) config(): u32; /// Minimum number of staking participants before emergency conditions are imposed. - pub MinimumValidatorCount get(minimum_validator_count) config(): + pub MinimumValidatorCount get(fn minimum_validator_count) config(): u32 = DEFAULT_MINIMUM_VALIDATOR_COUNT; /// Any validators that may never be slashed or forcibly kicked. It's a Vec since they're /// easy to initialize and the performance hit is minimal (we expect no more than four /// invulnerables) and restricted to testnets. - pub Invulnerables get(invulnerables) config(): Vec; + pub Invulnerables get(fn invulnerables) config(): Vec; /// Map from all locked "stash" accounts to the controller account. - pub Bonded get(bonded): map T::AccountId => Option; + pub Bonded get(fn bonded): map T::AccountId => Option; /// Map from all (unlocked) "controller" accounts to the info regarding the staking. - pub Ledger get(ledger): + pub Ledger get(fn ledger): map T::AccountId => Option>>; /// Where the reward payment should be made. Keyed by stash. - pub Payee get(payee): map T::AccountId => RewardDestination; + pub Payee get(fn payee): map T::AccountId => RewardDestination; /// The map from (wannabe) validator stash key to the preferences of that validator. - pub Validators get(validators): linked_map T::AccountId => ValidatorPrefs>; + pub Validators get(fn validators): linked_map T::AccountId => ValidatorPrefs>; /// The map from nominator stash key to the set of stash keys of all validators to nominate. - pub Nominators get(nominators): linked_map T::AccountId => Vec; + pub Nominators get(fn nominators): linked_map T::AccountId => Vec; /// Nominators for a particular account that is in action right now. You can't iterate /// through validators here, but you can find them in the Session module. /// /// This is keyed by the stash account. - pub Stakers get(stakers): map T::AccountId => Exposure>; + pub Stakers get(fn stakers): map T::AccountId => Exposure>; /// The currently elected validator set keyed by stash account ID. - pub CurrentElected get(current_elected): Vec; + pub CurrentElected get(fn current_elected): Vec; /// The current era index. - pub CurrentEra get(current_era) config(): EraIndex; + pub CurrentEra get(fn current_era) config(): EraIndex; /// The start of the current era. - pub CurrentEraStart get(current_era_start): MomentOf; + pub CurrentEraStart get(fn current_era_start): MomentOf; /// The session index at which the current era started. - pub CurrentEraStartSessionIndex get(current_era_start_session_index): SessionIndex; + pub CurrentEraStartSessionIndex get(fn current_era_start_session_index): SessionIndex; /// Rewards for the current era. Using indices of current elected set. - CurrentEraPointsEarned get(current_era_reward): EraPoints; + CurrentEraPointsEarned get(fn current_era_reward): EraPoints; /// The amount of balance actively at stake for each validator slot, currently. /// /// This is used to derive rewards and punishments. - pub SlotStake get(slot_stake) build(|config: &GenesisConfig| { + pub SlotStake get(fn slot_stake) build(|config: &GenesisConfig| { config.stakers.iter().map(|&(_, _, value, _)| value).min().unwrap_or_default() }): BalanceOf; /// True if the next session change will be a new era regardless of index. - pub ForceEra get(force_era) config(): Forcing; + pub ForceEra get(fn force_era) config(): Forcing; /// The percentage of the slash that is distributed to reporters. /// /// The rest of the slashed value is handled by the `Slash`. - pub SlashRewardFraction get(slash_reward_fraction) config(): Perbill; + pub SlashRewardFraction get(fn slash_reward_fraction) config(): Perbill; /// A mapping from still-bonded eras to the first session index of that era. BondedEras: Vec<(EraIndex, SessionIndex)>; /// All slashes that have occurred in a given era. - EraSlashJournal get(era_slash_journal): + EraSlashJournal get(fn era_slash_journal): map EraIndex => Vec>>; } add_extra_genesis { diff --git a/srml/sudo/src/lib.rs b/srml/sudo/src/lib.rs index c4e13eefe2..7801384abc 100644 --- a/srml/sudo/src/lib.rs +++ b/srml/sudo/src/lib.rs @@ -200,6 +200,6 @@ decl_event!( decl_storage! { trait Store for Module as Sudo { /// The `AccountId` of the sudo key. - Key get(key) config(): T::AccountId; + Key get(fn key) config(): T::AccountId; } } diff --git a/srml/support/procedural/src/lib.rs b/srml/support/procedural/src/lib.rs index 38d404712e..792f739f1c 100644 --- a/srml/support/procedural/src/lib.rs +++ b/srml/support/procedural/src/lib.rs @@ -33,7 +33,7 @@ use proc_macro::TokenStream; /// ```nocompile /// decl_storage! { /// trait Store for Module as Example { -/// Foo get(foo) config(): u32=12; +/// Foo get(fn foo) config(): u32=12; /// Bar: map u32 => u32; /// pub Zed build(|config| vec![(0, 0)]): linked_map u32 => u32; /// } @@ -120,11 +120,11 @@ use proc_macro::TokenStream; /// /// Basic storage can be extended as such: /// -/// `#vis #name get(#getter) config(#field_name) build(#closure): #type = #default;` +/// `#vis #name get(fn #getter) config(#field_name) build(#closure): #type = #default;` /// /// * `#vis`: Set the visibility of the structure. `pub` or nothing. /// * `#name`: Name of the storage item, used as a prefix in storage. -/// * [optional] `get(#getter)`: Implements the function #getter to `Module`. +/// * [optional] `get(fn #getter)`: Implements the function #getter to `Module`. /// * [optional] `config(#field_name)`: `field_name` is optional if get is set. /// Will include the item in `GenesisConfig`. /// * [optional] `build(#closure)`: Closure called with storage overlays. diff --git a/srml/support/procedural/src/storage/parse.rs b/srml/support/procedural/src/storage/parse.rs index 8464077ca2..53da5ae33e 100644 --- a/srml/support/procedural/src/storage/parse.rs +++ b/srml/support/procedural/src/storage/parse.rs @@ -113,11 +113,16 @@ struct DeclStorageLine { pub default_value: ext::Opt, } +#[derive(Parse, ToTokens, Debug)] +struct DeclStorageGetterBody { + fn_keyword: Option, + ident: Ident, +} #[derive(Parse, ToTokens, Debug)] struct DeclStorageGetter { pub getter_keyword: keyword::get, - pub getfn: ext::Parens, + pub getfn: ext::Parens, } #[derive(Parse, ToTokens, Debug)] @@ -301,17 +306,17 @@ pub fn parse(input: syn::parse::ParseStream) -> syn::Result as Example { - pub Data get(data) build(|_| vec![(15u32, 42u64)]): linked_map hasher(twox_64_concat) u32 => u64; + pub Data get(fn data) build(|_| vec![(15u32, 42u64)]): linked_map hasher(twox_64_concat) u32 => u64; pub OptionLinkedMap: linked_map u32 => Option; - pub GenericData get(generic_data): linked_map hasher(twox_128) T::BlockNumber => T::BlockNumber; - pub GenericData2 get(generic_data2): linked_map T::BlockNumber => Option; + pub GenericData get(fn generic_data): linked_map hasher(twox_128) T::BlockNumber => T::BlockNumber; + pub GenericData2 get(fn generic_data2): linked_map T::BlockNumber => Option; + pub GetterNoFnKeyword get(no_fn): Option; pub DataDM config(test_config) build(|_| vec![(15u32, 16u32, 42u64)]): double_map hasher(twox_64_concat) u32, blake2_256(u32) => u64; @@ -516,6 +517,15 @@ mod tests { ), documentation: DecodeDifferent::Encode(&[]), }, + StorageEntryMetadata { + name: DecodeDifferent::Encode("GetterNoFnKeyword"), + modifier: StorageEntryModifier::Optional, + ty: StorageEntryType::Plain(DecodeDifferent::Encode("u32")), + default: DecodeDifferent::Encode( + DefaultByteGetter(&__GetByteStructGetterNoFnKeyword(PhantomData::)) + ), + documentation: DecodeDifferent::Encode(&[]), + }, StorageEntryMetadata { name: DecodeDifferent::Encode("DataDM"), modifier: StorageEntryModifier::Default, diff --git a/srml/support/src/storage/storage_items.rs b/srml/support/src/storage/storage_items.rs index 1854d703c0..1edf9c03db 100644 --- a/srml/support/src/storage/storage_items.rs +++ b/srml/support/src/storage/storage_items.rs @@ -307,15 +307,15 @@ mod tests { // getters: pub / $default // we need at least one type which uses T, otherwise GenesisConfig will complain. - GETU32 get(u32_getter): T::Origin; - pub PUBGETU32 get(pub_u32_getter) build(|config: &GenesisConfig| config.u32_getter_with_config): u32; - GETU32WITHCONFIG get(u32_getter_with_config) config(): u32; - pub PUBGETU32WITHCONFIG get(pub_u32_getter_with_config) config(): u32; - GETU32MYDEF get(u32_getter_mydef): Option; - pub PUBGETU32MYDEF get(pub_u32_getter_mydef) config(): u32 = 3; - GETU32WITHCONFIGMYDEF get(u32_getter_with_config_mydef) config(): u32 = 2; - pub PUBGETU32WITHCONFIGMYDEF get(pub_u32_getter_with_config_mydef) config(): u32 = 1; - PUBGETU32WITHCONFIGMYDEFOPT get(pub_u32_getter_with_config_mydef_opt) config(): Option; + GETU32 get(fn u32_getter): T::Origin; + pub PUBGETU32 get(fn pub_u32_getter) build(|config: &GenesisConfig| config.u32_getter_with_config): u32; + GETU32WITHCONFIG get(fn u32_getter_with_config) config(): u32; + pub PUBGETU32WITHCONFIG get(fn pub_u32_getter_with_config) config(): u32; + GETU32MYDEF get(fn u32_getter_mydef): Option; + pub PUBGETU32MYDEF get(fn pub_u32_getter_mydef) config(): u32 = 3; + GETU32WITHCONFIGMYDEF get(fn u32_getter_with_config_mydef) config(): u32 = 2; + pub PUBGETU32WITHCONFIGMYDEF get(fn pub_u32_getter_with_config_mydef) config(): u32 = 1; + PUBGETU32WITHCONFIGMYDEFOPT get(fn pub_u32_getter_with_config_mydef_opt) config(): Option; // map non-getters: pub / $default MAPU32 : map u32 => Option; @@ -324,17 +324,17 @@ mod tests { pub PUBMAPU32MYDEF : map u32 => Option; // map getters: pub / $default - GETMAPU32 get(map_u32_getter): map u32 => String; - pub PUBGETMAPU32 get(pub_map_u32_getter): map u32 => String; + GETMAPU32 get(fn map_u32_getter): map u32 => String; + pub PUBGETMAPU32 get(fn pub_map_u32_getter): map u32 => String; - GETMAPU32MYDEF get(map_u32_getter_mydef): map u32 => String = "map".into(); - pub PUBGETMAPU32MYDEF get(pub_map_u32_getter_mydef): map u32 => String = "pubmap".into(); + GETMAPU32MYDEF get(fn map_u32_getter_mydef): map u32 => String = "map".into(); + pub PUBGETMAPU32MYDEF get(fn pub_map_u32_getter_mydef): map u32 => String = "pubmap".into(); // linked map LINKEDMAPU32 : linked_map u32 => Option; pub PUBLINKEDMAPU32MYDEF : linked_map u32 => Option; - GETLINKEDMAPU32 get(linked_map_u32_getter): linked_map u32 => String; - pub PUBGETLINKEDMAPU32MYDEF get(pub_linked_map_u32_getter_mydef): linked_map u32 => String = "pubmap".into(); + GETLINKEDMAPU32 get(fn linked_map_u32_getter): linked_map u32 => String; + pub PUBGETLINKEDMAPU32MYDEF get(fn pub_linked_map_u32_getter_mydef): linked_map u32 => String = "pubmap".into(); COMPLEXTYPE1: ::std::vec::Vec<::Origin>; COMPLEXTYPE2: (Vec)>>, u32); @@ -741,7 +741,7 @@ mod test3 { } crate::decl_storage! { trait Store for Module as Test { - Foo get(foo) config(initial_foo): u32; + Foo get(fn foo) config(initial_foo): u32; } } diff --git a/srml/support/test/tests/final_keys.rs b/srml/support/test/tests/final_keys.rs index 04b243ae7c..44a6b540a7 100644 --- a/srml/support/test/tests/final_keys.rs +++ b/srml/support/test/tests/final_keys.rs @@ -44,8 +44,8 @@ mod no_instance { pub DoubleMap: double_map u32, blake2_256(u32) => u32; pub DoubleMap2: double_map hasher(twox_128) u32, blake2_128(u32) => u32; - pub TestGenericValue get(test_generic_value) config(): Option; - pub TestGenericDoubleMap get(foo2) config(test_generic_double_map): + pub TestGenericValue get(fn test_generic_value) config(): Option; + pub TestGenericDoubleMap get(fn foo2) config(test_generic_double_map): double_map u32, blake2_256(T::BlockNumber) => Option; } } @@ -74,8 +74,8 @@ mod instance { pub DoubleMap: double_map u32, blake2_256(u32) => u32; pub DoubleMap2: double_map hasher(twox_128) u32, blake2_128(u32) => u32; - pub TestGenericValue get(test_generic_value) config(): Option; - pub TestGenericDoubleMap get(foo2) config(test_generic_double_map): + pub TestGenericValue get(fn test_generic_value) config(): Option; + pub TestGenericDoubleMap get(fn foo2) config(test_generic_double_map): double_map u32, blake2_256(T::BlockNumber) => Option; } add_extra_genesis { diff --git a/srml/support/test/tests/issue2219.rs b/srml/support/test/tests/issue2219.rs index 28bd9463ff..72e0bc8caf 100644 --- a/srml/support/test/tests/issue2219.rs +++ b/srml/support/test/tests/issue2219.rs @@ -102,7 +102,7 @@ mod module { support::decl_storage! { trait Store for Module as Actors { /// requirements to enter and maintain status in roles - pub Parameters get(parameters) build(|config: &GenesisConfig| { + pub Parameters get(fn parameters) build(|config: &GenesisConfig| { if config.enable_storage_role { let storage_params: RoleParameters = Default::default(); vec![(Role::Storage, storage_params)] @@ -112,7 +112,7 @@ mod module { }): map Role => Option>; /// the roles members can enter into - pub AvailableRoles get(available_roles) build(|config: &GenesisConfig| { + pub AvailableRoles get(fn available_roles) build(|config: &GenesisConfig| { if config.enable_storage_role { vec![(Role::Storage)] } else { @@ -121,13 +121,13 @@ mod module { }): Vec; /// Actors list - pub ActorAccountIds get(actor_account_ids) : Vec; + pub ActorAccountIds get(fn actor_account_ids) : Vec; /// actor accounts associated with a role - pub AccountIdsByRole get(account_ids_by_role) : map Role => Vec; + pub AccountIdsByRole get(fn account_ids_by_role) : map Role => Vec; /// tokens locked until given block number - pub Bondage get(bondage) : map T::AccountId => T::BlockNumber; + pub Bondage get(fn bondage) : map T::AccountId => T::BlockNumber; /// First step before enter a role is registering intent with a new account/key. /// This is done by sending a role_entry_request() from the new account. @@ -135,10 +135,10 @@ mod module { /// The account making the request will be bonded and must have /// sufficient balance to cover the minimum stake for the role. /// Bonding only occurs after successful entry into a role. - pub RoleEntryRequests get(role_entry_requests) : Requests; + pub RoleEntryRequests get(fn role_entry_requests) : Requests; /// Entry request expires after this number of blocks - pub RequestLifeTime get(request_life_time) config(request_life_time) : u64 = 0; + pub RequestLifeTime get(fn request_life_time) config(request_life_time) : u64 = 0; } add_extra_genesis { config(enable_storage_role): bool; diff --git a/srml/system/src/lib.rs b/srml/system/src/lib.rs index 76cbe7cbab..ed9dee2373 100644 --- a/srml/system/src/lib.rs +++ b/srml/system/src/lib.rs @@ -366,7 +366,7 @@ type EventIndex = u32; decl_storage! { trait Store for Module as System { /// Extrinsics nonce for accounts. - pub AccountNonce get(account_nonce): map T::AccountId => T::Index; + pub AccountNonce get(fn account_nonce): map T::AccountId => T::Index; /// Total extrinsics count for the current block. ExtrinsicCount: Option; /// Total weight for all extrinsics put together, for the current block. @@ -374,21 +374,21 @@ decl_storage! { /// Total length (in bytes) for all extrinsics put together, for the current block. AllExtrinsicsLen: Option; /// Map of block numbers to block hashes. - pub BlockHash get(block_hash) build(|_| vec![(T::BlockNumber::zero(), hash69())]): map T::BlockNumber => T::Hash; + pub BlockHash get(fn block_hash) build(|_| vec![(T::BlockNumber::zero(), hash69())]): map T::BlockNumber => T::Hash; /// Extrinsics data for the current block (maps an extrinsic's index to its data). - ExtrinsicData get(extrinsic_data): map u32 => Vec; + ExtrinsicData get(fn extrinsic_data): map u32 => Vec; /// The current block number being processed. Set by `execute_block`. - Number get(block_number) build(|_| 1.into()): T::BlockNumber; + Number get(fn block_number) build(|_| 1.into()): T::BlockNumber; /// Hash of the previous block. - ParentHash get(parent_hash) build(|_| hash69()): T::Hash; + ParentHash get(fn parent_hash) build(|_| hash69()): T::Hash; /// Extrinsics root of the current block, also part of the block header. - ExtrinsicsRoot get(extrinsics_root): T::Hash; + ExtrinsicsRoot get(fn extrinsics_root): T::Hash; /// Digest of the current block, also part of the block header. - Digest get(digest): DigestOf; + Digest get(fn digest): DigestOf; /// Events deposited for the current block. - Events get(events): Vec>; + Events get(fn events): Vec>; /// The number of events in the `Events` list. - EventCount get(event_count): EventIndex; + EventCount get(fn event_count): EventIndex; // TODO: https://github.com/paritytech/substrate/issues/2553 // Possibly, we can improve it by using something like: @@ -408,7 +408,7 @@ decl_storage! { /// The value has the type `(T::BlockNumber, EventIndex)` because if we used only just /// the `EventIndex` then in case if the topic has the same contents on the next block /// no notification will be triggered thus the event might be lost. - EventTopics get(event_topics): double_map hasher(blake2_256) (), blake2_256(T::Hash) + EventTopics get(fn event_topics): double_map hasher(blake2_256) (), blake2_256(T::Hash) => Vec<(T::BlockNumber, EventIndex)>; } add_extra_genesis { diff --git a/srml/timestamp/src/lib.rs b/srml/timestamp/src/lib.rs index 35546575c5..a48190da9a 100644 --- a/srml/timestamp/src/lib.rs +++ b/srml/timestamp/src/lib.rs @@ -244,7 +244,7 @@ decl_module! { decl_storage! { trait Store for Module as Timestamp { /// Current time for the current block. - pub Now get(now) build(|_| 0.into()): T::Moment; + pub Now get(fn now) build(|_| 0.into()): T::Moment; /// Did the timestamp get updated in this block? DidUpdate: bool; diff --git a/srml/transaction-payment/src/lib.rs b/srml/transaction-payment/src/lib.rs index f2e815fcd4..b662f55689 100644 --- a/srml/transaction-payment/src/lib.rs +++ b/srml/transaction-payment/src/lib.rs @@ -76,7 +76,7 @@ pub trait Trait: system::Trait { decl_storage! { trait Store for Module as Balances { - NextFeeMultiplier get(next_fee_multiplier): Multiplier = Multiplier::from_parts(0); + NextFeeMultiplier get(fn next_fee_multiplier): Multiplier = Multiplier::from_parts(0); } } diff --git a/srml/treasury/src/lib.rs b/srml/treasury/src/lib.rs index 936e4bd93d..67ee456139 100644 --- a/srml/treasury/src/lib.rs +++ b/srml/treasury/src/lib.rs @@ -225,13 +225,13 @@ pub struct Proposal { decl_storage! { trait Store for Module as Treasury { /// Number of proposals that have been made. - ProposalCount get(proposal_count): ProposalIndex; + ProposalCount get(fn proposal_count): ProposalIndex; /// Proposals that have been made. - Proposals get(proposals): map ProposalIndex => Option>>; + Proposals get(fn proposals): map ProposalIndex => Option>>; /// Proposal indices that have been approved but not yet awarded. - Approvals get(approvals): Vec; + Approvals get(fn approvals): Vec; } } -- GitLab From a0e47d13b570eeab3b7c7747569bec032627dcf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Tue, 22 Oct 2019 10:29:44 +0200 Subject: [PATCH 074/167] Improve logging for offchain transaction submission. (#3871) --- core/offchain/src/api.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/offchain/src/api.rs b/core/offchain/src/api.rs index d17a892d97..d4301d22ed 100644 --- a/core/offchain/src/api.rs +++ b/core/offchain/src/api.rs @@ -317,12 +317,12 @@ impl AsyncApi { }, }; - info!("Submitting to the pool: {:?} (isSigned: {:?})", xt, xt.is_signed()); + info!("Submitting transaction to the pool: {:?} (isSigned: {:?})", xt, xt.is_signed()); future::Either::Right(self.transaction_pool .submit_one(&self.at, xt.clone()) .map(|result| match result { Ok(hash) => { debug!("[{:?}] Offchain transaction added to the pool.", hash); }, - Err(e) => { debug!("Couldn't submit transaction: {:?}", e); }, + Err(e) => { warn!("Couldn't submit offchain transaction: {:?}", e); }, })) } } -- GitLab From 2e1d8310f58d6abc12e0f9ed223acbc560d6fb3a Mon Sep 17 00:00:00 2001 From: yjh Date: Tue, 22 Oct 2019 17:37:52 +0800 Subject: [PATCH 075/167] refactor map macro for more general use (#3850) * refactor map macro for more general use Signed-off-by: yjhmelody <465402634@qq.com> * use $(,)? Signed-off-by: yjhmelody <465402634@qq.com> * Update core/primitives/src/lib.rs Co-Authored-By: thiolliere * Update core/primitives/src/lib.rs Co-Authored-By: thiolliere --- core/primitives/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/primitives/src/lib.rs b/core/primitives/src/lib.rs index c2d23050f9..0a1f80aaa9 100644 --- a/core/primitives/src/lib.rs +++ b/core/primitives/src/lib.rs @@ -26,9 +26,9 @@ /// Can be used to create a `HashMap`. #[macro_export] macro_rules! map { - ($( $name:expr => $value:expr ),*) => ( + ($( $name:expr => $value:expr ),* $(,)? ) => ( vec![ $( ( $name, $value ) ),* ].into_iter().collect() - ) + ); } use rstd::prelude::*; -- GitLab From a61c0eb891a4942d0fa96333aa57472940fb181b Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Tue, 22 Oct 2019 13:02:20 +0300 Subject: [PATCH 076/167] fix ambiguity about start in doc (#3864) --- core/sr-sandbox/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/sr-sandbox/src/lib.rs b/core/sr-sandbox/src/lib.rs index e814a51ace..b04524b241 100755 --- a/core/sr-sandbox/src/lib.rs +++ b/core/sr-sandbox/src/lib.rs @@ -171,7 +171,7 @@ pub struct Instance { impl Instance { /// Instantiate a module with the given [`EnvironmentDefinitionBuilder`]. It will - /// run the `start` function with the given `state`. + /// run the `start` function (if it is present in the module) with the given `state`. /// /// Returns `Err(Error::Module)` if this module can't be instantiated with the given /// environment. If execution of `start` function generated a trap, then `Err(Error::Execution)` will -- GitLab From 27f741e11c2ccb3bd78852d5c3445a7055f48c5c Mon Sep 17 00:00:00 2001 From: Ashley Date: Tue, 22 Oct 2019 12:24:58 +0100 Subject: [PATCH 077/167] Remove sr-arithmetic/fuzzer from workspace to fix windows builds (#3872) * Remove sr-arithmetic/fuzzer from workspace to fix windows builds * Remove sr-arithmetic/fuzzer from check_runtime.sh --- Cargo.lock | 38 --- Cargo.toml | 1 - core/sr-arithmetic/fuzzer/Cargo.lock | 465 +++++++++++++++++++++++++++ core/sr-arithmetic/fuzzer/Cargo.toml | 2 + scripts/gitlab/check_runtime.sh | 2 +- 5 files changed, 468 insertions(+), 40 deletions(-) create mode 100644 core/sr-arithmetic/fuzzer/Cargo.lock diff --git a/Cargo.lock b/Cargo.lock index d77ba65cbd..6df1104377 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -92,11 +92,6 @@ dependencies = [ "xdg 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "arbitrary" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "arc-swap" version = "0.3.11" @@ -1279,16 +1274,6 @@ dependencies = [ "hmac 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "honggfuzz" -version = "0.5.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "arbitrary 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "http" version = "0.1.18" @@ -2191,15 +2176,6 @@ dependencies = [ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "memmap" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "memoffset" version = "0.5.1" @@ -3878,17 +3854,6 @@ dependencies = [ "sr-std 2.0.0", ] -[[package]] -name = "sr-arithmetic-fuzzer" -version = "2.0.0" -dependencies = [ - "honggfuzz 0.5.45 (registry+https://github.com/rust-lang/crates.io-index)", - "num-bigint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "primitive-types 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-arithmetic 2.0.0", -] - [[package]] name = "sr-io" version = "2.0.0" @@ -6792,7 +6757,6 @@ dependencies = [ "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" "checksum ansi_term 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" "checksum app_dirs 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e73a24bad9bd6a94d6395382a6c69fe071708ae4409f763c5475e14ee896313d" -"checksum arbitrary 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "64cf76cb6e2222ed0ea86b2b0ee2f71c96ec6edd5af42e84d59160e91b836ec4" "checksum arc-swap 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "bc4662175ead9cd84451d5c35070517777949a2ed84551764129cedb88384841" "checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee" "checksum arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" @@ -6930,7 +6894,6 @@ dependencies = [ "checksum hmac 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5dcb5e64cda4c23119ab41ba960d1e170a774c8e4b9d9e6a9bc18aabf5e59695" "checksum hmac-drbg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4fe727d41d2eec0a6574d887914347e5ff96a3b87177817e2a9820c5c87fecc2" "checksum hmac-drbg 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c6e570451493f10f6581b48cdd530413b63ea9e780f544bfd3bdcaa0d89d1a7b" -"checksum honggfuzz 0.5.45 (registry+https://github.com/rust-lang/crates.io-index)" = "24c27b4aa3049d6d10d8e33d52c9d03ca9aec18f8a449b246f8c4a5b0c10fb34" "checksum http 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "372bcb56f939e449117fb0869c2e8fd8753a8223d92a172c6e808cf123a5b6e4" "checksum http-body 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6741c859c1b2463a423a1dbce98d418e6c3c3fc720fb0d45528657320920292d" "checksum httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" @@ -7007,7 +6970,6 @@ dependencies = [ "checksum malloc_size_of_derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "35adee9ed962cf7d07d62cb58bc45029f3227f5b5b86246caa8632f06c187bc3" "checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" "checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" -"checksum memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b" "checksum memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce6075db033bbbb7ee5a0bbd3a3186bbae616f57fb001c485c7ff77955f8177f" "checksum memory-db 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ef49315991403ba5fa225a70399df5e115f57b274cb0b1b4bcd6e734fa5bd783" "checksum memory_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "71d96e3f3c0b6325d8ccd83c33b28acb183edcb6c67938ba104ec546854b0882" diff --git a/Cargo.toml b/Cargo.toml index 9d01fabc1e..8d3d04c4d0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -54,7 +54,6 @@ members = [ "core/session", "core/sr-api-macros", "core/sr-arithmetic", - "core/sr-arithmetic/fuzzer", "core/sr-io", "core/sr-primitives", "core/sr-staking-primitives", diff --git a/core/sr-arithmetic/fuzzer/Cargo.lock b/core/sr-arithmetic/fuzzer/Cargo.lock new file mode 100644 index 0000000000..f6ce6f1d47 --- /dev/null +++ b/core/sr-arithmetic/fuzzer/Cargo.lock @@ -0,0 +1,465 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "arbitrary" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "arrayvec" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "autocfg" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "bitvec" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "byte-slice-cast" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "byteorder" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "c2-chacha" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "fixed-hash" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "getrandom" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "honggfuzz" +version = "0.5.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "arbitrary 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "impl-codec" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "integer-sqrt" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "libc" +version = "0.2.65" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "memmap" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "nodrop" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "num-bigint" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-integer" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-traits" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "parity-scale-codec" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "bitvec 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", + "byte-slice-cast 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-scale-codec-derive 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro-crate 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "primitive-types" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "fixed-hash 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "impl-codec 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "uint 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "proc-macro-crate" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "toml 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "proc-macro2" +version = "0.4.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "proc-macro2" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "quote" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "quote" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_chacha" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rustc-hex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "serde" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde_derive" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "sr-arithmetic" +version = "2.0.0" +dependencies = [ + "integer-sqrt 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-std 2.0.0", +] + +[[package]] +name = "sr-arithmetic-fuzzer" +version = "2.0.0" +dependencies = [ + "honggfuzz 0.5.45 (registry+https://github.com/rust-lang/crates.io-index)", + "num-bigint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "primitive-types 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-arithmetic 2.0.0", +] + +[[package]] +name = "sr-std" +version = "2.0.0" +dependencies = [ + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "static_assertions" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "syn" +version = "0.15.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "syn" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "toml" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "uint" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crunchy 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-xid" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unicode-xid" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "wasi" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[metadata] +"checksum arbitrary 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "64cf76cb6e2222ed0ea86b2b0ee2f71c96ec6edd5af42e84d59160e91b836ec4" +"checksum arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" +"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" +"checksum bitvec 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9633b74910e1870f50f5af189b08487195cdb83c0e27a71d6f64d5e09dd0538b" +"checksum byte-slice-cast 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7cbcbf18128ec71d8d4a0d054461ec59fff5b75b7d10a4c9b7c7cb1a379c3e77" +"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" +"checksum c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb" +"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +"checksum crunchy 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +"checksum fixed-hash 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6357b15872f8126e4ea7cf79d579473f132ccd2de239494ad1bf4aa892faea68" +"checksum getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "473a1265acc8ff1e808cd0a1af8cee3c2ee5200916058a2ca113c29f2d903571" +"checksum honggfuzz 0.5.45 (registry+https://github.com/rust-lang/crates.io-index)" = "24c27b4aa3049d6d10d8e33d52c9d03ca9aec18f8a449b246f8c4a5b0c10fb34" +"checksum impl-codec 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3fa0086251524c50fd53b32e7b05eb6d79e2f97221eaf0c53c0ca9c3096f21d3" +"checksum integer-sqrt 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ea155abb3ba6f382a75f1418988c05fe82959ed9ce727de427f9cfd425b0c903" +"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +"checksum libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)" = "1a31a0627fdf1f6a39ec0dd577e101440b7db22672c0901fe00a9a6fbb5c24e8" +"checksum memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b" +"checksum nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" +"checksum num-bigint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f9c3f34cdd24f334cb265d9bf8bfa8a241920d026916785747a92f0e55541a1a" +"checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09" +"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" +"checksum parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "001fbbb956d8593f321c7a784f64d16b2c99b2657823976eea729006ad2c3668" +"checksum parity-scale-codec-derive 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "42af752f59119656fa3cb31e8852ed24e895b968c0bdb41847da7f0cea6d155f" +"checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" +"checksum primitive-types 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97b5a08dda18910f056e5c2060c034e77cab18e0bd7d895e44f03207af4c71d5" +"checksum proc-macro-crate 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e10d4b51f154c8a7fb96fd6dad097cb74b863943ec010ac94b9fd1be8861fe1e" +"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" +"checksum proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9c9e470a8dc4aeae2dee2f335e8f533e2d4b347e1434e5671afc49b054592f27" +"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" +"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" +"checksum rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3ae1b169243eaf61759b8475a998f0a385e42042370f3a7dbaf35246eacc8412" +"checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" +"checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +"checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +"checksum rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "403bb3a286107a04825a5f82e1270acc1e14028d3d554d7a1e08914549575ab8" +"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +"checksum serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "9796c9b7ba2ffe7a9ce53c2287dfc48080f4b2b362fcc245a259b3a7201119dd" +"checksum serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "4b133a43a1ecd55d4086bd5b4dc6c1751c68b1bfbeba7a5040442022c7e7c02e" +"checksum static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c19be23126415861cb3a23e501d34a708f7f9b2183c5252d690941c2e69199d5" +"checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" +"checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf" +"checksum toml 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c7aabe75941d914b72bf3e5d3932ed92ce0664d49d8432305a8b547c37227724" +"checksum uint 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f8f0f47ed099f0db671ce82c66548c5de012e3c0cba3963514d1db15c7588701" +"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" +"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" +"checksum wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b89c3ce4ce14bdc6fb6beaf9ec7928ca331de5df7e5ea278375642a2f478570d" +"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" +"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/core/sr-arithmetic/fuzzer/Cargo.toml b/core/sr-arithmetic/fuzzer/Cargo.toml index 8838e60436..482905c435 100644 --- a/core/sr-arithmetic/fuzzer/Cargo.toml +++ b/core/sr-arithmetic/fuzzer/Cargo.toml @@ -11,6 +11,8 @@ primitive-types = "0.6" num-bigint = "0.2" num-traits = "0.2" +[workspace] + [[bin]] name = "biguint" path = "src/biguint.rs" diff --git a/scripts/gitlab/check_runtime.sh b/scripts/gitlab/check_runtime.sh index 725c5077c5..cd988718d0 100755 --- a/scripts/gitlab/check_runtime.sh +++ b/scripts/gitlab/check_runtime.sh @@ -32,7 +32,7 @@ github_label () { # check if the wasm sources changed if ! git diff --name-only origin/master...${CI_COMMIT_SHA} \ - | grep -q -e '^node/src/runtime' -e '^srml/' -e '^core/sr-' + | grep -q -e '^node/src/runtime' -e '^srml/' -e '^core/sr-' | grep -v -e '^core/sr-arithmetic/fuzzer' then cat <<-EOT -- GitLab From a31c01b398d958ccf0a24d8c1c11fb073df66212 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Tue, 22 Oct 2019 14:13:44 +0200 Subject: [PATCH 078/167] Runtime logging. (#3821) * Implement Printable for tuples. * Add debugging function. * Add debug 1. * Implement for everything. * RuntimeDebug derive. * Introduce RuntimeDebug. * Add some dummy logging. * Replace RuntimeDebug with Debug. * Revert "Replace RuntimeDebug with Debug." This reverts commit bc47070a8cb30241b2b590b2fa29fd195088162f. * Working on Debug for all. * Fix bounds. * Add debug utils. * Implement runtime logging. * Add some docs and clean up. * Clean up derives. * Fix custom derive impl. * Bump runtime. * Fix long lines. * Fix doc test. * Use CARGO_CFG_STD. * Revert "Use CARGO_CFG_STD." This reverts commit ea429566de18ed0fa052571b359eb9826a64a9f4. * Use parse_macro_input * Update lockfile. * Apply review suggestions. * Remove stray re-export. * Add no-std impl. * Update lockfile. --- Cargo.lock | 15 ++ core/application-crypto/src/lib.rs | 16 +- core/application-crypto/src/traits.rs | 30 +-- .../authority-discovery/primitives/src/lib.rs | 9 +- core/consensus/babe/primitives/src/digest.rs | 3 +- core/consensus/babe/primitives/src/lib.rs | 8 +- core/executor/src/host_interface.rs | 16 ++ core/finality-grandpa/primitives/src/lib.rs | 10 +- core/phragmen/src/lib.rs | 15 +- core/primitives/Cargo.toml | 6 +- core/primitives/debug-derive/Cargo.toml | 19 ++ core/primitives/debug-derive/src/impls.rs | 217 ++++++++++++++++++ core/primitives/debug-derive/src/lib.rs | 44 ++++ core/primitives/debug-derive/tests/tests.rs | 63 +++++ core/primitives/src/crypto.rs | 4 +- core/primitives/src/ed25519.rs | 22 +- core/primitives/src/hexdisplay.rs | 8 +- core/primitives/src/lib.rs | 65 +++++- core/primitives/src/offchain.rs | 29 +-- core/primitives/src/sandbox.rs | 12 +- core/primitives/src/sr25519.rs | 25 +- core/primitives/storage/Cargo.toml | 1 + core/primitives/storage/src/lib.rs | 12 +- core/sr-arithmetic/Cargo.toml | 12 +- core/sr-arithmetic/src/biguint.rs | 8 +- core/sr-arithmetic/src/fixed64.rs | 9 +- core/sr-arithmetic/src/per_things.rs | 9 +- core/sr-arithmetic/src/rational128.rs | 4 +- core/sr-io/Cargo.toml | 6 +- core/sr-io/src/lib.rs | 15 ++ core/sr-io/with_std.rs | 16 ++ core/sr-io/without_std.rs | 24 ++ core/sr-primitives/Cargo.toml | 12 +- core/sr-primitives/src/curve.rs | 3 +- core/sr-primitives/src/generic/block.rs | 13 +- .../src/generic/checked_extrinsic.rs | 3 +- core/sr-primitives/src/generic/digest.rs | 11 +- core/sr-primitives/src/generic/era.rs | 4 +- core/sr-primitives/src/generic/header.rs | 26 +-- .../src/generic/unchecked_extrinsic.rs | 5 +- core/sr-primitives/src/lib.rs | 34 +-- core/sr-primitives/src/offchain/http.rs | 24 +- core/sr-primitives/src/traits.rs | 83 ++++--- .../sr-primitives/src/transaction_validity.rs | 16 +- core/sr-primitives/src/weights.rs | 11 +- core/sr-sandbox/src/lib.rs | 2 +- core/sr-staking-primitives/src/offence.rs | 3 +- core/sr-std/without_std.rs | 1 + core/sr-version/src/lib.rs | 6 +- core/test-runtime/src/lib.rs | 10 +- core/trie/src/node_header.rs | 2 +- node/primitives/src/lib.rs | 1 - node/runtime/src/lib.rs | 2 +- srml/authorship/src/lib.rs | 4 +- srml/balances/src/lib.rs | 23 +- srml/collective/src/lib.rs | 7 +- srml/contracts/rpc/runtime-api/Cargo.toml | 2 + srml/contracts/rpc/runtime-api/src/lib.rs | 5 +- srml/contracts/src/exec.rs | 5 +- srml/contracts/src/lib.rs | 36 +-- srml/democracy/src/lib.rs | 10 +- srml/democracy/src/vote_threshold.rs | 4 +- srml/elections/src/lib.rs | 11 +- srml/example/src/lib.rs | 3 +- srml/generic-asset/src/lib.rs | 38 ++- srml/im-online/src/lib.rs | 31 ++- srml/indices/src/address.rs | 4 +- srml/metadata/src/lib.rs | 87 ++++--- srml/scored-pool/src/lib.rs | 10 +- srml/staking/src/lib.rs | 29 +-- srml/support/Cargo.toml | 1 + .../procedural/src/storage/instance_trait.rs | 8 +- srml/support/src/debug.rs | 209 +++++++++++++++++ srml/support/src/dispatch.rs | 29 +-- srml/support/src/error.rs | 3 +- srml/support/src/event.rs | 25 +- srml/support/src/lib.rs | 7 +- srml/support/src/origin.rs | 4 +- srml/support/src/runtime.rs | 3 +- srml/support/src/traits.rs | 8 +- srml/support/test/tests/instance.rs | 6 +- srml/support/test/tests/system.rs | 3 +- srml/system/src/lib.rs | 82 ++++--- srml/timestamp/src/lib.rs | 4 +- srml/transaction-payment/src/lib.rs | 6 +- srml/treasury/src/lib.rs | 4 +- 86 files changed, 1266 insertions(+), 469 deletions(-) create mode 100644 core/primitives/debug-derive/Cargo.toml create mode 100644 core/primitives/debug-derive/src/impls.rs create mode 100644 core/primitives/debug-derive/src/lib.rs create mode 100644 core/primitives/debug-derive/tests/tests.rs create mode 100644 srml/support/src/debug.rs diff --git a/Cargo.lock b/Cargo.lock index 6df1104377..0ad4317dd9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3852,6 +3852,7 @@ dependencies = [ "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "sr-std 2.0.0", + "substrate-debug-derive 2.0.0", ] [[package]] @@ -3860,6 +3861,7 @@ version = "2.0.0" dependencies = [ "hash-db 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", "libsecp256k1 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "sr-std 2.0.0", @@ -4102,6 +4104,7 @@ version = "2.0.0" dependencies = [ "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-primitives 2.0.0", "sr-std 2.0.0", "substrate-client 2.0.0", ] @@ -4416,6 +4419,7 @@ version = "2.0.0" dependencies = [ "bitmask 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "impl-trait-for-tuples 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "once_cell 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "paste 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -5088,6 +5092,15 @@ dependencies = [ "substrate-primitives 2.0.0", ] +[[package]] +name = "substrate-debug-derive" +version = "2.0.0" +dependencies = [ + "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "substrate-executor" version = "2.0.0" @@ -5367,6 +5380,7 @@ dependencies = [ "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "sr-std 2.0.0", "substrate-bip39 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "substrate-debug-derive 2.0.0", "substrate-externalities 2.0.0", "substrate-primitives-storage 2.0.0", "substrate-serializer 2.0.0", @@ -5383,6 +5397,7 @@ dependencies = [ "impl-serde 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "sr-std 2.0.0", + "substrate-debug-derive 2.0.0", ] [[package]] diff --git a/core/application-crypto/src/lib.rs b/core/application-crypto/src/lib.rs index e3366a461a..16eda53238 100644 --- a/core/application-crypto/src/lib.rs +++ b/core/application-crypto/src/lib.rs @@ -21,7 +21,7 @@ #![cfg_attr(not(feature = "std"), no_std)] #[doc(hidden)] -pub use primitives::{self, crypto::{CryptoType, Public, Derive, IsWrappedBy, Wraps}}; +pub use primitives::{self, crypto::{CryptoType, Public, Derive, IsWrappedBy, Wraps}, RuntimeDebug}; #[doc(hidden)] #[cfg(feature = "std")] pub use primitives::crypto::{SecretStringError, DeriveJunction, Ss58Codec, Pair}; @@ -139,10 +139,12 @@ macro_rules! app_crypto { $crate::wrap!{ /// A generic `AppPublic` wrapper type over $public crypto; this has no specific App. #[derive( - Clone, Default, Eq, PartialEq, Ord, PartialOrd, $crate::codec::Encode, + Clone, Default, Eq, PartialEq, Ord, PartialOrd, + $crate::codec::Encode, $crate::codec::Decode, + $crate::RuntimeDebug, )] - #[cfg_attr(feature = "std", derive(Debug, Hash))] + #[cfg_attr(feature = "std", derive(Hash))] pub struct Public($public); } @@ -239,8 +241,12 @@ macro_rules! app_crypto { $crate::wrap! { /// A generic `AppPublic` wrapper type over $public crypto; this has no specific App. - #[derive(Clone, Default, Eq, PartialEq, $crate::codec::Encode, $crate::codec::Decode)] - #[cfg_attr(feature = "std", derive(Debug, Hash))] + #[derive(Clone, Default, Eq, PartialEq, + $crate::codec::Encode, + $crate::codec::Decode, + $crate::RuntimeDebug, + )] + #[cfg_attr(feature = "std", derive(Hash))] pub struct Signature($sig); } diff --git a/core/application-crypto/src/traits.rs b/core/application-crypto/src/traits.rs index aad076bd90..49d3a44aee 100644 --- a/core/application-crypto/src/traits.rs +++ b/core/application-crypto/src/traits.rs @@ -14,10 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -use primitives::crypto::{KeyTypeId, CryptoType, IsWrappedBy, Public}; #[cfg(feature = "std")] use primitives::crypto::Pair; + use codec::Codec; +use primitives::crypto::{KeyTypeId, CryptoType, IsWrappedBy, Public}; +use rstd::fmt::Debug; /// An application-specific key. pub trait AppKey: 'static + Send + Sync + Sized + CryptoType + Clone { @@ -38,23 +40,25 @@ pub trait AppKey: 'static + Send + Sync + Sized + CryptoType + Clone { const ID: KeyTypeId; } -/// Type which implements Debug and Hash in std, not when no-std (std variant). +/// Type which implements Hash in std, not when no-std (std variant). #[cfg(feature = "std")] -pub trait MaybeDebugHash: std::fmt::Debug + std::hash::Hash {} +pub trait MaybeHash: std::hash::Hash {} #[cfg(feature = "std")] -impl MaybeDebugHash for T {} +impl MaybeHash for T {} -/// Type which implements Debug and Hash in std, not when no-std (no-std variant). +/// Type which implements Hash in std, not when no-std (no-std variant). #[cfg(not(feature = "std"))] -pub trait MaybeDebugHash {} +pub trait MaybeHash {} #[cfg(not(feature = "std"))] -impl MaybeDebugHash for T {} +impl MaybeHash for T {} /// A application's public key. -pub trait AppPublic: AppKey + Public + Ord + PartialOrd + Eq + PartialEq + MaybeDebugHash + codec::Codec { +pub trait AppPublic: + AppKey + Public + Ord + PartialOrd + Eq + PartialEq + Debug + MaybeHash + codec::Codec +{ /// The wrapped type which is just a plain instance of `Public`. type Generic: - IsWrappedBy + Public + Ord + PartialOrd + Eq + PartialEq + MaybeDebugHash + codec::Codec; + IsWrappedBy + Public + Ord + PartialOrd + Eq + PartialEq + Debug + MaybeHash + codec::Codec; } /// A application's key pair. @@ -65,15 +69,15 @@ pub trait AppPair: AppKey + Pair::Public> { } /// A application's signature. -pub trait AppSignature: AppKey + Eq + PartialEq + MaybeDebugHash { +pub trait AppSignature: AppKey + Eq + PartialEq + Debug + MaybeHash { /// The wrapped type which is just a plain instance of `Signature`. - type Generic: IsWrappedBy + Eq + PartialEq + MaybeDebugHash; + type Generic: IsWrappedBy + Eq + PartialEq + Debug + MaybeHash; } /// A runtime interface for a public key. pub trait RuntimePublic: Sized { /// The signature that will be generated when signing with the corresponding private key. - type Signature: Codec + MaybeDebugHash + Eq + PartialEq + Clone; + type Signature: Codec + Debug + MaybeHash + Eq + PartialEq + Clone; /// Returns all public keys for the given key type in the keystore. fn all(key_type: KeyTypeId) -> crate::Vec; @@ -101,7 +105,7 @@ pub trait RuntimeAppPublic: Sized { const ID: KeyTypeId; /// The signature that will be generated when signing with the corresponding private key. - type Signature: Codec + MaybeDebugHash + Eq + PartialEq + Clone; + type Signature: Codec + Debug + MaybeHash + Eq + PartialEq + Clone; /// Returns all public keys for this application in the keystore. fn all() -> crate::Vec; diff --git a/core/authority-discovery/primitives/src/lib.rs b/core/authority-discovery/primitives/src/lib.rs index 13da4de020..7c56dc6ca4 100644 --- a/core/authority-discovery/primitives/src/lib.rs +++ b/core/authority-discovery/primitives/src/lib.rs @@ -20,12 +20,13 @@ use client::decl_runtime_apis; use rstd::vec::Vec; +use sr_primitives::RuntimeDebug; -#[derive(codec::Encode, codec::Decode, Eq, PartialEq, Clone)] -#[cfg_attr(feature = "std", derive(Debug, Hash))] +#[derive(codec::Encode, codec::Decode, Eq, PartialEq, Clone, RuntimeDebug)] +#[cfg_attr(feature = "std", derive(Hash))] pub struct Signature(pub Vec); -#[derive(codec::Encode, codec::Decode, Eq, PartialEq, Clone)] -#[cfg_attr(feature = "std", derive(Debug, Hash))] +#[derive(codec::Encode, codec::Decode, Eq, PartialEq, Clone, RuntimeDebug)] +#[cfg_attr(feature = "std", derive(Hash))] pub struct AuthorityId(pub Vec); decl_runtime_apis! { diff --git a/core/consensus/babe/primitives/src/digest.rs b/core/consensus/babe/primitives/src/digest.rs index ff62ae29c5..95dd247810 100644 --- a/core/consensus/babe/primitives/src/digest.rs +++ b/core/consensus/babe/primitives/src/digest.rs @@ -195,8 +195,7 @@ impl Decode for BabePreDigest { /// Information about the next epoch. This is broadcast in the first block /// of the epoch. -#[derive(Decode, Encode, Default, PartialEq, Eq, Clone)] -#[cfg_attr(any(feature = "std", test), derive(Debug))] +#[derive(Decode, Encode, Default, PartialEq, Eq, Clone, sr_primitives::RuntimeDebug)] pub struct NextEpochDescriptor { /// The authorities. pub authorities: Vec<(AuthorityId, BabeAuthorityWeight)>, diff --git a/core/consensus/babe/primitives/src/lib.rs b/core/consensus/babe/primitives/src/lib.rs index 1293b7c8ba..c464e797d8 100644 --- a/core/consensus/babe/primitives/src/lib.rs +++ b/core/consensus/babe/primitives/src/lib.rs @@ -23,7 +23,7 @@ mod digest; use codec::{Encode, Decode}; use rstd::vec::Vec; -use sr_primitives::ConsensusEngineId; +use sr_primitives::{ConsensusEngineId, RuntimeDebug}; use substrate_client::decl_runtime_apis; #[cfg(feature = "std")] @@ -79,8 +79,7 @@ pub type BabeAuthorityWeight = u64; pub type BabeBlockWeight = u32; /// BABE epoch information -#[derive(Decode, Encode, Default, PartialEq, Eq, Clone)] -#[cfg_attr(any(feature = "std", test), derive(Debug))] +#[derive(Decode, Encode, Default, PartialEq, Eq, Clone, RuntimeDebug)] pub struct Epoch { /// The epoch index pub epoch_index: u64, @@ -127,8 +126,7 @@ pub enum ConsensusLog { } /// Configuration data used by the BABE consensus engine. -#[derive(Clone, PartialEq, Eq, Encode, Decode)] -#[cfg_attr(any(feature = "std", test), derive(Debug))] +#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug)] pub struct BabeConfiguration { /// The slot duration in milliseconds for BABE. Currently, only /// the value provided by this type at genesis will be used. diff --git a/core/executor/src/host_interface.rs b/core/executor/src/host_interface.rs index 7c99415f6c..e6386ff1ac 100644 --- a/core/executor/src/host_interface.rs +++ b/core/executor/src/host_interface.rs @@ -151,6 +151,22 @@ impl_wasm_host_interface! { Ok(()) } + ext_log( + level: u32, + target_data: Pointer, + target_len: WordSize, + message_data: Pointer, + message_len: WordSize, + ) { + let target = context.read_memory(target_data, target_len) + .map_err(|_| "Invalid attempt to determine target in ext_log")?; + let message = context.read_memory(message_data, message_len) + .map_err(|_| "Invalid attempt to determine message in ext_log")?; + + runtime_io::log(level.into(), &target, &message); + Ok(()) + } + ext_set_storage( key_data: Pointer, key_len: WordSize, diff --git a/core/finality-grandpa/primitives/src/lib.rs b/core/finality-grandpa/primitives/src/lib.rs index a439953899..27139bbeef 100644 --- a/core/finality-grandpa/primitives/src/lib.rs +++ b/core/finality-grandpa/primitives/src/lib.rs @@ -24,7 +24,7 @@ extern crate alloc; #[cfg(feature = "std")] use serde::Serialize; use codec::{Encode, Decode, Codec}; -use sr_primitives::ConsensusEngineId; +use sr_primitives::{ConsensusEngineId, RuntimeDebug}; use client::decl_runtime_apis; use rstd::vec::Vec; @@ -59,8 +59,8 @@ pub type SetId = u64; pub type RoundNumber = u64; /// A scheduled change of authority set. -#[cfg_attr(feature = "std", derive(Debug, Serialize))] -#[derive(Clone, Eq, PartialEq, Encode, Decode)] +#[cfg_attr(feature = "std", derive(Serialize))] +#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug)] pub struct ScheduledChange { /// The new authorities after the change, along with their respective weights. pub next_authorities: Vec<(AuthorityId, AuthorityWeight)>, @@ -69,8 +69,8 @@ pub struct ScheduledChange { } /// An consensus log item for GRANDPA. -#[cfg_attr(feature = "std", derive(Serialize, Debug))] -#[derive(Decode, Encode, PartialEq, Eq, Clone)] +#[cfg_attr(feature = "std", derive(Serialize))] +#[derive(Decode, Encode, PartialEq, Eq, Clone, RuntimeDebug)] pub enum ConsensusLog { /// Schedule an authority set change. /// diff --git a/core/phragmen/src/lib.rs b/core/phragmen/src/lib.rs index e15a857b5f..7377bac2f8 100644 --- a/core/phragmen/src/lib.rs +++ b/core/phragmen/src/lib.rs @@ -34,6 +34,7 @@ #![cfg_attr(not(feature = "std"), no_std)] use rstd::{prelude::*, collections::btree_map::BTreeMap}; +use sr_primitives::RuntimeDebug; use sr_primitives::{helpers_128bit::multiply_by_rational, Perbill, Rational128}; use sr_primitives::traits::{Zero, Convert, Member, SimpleArithmetic, Saturating, Bounded}; @@ -54,8 +55,7 @@ pub type ExtendedBalance = u128; const DEN: u128 = u128::max_value(); /// A candidate entity for phragmen election. -#[derive(Clone, Default)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(Clone, Default, RuntimeDebug)] pub struct Candidate { /// Identifier. pub who: AccountId, @@ -68,8 +68,7 @@ pub struct Candidate { } /// A voter entity. -#[derive(Clone, Default)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(Clone, Default, RuntimeDebug)] pub struct Voter { /// Identifier. who: AccountId, @@ -82,8 +81,7 @@ pub struct Voter { } /// A candidate being backed by a voter. -#[derive(Clone, Default)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(Clone, Default, RuntimeDebug)] pub struct Edge { /// Identifier. who: AccountId, @@ -100,7 +98,7 @@ pub type PhragmenAssignment = (AccountId, Perbill); pub type PhragmenStakedAssignment = (AccountId, ExtendedBalance); /// Final result of the phragmen election. -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(RuntimeDebug)] pub struct PhragmenResult { /// Just winners zipped with their approval stake. Note that the approval stake is merely the /// sub of their received stake and could be used for very basic sorting and approval voting. @@ -117,8 +115,7 @@ pub struct PhragmenResult { /// /// This, at the current version, resembles the `Exposure` defined in the staking SRML module, yet /// they do not necessarily have to be the same. -#[derive(Default)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(Default, RuntimeDebug)] pub struct Support { /// The amount of support as the effect of self-vote. pub own: ExtendedBalance, diff --git a/core/primitives/Cargo.toml b/core/primitives/Cargo.toml index a527f16c1c..557ce55b88 100644 --- a/core/primitives/Cargo.toml +++ b/core/primitives/Cargo.toml @@ -8,12 +8,12 @@ edition = "2018" rstd = { package = "sr-std", path = "../sr-std", default-features = false } codec = { package = "parity-scale-codec", version = "1.0.0", default-features = false, features = ["derive"] } rustc-hex = { version = "2.0.1", default-features = false } +log = { version = "0.4.8", default-features = false } serde = { version = "1.0.101", optional = true, features = ["derive"] } twox-hash = { version = "1.5.0", optional = true } byteorder = { version = "1.3.2", default-features = false } primitive-types = { version = "0.5.1", default-features = false, features = ["codec"] } impl-serde = { version = "0.2.1", optional = true } -log = { version = "0.4.8", optional = true } wasmi = { version = "0.5.1", optional = true } hash-db = { version = "0.15.2", default-features = false } hash256-std-hasher = { version = "0.15.2", default-features = false } @@ -31,6 +31,7 @@ num-traits = { version = "0.2.8", default-features = false } zeroize = "0.10.1" lazy_static = { version = "1.4.0", optional = true } parking_lot = { version = "0.9.0", optional = true } +substrate-debug-derive = { version = "2.0.0", path = "./debug-derive" } externalities = { package = "substrate-externalities", path = "../externalities", optional = true } primitives-storage = { package = "substrate-primitives-storage", path = "storage", default-features = false } @@ -51,7 +52,7 @@ bench = false [features] default = ["std"] std = [ - "log", + "log/std", "wasmi", "lazy_static", "parking_lot", @@ -81,6 +82,7 @@ std = [ "schnorrkel", "regex", "num-traits/std", + "substrate-debug-derive/std", "externalities", "primitives-storage/std", ] diff --git a/core/primitives/debug-derive/Cargo.toml b/core/primitives/debug-derive/Cargo.toml new file mode 100644 index 0000000000..9c7b7aa1ba --- /dev/null +++ b/core/primitives/debug-derive/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "substrate-debug-derive" +version = "2.0.0" +authors = ["Parity Technologies "] +edition = "2018" + +[lib] +proc-macro = true + +[dependencies] +quote = "1.0.2" +syn = "1.0.5" +proc-macro2 = "1.0" + +[features] +std = [] + +[dev-dependencies] + diff --git a/core/primitives/debug-derive/src/impls.rs b/core/primitives/debug-derive/src/impls.rs new file mode 100644 index 0000000000..decceca044 --- /dev/null +++ b/core/primitives/debug-derive/src/impls.rs @@ -0,0 +1,217 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +use quote::quote; +use proc_macro2::TokenStream; +use syn::{Data, DeriveInput, parse_quote}; + +pub fn debug_derive(ast: DeriveInput) -> proc_macro::TokenStream { + let name_str = ast.ident.to_string(); + let implementation = implementation::derive(&name_str, &ast.data); + let name = &ast.ident; + let mut generics = ast.generics.clone(); + let (impl_generics, ty_generics, where_clause) = { + let wh = generics.make_where_clause(); + for t in ast.generics.type_params() { + let name = &t.ident; + wh.predicates.push(parse_quote!{ #name : core::fmt::Debug }); + } + generics.split_for_impl() + }; + let gen = quote!{ + impl #impl_generics core::fmt::Debug for #name #ty_generics #where_clause { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + #implementation + } + } + }; + + gen.into() +} + +#[cfg(not(feature = "std"))] +mod implementation { + use super::*; + + /// Derive the inner implementation of `Debug::fmt` function. + /// + /// Non-std environment. We do nothing to prevent bloating the size of runtime. + /// Implement `Printable` if you need to print the details. + pub fn derive(_name_str: &str, _data: &Data) -> TokenStream { + quote! { + fmt.write_str("") + } + } +} + +#[cfg(feature = "std")] +mod implementation { + use super::*; + use proc_macro2::Span; + use syn::{Ident, Index, token::SelfValue}; + + /// Derive the inner implementation of `Debug::fmt` function. + pub fn derive(name_str: &str, data: &Data) -> TokenStream { + match *data { + Data::Struct(ref s) => derive_struct(&name_str, &s.fields), + Data::Union(ref u) => derive_fields(&name_str, Fields::new(u.fields.named.iter(), None)), + Data::Enum(ref e) => derive_enum(&name_str, &e), + } + } + + enum Fields { + Indexed { + indices: Vec, + }, + Unnamed { + vars: Vec, + }, + Named { + names: Vec, + this: Option, + }, + } + + impl Fields { + fn new<'a>(fields: impl Iterator, this: Option) -> Self { + let mut indices = vec![]; + let mut names = vec![]; + + for (i, f) in fields.enumerate() { + if let Some(ident) = f.ident.clone() { + names.push(ident); + } else { + indices.push(Index::from(i)); + } + } + + if names.is_empty() { + Self::Indexed { + indices, + } + } else { + Self::Named { + names, + this, + } + } + } + } + + fn derive_fields<'a>( + name_str: &str, + fields: Fields, + ) -> TokenStream { + match fields { + Fields::Named { names, this } => { + let names_str: Vec<_> = names.iter() + .map(|x| x.to_string()) + .collect(); + + let fields = match this { + None => quote! { #( .field(#names_str, #names) )* }, + Some(this) => quote! { #( .field(#names_str, &#this.#names) )* }, + }; + + quote! { + fmt.debug_struct(#name_str) + #fields + .finish() + } + + }, + Fields::Indexed { indices } => { + quote! { + fmt.debug_tuple(#name_str) + #( .field(&self.#indices) )* + .finish() + } + }, + Fields::Unnamed { vars } => { + quote! { + fmt.debug_tuple(#name_str) + #( .field(#vars) )* + .finish() + } + }, + } + } + + fn derive_enum( + name: &str, + e: &syn::DataEnum, + ) -> TokenStream { + let v = e.variants + .iter() + .map(|v| { + let name = format!("{}::{}", name, v.ident); + let ident = &v.ident; + match v.fields { + syn::Fields::Named(ref f) => { + let names: Vec<_> = f.named.iter().flat_map(|f| f.ident.clone()).collect(); + let fields_impl = derive_fields(&name, Fields::Named { + names: names.clone(), + this: None, + }); + (ident, (quote!{ { #( ref #names ),* } }, fields_impl)) + }, + syn::Fields::Unnamed(ref f) => { + let names = f.unnamed.iter() + .enumerate() + .map(|(id, _)| Ident::new(&format!("a{}", id), Span::call_site())) + .collect::>(); + let fields_impl = derive_fields(&name, Fields::Unnamed { vars: names.clone() }); + (ident, (quote! { ( #( ref #names ),* ) }, fields_impl)) + }, + syn::Fields::Unit => { + let fields_impl = derive_fields(&name, Fields::Indexed { indices: vec![] }); + (ident, (quote! { }, fields_impl)) + }, + } + }); + + type Vecs = (Vec, Vec); + let (variants, others): Vecs<_, _> = v.unzip(); + let (match_fields, variants_impl): Vecs<_, _> = others.into_iter().unzip(); + + quote! { + match self { + #( Self::#variants #match_fields => #variants_impl, )* + _ => Ok(()), + } + } + } + + fn derive_struct( + name_str: &str, + fields: &syn::Fields, + ) -> TokenStream { + match *fields { + syn::Fields::Named(ref f) => derive_fields( + name_str, + Fields::new(f.named.iter(), Some(syn::Token!(self)(Span::call_site()))), + ), + syn::Fields::Unnamed(ref f) => derive_fields( + name_str, + Fields::new(f.unnamed.iter(), None), + ), + syn::Fields::Unit => derive_fields( + name_str, + Fields::Indexed { indices: vec![] }, + ), + } + } +} diff --git a/core/primitives/debug-derive/src/lib.rs b/core/primitives/debug-derive/src/lib.rs new file mode 100644 index 0000000000..5e6cf6098b --- /dev/null +++ b/core/primitives/debug-derive/src/lib.rs @@ -0,0 +1,44 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +//! Macros to derive runtime debug implementation. +//! +//! This custom derive implements a `core::fmt::Debug` trait, +//! but in case the `std` feature is enabled the implementation +//! will actually print out the structure as regular `derive(Debug)` +//! would do. If `std` is disabled the implementation will be empty. +//! +//! This behaviour is useful to prevent bloating the runtime WASM +//! blob from unneeded code. +//! +//! ```rust +//! #[derive(substrate_debug_derive::RuntimeDebug)] +//! struct MyStruct; +//! +//! assert_eq!(format!("{:?}", MyStruct), "MyStruct"); +//! ``` + +extern crate proc_macro; + +mod impls; + +use proc_macro::TokenStream; + +#[proc_macro_derive(RuntimeDebug)] +pub fn debug_derive(input: TokenStream) -> TokenStream { + impls::debug_derive(syn::parse_macro_input!(input)) +} + diff --git a/core/primitives/debug-derive/tests/tests.rs b/core/primitives/debug-derive/tests/tests.rs new file mode 100644 index 0000000000..63ad6a3e8d --- /dev/null +++ b/core/primitives/debug-derive/tests/tests.rs @@ -0,0 +1,63 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +use substrate_debug_derive::RuntimeDebug; + +#[derive(RuntimeDebug)] +struct Unnamed(u64, String); + +#[derive(RuntimeDebug)] +struct Named { + a: u64, + b: String, +} + +#[derive(RuntimeDebug)] +enum EnumLongName { + A, + B(A, String), + VariantLongName { + a: A, + b: String, + }, +} + + +#[test] +fn should_display_proper_debug() { + use self::EnumLongName as Enum; + + assert_eq!( + format!("{:?}", Unnamed(1, "abc".into())), + "Unnamed(1, \"abc\")" + ); + assert_eq!( + format!("{:?}", Named { a: 1, b: "abc".into() }), + "Named { a: 1, b: \"abc\" }" + ); + assert_eq!( + format!("{:?}", Enum::::A), + "EnumLongName::A" + ); + assert_eq!( + format!("{:?}", Enum::B(1, "abc".into())), + "EnumLongName::B(1, \"abc\")" + ); + assert_eq!( + format!("{:?}", Enum::VariantLongName { a: 1, b: "abc".into() }), + "EnumLongName::VariantLongName { a: 1, b: \"abc\" }" + ); +} diff --git a/core/primitives/src/crypto.rs b/core/primitives/src/crypto.rs index 8a336783b7..588f3bc6e2 100644 --- a/core/primitives/src/crypto.rs +++ b/core/primitives/src/crypto.rs @@ -43,7 +43,7 @@ pub const DEV_PHRASE: &str = "bottom drive obey lake curtain smoke basket hold r pub const DEV_ADDRESS: &str = "5DfhGyQdFobKM8NsWvEeAKk5EQQgYe9AydgJ7rMB6E1EqRzV"; /// The infallible type. -#[derive(Debug)] +#[derive(crate::RuntimeDebug)] pub enum Infallible {} /// The length of the junction identifier. Note that this is also referred to as the @@ -743,7 +743,7 @@ pub trait CryptoType { /// Values whose first character is `_` are reserved for private use and won't conflict with any /// public modules. #[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Encode, Decode)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(crate::RuntimeDebug)] pub struct KeyTypeId(pub [u8; 4]); impl From for KeyTypeId { diff --git a/core/primitives/src/ed25519.rs b/core/primitives/src/ed25519.rs index b674a150c4..ff3b21e160 100644 --- a/core/primitives/src/ed25519.rs +++ b/core/primitives/src/ed25519.rs @@ -130,12 +130,17 @@ impl std::fmt::Display for Public { } } -#[cfg(feature = "std")] -impl std::fmt::Debug for Public { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { +impl rstd::fmt::Debug for Public { + #[cfg(feature = "std")] + fn fmt(&self, f: &mut rstd::fmt::Formatter) -> rstd::fmt::Result { let s = self.to_ss58check(); write!(f, "{} ({}...)", crate::hexdisplay::HexDisplay::from(&self.0), &s[0..8]) } + + #[cfg(not(feature = "std"))] + fn fmt(&self, _: &mut rstd::fmt::Formatter) -> rstd::fmt::Result { + Ok(()) + } } #[cfg(feature = "std")] @@ -223,11 +228,16 @@ impl AsMut<[u8]> for Signature { } } -#[cfg(feature = "std")] -impl std::fmt::Debug for Signature { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { +impl rstd::fmt::Debug for Signature { + #[cfg(feature = "std")] + fn fmt(&self, f: &mut rstd::fmt::Formatter) -> rstd::fmt::Result { write!(f, "{}", crate::hexdisplay::HexDisplay::from(&self.0)) } + + #[cfg(not(feature = "std"))] + fn fmt(&self, _: &mut rstd::fmt::Formatter) -> rstd::fmt::Result { + Ok(()) + } } #[cfg(feature = "std")] diff --git a/core/primitives/src/hexdisplay.rs b/core/primitives/src/hexdisplay.rs index 87be587a7d..6765ce517e 100644 --- a/core/primitives/src/hexdisplay.rs +++ b/core/primitives/src/hexdisplay.rs @@ -24,8 +24,8 @@ impl<'a> HexDisplay<'a> { pub fn from(d: &'a R) -> Self { HexDisplay(d.as_bytes_ref()) } } -impl<'a> ::core::fmt::Display for HexDisplay<'a> { - fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> { +impl<'a> rstd::fmt::Display for HexDisplay<'a> { + fn fmt(&self, f: &mut rstd::fmt::Formatter) -> Result<(), rstd::fmt::Error> { if self.0.len() < 1027 { for byte in self.0 { f.write_fmt(format_args!("{:02x}", byte))?; @@ -43,8 +43,8 @@ impl<'a> ::core::fmt::Display for HexDisplay<'a> { } } -impl<'a> core::fmt::Debug for HexDisplay<'a> { - fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> { +impl<'a> rstd::fmt::Debug for HexDisplay<'a> { + fn fmt(&self, f: &mut rstd::fmt::Formatter) -> Result<(), rstd::fmt::Error> { for byte in self.0 { f.write_fmt(format_args!("{:02x}", byte))?; } diff --git a/core/primitives/src/lib.rs b/core/primitives/src/lib.rs index 0a1f80aaa9..48d3d998fa 100644 --- a/core/primitives/src/lib.rs +++ b/core/primitives/src/lib.rs @@ -42,6 +42,8 @@ pub use serde;// << for macro #[doc(hidden)] pub use codec::{Encode, Decode};// << for macro +pub use substrate_debug_derive::RuntimeDebug; + #[cfg(feature = "std")] pub use impl_serde::serialize as bytes; @@ -116,8 +118,8 @@ impl ExecutionContext { } /// Hex-serialized shim for `Vec`. -#[derive(PartialEq, Eq, Clone)] -#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug, Hash, PartialOrd, Ord))] +#[derive(PartialEq, Eq, Clone, RuntimeDebug)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Hash, PartialOrd, Ord))] pub struct Bytes(#[cfg_attr(feature = "std", serde(with="bytes"))] pub Vec); impl From> for Bytes { @@ -162,8 +164,8 @@ pub enum NativeOrEncoded { } #[cfg(feature = "std")] -impl ::std::fmt::Debug for NativeOrEncoded { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { +impl rstd::fmt::Debug for NativeOrEncoded { + fn fmt(&self, f: &mut rstd::fmt::Formatter) -> rstd::fmt::Result { hexdisplay::HexDisplay::from(&self.as_encoded().as_ref()).fmt(f) } } @@ -229,3 +231,58 @@ pub trait TypeId { /// Simple 4 byte identifier. const TYPE_ID: [u8; 4]; } + +/// A log level matching the one from `log` crate. +/// +/// Used internally by `runtime_io::log` method. +#[repr(u32)] +pub enum LogLevel { + /// `Error` log level. + Error = 1, + /// `Warn` log level. + Warn = 2, + /// `Info` log level. + Info = 3, + /// `Debug` log level. + Debug = 4, + /// `Trace` log level. + Trace = 5, +} + +impl From for LogLevel { + fn from(val: u32) -> Self { + match val { + x if x == LogLevel::Warn as u32 => LogLevel::Warn, + x if x == LogLevel::Info as u32 => LogLevel::Info, + x if x == LogLevel::Debug as u32 => LogLevel::Debug, + x if x == LogLevel::Trace as u32 => LogLevel::Trace, + _ => LogLevel::Error, + } + } +} + +impl From for LogLevel { + fn from(l: log::Level) -> Self { + use log::Level::*; + match l { + Error => Self::Error, + Warn => Self::Warn, + Info => Self::Info, + Debug => Self::Debug, + Trace => Self::Trace, + } + } +} + +impl From for log::Level { + fn from(l: LogLevel) -> Self { + use self::LogLevel::*; + match l { + Error => Self::Error, + Warn => Self::Warn, + Info => Self::Info, + Debug => Self::Debug, + Trace => Self::Trace, + } + } +} diff --git a/core/primitives/src/offchain.rs b/core/primitives/src/offchain.rs index 84fee530f6..27bd29a00d 100644 --- a/core/primitives/src/offchain.rs +++ b/core/primitives/src/offchain.rs @@ -18,12 +18,12 @@ use codec::{Encode, Decode}; use rstd::{prelude::{Vec, Box}, convert::TryFrom}; +use crate::RuntimeDebug; pub use crate::crypto::KeyTypeId; /// A type of supported crypto. -#[derive(Clone, Copy, PartialEq, Eq, Encode, Decode)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(Clone, Copy, PartialEq, Eq, Encode, Decode, RuntimeDebug)] #[repr(C)] pub enum StorageKind { /// Persistent storage is non-revertible and not fork-aware. It means that any value @@ -59,8 +59,8 @@ impl From for u32 { } /// Opaque type for offchain http requests. -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -#[cfg_attr(feature = "std", derive(Debug, Hash))] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug)] +#[cfg_attr(feature = "std", derive(Hash))] pub struct HttpRequestId(pub u16); impl From for u32 { @@ -70,8 +70,7 @@ impl From for u32 { } /// An error enum returned by some http methods. -#[derive(Clone, Copy, PartialEq, Eq)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(Clone, Copy, PartialEq, Eq, RuntimeDebug)] #[repr(C)] pub enum HttpError { /// The requested action couldn't been completed within a deadline. @@ -102,8 +101,7 @@ impl From for u32 { } /// Status of the HTTP request -#[derive(Clone, Copy, PartialEq, Eq)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(Clone, Copy, PartialEq, Eq, RuntimeDebug)] pub enum HttpRequestStatus { /// Deadline was reached while we waited for this request to finish. /// @@ -149,8 +147,7 @@ impl TryFrom for HttpRequestStatus { /// A blob to hold information about the local node's network state /// without committing to its format. -#[derive(Clone, Eq, PartialEq, Encode, Decode)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug)] pub struct OpaqueNetworkState { /// PeerId of the local node. pub peer_id: OpaquePeerId, @@ -159,8 +156,7 @@ pub struct OpaqueNetworkState { } /// Simple blob to hold a `PeerId` without committing to its format. -#[derive(Default, Clone, Eq, PartialEq, Encode, Decode)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(Default, Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug)] pub struct OpaquePeerId(pub Vec); impl OpaquePeerId { @@ -171,8 +167,7 @@ impl OpaquePeerId { } /// Simple blob to hold a `Multiaddr` without committing to its format. -#[derive(Clone, Eq, PartialEq, Encode, Decode)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug)] pub struct OpaqueMultiaddr(pub Vec); impl OpaqueMultiaddr { @@ -183,13 +178,11 @@ impl OpaqueMultiaddr { } /// Opaque timestamp type -#[derive(Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Default)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Default, RuntimeDebug)] pub struct Timestamp(u64); /// Duration type -#[derive(Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Default)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Default, RuntimeDebug)] pub struct Duration(u64); impl Duration { diff --git a/core/primitives/src/sandbox.rs b/core/primitives/src/sandbox.rs index e47a30ca5b..dd91ad6a1f 100644 --- a/core/primitives/src/sandbox.rs +++ b/core/primitives/src/sandbox.rs @@ -21,12 +21,12 @@ use rstd::vec::Vec; /// Error error that can be returned from host function. #[derive(Encode, Decode)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(crate::RuntimeDebug)] pub struct HostError; /// Representation of a typed wasm value. #[derive(Clone, Copy, PartialEq, Encode, Decode)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(crate::RuntimeDebug)] pub enum TypedValue { /// Value of 32-bit signed or unsigned integer. #[codec(index = "1")] @@ -86,7 +86,7 @@ impl From for ::wasmi::RuntimeValue { /// /// Basically a `TypedValue` plus `Unit`, for functions which return nothing. #[derive(Clone, Copy, PartialEq, Encode, Decode)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(crate::RuntimeDebug)] pub enum ReturnValue { /// For returning nothing. Unit, @@ -119,7 +119,7 @@ fn return_value_encoded_max_size() { /// Describes an entity to define or import into the environment. #[derive(Clone, PartialEq, Eq, Encode, Decode)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(crate::RuntimeDebug)] pub enum ExternEntity { /// Function that is specified by an index in a default table of /// a module that creates the sandbox. @@ -137,7 +137,7 @@ pub enum ExternEntity { /// Each entry has a two-level name and description of an entity /// being defined. #[derive(Clone, PartialEq, Eq, Encode, Decode)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(crate::RuntimeDebug)] pub struct Entry { /// Module name of which corresponding entity being defined. pub module_name: Vec, @@ -149,7 +149,7 @@ pub struct Entry { /// Definition of runtime that could be used by sandboxed code. #[derive(Clone, PartialEq, Eq, Encode, Decode)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(crate::RuntimeDebug)] pub struct EnvironmentDefinition { /// Vector of all entries in the environment definition. pub entries: Vec, diff --git a/core/primitives/src/sr25519.rs b/core/primitives/src/sr25519.rs index ed8bb72c9e..f2160b88b7 100644 --- a/core/primitives/src/sr25519.rs +++ b/core/primitives/src/sr25519.rs @@ -129,12 +129,20 @@ impl std::fmt::Display for Public { } } -#[cfg(feature = "std")] -impl std::fmt::Debug for Public { - fn fmt(&self, f: &mut std::fmt::Formatter) -> ::std::fmt::Result { +#[cfg(not(feature = "std"))] +use core as std; + +impl rstd::fmt::Debug for Public { + #[cfg(feature = "std")] + fn fmt(&self, f: &mut rstd::fmt::Formatter) -> rstd::fmt::Result { let s = self.to_ss58check(); write!(f, "{} ({}...)", crate::hexdisplay::HexDisplay::from(&self.0), &s[0..8]) } + + #[cfg(not(feature = "std"))] + fn fmt(&self, _: &mut rstd::fmt::Formatter) -> rstd::fmt::Result { + Ok(()) + } } #[cfg(feature = "std")] @@ -231,11 +239,16 @@ impl From for Signature { } } -#[cfg(feature = "std")] -impl std::fmt::Debug for Signature { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { +impl rstd::fmt::Debug for Signature { + #[cfg(feature = "std")] + fn fmt(&self, f: &mut rstd::fmt::Formatter) -> rstd::fmt::Result { write!(f, "{}", crate::hexdisplay::HexDisplay::from(&self.0)) } + + #[cfg(not(feature = "std"))] + fn fmt(&self, _: &mut rstd::fmt::Formatter) -> rstd::fmt::Result { + Ok(()) + } } #[cfg(feature = "std")] diff --git a/core/primitives/storage/Cargo.toml b/core/primitives/storage/Cargo.toml index 5b1ed37d6a..7bb2b95623 100644 --- a/core/primitives/storage/Cargo.toml +++ b/core/primitives/storage/Cargo.toml @@ -9,6 +9,7 @@ description = "Storage related primitives" rstd = { package = "sr-std", path = "../../sr-std", default-features = false } serde = { version = "1.0.101", optional = true, features = ["derive"] } impl-serde = { version = "0.2.1", optional = true } +substrate-debug-derive = { version = "2.0.0", path = "../debug-derive" } [features] default = [ "std" ] diff --git a/core/primitives/storage/src/lib.rs b/core/primitives/storage/src/lib.rs index 334779ed5f..dcdc223994 100644 --- a/core/primitives/storage/src/lib.rs +++ b/core/primitives/storage/src/lib.rs @@ -20,27 +20,29 @@ #[cfg(feature = "std")] use serde::{Serialize, Deserialize}; +use substrate_debug_derive::RuntimeDebug; use rstd::{vec::Vec, borrow::Cow}; /// Storage key. -#[derive(PartialEq, Eq)] -#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug, Hash, PartialOrd, Ord, Clone))] +#[derive(PartialEq, Eq, RuntimeDebug)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Hash, PartialOrd, Ord, Clone))] pub struct StorageKey( #[cfg_attr(feature = "std", serde(with="impl_serde::serialize"))] pub Vec, ); /// Storage data associated to a [`StorageKey`]. -#[derive(PartialEq, Eq)] -#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug, Hash, PartialOrd, Ord, Clone))] +#[derive(PartialEq, Eq, RuntimeDebug)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Hash, PartialOrd, Ord, Clone))] pub struct StorageData( #[cfg_attr(feature = "std", serde(with="impl_serde::serialize"))] pub Vec, ); /// Storage change set -#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug, PartialEq, Eq))] +#[derive(RuntimeDebug)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize, PartialEq, Eq))] #[cfg_attr(feature = "std", serde(rename_all = "camelCase"))] pub struct StorageChangeSet { /// Block hash diff --git a/core/sr-arithmetic/Cargo.toml b/core/sr-arithmetic/Cargo.toml index d98404db94..3962daf493 100644 --- a/core/sr-arithmetic/Cargo.toml +++ b/core/sr-arithmetic/Cargo.toml @@ -5,11 +5,12 @@ authors = ["Parity Technologies "] edition = "2018" [dependencies] -num-traits = { version = "0.2.8", default-features = false } -serde = { version = "1.0.101", optional = true, features = ["derive"] } codec = { package = "parity-scale-codec", version = "1.0.0", default-features = false, features = ["derive"] } -rstd = { package = "sr-std", path = "../sr-std", default-features = false } integer-sqrt = "0.1.2" +num-traits = { version = "0.2.8", default-features = false } +rstd = { package = "sr-std", path = "../sr-std", default-features = false } +serde = { version = "1.0.101", optional = true, features = ["derive"] } +substrate-debug-derive = { path = "../primitives/debug-derive", default-features = false } [dev-dependencies] primitive-types = "0.6.0" @@ -19,8 +20,9 @@ rand = "0.7.2" bench = [] default = ["std"] std = [ - "serde", + "codec/std", "num-traits/std", "rstd/std", - "codec/std", + "serde", + "substrate-debug-derive/std", ] diff --git a/core/sr-arithmetic/src/biguint.rs b/core/sr-arithmetic/src/biguint.rs index d90ad4862b..b7d93c2f0d 100644 --- a/core/sr-arithmetic/src/biguint.rs +++ b/core/sr-arithmetic/src/biguint.rs @@ -427,8 +427,8 @@ impl BigUint { } } -#[cfg(feature = "std")] impl rstd::fmt::Debug for BigUint { + #[cfg(feature = "std")] fn fmt(&self, f: &mut rstd::fmt::Formatter<'_>) -> rstd::fmt::Result { write!( f, @@ -437,6 +437,12 @@ impl rstd::fmt::Debug for BigUint { u128::try_from(self.clone()).unwrap_or(0), ) } + + #[cfg(not(feature = "std"))] + fn fmt(&self, _: &mut rstd::fmt::Formatter<'_>) -> rstd::fmt::Result { + Ok(()) + } + } impl PartialEq for BigUint { diff --git a/core/sr-arithmetic/src/fixed64.rs b/core/sr-arithmetic/src/fixed64.rs index 7dfc8414d2..3bac75898e 100644 --- a/core/sr-arithmetic/src/fixed64.rs +++ b/core/sr-arithmetic/src/fixed64.rs @@ -144,11 +144,16 @@ impl CheckedAdd for Fixed64 { } } -#[cfg(feature = "std")] impl rstd::fmt::Debug for Fixed64 { - fn fmt(&self, f: &mut rstd::fmt::Formatter<'_>) -> rstd::fmt::Result { + #[cfg(feature = "std")] + fn fmt(&self, f: &mut rstd::fmt::Formatter) -> rstd::fmt::Result { write!(f, "Fixed64({},{})", self.0 / DIV, (self.0 % DIV) / 1000) } + + #[cfg(not(feature = "std"))] + fn fmt(&self, _: &mut rstd::fmt::Formatter) -> rstd::fmt::Result { + Ok(()) + } } #[cfg(test)] diff --git a/core/sr-arithmetic/src/per_things.rs b/core/sr-arithmetic/src/per_things.rs index afd8100a84..2dd1e62d0b 100644 --- a/core/sr-arithmetic/src/per_things.rs +++ b/core/sr-arithmetic/src/per_things.rs @@ -20,14 +20,15 @@ use serde::{Serialize, Deserialize}; use rstd::{ops, prelude::*, convert::TryInto}; use codec::{Encode, Decode, CompactAs}; use crate::traits::{SaturatedConversion, UniqueSaturatedInto, Saturating}; +use substrate_debug_derive::RuntimeDebug; macro_rules! implement_per_thing { ($name:ident, $test_mod:ident, [$($test_units:tt),+], $max:tt, $type:ty, $upper_type:ty, $title:expr $(,)?) => { /// A fixed point representation of a number between in the range [0, 1]. /// #[doc = $title] - #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug, Ord, PartialOrd))] - #[derive(Encode, Decode, Default, Copy, Clone, PartialEq, Eq, CompactAs)] + #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Ord, PartialOrd))] + #[derive(Encode, Decode, Default, Copy, Clone, PartialEq, Eq, RuntimeDebug, CompactAs)] pub struct $name($type); impl $name { @@ -189,7 +190,7 @@ macro_rules! implement_per_thing { #[cfg(test)] mod $test_mod { use codec::{Encode, Decode}; - use super::{$name, Saturating}; + use super::{$name, Saturating, RuntimeDebug}; use crate::traits::Zero; @@ -208,7 +209,7 @@ macro_rules! implement_per_thing { assert!(<$upper_type>::from($max).checked_mul($max.into()).is_some()); } - #[derive(Encode, Decode, PartialEq, Eq, Debug)] + #[derive(Encode, Decode, PartialEq, Eq, RuntimeDebug)] struct WithCompact { data: T, } diff --git a/core/sr-arithmetic/src/rational128.rs b/core/sr-arithmetic/src/rational128.rs index 706d6a5eba..3247321199 100644 --- a/core/sr-arithmetic/src/rational128.rs +++ b/core/sr-arithmetic/src/rational128.rs @@ -17,10 +17,10 @@ use rstd::{cmp::Ordering, prelude::*}; use crate::helpers_128bit; use num_traits::Zero; +use substrate_debug_derive::RuntimeDebug; /// A wrapper for any rational number with a 128 bit numerator and denominator. -#[derive(Clone, Copy, Default, Eq)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(Clone, Copy, Default, Eq, RuntimeDebug)] pub struct Rational128(u128, u128); impl Rational128 { diff --git a/core/sr-io/Cargo.toml b/core/sr-io/Cargo.toml index e2b681b75b..4d140d289d 100644 --- a/core/sr-io/Cargo.toml +++ b/core/sr-io/Cargo.toml @@ -9,15 +9,16 @@ edition = "2018" rustc_version = "0.2.3" [dependencies] -rstd = { package = "sr-std", path = "../sr-std", default-features = false } -primitives = { package = "substrate-primitives", path = "../primitives", default-features = false } codec = { package = "parity-scale-codec", version = "1.0.0", default-features = false } hash-db = { version = "0.15.2", default-features = false } +primitives = { package = "substrate-primitives", path = "../primitives", default-features = false } +rstd = { package = "sr-std", path = "../sr-std", default-features = false } libsecp256k1 = { version = "0.3.0", optional = true } tiny-keccak = { version = "1.5.0", optional = true } substrate-state-machine = { path = "../state-machine", optional = true } trie = { package = "substrate-trie", path = "../trie", optional = true } externalities = { package = "substrate-externalities", path = "../externalities", optional = true } +log = { version = "0.4.8", optional = true } [features] default = ["std"] @@ -31,6 +32,7 @@ std = [ "libsecp256k1", "tiny-keccak", "externalities", + "log", ] nightly = [] strict = [] diff --git a/core/sr-io/src/lib.rs b/core/sr-io/src/lib.rs index 24f964c7b5..b0274286dc 100644 --- a/core/sr-io/src/lib.rs +++ b/core/sr-io/src/lib.rs @@ -33,6 +33,7 @@ use primitives::{ offchain::{ Timestamp, HttpRequestId, HttpRequestStatus, HttpError, StorageKind, OpaqueNetworkState, }, + LogLevel, }; /// Error verifying ECDSA signature @@ -158,6 +159,20 @@ export_api! { fn print_utf8(utf8: &[u8]); /// Print any `u8` slice as hex. fn print_hex(data: &[u8]); + + /// Request to print a log message (stderr) on the host. + /// + /// Note that this will be only displayed if the host + /// is enabed to display log messages with given + /// level and target. + /// + /// Instead of using directly, prefer setting up `RuntimeLogger` + /// and using `log` macros. + fn log( + level: LogLevel, + target: &[u8], + message: &[u8] + ); } } diff --git a/core/sr-io/with_std.rs b/core/sr-io/with_std.rs index e431ae1f6e..de40115cbe 100644 --- a/core/sr-io/with_std.rs +++ b/core/sr-io/with_std.rs @@ -192,6 +192,22 @@ impl OtherApi for () { fn print_hex(data: &[u8]) { println!("{}", HexDisplay::from(&data)); } + + fn log( + level: LogLevel, + target: &[u8], + message: &[u8], + ) { + let target = std::str::from_utf8(target).unwrap_or("invalid utf8"); + let msg = std::str::from_utf8(message).unwrap_or("invalid utf8"); + + log::log!( + target: target, + log::Level::from(level), + "{}", + msg, + ) + } } impl CryptoApi for () { diff --git a/core/sr-io/without_std.rs b/core/sr-io/without_std.rs index 90ec5a9ee4..789098185e 100644 --- a/core/sr-io/without_std.rs +++ b/core/sr-io/without_std.rs @@ -160,6 +160,14 @@ pub mod ext { fn ext_print_hex(data: *const u8, len: u32); /// Print a number fn ext_print_num(value: u64); + /// Print a log line if logging for given level and target is enabled. + fn ext_log( + level: u32, + target_data: *const u8, + target_len: u32, + message_data: *const u8, + message_len: u32, + ); /// Set value for key in storage. fn ext_set_storage(key_data: *const u8, key_len: u32, value_data: *const u8, value_len: u32); @@ -780,6 +788,22 @@ impl OtherApi for () { ext_print_hex.get()(data.as_ptr(), data.len() as u32); } } + + fn log( + level: LogLevel, + target: &[u8], + message: &[u8] + ) { + unsafe { + ext_log.get()( + level as u32, + target.as_ptr(), + target.len() as u32, + message.as_ptr(), + message.len() as u32, + ) + } + } } impl HashingApi for () { diff --git a/core/sr-primitives/Cargo.toml b/core/sr-primitives/Cargo.toml index 249b89acee..d330301426 100644 --- a/core/sr-primitives/Cargo.toml +++ b/core/sr-primitives/Cargo.toml @@ -26,13 +26,13 @@ substrate-offchain = { path = "../offchain" } bench = [] default = ["std"] std = [ - "serde", - "log", - "rstd/std", - "runtime_io/std", - "codec/std", - "primitives/std", "app-crypto/std", "arithmetic/std", + "codec/std", + "log", + "primitives/std", "rand", + "rstd/std", + "runtime_io/std", + "serde", ] diff --git a/core/sr-primitives/src/curve.rs b/core/sr-primitives/src/curve.rs index dc6316bd47..6f25af3e10 100644 --- a/core/sr-primitives/src/curve.rs +++ b/core/sr-primitives/src/curve.rs @@ -20,8 +20,7 @@ use crate::{Perbill, traits::{SimpleArithmetic, SaturatedConversion}}; use core::ops::Sub; /// Piecewise Linear function in [0, 1] -> [0, 1]. -#[cfg_attr(feature = "std", derive(Debug))] -#[derive(PartialEq, Eq)] +#[derive(PartialEq, Eq, primitives::RuntimeDebug)] pub struct PiecewiseLinear<'a> { /// Array of points. Must be in order from the lowest abscissas to the highest. pub points: &'a [(Perbill, Perbill)] diff --git a/core/sr-primitives/src/generic/block.rs b/core/sr-primitives/src/generic/block.rs index 29fcaab572..3383e25760 100644 --- a/core/sr-primitives/src/generic/block.rs +++ b/core/sr-primitives/src/generic/block.rs @@ -23,13 +23,14 @@ use std::fmt; use serde::{Deserialize, Serialize}; use rstd::prelude::*; +use primitives::RuntimeDebug; use crate::codec::{Codec, Encode, Decode}; use crate::traits::{self, Member, Block as BlockT, Header as HeaderT, MaybeSerialize}; use crate::Justification; /// Something to identify a block. -#[derive(PartialEq, Eq, Clone)] -#[cfg_attr(feature = "std", derive(Debug, Serialize))] +#[derive(PartialEq, Eq, Clone, RuntimeDebug)] +#[cfg_attr(feature = "std", derive(Serialize))] #[cfg_attr(feature = "std", serde(rename_all = "camelCase"))] #[cfg_attr(feature = "std", serde(deny_unknown_fields))] pub enum BlockId { @@ -61,8 +62,8 @@ impl fmt::Display for BlockId { } /// Abstraction over a substrate block. -#[derive(PartialEq, Eq, Clone, Encode, Decode)] -#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))] +#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] #[cfg_attr(feature = "std", serde(rename_all = "camelCase"))] #[cfg_attr(feature = "std", serde(deny_unknown_fields))] pub struct Block { @@ -99,8 +100,8 @@ where } /// Abstraction over a substrate block and justification. -#[derive(PartialEq, Eq, Clone, Encode, Decode)] -#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))] +#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] #[cfg_attr(feature = "std", serde(rename_all = "camelCase"))] #[cfg_attr(feature = "std", serde(deny_unknown_fields))] pub struct SignedBlock { diff --git a/core/sr-primitives/src/generic/checked_extrinsic.rs b/core/sr-primitives/src/generic/checked_extrinsic.rs index e8d41325c4..1e030ea1d8 100644 --- a/core/sr-primitives/src/generic/checked_extrinsic.rs +++ b/core/sr-primitives/src/generic/checked_extrinsic.rs @@ -26,8 +26,7 @@ use crate::transaction_validity::TransactionValidity; /// Definition of something that the external world might want to say; its /// existence implies that it has been checked and is good, particularly with /// regards to the signature. -#[derive(PartialEq, Eq, Clone)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(PartialEq, Eq, Clone, primitives::RuntimeDebug)] pub struct CheckedExtrinsic { /// Who this purports to be from and the number of extrinsics have come before /// from the same signer, if anyone (note this is not a signature). diff --git a/core/sr-primitives/src/generic/digest.rs b/core/sr-primitives/src/generic/digest.rs index d2974444e2..83f2c6f174 100644 --- a/core/sr-primitives/src/generic/digest.rs +++ b/core/sr-primitives/src/generic/digest.rs @@ -23,10 +23,11 @@ use rstd::prelude::*; use crate::ConsensusEngineId; use crate::codec::{Decode, Encode, Input, Error}; +use primitives::RuntimeDebug; /// Generic header digest. -#[derive(PartialEq, Eq, Clone, Encode, Decode)] -#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))] +#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] pub struct Digest { /// A list of logs in the digest. pub logs: Vec>, @@ -72,8 +73,7 @@ impl Digest { /// Digest item that is able to encode/decode 'system' digest items and /// provide opaque access to other items. -#[derive(PartialEq, Eq, Clone)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(PartialEq, Eq, Clone, RuntimeDebug)] pub enum DigestItem { /// System digest item that contains the root of changes trie at given /// block. It is created for every block iff runtime supports changes @@ -123,8 +123,7 @@ impl<'a, Hash: Decode> serde::Deserialize<'a> for DigestItem { /// A 'referencing view' for digest item. Does not own its contents. Used by /// final runtime implementations for encoding/decoding its log items. -#[derive(PartialEq, Eq, Clone)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(PartialEq, Eq, Clone, RuntimeDebug)] pub enum DigestItemRef<'a, Hash: 'a> { /// Reference to `DigestItem::ChangesTrieRoot`. ChangesTrieRoot(&'a Hash), diff --git a/core/sr-primitives/src/generic/era.rs b/core/sr-primitives/src/generic/era.rs index 7308a8adc5..305951b1ee 100644 --- a/core/sr-primitives/src/generic/era.rs +++ b/core/sr-primitives/src/generic/era.rs @@ -28,8 +28,8 @@ pub type Period = u64; pub type Phase = u64; /// An era to describe the longevity of a transaction. -#[derive(PartialEq, Eq, Clone, Copy)] -#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] +#[derive(PartialEq, Eq, Clone, Copy, primitives::RuntimeDebug)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] pub enum Era { /// The transaction is valid forever. The genesis hash must be present in the signed content. Immortal, diff --git a/core/sr-primitives/src/generic/header.rs b/core/sr-primitives/src/generic/header.rs index e9a8405fe2..75994749c5 100644 --- a/core/sr-primitives/src/generic/header.rs +++ b/core/sr-primitives/src/generic/header.rs @@ -18,20 +18,21 @@ #[cfg(feature = "std")] use serde::{Deserialize, Serialize}; -#[cfg(feature = "std")] -use log::debug; use crate::codec::{Decode, Encode, Codec, Input, Output, HasCompact, EncodeAsRef, Error}; use crate::traits::{ - self, Member, SimpleArithmetic, SimpleBitOps, MaybeDisplay, Hash as HashT, MaybeSerializeDebug, - MaybeSerializeDebugButNotDeserialize + self, Member, SimpleArithmetic, SimpleBitOps, Hash as HashT, + MaybeSerializeDeserialize, MaybeSerialize, MaybeDisplay, }; use crate::generic::Digest; use primitives::U256; -use core::convert::TryFrom; +use rstd::{ + convert::TryFrom, + fmt::Debug, +}; /// Abstraction over a block header for a substrate chain. -#[derive(PartialEq, Eq, Clone)] -#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))] +#[derive(PartialEq, Eq, Clone, primitives::RuntimeDebug)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] #[cfg_attr(feature = "std", serde(rename_all = "camelCase"))] #[cfg_attr(feature = "std", serde(deny_unknown_fields))] pub struct Header + TryFrom, Hash: HashT> { @@ -103,11 +104,11 @@ impl codec::EncodeLike for Header where {} impl traits::Header for Header where - Number: Member + MaybeSerializeDebug + rstd::hash::Hash + MaybeDisplay + + Number: Member + MaybeSerializeDeserialize + Debug + rstd::hash::Hash + MaybeDisplay + SimpleArithmetic + Codec + Copy + Into + TryFrom, Hash: HashT, Hash::Output: Default + rstd::hash::Hash + Copy + Member + - MaybeSerializeDebugButNotDeserialize + MaybeDisplay + SimpleBitOps + Codec, + MaybeSerialize + Debug + MaybeDisplay + SimpleBitOps + Codec, { type Number = Number; type Hash = ::Output; @@ -127,15 +128,12 @@ impl traits::Header for Header where fn digest(&self) -> &Digest { &self.digest } - #[cfg(feature = "std")] fn digest_mut(&mut self) -> &mut Digest { - debug!(target: "header", "Retrieving mutable reference to digest"); + #[cfg(feature = "std")] + log::debug!(target: "header", "Retrieving mutable reference to digest"); &mut self.digest } - #[cfg(not(feature = "std"))] - fn digest_mut(&mut self) -> &mut Digest { &mut self.digest } - fn new( number: Self::Number, extrinsics_root: Self::Hash, diff --git a/core/sr-primitives/src/generic/unchecked_extrinsic.rs b/core/sr-primitives/src/generic/unchecked_extrinsic.rs index c5ee76e21c..d50314f33b 100644 --- a/core/sr-primitives/src/generic/unchecked_extrinsic.rs +++ b/core/sr-primitives/src/generic/unchecked_extrinsic.rs @@ -16,10 +16,8 @@ //! Generic implementation of an unchecked (pre-verification) extrinsic. -#[cfg(feature = "std")] -use std::fmt; - use rstd::prelude::*; +use rstd::fmt; use runtime_io::blake2_256; use codec::{Decode, Encode, EncodeLike, Input, Error}; use crate::{ @@ -264,7 +262,6 @@ impl s } } -#[cfg(feature = "std")] impl fmt::Debug for UncheckedExtrinsic where diff --git a/core/sr-primitives/src/lib.rs b/core/sr-primitives/src/lib.rs index 590b6fedd7..ea295fbea6 100644 --- a/core/sr-primitives/src/lib.rs +++ b/core/sr-primitives/src/lib.rs @@ -62,6 +62,9 @@ pub use generic::{DigestItem, Digest}; pub use primitives::{TypeId, crypto::{key_types, KeyTypeId, CryptoType}}; pub use app_crypto::RuntimeAppPublic; +/// Re-export `RuntimeDebug`, to avoid dependency clutter. +pub use primitives::RuntimeDebug; + /// Re-export top-level arithmetic stuff. pub use arithmetic::{ Perquintill, Perbill, Permill, Percent, @@ -166,8 +169,7 @@ impl BuildStorage for (StorageOverlay, ChildrenStorageOverlay) { pub type ConsensusEngineId = [u8; 4]; /// Signature verify that can work with any known signature types.. -#[derive(Eq, PartialEq, Clone, Encode, Decode)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(Eq, PartialEq, Clone, Encode, Decode, RuntimeDebug)] pub enum MultiSignature { /// An Ed25519 signature. Ed25519(ed25519::Signature), @@ -194,8 +196,8 @@ impl Default for MultiSignature { } /// Public key for any known crypto algorithm. -#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Encode, Decode)] -#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))] +#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Encode, Decode, RuntimeDebug)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] pub enum MultiSigner { /// An Ed25519 identity. Ed25519(ed25519::Public), @@ -260,8 +262,8 @@ impl Verify for MultiSignature { } /// Signature verify that can work with any known signature types.. -#[derive(Eq, PartialEq, Clone, Default, Encode, Decode)] -#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))] +#[derive(Eq, PartialEq, Clone, Default, Encode, Decode, RuntimeDebug)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] pub struct AnySignature(H512); impl Verify for AnySignature { @@ -289,8 +291,8 @@ impl From for AnySignature { } } -#[derive(Eq, PartialEq, Clone, Copy, Decode, Encode)] -#[cfg_attr(feature = "std", derive(Debug, Serialize))] +#[derive(Eq, PartialEq, Clone, Copy, Decode, Encode, RuntimeDebug)] +#[cfg_attr(feature = "std", derive(Serialize))] /// Reason why an extrinsic couldn't be applied (i.e. invalid extrinsic). pub enum ApplyError { /// General error to do with the permissions of the sender. @@ -341,8 +343,8 @@ impl From for ApplyOutcome { /// Result from attempt to apply an extrinsic. pub type ApplyResult = Result; -#[derive(Eq, PartialEq, Clone, Copy, Encode, Decode)] -#[cfg_attr(feature = "std", derive(Debug, Serialize))] +#[derive(Eq, PartialEq, Clone, Copy, Encode, Decode, RuntimeDebug)] +#[cfg_attr(feature = "std", derive(Serialize))] /// Reason why a dispatch call failed pub struct DispatchError { /// Module index, matching the metadata module index @@ -564,13 +566,19 @@ macro_rules! assert_eq_error_rate { #[derive(PartialEq, Eq, Clone, Default, Encode, Decode)] pub struct OpaqueExtrinsic(pub Vec); -#[cfg(feature = "std")] -impl std::fmt::Debug for OpaqueExtrinsic { - fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { +impl rstd::fmt::Debug for OpaqueExtrinsic { + #[cfg(feature = "std")] + fn fmt(&self, fmt: &mut rstd::fmt::Formatter) -> rstd::fmt::Result { write!(fmt, "{}", primitives::hexdisplay::HexDisplay::from(&self.0)) } + + #[cfg(not(feature = "std"))] + fn fmt(&self, _fmt: &mut rstd::fmt::Formatter) -> rstd::fmt::Result { + Ok(()) + } } + #[cfg(feature = "std")] impl ::serde::Serialize for OpaqueExtrinsic { fn serialize(&self, seq: S) -> Result where S: ::serde::Serializer { diff --git a/core/sr-primitives/src/offchain/http.rs b/core/sr-primitives/src/offchain/http.rs index b68cf28365..77e514d653 100644 --- a/core/sr-primitives/src/offchain/http.rs +++ b/core/sr-primitives/src/offchain/http.rs @@ -51,6 +51,7 @@ use rstd::str; use rstd::prelude::Vec; #[cfg(not(feature = "std"))] use rstd::prelude::vec; +use primitives::RuntimeDebug; use primitives::offchain::{ Timestamp, HttpRequestId as RequestId, @@ -59,8 +60,7 @@ use primitives::offchain::{ }; /// Request method (HTTP verb) -#[derive(Clone, PartialEq, Eq)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(Clone, PartialEq, Eq, RuntimeDebug)] pub enum Method { /// GET request Get, @@ -93,8 +93,7 @@ mod header { use super::*; /// A header type. - #[derive(Clone, PartialEq, Eq)] - #[cfg_attr(feature = "std", derive(Debug))] + #[derive(Clone, PartialEq, Eq, RuntimeDebug)] pub struct Header { name: Vec, value: Vec, @@ -128,8 +127,7 @@ mod header { } /// An HTTP request builder. -#[derive(Clone, PartialEq, Eq)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(Clone, PartialEq, Eq, RuntimeDebug)] pub struct Request<'a, T = Vec<&'static [u8]>> { /// Request method pub method: Method, @@ -249,8 +247,7 @@ impl<'a, I: AsRef<[u8]>, T: IntoIterator> Request<'a, T> { } /// A request error -#[derive(Clone, PartialEq, Eq)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(Clone, PartialEq, Eq, RuntimeDebug)] pub enum Error { /// Deadline has been reached. DeadlineReached, @@ -261,8 +258,7 @@ pub enum Error { } /// A struct representing an uncompleted http request. -#[derive(PartialEq, Eq)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(PartialEq, Eq, RuntimeDebug)] pub struct PendingRequest { /// Request ID pub id: RequestId, @@ -323,7 +319,7 @@ impl PendingRequest { } /// A HTTP response. -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(RuntimeDebug)] pub struct Response { /// Request id pub id: RequestId, @@ -452,8 +448,7 @@ impl Iterator for ResponseBody { } /// A collection of Headers in the response. -#[derive(Clone, PartialEq, Eq)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(Clone, PartialEq, Eq, RuntimeDebug)] pub struct Headers { /// Raw headers pub raw: Vec<(Vec, Vec)>, @@ -483,8 +478,7 @@ impl Headers { } /// A custom iterator traversing all the headers. -#[derive(Clone)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(Clone, RuntimeDebug)] pub struct HeadersIterator<'a> { collection: &'a [(Vec, Vec)], index: Option, diff --git a/core/sr-primitives/src/traits.rs b/core/sr-primitives/src/traits.rs index a384c95e19..0497f094d2 100644 --- a/core/sr-primitives/src/traits.rs +++ b/core/sr-primitives/src/traits.rs @@ -17,10 +17,10 @@ //! Primitives for the runtime modules. use rstd::prelude::*; -use rstd::{self, result, marker::PhantomData, convert::{TryFrom, TryInto}}; +use rstd::{self, result, marker::PhantomData, convert::{TryFrom, TryInto}, fmt::Debug}; use runtime_io; #[cfg(feature = "std")] -use std::fmt::{Debug, Display}; +use std::fmt::Display; #[cfg(feature = "std")] use serde::{Serialize, Deserialize, de::DeserializeOwned}; use primitives::{self, Hasher, Blake2Hasher, TypeId}; @@ -147,7 +147,7 @@ pub trait Lookup { /// context. pub trait StaticLookup { /// Type to lookup from. - type Source: Codec + Clone + PartialEq + MaybeDebug; + type Source: Codec + Clone + PartialEq + Debug; /// Type to lookup into. type Target; /// Attempt a lookup. @@ -159,7 +159,7 @@ pub trait StaticLookup { /// A lookup implementation returning the input value. #[derive(Default)] pub struct IdentityLookup(PhantomData); -impl StaticLookup for IdentityLookup { +impl StaticLookup for IdentityLookup { type Source = T; type Target = T; fn lookup(x: T) -> Result { Ok(x) } @@ -323,10 +323,10 @@ pub trait OffchainWorker { /// Abstraction around hashing // Stupid bug in the Rust compiler believes derived // traits must be fulfilled by all type parameters. -pub trait Hash: 'static + MaybeSerializeDebug + Clone + Eq + PartialEq { +pub trait Hash: 'static + MaybeSerializeDeserialize + Debug + Clone + Eq + PartialEq { /// The hash type produced. - type Output: Member + MaybeSerializeDebug + rstd::hash::Hash + AsRef<[u8]> + AsMut<[u8]> + Copy - + Default + Encode + Decode; + type Output: Member + MaybeSerializeDeserialize + Debug + rstd::hash::Hash + + AsRef<[u8]> + AsMut<[u8]> + Copy + Default + Encode + Decode; /// The associated hash_db Hasher type. type Hasher: Hasher; @@ -353,8 +353,8 @@ pub trait Hash: 'static + MaybeSerializeDebug + Clone + Eq + PartialEq { } /// Blake2-256 Hash implementation. -#[derive(PartialEq, Eq, Clone)] -#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))] +#[derive(PartialEq, Eq, Clone, primitives::RuntimeDebug)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] pub struct BlakeTwo256; impl Hash for BlakeTwo256 { @@ -410,7 +410,7 @@ impl CheckEqual for primitives::H256 { } } -impl CheckEqual for super::generic::DigestItem where H: Encode { +impl CheckEqual for super::generic::DigestItem where H: Encode { #[cfg(feature = "std")] fn check_equal(&self, other: &Self) { if self != other { @@ -447,23 +447,17 @@ macro_rules! impl_maybe_marker { } impl_maybe_marker!( - /// A type that implements Debug when in std environment. - MaybeDebug: Debug; - /// A type that implements Display when in std environment. MaybeDisplay: Display; /// A type that implements Hash when in std environment. - MaybeHash: ::rstd::hash::Hash; + MaybeHash: rstd::hash::Hash; /// A type that implements Serialize when in std environment. MaybeSerialize: Serialize; /// A type that implements Serialize, DeserializeOwned and Debug when in std environment. - MaybeSerializeDebug: Debug, DeserializeOwned, Serialize; - - /// A type that implements Serialize and Debug when in std environment. - MaybeSerializeDebugButNotDeserialize: Debug, Serialize + MaybeSerializeDeserialize: DeserializeOwned, Serialize ); /// A type that provides a randomness beacon. @@ -483,8 +477,8 @@ pub trait RandomnessBeacon { } /// A type that can be used in runtime structures. -pub trait Member: Send + Sync + Sized + MaybeDebug + Eq + PartialEq + Clone + 'static {} -impl Member for T {} +pub trait Member: Send + Sync + Sized + Debug + Eq + PartialEq + Clone + 'static {} +impl Member for T {} /// Determine if a `MemberId` is a valid member. pub trait IsMember { @@ -497,11 +491,13 @@ pub trait IsMember { /// `parent_hash`, as well as a `digest` and a block `number`. /// /// You can also create a `new` one from those fields. -pub trait Header: Clone + Send + Sync + Codec + Eq + MaybeSerializeDebugButNotDeserialize + 'static { +pub trait Header: Clone + Send + Sync + Codec + Eq + MaybeSerialize + Debug + 'static { /// Header number. - type Number: Member + MaybeSerializeDebug + ::rstd::hash::Hash + Copy + MaybeDisplay + SimpleArithmetic + Codec; + type Number: Member + MaybeSerializeDeserialize + Debug + rstd::hash::Hash + + Copy + MaybeDisplay + SimpleArithmetic + Codec; /// Header hash type - type Hash: Member + MaybeSerializeDebug + ::rstd::hash::Hash + Copy + MaybeDisplay + Default + SimpleBitOps + Codec + AsRef<[u8]> + AsMut<[u8]>; + type Hash: Member + MaybeSerializeDeserialize + Debug + rstd::hash::Hash + + Copy + MaybeDisplay + Default + SimpleBitOps + Codec + AsRef<[u8]> + AsMut<[u8]>; /// Hashing algorithm type Hashing: Hash; @@ -549,13 +545,14 @@ pub trait Header: Clone + Send + Sync + Codec + Eq + MaybeSerializeDebugButNotDe /// `Extrinsic` piece of information as well as a `Header`. /// /// You can get an iterator over each of the `extrinsics` and retrieve the `header`. -pub trait Block: Clone + Send + Sync + Codec + Eq + MaybeSerializeDebugButNotDeserialize + 'static { +pub trait Block: Clone + Send + Sync + Codec + Eq + MaybeSerialize + Debug + 'static { /// Type of extrinsics. type Extrinsic: Member + Codec + Extrinsic + MaybeSerialize; /// Header type. type Header: Header; /// Block hash type. - type Hash: Member + MaybeSerializeDebug + ::rstd::hash::Hash + Copy + MaybeDisplay + Default + SimpleBitOps + Codec + AsRef<[u8]> + AsMut<[u8]>; + type Hash: Member + MaybeSerializeDeserialize + Debug + rstd::hash::Hash + + Copy + MaybeDisplay + Default + SimpleBitOps + Codec + AsRef<[u8]> + AsMut<[u8]>; /// Returns a reference to the header. fn header(&self) -> &Self::Header; @@ -661,7 +658,7 @@ pub trait Dispatchable { /// Means by which a transaction may be extended. This type embodies both the data and the logic /// that should be additionally associated with the transaction. It should be plain old data. -pub trait SignedExtension: Codec + MaybeDebug + Sync + Send + Clone + Eq + PartialEq { +pub trait SignedExtension: Codec + Debug + Sync + Send + Clone + Eq + PartialEq { /// The type which encodes the sender identity. type AccountId; @@ -1080,8 +1077,13 @@ macro_rules! impl_opaque_keys { )* } ) => { - #[derive(Default, Clone, PartialEq, Eq, $crate::codec::Encode, $crate::codec::Decode)] - #[cfg_attr(feature = "std", derive(Debug, $crate::serde::Serialize, $crate::serde::Deserialize))] + #[derive( + Default, Clone, PartialEq, Eq, + $crate::codec::Encode, + $crate::codec::Decode, + $crate::RuntimeDebug + )] + #[cfg_attr(feature = "std", derive($crate::serde::Serialize, $crate::serde::Deserialize))] pub struct $name { $( pub $field: $type, @@ -1131,7 +1133,25 @@ pub trait Printable { impl Printable for u8 { fn print(&self) { - u64::from(*self).print() + (*self as u64).print() + } +} + +impl Printable for u32 { + fn print(&self) { + (*self as u64).print() + } +} + +impl Printable for usize { + fn print(&self) { + (*self as u64).print() + } +} + +impl Printable for u64 { + fn print(&self) { + runtime_io::print_num(*self); } } @@ -1147,9 +1167,10 @@ impl Printable for &str { } } -impl Printable for u64 { +#[impl_for_tuples(1, 12)] +impl Printable for Tuple { fn print(&self) { - runtime_io::print_num(*self); + for_tuples!( #( Tuple.print(); )* ) } } diff --git a/core/sr-primitives/src/transaction_validity.rs b/core/sr-primitives/src/transaction_validity.rs index eb6cf3bdbb..3e765215b9 100644 --- a/core/sr-primitives/src/transaction_validity.rs +++ b/core/sr-primitives/src/transaction_validity.rs @@ -18,6 +18,7 @@ use rstd::prelude::*; use crate::codec::{Encode, Decode}; +use crate::RuntimeDebug; /// Priority for a transaction. Additive. Higher is better. pub type TransactionPriority = u64; @@ -30,8 +31,8 @@ pub type TransactionLongevity = u64; pub type TransactionTag = Vec; /// An invalid transaction validity. -#[derive(Clone, PartialEq, Eq, Encode, Decode, Copy)] -#[cfg_attr(feature = "std", derive(Debug, serde::Serialize))] +#[derive(Clone, PartialEq, Eq, Encode, Decode, Copy, RuntimeDebug)] +#[cfg_attr(feature = "std", derive(serde::Serialize))] pub enum InvalidTransaction { /// The call of the transaction is not expected. Call, @@ -81,8 +82,8 @@ impl From for &'static str { } /// An unknown transaction validity. -#[derive(Clone, PartialEq, Eq, Encode, Decode, Copy)] -#[cfg_attr(feature = "std", derive(Debug, serde::Serialize))] +#[derive(Clone, PartialEq, Eq, Encode, Decode, Copy, RuntimeDebug)] +#[cfg_attr(feature = "std", derive(serde::Serialize))] pub enum UnknownTransaction { /// Could not lookup some information that is required to validate the transaction. CannotLookup, @@ -105,8 +106,8 @@ impl From for &'static str { } /// Errors that can occur while checking the validity of a transaction. -#[derive(Clone, PartialEq, Eq, Encode, Decode, Copy)] -#[cfg_attr(feature = "std", derive(Debug, serde::Serialize))] +#[derive(Clone, PartialEq, Eq, Encode, Decode, Copy, RuntimeDebug)] +#[cfg_attr(feature = "std", derive(serde::Serialize))] pub enum TransactionValidityError { /// The transaction is invalid. Invalid(InvalidTransaction), @@ -173,8 +174,7 @@ impl Into for UnknownTransaction { } /// Information concerning a valid transaction. -#[derive(Clone, PartialEq, Eq, Encode, Decode)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug)] pub struct ValidTransaction { /// Priority of the transaction. /// diff --git a/core/sr-primitives/src/weights.rs b/core/sr-primitives/src/weights.rs index b1cce0f77f..b245f90247 100644 --- a/core/sr-primitives/src/weights.rs +++ b/core/sr-primitives/src/weights.rs @@ -23,16 +23,17 @@ //! Note that the decl_module macro _cannot_ enforce this and will simply fail if an invalid struct //! (something that does not implement `Weighable`) is passed in. -pub use crate::transaction_validity::TransactionPriority; use arithmetic::traits::Bounded; +use crate::RuntimeDebug; + +pub use crate::transaction_validity::TransactionPriority; /// Numeric range of a transaction weight. pub type Weight = u32; /// A generalized group of dispatch types. This is only distinguishing normal, user-triggered transactions /// (`Normal`) and anything beyond which serves a higher purpose to the system (`Operational`). -#[cfg_attr(feature = "std", derive(Debug))] -#[derive(PartialEq, Eq, Clone, Copy)] +#[derive(PartialEq, Eq, Clone, Copy, RuntimeDebug)] pub enum DispatchClass { /// A normal dispatch. Normal, @@ -61,8 +62,8 @@ impl From for DispatchClass { } /// A bundle of static information collected from the `#[weight = $x]` attributes. -#[cfg_attr(feature = "std", derive(PartialEq, Eq, Debug))] -#[derive(Clone, Copy, Default)] +#[cfg_attr(feature = "std", derive(PartialEq, Eq))] +#[derive(Clone, Copy, Default, RuntimeDebug)] pub struct DispatchInfo { /// Weight of this transaction. pub weight: Weight, diff --git a/core/sr-sandbox/src/lib.rs b/core/sr-sandbox/src/lib.rs index b04524b241..c9f9135661 100755 --- a/core/sr-sandbox/src/lib.rs +++ b/core/sr-sandbox/src/lib.rs @@ -51,7 +51,7 @@ mod imp { } /// Error that can occur while using this crate. -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(primitives::RuntimeDebug)] pub enum Error { /// Module is not valid, couldn't be instantiated. Module, diff --git a/core/sr-staking-primitives/src/offence.rs b/core/sr-staking-primitives/src/offence.rs index c076103c18..db51f75df1 100644 --- a/core/sr-staking-primitives/src/offence.rs +++ b/core/sr-staking-primitives/src/offence.rs @@ -131,8 +131,7 @@ impl OnOffenceHandler for () { } /// A details about an offending authority for a particular kind of offence. -#[derive(Clone, PartialEq, Eq, Encode, Decode)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(Clone, PartialEq, Eq, Encode, Decode, sr_primitives::RuntimeDebug)] pub struct OffenceDetails { /// The offending authority id pub offender: Offender, diff --git a/core/sr-std/without_std.rs b/core/sr-std/without_std.rs index 134cc25c94..9762c74367 100755 --- a/core/sr-std/without_std.rs +++ b/core/sr-std/without_std.rs @@ -53,6 +53,7 @@ pub use core::clone; pub use core::cmp; pub use core::convert; pub use core::default; +pub use core::fmt; pub use core::hash; pub use core::intrinsics; pub use core::iter; diff --git a/core/sr-version/src/lib.rs b/core/sr-version/src/lib.rs index ca98f3c221..24c54a739a 100644 --- a/core/sr-version/src/lib.rs +++ b/core/sr-version/src/lib.rs @@ -62,8 +62,8 @@ macro_rules! create_apis_vec { /// This triplet have different semantics and mis-interpretation could cause problems. /// In particular: bug fixes should result in an increment of `spec_version` and possibly `authoring_version`, /// absolutely not `impl_version` since they change the semantics of the runtime. -#[derive(Clone, PartialEq, Eq, Encode, Default)] -#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize, Decode))] +#[derive(Clone, PartialEq, Eq, Encode, Default, sr_primitives::RuntimeDebug)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Decode))] #[cfg_attr(feature = "std", serde(rename_all = "camelCase"))] pub struct RuntimeVersion { /// Identifies the different Substrate runtimes. There'll be at least polkadot and node. @@ -147,7 +147,7 @@ impl RuntimeVersion { } #[cfg(feature = "std")] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(Debug)] pub struct NativeVersion { /// Basic runtime version info. pub runtime_version: RuntimeVersion, diff --git a/core/test-runtime/src/lib.rs b/core/test-runtime/src/lib.rs index 3cb89de56f..45d86f891c 100644 --- a/core/test-runtime/src/lib.rs +++ b/core/test-runtime/src/lib.rs @@ -28,6 +28,7 @@ use codec::{Encode, Decode, Input, Error}; use primitives::{ Blake2Hasher, OpaqueMetadata, + RuntimeDebug, testing::{ ED25519, SR25519, @@ -93,8 +94,7 @@ pub fn native_version() -> NativeVersion { } /// Calls in transactions. -#[derive(Clone, PartialEq, Eq, Encode, Decode)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug)] pub struct Transfer { pub from: AccountId, pub to: AccountId, @@ -113,8 +113,7 @@ impl Transfer { } /// Extrinsic for test-runtime. -#[derive(Clone, PartialEq, Eq, Encode, Decode)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug)] pub enum Extrinsic { AuthoritiesChange(Vec), Transfer(Transfer, AccountSignature), @@ -353,8 +352,7 @@ impl_outer_origin!{ pub enum Origin for Runtime where system = srml_system {} } -#[derive(Clone, Encode, Decode, Eq, PartialEq)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug)] pub struct Event; impl From for Event { diff --git a/core/trie/src/node_header.rs b/core/trie/src/node_header.rs index 50d3d87250..616273e574 100644 --- a/core/trie/src/node_header.rs +++ b/core/trie/src/node_header.rs @@ -22,7 +22,7 @@ use rstd::iter::once; /// A node header #[derive(Copy, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(primitives::RuntimeDebug)] pub(crate) enum NodeHeader { Null, Branch(bool, usize), diff --git a/node/primitives/src/lib.rs b/node/primitives/src/lib.rs index b8abdd7421..431ba17c00 100644 --- a/node/primitives/src/lib.rs +++ b/node/primitives/src/lib.rs @@ -66,4 +66,3 @@ pub type BlockId = generic::BlockId; /// Opaque, encoded, unchecked extrinsic. pub type UncheckedExtrinsic = OpaqueExtrinsic; - diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index 75e1c9eefd..472dec02b8 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -85,7 +85,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // implementation changes and behavior does not, then leave spec_version as // is and increment impl_version. spec_version: 181, - impl_version: 181, + impl_version: 182, apis: RUNTIME_API_VERSIONS, }; diff --git a/srml/authorship/src/lib.rs b/srml/authorship/src/lib.rs index b42104a26b..173af5f729 100644 --- a/srml/authorship/src/lib.rs +++ b/srml/authorship/src/lib.rs @@ -195,8 +195,8 @@ where } } -#[derive(Encode, Decode)] -#[cfg_attr(any(feature = "std", test), derive(PartialEq, Debug))] +#[derive(Encode, Decode, sr_primitives::RuntimeDebug)] +#[cfg_attr(any(feature = "std", test), derive(PartialEq))] enum UncleEntryItem { InclusionHeight(BlockNumber), Uncle(Hash, Option), diff --git a/srml/balances/src/lib.rs b/srml/balances/src/lib.rs index b0b0a60efa..3c354da508 100644 --- a/srml/balances/src/lib.rs +++ b/srml/balances/src/lib.rs @@ -148,7 +148,7 @@ #![cfg_attr(not(feature = "std"), no_std)] use rstd::prelude::*; -use rstd::{cmp, result, mem}; +use rstd::{cmp, result, mem, fmt::Debug}; use codec::{Codec, Encode, Decode}; use support::{ StorageValue, Parameter, decl_event, decl_storage, decl_module, @@ -160,8 +160,9 @@ use support::{ dispatch::Result, }; use sr_primitives::{ + RuntimeDebug, traits::{ - Zero, SimpleArithmetic, StaticLookup, Member, CheckedAdd, CheckedSub, MaybeSerializeDebug, + Zero, SimpleArithmetic, StaticLookup, Member, CheckedAdd, CheckedSub, MaybeSerializeDeserialize, Saturating, Bounded, }, weights::SimpleDispatchInfo, @@ -176,7 +177,7 @@ pub use self::imbalances::{PositiveImbalance, NegativeImbalance}; pub trait Subtrait: system::Trait { /// The balance of an account. type Balance: Parameter + Member + SimpleArithmetic + Codec + Default + Copy + - MaybeSerializeDebug + From; + MaybeSerializeDeserialize + Debug + From; /// A function that is invoked when the free-balance has fallen below the existential deposit and /// has been reduced to zero. @@ -200,7 +201,7 @@ pub trait Subtrait: system::Trait { pub trait Trait: system::Trait { /// The balance of an account. type Balance: Parameter + Member + SimpleArithmetic + Codec + Default + Copy + - MaybeSerializeDebug + From; + MaybeSerializeDeserialize + Debug + From; /// A function that is invoked when the free-balance has fallen below the existential deposit and /// has been reduced to zero. @@ -255,8 +256,7 @@ decl_event!( ); /// Struct to encode the vesting schedule of an individual account. -#[derive(Encode, Decode, Copy, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(Encode, Decode, Copy, Clone, PartialEq, Eq, RuntimeDebug)] pub struct VestingSchedule { /// Locked amount at genesis. pub locked: Balance, @@ -283,8 +283,7 @@ impl Ves } } -#[derive(Encode, Decode, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug)] pub struct BalanceLock { pub id: LockIdentifier, pub amount: Balance, @@ -772,7 +771,7 @@ impl, I: Instance> Trait for ElevatedTrait { impl, I: Instance> Currency for Module where - T::Balance: MaybeSerializeDebug + T::Balance: MaybeSerializeDeserialize + Debug { type Balance = T::Balance; type PositiveImbalance = PositiveImbalance; @@ -1009,7 +1008,7 @@ where impl, I: Instance> ReservableCurrency for Module where - T::Balance: MaybeSerializeDebug + T::Balance: MaybeSerializeDeserialize + Debug { fn can_reserve(who: &T::AccountId, value: Self::Balance) -> bool { Self::free_balance(who) @@ -1072,7 +1071,7 @@ where impl, I: Instance> LockableCurrency for Module where - T::Balance: MaybeSerializeDebug + T::Balance: MaybeSerializeDeserialize + Debug { type Moment = T::BlockNumber; @@ -1146,7 +1145,7 @@ where impl, I: Instance> IsDeadAccount for Module where - T::Balance: MaybeSerializeDebug + T::Balance: MaybeSerializeDeserialize + Debug { fn is_dead_account(who: &T::AccountId) -> bool { Self::total_balance(who).is_zero() diff --git a/srml/collective/src/lib.rs b/srml/collective/src/lib.rs index a965230246..37c1482f9b 100644 --- a/srml/collective/src/lib.rs +++ b/srml/collective/src/lib.rs @@ -25,6 +25,7 @@ use rstd::{prelude::*, result}; use primitives::u32_trait::Value as U32; +use sr_primitives::RuntimeDebug; use sr_primitives::traits::{Hash, EnsureOrigin}; use sr_primitives::weights::SimpleDispatchInfo; use support::{ @@ -55,8 +56,7 @@ pub trait Trait: system::Trait { } /// Origin for the collective module. -#[derive(PartialEq, Eq, Clone)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(PartialEq, Eq, Clone, RuntimeDebug)] pub enum RawOrigin { /// It has been condoned by a given number of members of the collective from a given total. Members(MemberCount, MemberCount), @@ -69,8 +69,7 @@ pub enum RawOrigin { /// Origin for the collective module. pub type Origin = RawOrigin<::AccountId, I>; -#[derive(PartialEq, Eq, Clone, Encode, Decode)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug)] /// Info for keeping track of a motion being voted on. pub struct Votes { /// The proposal's unique index. diff --git a/srml/contracts/rpc/runtime-api/Cargo.toml b/srml/contracts/rpc/runtime-api/Cargo.toml index fce82aed2a..2a36ed2c96 100644 --- a/srml/contracts/rpc/runtime-api/Cargo.toml +++ b/srml/contracts/rpc/runtime-api/Cargo.toml @@ -9,6 +9,7 @@ client = { package = "substrate-client", path = "../../../../core/client", defau codec = { package = "parity-scale-codec", version = "1.0.0", default-features = false, features = ["derive"] } rstd = { package = "sr-std", path = "../../../../core/sr-std", default-features = false } serde = { version = "1.0.101", optional = true, features = ["derive"] } +sr-primitives = { path = "../../../../core/sr-primitives", default-features = false } [features] default = ["std"] @@ -17,4 +18,5 @@ std = [ "codec/std", "rstd/std", "serde", + "sr-primitives/std", ] diff --git a/srml/contracts/rpc/runtime-api/src/lib.rs b/srml/contracts/rpc/runtime-api/src/lib.rs index a5b56888ce..7f01b8bdfa 100644 --- a/srml/contracts/rpc/runtime-api/src/lib.rs +++ b/srml/contracts/rpc/runtime-api/src/lib.rs @@ -24,10 +24,11 @@ use rstd::vec::Vec; use codec::{Encode, Decode, Codec}; +use sr_primitives::RuntimeDebug; /// A result of execution of a contract. -#[derive(Eq, PartialEq, Encode, Decode)] -#[cfg_attr(feature = "std", derive(Debug, serde::Serialize, serde::Deserialize))] +#[derive(Eq, PartialEq, Encode, Decode, RuntimeDebug)] +#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] pub enum ContractExecResult { /// The contract returned successfully. /// diff --git a/srml/contracts/src/exec.rs b/srml/contracts/src/exec.rs index f85797378f..af79c6c818 100644 --- a/srml/contracts/src/exec.rs +++ b/srml/contracts/src/exec.rs @@ -60,7 +60,7 @@ impl ExecReturnValue { /// VM-specific errors during execution (eg. division by 0, OOB access, failure to satisfy some /// precondition of a system call, etc.) or errors with the orchestration (eg. out-of-gas errors, a /// non-existent destination contract, etc.). -#[cfg_attr(test, derive(Debug))] +#[cfg_attr(test, derive(sr_primitives::RuntimeDebug))] pub struct ExecError { pub reason: &'static str, /// This is an allocated buffer that may be reused. The buffer must be cleared explicitly @@ -231,7 +231,8 @@ impl Token for ExecFeeToken { } } -#[cfg_attr(any(feature = "std", test), derive(Debug, PartialEq, Eq, Clone))] +#[cfg_attr(any(feature = "std", test), derive(PartialEq, Eq, Clone))] +#[derive(sr_primitives::RuntimeDebug)] pub enum DeferredAction { DepositEvent { /// A list of topics this event will be deposited with. diff --git a/srml/contracts/src/lib.rs b/srml/contracts/src/lib.rs index b3c8c9b764..4346211ab6 100644 --- a/srml/contracts/src/lib.rs +++ b/srml/contracts/src/lib.rs @@ -109,15 +109,16 @@ pub use crate::exec::{ExecResult, ExecReturnValue, ExecError, StatusCode}; #[cfg(feature = "std")] use serde::{Serialize, Deserialize}; use primitives::crypto::UncheckedFrom; -use rstd::{prelude::*, marker::PhantomData}; +use rstd::{prelude::*, marker::PhantomData, fmt::Debug}; use codec::{Codec, Encode, Decode}; use runtime_io::blake2_256; use sr_primitives::{ - traits::{Hash, StaticLookup, Zero, MaybeSerializeDebug, Member, SignedExtension}, + traits::{Hash, StaticLookup, Zero, MaybeSerializeDeserialize, Member, SignedExtension}, weights::DispatchInfo, transaction_validity::{ ValidTransaction, InvalidTransaction, TransactionValidity, TransactionValidityError, }, + RuntimeDebug, }; use support::dispatch::{Result, Dispatchable}; use support::{ @@ -143,8 +144,7 @@ pub trait ComputeDispatchFee { /// Information for managing an acocunt and its sub trie abstraction. /// This is the required info to cache for an account -#[derive(Encode, Decode)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(Encode, Decode, RuntimeDebug)] pub enum ContractInfo { Alive(AliveContractInfo), Tombstone(TombstoneContractInfo), @@ -207,9 +207,7 @@ pub type AliveContractInfo = /// Information for managing an account and its sub trie abstraction. /// This is the required info to cache for an account. -// Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted. -#[derive(Encode, Decode, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug)] pub struct RawAliveContractInfo { /// Unique ID for the subtree encoded as a bytes vector. pub trie_id: TrieId, @@ -228,15 +226,14 @@ pub struct RawAliveContractInfo { pub type TombstoneContractInfo = RawTombstoneContractInfo<::Hash, ::Hashing>; -// Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted. -#[derive(Encode, Decode, PartialEq, Eq)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(Encode, Decode, PartialEq, Eq, RuntimeDebug)] pub struct RawTombstoneContractInfo(H, PhantomData); impl RawTombstoneContractInfo where - H: Member + MaybeSerializeDebug + AsRef<[u8]> + AsMut<[u8]> + Copy + Default + rstd::hash::Hash - + Codec, + H: Member + MaybeSerializeDeserialize+ Debug + + AsRef<[u8]> + AsMut<[u8]> + Copy + Default + + rstd::hash::Hash + Codec, Hasher: Hash, { fn new(storage_root: &[u8], code_hash: H) -> Self { @@ -891,8 +888,8 @@ impl Config { } /// Definition of the cost schedule and other parameterizations for wasm vm. -#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] -#[derive(Clone, Encode, Decode, PartialEq, Eq)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +#[derive(Clone, Encode, Decode, PartialEq, Eq, RuntimeDebug)] pub struct Schedule { /// Version of the schedule. pub version: u32, @@ -988,9 +985,14 @@ impl Default for CheckBlockGasLimit { } } -#[cfg(feature = "std")] -impl std::fmt::Debug for CheckBlockGasLimit { - fn fmt(&self, _: &mut std::fmt::Formatter) -> std::fmt::Result { +impl rstd::fmt::Debug for CheckBlockGasLimit { + #[cfg(feature = "std")] + fn fmt(&self, f: &mut rstd::fmt::Formatter) -> rstd::fmt::Result { + write!(f, "CheckBlockGasLimit") + } + + #[cfg(not(feature = "std"))] + fn fmt(&self, _: &mut rstd::fmt::Formatter) -> rstd::fmt::Result { Ok(()) } } diff --git a/srml/democracy/src/lib.rs b/srml/democracy/src/lib.rs index af145828ab..f1f10a7319 100644 --- a/srml/democracy/src/lib.rs +++ b/srml/democracy/src/lib.rs @@ -21,6 +21,7 @@ use rstd::prelude::*; use rstd::{result, convert::TryFrom}; use sr_primitives::{ + RuntimeDebug, traits::{Zero, Bounded, CheckedMul, CheckedDiv, EnsureOrigin, Hash, Dispatchable}, weights::SimpleDispatchInfo, }; @@ -48,8 +49,7 @@ pub type PropIndex = u32; pub type ReferendumIndex = u32; /// A value denoting the strength of conviction of a vote. -#[derive(Encode, Decode, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(Encode, Decode, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, RuntimeDebug)] pub enum Conviction { /// 0.1x votes, unlocked. None, @@ -148,8 +148,7 @@ impl Bounded for Conviction { const MAX_RECURSION_LIMIT: u32 = 16; /// A number of lock periods, plus a vote, one way or the other. -#[derive(Copy, Clone, Eq, PartialEq, Default)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(Copy, Clone, Eq, PartialEq, Default, RuntimeDebug)] pub struct Vote { pub aye: bool, pub conviction: Conviction, @@ -231,8 +230,7 @@ pub trait Trait: system::Trait + Sized { } /// Info regarding an ongoing referendum. -#[derive(Encode, Decode, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug)] pub struct ReferendumInfo { /// When voting on this referendum will end. end: BlockNumber, diff --git a/srml/democracy/src/vote_threshold.rs b/srml/democracy/src/vote_threshold.rs index d304c36f32..61e7e65359 100644 --- a/srml/democracy/src/vote_threshold.rs +++ b/srml/democracy/src/vote_threshold.rs @@ -23,8 +23,8 @@ use sr_primitives::traits::{Zero, IntegerSquareRoot}; use rstd::ops::{Add, Mul, Div, Rem}; /// A means of determining if a vote is past pass threshold. -#[derive(Clone, Copy, PartialEq, Eq, Encode, Decode)] -#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] +#[derive(Clone, Copy, PartialEq, Eq, Encode, Decode, sr_primitives::RuntimeDebug)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] pub enum VoteThreshold { /// A supermajority of approvals is needed to pass this vote. SuperMajorityApprove, diff --git a/srml/elections/src/lib.rs b/srml/elections/src/lib.rs index 439be7e76c..87e29f3b14 100644 --- a/srml/elections/src/lib.rs +++ b/srml/elections/src/lib.rs @@ -25,7 +25,10 @@ use rstd::prelude::*; use sr_primitives::{ - print, traits::{Zero, One, StaticLookup, Bounded, Saturating}, weights::SimpleDispatchInfo, + RuntimeDebug, + print, + traits::{Zero, One, StaticLookup, Bounded, Saturating}, + weights::SimpleDispatchInfo, }; use support::{ dispatch::Result, decl_storage, decl_event, ensure, decl_module, @@ -98,8 +101,7 @@ mod tests; // entries before they increase the capacity. /// The activity status of a voter. -#[derive(PartialEq, Eq, Copy, Clone, Encode, Decode, Default)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(PartialEq, Eq, Copy, Clone, Encode, Decode, Default, RuntimeDebug)] pub struct VoterInfo { /// Last VoteIndex in which this voter assigned (or initialized) approvals. last_active: VoteIndex, @@ -114,8 +116,7 @@ pub struct VoterInfo { } /// Used to demonstrate the status of a particular index in the global voter list. -#[derive(PartialEq, Eq)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(PartialEq, Eq, RuntimeDebug)] pub enum CellStatus { /// Any out of bound index. Means a push a must happen to the chunk pointed by `NextVoterSet`. /// Voting fee is applied in case a new chunk is created. diff --git a/srml/example/src/lib.rs b/srml/example/src/lib.rs index bc85241456..c9d9d93cc7 100644 --- a/srml/example/src/lib.rs +++ b/srml/example/src/lib.rs @@ -584,10 +584,9 @@ impl Module { #[derive(Encode, Decode, Clone, Eq, PartialEq)] pub struct WatchDummy(PhantomData); -#[cfg(feature = "std")] impl rstd::fmt::Debug for WatchDummy { fn fmt(&self, f: &mut rstd::fmt::Formatter) -> rstd::fmt::Result { - write!(f, "WatchDummy") + write!(f, "WatchDummy") } } diff --git a/srml/generic-asset/src/lib.rs b/srml/generic-asset/src/lib.rs index 12e9d2cbf6..fdbb57f56f 100644 --- a/srml/generic-asset/src/lib.rs +++ b/srml/generic-asset/src/lib.rs @@ -153,12 +153,13 @@ use codec::{Decode, Encode, HasCompact, Input, Output, Error}; +use sr_primitives::RuntimeDebug; use sr_primitives::traits::{ - CheckedAdd, CheckedSub, MaybeSerializeDebug, Member, One, Saturating, SimpleArithmetic, Zero, Bounded + CheckedAdd, CheckedSub, MaybeSerializeDeserialize, Member, One, Saturating, SimpleArithmetic, Zero, Bounded }; use rstd::prelude::*; -use rstd::{cmp, result}; +use rstd::{cmp, result, fmt::Debug}; use support::dispatch::Result; use support::{ decl_event, decl_module, decl_storage, ensure, @@ -181,7 +182,8 @@ pub trait Trait: system::Trait { + SimpleArithmetic + Default + Copy - + MaybeSerializeDebug; + + MaybeSerializeDeserialize + + Debug; type AssetId: Parameter + Member + SimpleArithmetic + Default + Copy; type Event: From> + Into<::Event>; } @@ -192,7 +194,8 @@ pub trait Subtrait: system::Trait { + SimpleArithmetic + Default + Copy - + MaybeSerializeDebug; + + MaybeSerializeDeserialize + + Debug; type AssetId: Parameter + Member + SimpleArithmetic + Default + Copy; } @@ -202,8 +205,7 @@ impl Subtrait for T { } /// Asset creation options. -#[cfg_attr(feature = "std", derive(Debug))] -#[derive(Clone, Encode, Decode, PartialEq, Eq)] +#[derive(Clone, Encode, Decode, PartialEq, Eq, RuntimeDebug)] pub struct AssetOptions { /// Initial issuance of this asset. All deposit to the creater of the asset. #[codec(compact)] @@ -213,8 +215,7 @@ pub struct AssetOptions { } /// Owner of an asset. -#[cfg_attr(feature = "std", derive(Debug))] -#[derive(Clone, Encode, Decode, PartialEq, Eq)] +#[derive(Clone, Encode, Decode, PartialEq, Eq, RuntimeDebug)] pub enum Owner { /// No owner. None, @@ -229,8 +230,7 @@ impl Default for Owner { } /// Asset permissions -#[cfg_attr(feature = "std", derive(Debug))] -#[derive(Clone, Encode, Decode, PartialEq, Eq)] +#[derive(Clone, Encode, Decode, PartialEq, Eq, RuntimeDebug)] pub struct PermissionsV1 { /// Who have permission to update asset permission pub update: Owner, @@ -240,16 +240,14 @@ pub struct PermissionsV1 { pub burn: Owner, } -#[cfg_attr(feature = "std", derive(Debug))] -#[derive(Clone, Encode, Decode, PartialEq, Eq)] +#[derive(Clone, Encode, Decode, PartialEq, Eq, RuntimeDebug)] #[repr(u8)] enum PermissionVersionNumber { V1 = 0, } /// Versioned asset permission -#[cfg_attr(feature = "std", derive(Debug))] -#[derive(Clone, PartialEq, Eq)] +#[derive(Clone, PartialEq, Eq, RuntimeDebug)] pub enum PermissionVersions { V1(PermissionsV1), } @@ -435,8 +433,7 @@ decl_module! { } } -#[derive(Encode, Decode, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug)] pub struct BalanceLock { pub id: LockIdentifier, pub amount: Balance, @@ -1065,8 +1062,7 @@ impl Trait for ElevatedTrait { type Event = (); } -#[derive(Encode, Decode, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug)] pub struct AssetCurrency(rstd::marker::PhantomData, rstd::marker::PhantomData); impl Currency for AssetCurrency @@ -1200,7 +1196,9 @@ where Self::free_balance(who) .checked_sub(&value) .map_or(false, |new_balance| - >::ensure_can_withdraw(&U::asset_id(), who, value, WithdrawReason::Reserve, new_balance).is_ok() + >::ensure_can_withdraw( + &U::asset_id(), who, value, WithdrawReason::Reserve, new_balance + ).is_ok() ) } @@ -1254,7 +1252,7 @@ impl AssetIdProvider for SpendingAssetIdProvider { impl LockableCurrency for AssetCurrency> where T: Trait, - T::Balance: MaybeSerializeDebug, + T::Balance: MaybeSerializeDeserialize + Debug, { type Moment = T::BlockNumber; diff --git a/srml/im-online/src/lib.rs b/srml/im-online/src/lib.rs index 1a75cebd2e..202507bef9 100644 --- a/srml/im-online/src/lib.rs +++ b/srml/im-online/src/lib.rs @@ -76,6 +76,7 @@ use primitives::offchain::{OpaqueNetworkState, StorageKind}; use rstd::prelude::*; use session::historical::IdentificationTuple; use sr_primitives::{ + RuntimeDebug, traits::{Convert, Member, Printable, Saturating}, Perbill, transaction_validity::{ TransactionValidity, TransactionLongevity, ValidTransaction, InvalidTransaction, @@ -86,7 +87,7 @@ use sr_staking_primitives::{ offence::{ReportOffence, Offence, Kind}, }; use support::{ - decl_module, decl_event, decl_storage, print, ensure, Parameter + decl_module, decl_event, decl_storage, print, ensure, Parameter, debug }; use system::ensure_none; use system::offchain::SubmitUnsignedTransaction; @@ -146,15 +147,14 @@ const DB_KEY: &[u8] = b"srml/im-online-worker-status"; /// finishing it. With every execution of the off-chain worker we check /// if we need to recover and resume gossipping or if there is already /// another off-chain worker in the process of gossipping. -#[derive(Encode, Decode, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug)] struct WorkerStatus { done: bool, gossipping_at: BlockNumber, } /// Error which may occur while executing the off-chain code. -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(RuntimeDebug)] enum OffchainErr { DecodeWorkerStatus, FailedSigning, @@ -176,8 +176,7 @@ impl Printable for OffchainErr { pub type AuthIndex = u32; /// Heartbeat which is sent/received. -#[derive(Encode, Decode, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug)] pub struct Heartbeat where BlockNumber: PartialEq + Eq + Decode + Encode, { @@ -280,6 +279,8 @@ decl_module! { // Runs after every block. fn offchain_worker(now: T::BlockNumber) { + debug::RuntimeLogger::init(); + // Only send messages if we are a potential validator. if runtime_io::is_validator() { Self::offchain(now); @@ -319,6 +320,14 @@ impl Module { Ok(_) => {}, Err(err) => print(err), } + } else { + debug::native::trace!( + target: "imonline", + "Skipping gossip at: {:?} >= {:?} || {:?}", + next_gossip, + now, + if not_yet_gossipped { "not gossipped" } else { "gossipped" } + ); } } @@ -346,6 +355,13 @@ impl Module { let signature = key.sign(&heartbeat_data.encode()).ok_or(OffchainErr::FailedSigning)?; let call = Call::heartbeat(heartbeat_data, signature); + + debug::info!( + target: "imonline", + "[index: {:?}] Reporting im-online at block: {:?}", + authority_index, + block_number + ); T::SubmitTransaction::submit_unsigned(call) .map_err(|_| OffchainErr::SubmitTransaction)?; @@ -538,7 +554,8 @@ impl support::unsigned::ValidateUnsigned for Module { } /// An offence that is filed if a validator didn't send a heartbeat message. -#[cfg_attr(feature = "std", derive(Clone, Debug, PartialEq, Eq))] +#[derive(RuntimeDebug)] +#[cfg_attr(feature = "std", derive(Clone, PartialEq, Eq))] pub struct UnresponsivenessOffence { /// The current session index in which we report the unresponsive validators. /// diff --git a/srml/indices/src/address.rs b/srml/indices/src/address.rs index caef4728fb..21ee654cf2 100644 --- a/srml/indices/src/address.rs +++ b/srml/indices/src/address.rs @@ -24,8 +24,8 @@ use codec::{Encode, Decode, Input, Output, Error}; /// An indices-aware address, which can be either a direct `AccountId` or /// an index. -#[derive(PartialEq, Eq, Clone)] -#[cfg_attr(feature = "std", derive(Debug, Hash))] +#[derive(PartialEq, Eq, Clone, sr_primitives::RuntimeDebug)] +#[cfg_attr(feature = "std", derive(Hash))] pub enum Address where AccountId: Member, AccountIndex: Member, diff --git a/srml/metadata/src/lib.rs b/srml/metadata/src/lib.rs index 244d117564..d85a6837fc 100644 --- a/srml/metadata/src/lib.rs +++ b/srml/metadata/src/lib.rs @@ -28,6 +28,7 @@ use serde::Serialize; use codec::{Decode, Input, Error}; use codec::{Encode, Output}; use rstd::vec::Vec; +use primitives::RuntimeDebug; #[cfg(feature = "std")] type StringBuf = String; @@ -84,13 +85,12 @@ impl Eq for DecodeDifferent where B: Encode + Eq + PartialEq + 'static, O: Encode + Eq + PartialEq + 'static {} -#[cfg(feature = "std")] -impl std::fmt::Debug for DecodeDifferent +impl rstd::fmt::Debug for DecodeDifferent where - B: std::fmt::Debug + Eq + 'static, - O: std::fmt::Debug + Eq + 'static, + B: rstd::fmt::Debug + Eq + 'static, + O: rstd::fmt::Debug + Eq + 'static, { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + fn fmt(&self, f: &mut rstd::fmt::Formatter) -> rstd::fmt::Result { match self { DecodeDifferent::Encode(b) => b.fmt(f), DecodeDifferent::Decoded(o) => o.fmt(f), @@ -114,14 +114,11 @@ impl serde::Serialize for DecodeDifferent pub type DecodeDifferentArray = DecodeDifferent<&'static [B], Vec>; -#[cfg(feature = "std")] -type DecodeDifferentStr = DecodeDifferent<&'static str, StringBuf>; -#[cfg(not(feature = "std"))] type DecodeDifferentStr = DecodeDifferent<&'static str, StringBuf>; /// All the metadata about a function. -#[derive(Clone, PartialEq, Eq, Encode)] -#[cfg_attr(feature = "std", derive(Decode, Debug, Serialize))] +#[derive(Clone, PartialEq, Eq, Encode, RuntimeDebug)] +#[cfg_attr(feature = "std", derive(Decode, Serialize))] pub struct FunctionMetadata { pub name: DecodeDifferentStr, pub arguments: DecodeDifferentArray, @@ -129,8 +126,8 @@ pub struct FunctionMetadata { } /// All the metadata about a function argument. -#[derive(Clone, PartialEq, Eq, Encode)] -#[cfg_attr(feature = "std", derive(Decode, Debug, Serialize))] +#[derive(Clone, PartialEq, Eq, Encode, RuntimeDebug)] +#[cfg_attr(feature = "std", derive(Decode, Serialize))] pub struct FunctionArgumentMetadata { pub name: DecodeDifferentStr, pub ty: DecodeDifferentStr, @@ -154,9 +151,8 @@ impl PartialEq for FnEncode { } } -#[cfg(feature = "std")] -impl std::fmt::Debug for FnEncode { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { +impl rstd::fmt::Debug for FnEncode { + fn fmt(&self, f: &mut rstd::fmt::Formatter) -> rstd::fmt::Result { self.0().fmt(f) } } @@ -169,8 +165,8 @@ impl serde::Serialize for FnEncode { } /// All the metadata about an outer event. -#[derive(Clone, PartialEq, Eq, Encode)] -#[cfg_attr(feature = "std", derive(Decode, Debug, Serialize))] +#[derive(Clone, PartialEq, Eq, Encode, RuntimeDebug)] +#[cfg_attr(feature = "std", derive(Decode, Serialize))] pub struct OuterEventMetadata { pub name: DecodeDifferentStr, pub events: DecodeDifferentArray< @@ -180,8 +176,8 @@ pub struct OuterEventMetadata { } /// All the metadata about an event. -#[derive(Clone, PartialEq, Eq, Encode)] -#[cfg_attr(feature = "std", derive(Decode, Debug, Serialize))] +#[derive(Clone, PartialEq, Eq, Encode, RuntimeDebug)] +#[cfg_attr(feature = "std", derive(Decode, Serialize))] pub struct EventMetadata { pub name: DecodeDifferentStr, pub arguments: DecodeDifferentArray<&'static str, StringBuf>, @@ -189,8 +185,8 @@ pub struct EventMetadata { } /// All the metadata about one storage entry. -#[derive(Clone, PartialEq, Eq, Encode)] -#[cfg_attr(feature = "std", derive(Decode, Debug, Serialize))] +#[derive(Clone, PartialEq, Eq, Encode, RuntimeDebug)] +#[cfg_attr(feature = "std", derive(Decode, Serialize))] pub struct StorageEntryMetadata { pub name: DecodeDifferentStr, pub modifier: StorageEntryModifier, @@ -200,8 +196,8 @@ pub struct StorageEntryMetadata { } /// All the metadata about one module constant. -#[derive(Clone, PartialEq, Eq, Encode)] -#[cfg_attr(feature = "std", derive(Decode, Debug, Serialize))] +#[derive(Clone, PartialEq, Eq, Encode, RuntimeDebug)] +#[cfg_attr(feature = "std", derive(Decode, Serialize))] pub struct ModuleConstantMetadata { pub name: DecodeDifferentStr, pub ty: DecodeDifferentStr, @@ -210,8 +206,8 @@ pub struct ModuleConstantMetadata { } /// All the metadata about a module error. -#[derive(Clone, PartialEq, Eq, Encode)] -#[cfg_attr(feature = "std", derive(Decode, Debug, Serialize))] +#[derive(Clone, PartialEq, Eq, Encode, RuntimeDebug)] +#[cfg_attr(feature = "std", derive(Decode, Serialize))] pub struct ErrorMetadata { pub name: DecodeDifferentStr, pub documentation: DecodeDifferentArray<&'static str, StringBuf>, @@ -265,16 +261,15 @@ impl serde::Serialize for DefaultByteGetter { } } -#[cfg(feature = "std")] -impl std::fmt::Debug for DefaultByteGetter { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { +impl rstd::fmt::Debug for DefaultByteGetter { + fn fmt(&self, f: &mut rstd::fmt::Formatter) -> rstd::fmt::Result { self.0.default_byte().fmt(f) } } /// Hasher used by storage maps -#[derive(Clone, PartialEq, Eq, Encode)] -#[cfg_attr(feature = "std", derive(Decode, Debug, Serialize))] +#[derive(Clone, PartialEq, Eq, Encode, RuntimeDebug)] +#[cfg_attr(feature = "std", derive(Decode, Serialize))] pub enum StorageHasher { Blake2_128, Blake2_256, @@ -284,8 +279,8 @@ pub enum StorageHasher { } /// A storage entry type. -#[derive(Clone, PartialEq, Eq, Encode)] -#[cfg_attr(feature = "std", derive(Decode, Debug, Serialize))] +#[derive(Clone, PartialEq, Eq, Encode, RuntimeDebug)] +#[cfg_attr(feature = "std", derive(Decode, Serialize))] pub enum StorageEntryType { Plain(DecodeDifferentStr), Map { @@ -304,32 +299,32 @@ pub enum StorageEntryType { } /// A storage entry modifier. -#[derive(Clone, PartialEq, Eq, Encode)] -#[cfg_attr(feature = "std", derive(Decode, Debug, Serialize))] +#[derive(Clone, PartialEq, Eq, Encode, RuntimeDebug)] +#[cfg_attr(feature = "std", derive(Decode, Serialize))] pub enum StorageEntryModifier { Optional, Default, } /// All metadata of the storage. -#[derive(Clone, PartialEq, Eq, Encode)] -#[cfg_attr(feature = "std", derive(Decode, Debug, Serialize))] +#[derive(Clone, PartialEq, Eq, Encode, RuntimeDebug)] +#[cfg_attr(feature = "std", derive(Decode, Serialize))] pub struct StorageMetadata { /// The common prefix used by all storage entries. pub prefix: DecodeDifferent<&'static str, StringBuf>, pub entries: DecodeDifferent<&'static [StorageEntryMetadata], Vec>, } -#[derive(Eq, Encode, PartialEq)] -#[cfg_attr(feature = "std", derive(Decode, Debug, Serialize))] +#[derive(Eq, Encode, PartialEq, RuntimeDebug)] +#[cfg_attr(feature = "std", derive(Decode, Serialize))] /// Metadata prefixed by a u32 for reserved usage pub struct RuntimeMetadataPrefixed(pub u32, pub RuntimeMetadata); /// The metadata of a runtime. /// The version ID encoded/decoded through /// the enum nature of `RuntimeMetadata`. -#[derive(Eq, Encode, PartialEq)] -#[cfg_attr(feature = "std", derive(Decode, Debug, Serialize))] +#[derive(Eq, Encode, PartialEq, RuntimeDebug)] +#[cfg_attr(feature = "std", derive(Decode, Serialize))] pub enum RuntimeMetadata { /// Unused; enum filler. V0(RuntimeMetadataDeprecated), @@ -352,8 +347,8 @@ pub enum RuntimeMetadata { } /// Enum that should fail. -#[derive(Eq, PartialEq)] -#[cfg_attr(feature = "std", derive(Debug, Serialize))] +#[derive(Eq, PartialEq, RuntimeDebug)] +#[cfg_attr(feature = "std", derive(Serialize))] pub enum RuntimeMetadataDeprecated { } impl Encode for RuntimeMetadataDeprecated { @@ -370,8 +365,8 @@ impl Decode for RuntimeMetadataDeprecated { } /// The metadata of a runtime. -#[derive(Eq, Encode, PartialEq)] -#[cfg_attr(feature = "std", derive(Decode, Debug, Serialize))] +#[derive(Eq, Encode, PartialEq, RuntimeDebug)] +#[cfg_attr(feature = "std", derive(Decode, Serialize))] pub struct RuntimeMetadataV8 { pub modules: DecodeDifferentArray, } @@ -380,8 +375,8 @@ pub struct RuntimeMetadataV8 { pub type RuntimeMetadataLastVersion = RuntimeMetadataV8; /// All metadata about an runtime module. -#[derive(Clone, PartialEq, Eq, Encode)] -#[cfg_attr(feature = "std", derive(Decode, Debug, Serialize))] +#[derive(Clone, PartialEq, Eq, Encode, RuntimeDebug)] +#[cfg_attr(feature = "std", derive(Decode, Serialize))] pub struct ModuleMetadata { pub name: DecodeDifferentStr, pub storage: Option, StorageMetadata>>, diff --git a/srml/scored-pool/src/lib.rs b/srml/scored-pool/src/lib.rs index fa18d899e2..5fde1e9c45 100644 --- a/srml/scored-pool/src/lib.rs +++ b/srml/scored-pool/src/lib.rs @@ -89,14 +89,17 @@ mod mock; mod tests; use codec::FullCodec; -use rstd::prelude::*; +use rstd::{ + fmt::Debug, + prelude::*, +}; use support::{ decl_module, decl_storage, decl_event, ensure, traits::{ChangeMembers, InitializeMembers, Currency, Get, ReservableCurrency}, }; use system::{self, ensure_root, ensure_signed}; use sr_primitives::{ - traits::{EnsureOrigin, SimpleArithmetic, MaybeSerializeDebug, Zero, StaticLookup}, + traits::{EnsureOrigin, SimpleArithmetic, MaybeSerializeDeserialize, Zero, StaticLookup}, }; type BalanceOf = <>::Currency as Currency<::AccountId>>::Balance; @@ -117,7 +120,8 @@ pub trait Trait: system::Trait { type Currency: Currency + ReservableCurrency; /// The score attributed to a member or candidate. - type Score: SimpleArithmetic + Clone + Copy + Default + FullCodec + MaybeSerializeDebug; + type Score: + SimpleArithmetic + Clone + Copy + Default + FullCodec + MaybeSerializeDeserialize + Debug; /// The overarching event type. type Event: From> + Into<::Event>; diff --git a/srml/staking/src/lib.rs b/srml/staking/src/lib.rs index 013aed2729..e7d7c073a1 100644 --- a/srml/staking/src/lib.rs +++ b/srml/staking/src/lib.rs @@ -263,6 +263,7 @@ use support::{ use session::{historical::OnSessionEnding, SelectInitialValidators}; use sr_primitives::{ Perbill, + RuntimeDebug, curve::PiecewiseLinear, weights::SimpleDispatchInfo, traits::{ @@ -313,7 +314,8 @@ impl EraPoints { } /// Indicates the initial status of the staker. -#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))] +#[derive(RuntimeDebug)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] pub enum StakerStatus { /// Chilling. Idle, @@ -324,8 +326,7 @@ pub enum StakerStatus { } /// A destination account for payment. -#[derive(PartialEq, Eq, Copy, Clone, Encode, Decode)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(PartialEq, Eq, Copy, Clone, Encode, Decode, RuntimeDebug)] pub enum RewardDestination { /// Pay into the stash account, increasing the amount at stake accordingly. Staked, @@ -342,8 +343,7 @@ impl Default for RewardDestination { } /// Preference of what happens on a slash event. -#[derive(PartialEq, Eq, Clone, Encode, Decode)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug)] pub struct ValidatorPrefs { /// Reward that validator takes up-front; only the rest is split between themselves and /// nominators. @@ -360,8 +360,7 @@ impl Default for ValidatorPrefs { } /// Just a Balance/BlockNumber tuple to encode when a chunk of funds will be unlocked. -#[derive(PartialEq, Eq, Clone, Encode, Decode)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug)] pub struct UnlockChunk { /// Amount of funds to be unlocked. #[codec(compact)] @@ -372,8 +371,7 @@ pub struct UnlockChunk { } /// The ledger of a (bonded) stash. -#[derive(PartialEq, Eq, Clone, Encode, Decode)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug)] pub struct StakingLedger { /// The stash account whose balance is actually locked and at stake. pub stash: AccountId, @@ -411,8 +409,7 @@ impl< } /// The amount of exposure (to slashing) than an individual nominator has. -#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Decode)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Decode, RuntimeDebug)] pub struct IndividualExposure { /// The stash account of the nominator in question. who: AccountId, @@ -422,8 +419,7 @@ pub struct IndividualExposure { } /// A snapshot of the stake backing a single validator in the system. -#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Decode, Default)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Decode, Default, RuntimeDebug)] pub struct Exposure { /// The total balance backing this validator. #[codec(compact)] @@ -436,8 +432,7 @@ pub struct Exposure { } /// A slashing event occurred, slashing a validator for a given amount of balance. -#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Decode, Default)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Decode, Default, RuntimeDebug)] pub struct SlashJournalEntry { who: AccountId, amount: Balance, @@ -532,8 +527,8 @@ pub trait Trait: system::Trait { } /// Mode of era-forcing. -#[derive(Copy, Clone, PartialEq, Eq, Encode, Decode)] -#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))] +#[derive(Copy, Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] pub enum Forcing { /// Not forcing anything - just let whatever happen. NotForcing, diff --git a/srml/support/Cargo.toml b/srml/support/Cargo.toml index 79a3beb6dc..2b8c4cb9f9 100644 --- a/srml/support/Cargo.toml +++ b/srml/support/Cargo.toml @@ -5,6 +5,7 @@ authors = ["Parity Technologies "] edition = "2018" [dependencies] +log = "0.4" serde = { version = "1.0.101", optional = true, features = ["derive"] } codec = { package = "parity-scale-codec", version = "1.0.6", default-features = false, features = ["derive"] } srml-metadata = { path = "../metadata", default-features = false } diff --git a/srml/support/procedural/src/storage/instance_trait.rs b/srml/support/procedural/src/storage/instance_trait.rs index fe81dfe0db..1a7add89a4 100644 --- a/srml/support/procedural/src/storage/instance_trait.rs +++ b/srml/support/procedural/src/storage/instance_trait.rs @@ -184,8 +184,12 @@ fn create_and_impl_instance_struct( quote! { // Those trait are derived because of wrong bounds for generics - #[cfg_attr(feature = "std", derive(Debug))] - #[derive(Clone, Eq, PartialEq, #scrate::codec::Encode, #scrate::codec::Decode)] + #[derive( + Clone, Eq, PartialEq, + #scrate::codec::Encode, + #scrate::codec::Decode, + #scrate::RuntimeDebug, + )] #doc pub struct #instance_struct; impl #instance_trait for #instance_struct { diff --git a/srml/support/src/debug.rs b/srml/support/src/debug.rs new file mode 100644 index 0000000000..1c4e463bf1 --- /dev/null +++ b/srml/support/src/debug.rs @@ -0,0 +1,209 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +//! Runtime debugging and logging utilities. +//! +//! This module contains macros and functions that will allow +//! you to print logs out of the runtime code. +//! +//! First and foremost be aware that adding regular logging code to +//! your runtime will have a negative effect on the performance +//! and size of the blob. Luckily there are some ways to mitigate +//! this that are described below. +//! +//! First component to utilize debug-printing and loggin is actually +//! located in `primitives` crate: `primitives::RuntimeDebug`. +//! This custom-derive generates `core::fmt::Debug` implementation, +//! just like regular `derive(Debug)`, however it does not generate +//! any code when the code is compiled to WASM. This means that +//! you can safely sprinkle `RuntimeDebug` in your runtime codebase, +//! without affecting the size. This also allows you to print/log +//! both when the code is running natively or in WASM, but note +//! that WASM debug formatting of structs will be empty. +//! +//! ```rust,no_run +//! use srml_support::debug; +//! +//! #[derive(primitives::RuntimeDebug)] +//! struct MyStruct { +//! a: u64, +//! } +//! +//! // First initialize the logger. +//! // +//! // This is only required when you want the logs to be printed +//! // also during non-native run. +//! // Note that enabling the logger has performance impact on +//! // WASM runtime execution and should be used sparingly. +//! debug::RuntimeLogger::init(); +//! +//! let x = MyStruct { a: 5 }; +//! // will log an info line `"My struct: MyStruct{a:5}"` when running +//! // natively, but will only print `"My struct: "` when running WASM. +//! debug::info!("My struct: {:?}", x); +//! +//! // same output here, although this will print to stdout +//! // (and without log format) +//! debug::print!("My struct: {:?}", x); +//! ``` +//! +//! If you want to avoid extra overhead in WASM, but still be able +//! to print / log when the code is executed natively you can use +//! macros coming from `native` sub-module. This module enables +//! logs conditionally and strips out logs in WASM. +//! +//! ```rust,no_run +//! use srml_support::debug::native; +//! +//! #[derive(primitives::RuntimeDebug)] +//! struct MyStruct { +//! a: u64, +//! } +//! +//! // We don't initialize the logger, since +//! // we are not printing anything out in WASM. +//! // debug::RuntimeLogger::init(); +//! +//! let x = MyStruct { a: 5 }; +//! +//! // Displays an info log when running natively, nothing when WASM. +//! native::info!("My struct: {:?}", x); +//! +//! // same output to stdout, no overhead on WASM. +//! native::print!("My struct: {:?}", x); +//! ``` + +use rstd::vec::Vec; +use rstd::fmt::{self, Debug}; + +pub use log::{info, debug, error, trace, warn}; +pub use crate::runtime_print as print; + +/// Native-only logging. +/// +/// Using any functions from this module will have any effect +/// only if the runtime is running natively (i.e. not via WASM) +#[cfg(feature = "std")] +pub mod native { + pub use super::{info, debug, error, trace, warn, print}; +} + +/// Native-only logging. +/// +/// Using any functions from this module will have any effect +/// only if the runtime is running natively (i.e. not via WASM) +#[cfg(not(feature = "std"))] +pub mod native { + #[macro_export] + macro_rules! noop { + ($($arg:tt)+) => {} + } + pub use noop as info; + pub use noop as debug; + pub use noop as error; + pub use noop as trace; + pub use noop as warn; + pub use noop as print; +} + +/// Print out a formatted message. +#[macro_export] +macro_rules! runtime_print { + ($($arg:tt)+) => { + use core::fmt::Write; + let mut w = $crate::debug::Writer::default(); + let _ = core::write!(&mut w, $($arg)+); + w.print(); + } +} + +/// Print out the debuggable type. +pub fn debug(data: &impl Debug) { + runtime_print!("{:?}", data); +} + +/// A target for `core::write!` macro - constructs a string in memory. +#[derive(Default)] +pub struct Writer(Vec); + +impl fmt::Write for Writer { + fn write_str(&mut self, s: &str) -> fmt::Result { + self.0.extend(s.as_bytes()); + Ok(()) + } +} + +impl Writer { + /// Print the content of this `Writer` out. + pub fn print(&self) { + runtime_io::print_utf8(&self.0) + } +} + +/// Runtime logger implementation - `log` crate backend. +/// +/// The logger should be initialized if you want to display +/// logs inside the runtime that is not necessarily running natively. +/// +/// When runtime is executed natively any log statements are displayed +/// even if this logger is NOT initialized. +/// +/// Note that even though the logs are not displayed in WASM, they +/// may still affect the size and performance of the generated runtime. +/// To lower the footprint make sure to only use macros from `native` +/// sub-module. +pub struct RuntimeLogger; + +impl RuntimeLogger { + /// Initialize the logger. + /// + /// This is a no-op when running natively (`std`). + #[cfg(feature = "std")] + pub fn init() {} + + /// Initialize the logger. + /// + /// This is a no-op when running natively (`std`). + #[cfg(not(feature = "std"))] + pub fn init() { + static LOGGER: RuntimeLogger = RuntimeLogger;; + let _ = log::set_logger(&LOGGER); + } +} + +impl log::Log for RuntimeLogger { + fn enabled(&self, _metadata: &log::Metadata) -> bool { + // to avoid calling to host twice, we pass everything + // and let the host decide what to print. + // If someone is initializing the logger they should + // know what they are doing. + true + } + + fn log(&self, record: &log::Record) { + use fmt::Write; + let mut w = Writer::default(); + let _ = core::write!(&mut w, "{}", record.args()); + + runtime_io::log( + record.level().into(), + record.target().as_bytes(), + &w.0, + ); + } + + fn flush(&self) {} +} diff --git a/srml/support/src/dispatch.rs b/srml/support/src/dispatch.rs index fd24c257ae..df86f43611 100644 --- a/srml/support/src/dispatch.rs +++ b/srml/support/src/dispatch.rs @@ -17,9 +17,7 @@ //! Dispatch system. Contains a macro for defining runtime modules and //! generating values representing lazy module function calls. -pub use crate::rstd::{result, prelude::{Vec, Clone, Eq, PartialEq}, marker}; -#[cfg(feature = "std")] -pub use std::fmt; +pub use crate::rstd::{result, fmt, prelude::{Vec, Clone, Eq, PartialEq}, marker}; pub use crate::codec::{Codec, EncodeLike, Decode, Encode, Input, Output, HasCompact, EncodeAsRef}; pub use srml_metadata::{ FunctionMetadata, DecodeDifferent, DecodeDifferentArray, FunctionArgumentMetadata, @@ -29,7 +27,9 @@ pub use sr_primitives::{ weights::{ SimpleDispatchInfo, GetDispatchInfo, DispatchInfo, WeighData, ClassifyDispatch, TransactionPriority - }, traits::{Dispatchable, DispatchResult, ModuleDispatchError}, DispatchError + }, + traits::{Dispatchable, DispatchResult, ModuleDispatchError}, + DispatchError, }; /// A type that cannot be instantiated. @@ -48,18 +48,9 @@ pub trait Callable { // https://github.com/rust-lang/rust/issues/51331 pub type CallableCallFor = >::Call; -#[cfg(feature = "std")] pub trait Parameter: Codec + EncodeLike + Clone + Eq + fmt::Debug {} - -#[cfg(feature = "std")] impl Parameter for T where T: Codec + EncodeLike + Clone + Eq + fmt::Debug {} -#[cfg(not(feature = "std"))] -pub trait Parameter: Codec + EncodeLike + Clone + Eq {} - -#[cfg(not(feature = "std"))] -impl Parameter for T where T: Codec + EncodeLike + Clone + Eq {} - /// Declares a `Module` struct and a `Call` enum, which implements the dispatch logic. /// /// ## Declaration @@ -1071,8 +1062,7 @@ macro_rules! decl_module { $crate::__check_reserved_fn_name! { $( $fn_name )* } // Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted. - #[derive(Clone, Copy, PartialEq, Eq)] - #[cfg_attr(feature = "std", derive(Debug))] + #[derive(Clone, Copy, PartialEq, Eq, $crate::RuntimeDebug)] pub struct $mod_type< $trait_instance: $trait_name $(, $instance: $instantiable $( = $module_default_instance)?)? @@ -1223,7 +1213,6 @@ macro_rules! decl_module { for $call_type<$trait_instance $(, $instance)?> where $( $other_where_bounds )* {} - #[cfg(feature = "std")] impl<$trait_instance: $trait_name $(, $instance: $instantiable)?> $crate::dispatch::fmt::Debug for $call_type<$trait_instance $(, $instance)?> where $( $other_where_bounds )* { @@ -1325,8 +1314,12 @@ macro_rules! impl_outer_dispatch { } ) => { $(#[$attr])* - #[derive(Clone, PartialEq, Eq, $crate::codec::Encode, $crate::codec::Decode)] - #[cfg_attr(feature = "std", derive(Debug))] + #[derive( + Clone, PartialEq, Eq, + $crate::codec::Encode, + $crate::codec::Decode, + $crate::RuntimeDebug, + )] pub enum $call_type { $( $camelcase ( $crate::dispatch::CallableCallFor<$camelcase, $runtime> ) diff --git a/srml/support/src/error.rs b/srml/support/src/error.rs index 848bd126d2..9aa13713da 100644 --- a/srml/support/src/error.rs +++ b/srml/support/src/error.rs @@ -56,8 +56,7 @@ macro_rules! decl_error { $(,)? } ) => { - #[derive(Clone, PartialEq, Eq)] - #[cfg_attr(feature = "std", derive(Debug))] + #[derive(Clone, PartialEq, Eq, $crate::RuntimeDebug)] $(#[$attr])* pub enum $error { Other(&'static str), diff --git a/srml/support/src/event.rs b/srml/support/src/event.rs index eb5cc20635..3411c93922 100644 --- a/srml/support/src/event.rs +++ b/srml/support/src/event.rs @@ -121,8 +121,12 @@ macro_rules! decl_event { } ) => { // Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted. - #[derive(Clone, PartialEq, Eq, $crate::codec::Encode, $crate::codec::Decode)] - #[cfg_attr(feature = "std", derive(Debug))] + #[derive( + Clone, PartialEq, Eq, + $crate::codec::Encode, + $crate::codec::Decode, + $crate::RuntimeDebug, + )] /// Events for this module. /// $(#[$attr])* @@ -260,9 +264,12 @@ macro_rules! __decl_generic_event { /// [`Trait`]: trait.Trait.html pub type Event<$event_generic_param $(, $instance $( = $event_default_instance)? )?> = RawEvent<$( $generic_type ),* $(, $instance)? >; - // Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted. - #[derive(Clone, PartialEq, Eq, $crate::codec::Encode, $crate::codec::Decode)] - #[cfg_attr(feature = "std", derive(Debug))] + #[derive( + Clone, PartialEq, Eq, + $crate::codec::Encode, + $crate::codec::Decode, + $crate::RuntimeDebug, + )] /// Events for this module. /// $(#[$attr])* @@ -452,8 +459,12 @@ macro_rules! impl_outer_event { $( $module_name:ident::Event $( <$generic_param:ident> )? $( { $generic_instance:ident } )?, )*; ) => { $crate::paste::item! { - #[derive(Clone, PartialEq, Eq, $crate::codec::Encode, $crate::codec::Decode)] - #[cfg_attr(feature = "std", derive(Debug))] + #[derive( + Clone, PartialEq, Eq, + $crate::codec::Encode, + $crate::codec::Decode, + $crate::RuntimeDebug, + )] $(#[$attr])* #[allow(non_camel_case_types)] pub enum $name { diff --git a/srml/support/src/lib.rs b/srml/support/src/lib.rs index 728749d657..2a9f66bd52 100644 --- a/srml/support/src/lib.rs +++ b/srml/support/src/lib.rs @@ -40,7 +40,11 @@ pub use paste; pub use runtime_io::with_storage; #[doc(hidden)] pub use runtime_io::storage_root; +#[doc(hidden)] +pub use sr_primitives::RuntimeDebug; +#[macro_use] +pub mod debug; #[macro_use] pub mod dispatch; #[macro_use] @@ -224,8 +228,7 @@ macro_rules! __assert_eq_uvec { /// The void type - it cannot exist. // Oh rust, you crack me up... -#[derive(Clone, Eq, PartialEq)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(Clone, Eq, PartialEq, RuntimeDebug)] pub enum Void {} #[cfg(feature = "std")] diff --git a/srml/support/src/origin.rs b/srml/support/src/origin.rs index f3fec6e3ae..6da9bc1385 100644 --- a/srml/support/src/origin.rs +++ b/srml/support/src/origin.rs @@ -151,9 +151,7 @@ macro_rules! impl_outer_origin { $( $module:ident $( < $generic:ident > )? $( { $generic_instance:ident } )? ,)* ) => { $crate::paste::item! { - // Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted. - #[derive(Clone, PartialEq, Eq)] - #[cfg_attr(feature = "std", derive(Debug))] + #[derive(Clone, PartialEq, Eq, $crate::RuntimeDebug)] $(#[$attr])* #[allow(non_camel_case_types)] pub enum $name { diff --git a/srml/support/src/runtime.rs b/srml/support/src/runtime.rs index 491252ce70..52bf48baa5 100644 --- a/srml/support/src/runtime.rs +++ b/srml/support/src/runtime.rs @@ -191,8 +191,7 @@ macro_rules! construct_runtime { )* }; ) => { - #[derive(Clone, Copy, PartialEq, Eq)] - #[cfg_attr(feature = "std", derive(Debug))] + #[derive(Clone, Copy, PartialEq, Eq, $crate::RuntimeDebug)] pub struct $runtime; impl $crate::sr_primitives::traits::GetNodeBlockType for $runtime { type NodeBlock = $node_block; diff --git a/srml/support/src/traits.rs b/srml/support/src/traits.rs index 05f3cd070c..c58d60ffc9 100644 --- a/srml/support/src/traits.rs +++ b/srml/support/src/traits.rs @@ -18,12 +18,12 @@ //! //! NOTE: If you're looking for `parameter_types`, it has moved in to the top-level module. -use rstd::{prelude::*, result, marker::PhantomData, ops::Div}; +use rstd::{prelude::*, result, marker::PhantomData, ops::Div, fmt::Debug}; use codec::{FullCodec, Codec, Encode, Decode}; use primitives::u32_trait::Value as U32; use sr_primitives::{ ConsensusEngineId, - traits::{MaybeSerializeDebug, SimpleArithmetic, Saturating}, + traits::{MaybeSerializeDeserialize, SimpleArithmetic, Saturating}, }; /// Anything that can have a `::len()` method. @@ -257,7 +257,7 @@ pub enum SignedImbalance>{ impl< P: Imbalance, N: Imbalance, - B: SimpleArithmetic + FullCodec + Copy + MaybeSerializeDebug + Default, + B: SimpleArithmetic + FullCodec + Copy + MaybeSerializeDeserialize + Debug + Default, > SignedImbalance { pub fn zero() -> Self { SignedImbalance::Positive(P::zero()) @@ -320,7 +320,7 @@ impl< /// Abstraction over a fungible assets system. pub trait Currency { /// The balance of an account. - type Balance: SimpleArithmetic + FullCodec + Copy + MaybeSerializeDebug + Default; + type Balance: SimpleArithmetic + FullCodec + Copy + MaybeSerializeDeserialize + Debug + Default; /// The opaque token type for an imbalance. This is returned by unbalanced operations /// and must be dealt with. It may be dropped but cannot be cloned. diff --git a/srml/support/test/tests/instance.rs b/srml/support/test/tests/instance.rs index a8465adfd7..dd05cb1d8c 100644 --- a/srml/support/test/tests/instance.rs +++ b/srml/support/test/tests/instance.rs @@ -87,8 +87,7 @@ mod module1 { } } - #[derive(PartialEq, Eq, Clone)] - #[cfg_attr(feature = "std", derive(Debug))] + #[derive(PartialEq, Eq, Clone, sr_primitives::RuntimeDebug)] pub enum Origin, I> where T::BlockNumber: From { Members(u32), _Phantom(std::marker::PhantomData<(T, I)>), @@ -150,8 +149,7 @@ mod module2 { } } - #[derive(PartialEq, Eq, Clone)] - #[cfg_attr(feature = "std", derive(Debug))] + #[derive(PartialEq, Eq, Clone, sr_primitives::RuntimeDebug)] pub enum Origin, I=DefaultInstance> { Members(u32), _Phantom(std::marker::PhantomData<(T, I)>), diff --git a/srml/support/test/tests/system.rs b/srml/support/test/tests/system.rs index f1a427060a..2996724f62 100644 --- a/srml/support/test/tests/system.rs +++ b/srml/support/test/tests/system.rs @@ -38,8 +38,7 @@ support::decl_error! { } /// Origin for the system module. -#[derive(PartialEq, Eq, Clone)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(PartialEq, Eq, Clone, sr_primitives::RuntimeDebug)] pub enum RawOrigin { Root, Signed(AccountId), diff --git a/srml/system/src/lib.rs b/srml/system/src/lib.rs index ed9dee2373..c9dcca53cb 100644 --- a/srml/system/src/lib.rs +++ b/srml/system/src/lib.rs @@ -94,8 +94,10 @@ use rstd::prelude::*; #[cfg(any(feature = "std", test))] use rstd::map; use rstd::marker::PhantomData; +use rstd::fmt::Debug; use sr_version::RuntimeVersion; use sr_primitives::{ + RuntimeDebug, generic::{self, Era}, Perbill, ApplyError, ApplyOutcome, DispatchError, weights::{Weight, DispatchInfo, DispatchClass, SimpleDispatchInfo}, transaction_validity::{ @@ -105,7 +107,7 @@ use sr_primitives::{ traits::{ self, CheckEqual, SimpleArithmetic, Zero, SignedExtension, Lookup, LookupError, SimpleBitOps, Hash, Member, MaybeDisplay, EnsureOrigin, SaturatedConversion, - MaybeSerializeDebugButNotDeserialize, MaybeSerializeDebug, StaticLookup, One, Bounded, + MaybeSerialize, MaybeSerializeDeserialize, StaticLookup, One, Bounded, }, }; @@ -158,28 +160,28 @@ pub trait Trait: 'static + Eq + Clone { type Origin: Into, Self::Origin>> + From>; /// The aggregated `Call` type. - type Call; + type Call: Debug; /// Account index (aka nonce) type. This stores the number of previous transactions associated with a sender /// account. type Index: - Parameter + Member + MaybeSerializeDebugButNotDeserialize + Default + MaybeDisplay + SimpleArithmetic + Copy; + Parameter + Member + MaybeSerialize + Debug + Default + MaybeDisplay + SimpleArithmetic + Copy; /// The block number type used by the runtime. type BlockNumber: - Parameter + Member + MaybeSerializeDebug + MaybeDisplay + SimpleArithmetic + Default + Bounded + Copy - + rstd::hash::Hash; + Parameter + Member + MaybeSerializeDeserialize + Debug + MaybeDisplay + SimpleArithmetic + + Default + Bounded + Copy + rstd::hash::Hash; /// The output of the `Hashing` function. type Hash: - Parameter + Member + MaybeSerializeDebug + MaybeDisplay + SimpleBitOps + Default + Copy + CheckEqual - + rstd::hash::Hash + AsRef<[u8]> + AsMut<[u8]>; + Parameter + Member + MaybeSerializeDeserialize + Debug + MaybeDisplay + SimpleBitOps + + Default + Copy + CheckEqual + rstd::hash::Hash + AsRef<[u8]> + AsMut<[u8]>; /// The hashing system (algorithm) being used in the runtime (e.g. Blake2). type Hashing: Hash; /// The user account identifier type for the runtime. - type AccountId: Parameter + Member + MaybeSerializeDebug + MaybeDisplay + Ord + Default; + type AccountId: Parameter + Member + MaybeSerializeDeserialize + Debug + MaybeDisplay + Ord + Default; /// Converting trait to take a source type and convert to `AccountId`. /// @@ -195,7 +197,7 @@ pub trait Trait: 'static + Eq + Clone { >; /// The aggregated event type of the runtime. - type Event: Parameter + Member + From; + type Event: Parameter + Member + From + Debug; /// Maximum number of block number to block hash mappings to keep (oldest pruned first). type BlockHashCount: Get; @@ -280,8 +282,8 @@ decl_module! { } /// A phase of a block's execution. -#[derive(Encode, Decode)] -#[cfg_attr(feature = "std", derive(Serialize, PartialEq, Eq, Clone, Debug))] +#[derive(Encode, Decode, RuntimeDebug)] +#[cfg_attr(feature = "std", derive(Serialize, PartialEq, Eq, Clone))] pub enum Phase { /// Applying an extrinsic. ApplyExtrinsic(u32), @@ -290,8 +292,8 @@ pub enum Phase { } /// Record of an event happening. -#[derive(Encode, Decode)] -#[cfg_attr(feature = "std", derive(Serialize, PartialEq, Eq, Clone, Debug))] +#[derive(Encode, Decode, RuntimeDebug)] +#[cfg_attr(feature = "std", derive(Serialize, PartialEq, Eq, Clone))] pub struct EventRecord { /// The phase of the block it happened in. pub phase: Phase, @@ -323,8 +325,7 @@ decl_error! { } /// Origin for the System module. -#[derive(PartialEq, Eq, Clone)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(PartialEq, Eq, Clone, RuntimeDebug)] pub enum RawOrigin { /// The system itself ordained this dispatch to happen: this is the highest privilege level. Root, @@ -855,10 +856,15 @@ impl SignedExtension for CheckWeight { } } -#[cfg(feature = "std")] -impl rstd::fmt::Debug for CheckWeight { +impl Debug for CheckWeight { + #[cfg(feature = "std")] fn fmt(&self, f: &mut rstd::fmt::Formatter) -> rstd::fmt::Result { - write!(f, "CheckWeight") + write!(f, "CheckWeight") + } + + #[cfg(not(feature = "std"))] + fn fmt(&self, _: &mut rstd::fmt::Formatter) -> rstd::fmt::Result { + Ok(()) } } @@ -873,11 +879,16 @@ impl CheckNonce { } } -#[cfg(feature = "std")] -impl rstd::fmt::Debug for CheckNonce { +impl Debug for CheckNonce { + #[cfg(feature = "std")] fn fmt(&self, f: &mut rstd::fmt::Formatter) -> rstd::fmt::Result { self.0.fmt(f) } + + #[cfg(not(feature = "std"))] + fn fmt(&self, _: &mut rstd::fmt::Formatter) -> rstd::fmt::Result { + Ok(()) + } } impl SignedExtension for CheckNonce { @@ -951,11 +962,16 @@ impl CheckEra { } } -#[cfg(feature = "std")] -impl rstd::fmt::Debug for CheckEra { +impl Debug for CheckEra { + #[cfg(feature = "std")] fn fmt(&self, f: &mut rstd::fmt::Formatter) -> rstd::fmt::Result { self.0.fmt(f) } + + #[cfg(not(feature = "std"))] + fn fmt(&self, _: &mut rstd::fmt::Formatter) -> rstd::fmt::Result { + Ok(()) + } } impl SignedExtension for CheckEra { @@ -994,9 +1010,14 @@ impl SignedExtension for CheckEra { #[derive(Encode, Decode, Clone, Eq, PartialEq)] pub struct CheckGenesis(rstd::marker::PhantomData); -#[cfg(feature = "std")] -impl rstd::fmt::Debug for CheckGenesis { - fn fmt(&self, _f: &mut rstd::fmt::Formatter) -> rstd::fmt::Result { +impl Debug for CheckGenesis { + #[cfg(feature = "std")] + fn fmt(&self, f: &mut rstd::fmt::Formatter) -> rstd::fmt::Result { + write!(f, "CheckGenesis") + } + + #[cfg(not(feature = "std"))] + fn fmt(&self, _: &mut rstd::fmt::Formatter) -> rstd::fmt::Result { Ok(()) } } @@ -1023,9 +1044,14 @@ impl SignedExtension for CheckGenesis { #[derive(Encode, Decode, Clone, Eq, PartialEq)] pub struct CheckVersion(rstd::marker::PhantomData); -#[cfg(feature = "std")] -impl rstd::fmt::Debug for CheckVersion { - fn fmt(&self, _f: &mut rstd::fmt::Formatter) -> rstd::fmt::Result { +impl Debug for CheckVersion { + #[cfg(feature = "std")] + fn fmt(&self, f: &mut rstd::fmt::Formatter) -> rstd::fmt::Result { + write!(f, "CheckVersion") + } + + #[cfg(not(feature = "std"))] + fn fmt(&self, _: &mut rstd::fmt::Formatter) -> rstd::fmt::Result { Ok(()) } } diff --git a/srml/timestamp/src/lib.rs b/srml/timestamp/src/lib.rs index a48190da9a..2ab751088e 100644 --- a/srml/timestamp/src/lib.rs +++ b/srml/timestamp/src/lib.rs @@ -111,8 +111,8 @@ pub const INHERENT_IDENTIFIER: InherentIdentifier = *b"timstap0"; pub type InherentType = u64; /// Errors that can occur while checking the timestamp inherent. -#[derive(Encode)] -#[cfg_attr(feature = "std", derive(Debug, Decode))] +#[derive(Encode, sr_primitives::RuntimeDebug)] +#[cfg_attr(feature = "std", derive(Decode))] pub enum InherentError { /// The timestamp is valid in the future. /// This is a non-fatal-error and will not stop checking the inherents. diff --git a/srml/transaction-payment/src/lib.rs b/srml/transaction-payment/src/lib.rs index b662f55689..ab120322f6 100644 --- a/srml/transaction-payment/src/lib.rs +++ b/srml/transaction-payment/src/lib.rs @@ -145,11 +145,15 @@ impl ChargeTransactionPayment { } } -#[cfg(feature = "std")] impl rstd::fmt::Debug for ChargeTransactionPayment { + #[cfg(feature = "std")] fn fmt(&self, f: &mut rstd::fmt::Formatter) -> rstd::fmt::Result { write!(f, "ChargeTransactionPayment<{:?}>", self.0) } + #[cfg(not(feature = "std"))] + fn fmt(&self, _: &mut rstd::fmt::Formatter) -> rstd::fmt::Result { + Ok(()) + } } impl SignedExtension for ChargeTransactionPayment diff --git a/srml/treasury/src/lib.rs b/srml/treasury/src/lib.rs index 67ee456139..08e2f729ab 100644 --- a/srml/treasury/src/lib.rs +++ b/srml/treasury/src/lib.rs @@ -213,8 +213,8 @@ decl_module! { } /// A spending proposal. -#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] -#[derive(Encode, Decode, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +#[derive(Encode, Decode, Clone, PartialEq, Eq, sr_primitives::RuntimeDebug)] pub struct Proposal { proposer: AccountId, value: Balance, -- GitLab From 3d84e941c3c59a6f2f3e2328a2e45e0f4a24e537 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= Date: Tue, 22 Oct 2019 14:51:59 +0100 Subject: [PATCH 079/167] cli: disable pruning on validators (#3835) --- core/cli/src/lib.rs | 29 ++++++++++++++++++++++------- core/cli/src/params.rs | 14 ++++++++++++-- 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/core/cli/src/lib.rs b/core/cli/src/lib.rs index e891f90dc2..e588c5e8f1 100644 --- a/core/cli/src/lib.rs +++ b/core/cli/src/lib.rs @@ -675,13 +675,6 @@ where config.database_path = db_path(&base_path, config.chain_spec.id()); config.database_cache_size = cli.database_cache_size; config.state_cache_size = cli.state_cache_size; - config.pruning = match cli.pruning { - Some(ref s) if s == "archive" => PruningMode::ArchiveAll, - None => PruningMode::default(), - Some(s) => PruningMode::keep_blocks(s.parse() - .map_err(|_| error::Error::Input("Invalid pruning mode specified".to_string()))? - ), - }; let is_dev = cli.shared_params.dev; @@ -694,6 +687,28 @@ where service::Roles::FULL }; + // by default we disable pruning if the node is an authority (i.e. + // `ArchiveAll`), otherwise we keep state for the last 256 blocks. if the + // node is an authority and pruning is enabled explicitly, then we error + // unless `unsafe_pruning` is set. + config.pruning = match cli.pruning { + Some(ref s) if s == "archive" => PruningMode::ArchiveAll, + None if role == service::Roles::AUTHORITY => PruningMode::ArchiveAll, + None => PruningMode::default(), + Some(s) => { + if role == service::Roles::AUTHORITY && !cli.unsafe_pruning { + return Err(error::Error::Input( + "Validators should run with state pruning disabled (i.e. archive). \ + You can ignore this check with `--unsafe-pruning`.".to_string() + )); + } + + PruningMode::keep_blocks(s.parse() + .map_err(|_| error::Error::Input("Invalid pruning mode specified".to_string()))? + ) + }, + }; + config.wasm_method = cli.wasm_method.into(); let exec = cli.execution_strategies; diff --git a/core/cli/src/params.rs b/core/cli/src/params.rs index b949b336de..e75defec1d 100644 --- a/core/cli/src/params.rs +++ b/core/cli/src/params.rs @@ -366,12 +366,22 @@ pub struct RunCmd { #[structopt(long = "rpc-cors", value_name = "ORIGINS", parse(try_from_str = parse_cors))] pub rpc_cors: Option, - /// Specify the pruning mode, a number of blocks to keep or 'archive'. + /// Specify the state pruning mode, a number of blocks to keep or 'archive'. /// - /// Default is 256. + /// Default is to keep all block states if the node is running as a + /// validator (i.e. 'archive'), otherwise state is only kept for the last + /// 256 blocks. #[structopt(long = "pruning", value_name = "PRUNING_MODE")] pub pruning: Option, + /// Force start with unsafe pruning settings. + /// + /// When running as a validator it is highly recommended to disable state + /// pruning (i.e. 'archive') which is the default. The node will refuse to + /// start as a validator if pruning is enabled unless this option is set. + #[structopt(long = "unsafe-pruning")] + pub unsafe_pruning: bool, + /// The human-readable name for this node. /// /// The node name will be reported to the telemetry server, if enabled. -- GitLab From d1e6f1b39a0d87fc52e7df7dde7f9f04ecfe7d02 Mon Sep 17 00:00:00 2001 From: Arkadiy Paronyan Date: Tue, 22 Oct 2019 15:52:38 +0200 Subject: [PATCH 080/167] Fail on pruning mode change (#3882) --- core/state-db/src/lib.rs | 67 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 65 insertions(+), 2 deletions(-) diff --git a/core/state-db/src/lib.rs b/core/state-db/src/lib.rs index 81772e554b..e561d9ce96 100644 --- a/core/state-db/src/lib.rs +++ b/core/state-db/src/lib.rs @@ -41,6 +41,11 @@ use noncanonical::NonCanonicalOverlay; use pruning::RefWindow; use log::trace; +const PRUNING_MODE: &[u8] = b"mode"; +const PRUNING_MODE_ARCHIVE: &[u8] = b"archive"; +const PRUNING_MODE_ARCHIVE_CANON: &[u8] = b"archive_canonical"; +const PRUNING_MODE_CONSTRAINED: &[u8] = b"constrained"; + /// Database value type. pub type DBValue = Vec; @@ -77,6 +82,8 @@ pub enum Error { InvalidBlockNumber, /// Trying to insert block with unknown parent. InvalidParent, + /// Invalid pruning mode specified. Contains expected mode. + InvalidPruningMode(String), } /// Pinning error type. @@ -99,6 +106,7 @@ impl fmt::Debug for Error { Error::InvalidBlock => write!(f, "Trying to canonicalize invalid block"), Error::InvalidBlockNumber => write!(f, "Trying to insert block with invalid number"), Error::InvalidParent => write!(f, "Trying to insert block with unknown parent"), + Error::InvalidPruningMode(e) => write!(f, "Expected pruning mode: {}", e), } } } @@ -159,6 +167,14 @@ impl PruningMode { } } + /// Is this an archive (either ArchiveAll or ArchiveCanonical) pruning mode? + pub fn id(&self) -> &[u8] { + match self { + PruningMode::ArchiveAll => PRUNING_MODE_ARCHIVE, + PruningMode::ArchiveCanonical => PRUNING_MODE_ARCHIVE_CANON, + PruningMode::Constrained(_) => PRUNING_MODE_CONSTRAINED, + } + } } impl Default for PruningMode { @@ -183,6 +199,10 @@ struct StateDbSync { impl StateDbSync { pub fn new(mode: PruningMode, db: &D) -> Result, Error> { trace!(target: "state-db", "StateDb settings: {:?}", mode); + + // Check that settings match + Self::check_meta(&mode, db)?; + let non_canonical: NonCanonicalOverlay = NonCanonicalOverlay::new(db)?; let pruning: Option> = match mode { PruningMode::Constrained(Constraints { @@ -192,6 +212,7 @@ impl StateDbSync { PruningMode::Constrained(_) => Some(RefWindow::new(db)?), PruningMode::ArchiveAll | PruningMode::ArchiveCanonical => None, }; + Ok(StateDbSync { mode, non_canonical, @@ -200,18 +221,41 @@ impl StateDbSync { }) } + fn check_meta(mode: &PruningMode, db: &D) -> Result<(), Error> { + let db_mode = db.get_meta(&to_meta_key(PRUNING_MODE, &())).map_err(Error::Db)?; + trace!(target: "state-db", + "DB pruning mode: {:?}", + db_mode.as_ref().map(|v| std::str::from_utf8(&v)) + ); + match &db_mode { + Some(v) if v.as_slice() == mode.id() => Ok(()), + Some(v) => Err(Error::InvalidPruningMode(String::from_utf8_lossy(v).into())), + None => Ok(()), + } + } + pub fn insert_block(&mut self, hash: &BlockHash, number: u64, parent_hash: &BlockHash, mut changeset: ChangeSet) -> Result, Error> { + let mut meta = ChangeSet::default(); + if number == 0 { + // Save pruning mode when writing first block. + meta.inserted.push((to_meta_key(PRUNING_MODE, &()), self.mode.id().into())); + } + match self.mode { PruningMode::ArchiveAll => { changeset.deleted.clear(); // write changes immediately Ok(CommitSet { data: changeset, - meta: Default::default(), + meta: meta, }) }, PruningMode::Constrained(_) | PruningMode::ArchiveCanonical => { - self.non_canonical.insert(hash, number, parent_hash, changeset) + let commit = self.non_canonical.insert(hash, number, parent_hash, changeset); + commit.map(|mut c| { + c.meta.inserted.extend(meta.inserted); + c + }) } } } @@ -544,4 +588,23 @@ mod tests { assert!(sdb.is_pruned(&H256::from_low_u64_be(22), 2)); assert!(db.data_eq(&make_db(&[1, 21, 3, 921, 922, 93, 94]))); } + + #[test] + fn detects_incompatible_mode() { + let mut db = make_db(&[]); + let state_db = StateDb::new(PruningMode::ArchiveAll, &db).unwrap(); + db.commit( + &state_db + .insert_block::( + &H256::from_low_u64_be(0), + 0, + &H256::from_low_u64_be(0), + make_changeset(&[], &[]), + ) + .unwrap(), + ); + let new_mode = PruningMode::Constrained(Constraints { max_blocks: Some(2), max_mem: None }); + let state_db: Result, _> = StateDb::new(new_mode, &db); + assert!(state_db.is_err()); + } } -- GitLab From b9d66637857017356983dd021c1d200898561eb7 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Tue, 22 Oct 2019 16:53:20 +0300 Subject: [PATCH 081/167] Dry out author rpc tests (#3878) --- core/rpc/src/author/tests.rs | 149 ++++++++++++++--------------------- 1 file changed, 60 insertions(+), 89 deletions(-) diff --git a/core/rpc/src/author/tests.rs b/core/rpc/src/author/tests.rs index e8ba4c132a..5ae044ff49 100644 --- a/core/rpc/src/author/tests.rs +++ b/core/rpc/src/author/tests.rs @@ -20,13 +20,13 @@ use std::sync::Arc; use assert_matches::assert_matches; use codec::Encode; use primitives::{ - H256, blake2_256, hexdisplay::HexDisplay, testing::{ED25519, SR25519, KeyStore}, ed25519, + H256, blake2_256, hexdisplay::HexDisplay, testing::{ED25519, SR25519, KeyStore}, traits::BareCryptoStorePtr, ed25519, crypto::Pair, }; use rpc::futures::Stream as _; use test_client::{ - self, AccountKeyring, runtime::{Extrinsic, Transfer, SessionKeys}, DefaultTestClientBuilderExt, - TestClientBuilderExt, + self, AccountKeyring, runtime::{Extrinsic, Transfer, SessionKeys, RuntimeApi, Block}, DefaultTestClientBuilderExt, + TestClientBuilderExt, Backend, Client, Executor }; use transaction_pool::{ txpool::Pool, @@ -44,17 +44,41 @@ fn uxt(sender: AccountKeyring, nonce: u64) -> Extrinsic { tx.into_signed_tx() } +struct TestSetup { + pub runtime: runtime::Runtime, + pub client: Arc>, + pub keystore: BareCryptoStorePtr, + pub pool: Arc, Block>>>, +} + +impl Default for TestSetup { + fn default() -> Self { + let keystore = KeyStore::new(); + let client = Arc::new(test_client::TestClientBuilder::new().set_keystore(keystore.clone()).build()); + let pool = Arc::new(Pool::new(Default::default(), FullChainApi::new(client.clone()))); + TestSetup { + runtime: runtime::Runtime::new().expect("Failed to create runtime in test setup"), + client, + keystore, + pool, + } + } +} + +impl TestSetup { + fn author(&self) -> Author, Block>, RuntimeApi> { + Author { + client: self.client.clone(), + pool: self.pool.clone(), + subscriptions: Subscriptions::new(Arc::new(self.runtime.executor())), + keystore: self.keystore.clone(), + } + } +} + #[test] fn submit_transaction_should_not_cause_error() { - let runtime = runtime::Runtime::new().unwrap(); - let client = Arc::new(test_client::new()); - let keystore = KeyStore::new(); - let p = Author { - client: client.clone(), - pool: Arc::new(Pool::new(Default::default(), FullChainApi::new(client))), - subscriptions: Subscriptions::new(Arc::new(runtime.executor())), - keystore: keystore.clone(), - }; + let p = TestSetup::default().author(); let xt = uxt(AccountKeyring::Alice, 1).encode(); let h: H256 = blake2_256(&xt).into(); @@ -69,15 +93,7 @@ fn submit_transaction_should_not_cause_error() { #[test] fn submit_rich_transaction_should_not_cause_error() { - let runtime = runtime::Runtime::new().unwrap(); - let client = Arc::new(test_client::new()); - let keystore = KeyStore::new(); - let p = Author { - client: client.clone(), - pool: Arc::new(Pool::new(Default::default(), FullChainApi::new(client.clone()))), - subscriptions: Subscriptions::new(Arc::new(runtime.executor())), - keystore: keystore.clone(), - }; + let p = TestSetup::default().author(); let xt = uxt(AccountKeyring::Alice, 0).encode(); let h: H256 = blake2_256(&xt).into(); @@ -93,23 +109,16 @@ fn submit_rich_transaction_should_not_cause_error() { #[test] fn should_watch_extrinsic() { //given - let mut runtime = runtime::Runtime::new().unwrap(); - let client = Arc::new(test_client::new()); - let pool = Arc::new(Pool::new(Default::default(), FullChainApi::new(client.clone()))); - let keystore = KeyStore::new(); - let p = Author { - client, - pool: pool.clone(), - subscriptions: Subscriptions::new(Arc::new(runtime.executor())), - keystore: keystore.clone(), - }; + let mut setup = TestSetup::default(); + let p = setup.author(); + let (subscriber, id_rx, data) = jsonrpc_pubsub::typed::Subscriber::new_test("test"); // when p.watch_extrinsic(Default::default(), subscriber, uxt(AccountKeyring::Alice, 0).encode().into()); // then - assert_eq!(runtime.block_on(id_rx), Ok(Ok(1.into()))); + assert_eq!(setup.runtime.block_on(id_rx), Ok(Ok(1.into()))); // check notifications let replacement = { let tx = Transfer { @@ -121,14 +130,14 @@ fn should_watch_extrinsic() { tx.into_signed_tx() }; AuthorApi::submit_extrinsic(&p, replacement.encode().into()).wait().unwrap(); - let (res, data) = runtime.block_on(data.into_future()).unwrap(); + let (res, data) = setup.runtime.block_on(data.into_future()).unwrap(); assert_eq!( res, Some(r#"{"jsonrpc":"2.0","method":"test","params":{"result":"ready","subscription":1}}"#.into()) ); let h = blake2_256(&replacement.encode()); assert_eq!( - runtime.block_on(data.into_future()).unwrap().0, + setup.runtime.block_on(data.into_future()).unwrap().0, Some(format!(r#"{{"jsonrpc":"2.0","method":"test","params":{{"result":{{"usurped":"0x{}"}},"subscription":1}}}}"#, HexDisplay::from(&h))) ); } @@ -136,38 +145,23 @@ fn should_watch_extrinsic() { #[test] fn should_return_watch_validation_error() { //given - let mut runtime = runtime::Runtime::new().unwrap(); - let client = Arc::new(test_client::new()); - let pool = Arc::new(Pool::new(Default::default(), FullChainApi::new(client.clone()))); - let keystore = KeyStore::new(); - let p = Author { - client, - pool: pool.clone(), - subscriptions: Subscriptions::new(Arc::new(runtime.executor())), - keystore: keystore.clone(), - }; + let mut setup = TestSetup::default(); + let p = setup.author(); + let (subscriber, id_rx, _data) = jsonrpc_pubsub::typed::Subscriber::new_test("test"); // when p.watch_extrinsic(Default::default(), subscriber, uxt(AccountKeyring::Alice, 179).encode().into()); // then - let res = runtime.block_on(id_rx).unwrap(); + let res = setup.runtime.block_on(id_rx).unwrap(); assert!(res.is_err(), "Expected the transaction to be rejected as invalid."); } #[test] fn should_return_pending_extrinsics() { - let runtime = runtime::Runtime::new().unwrap(); - let client = Arc::new(test_client::new()); - let pool = Arc::new(Pool::new(Default::default(), FullChainApi::new(client.clone()))); - let keystore = KeyStore::new(); - let p = Author { - client, - pool: pool.clone(), - subscriptions: Subscriptions::new(Arc::new(runtime.executor())), - keystore: keystore.clone(), - }; + let p = TestSetup::default().author(); + let ex = uxt(AccountKeyring::Alice, 0); AuthorApi::submit_extrinsic(&p, ex.encode().into()).wait().unwrap(); assert_matches!( @@ -178,23 +172,16 @@ fn should_return_pending_extrinsics() { #[test] fn should_remove_extrinsics() { - let runtime = runtime::Runtime::new().unwrap(); - let client = Arc::new(test_client::new()); - let pool = Arc::new(Pool::new(Default::default(), FullChainApi::new(client.clone()))); - let keystore = KeyStore::new(); - let p = Author { - client, - pool: pool.clone(), - subscriptions: Subscriptions::new(Arc::new(runtime.executor())), - keystore: keystore.clone(), - }; + let setup = TestSetup::default(); + let p = setup.author(); + let ex1 = uxt(AccountKeyring::Alice, 0); p.submit_extrinsic(ex1.encode().into()).wait().unwrap(); let ex2 = uxt(AccountKeyring::Alice, 1); p.submit_extrinsic(ex2.encode().into()).wait().unwrap(); let ex3 = uxt(AccountKeyring::Bob, 0); let hash3 = p.submit_extrinsic(ex3.encode().into()).wait().unwrap(); - assert_eq!(pool.status().ready, 3); + assert_eq!(setup.pool.status().ready, 3); // now remove all 3 let removed = p.remove_extrinsic(vec![ @@ -208,15 +195,8 @@ fn should_remove_extrinsics() { #[test] fn should_insert_key() { - let runtime = runtime::Runtime::new().unwrap(); - let client = Arc::new(test_client::new()); - let keystore = KeyStore::new(); - let p = Author { - client: client.clone(), - pool: Arc::new(Pool::new(Default::default(), FullChainApi::new(client))), - subscriptions: Subscriptions::new(Arc::new(runtime.executor())), - keystore: keystore.clone(), - }; + let setup = TestSetup::default(); + let p = setup.author(); let suri = "//Alice"; let key_pair = ed25519::Pair::from_string(suri, None).expect("Generates keypair"); @@ -226,7 +206,7 @@ fn should_insert_key() { key_pair.public().0.to_vec().into(), ).expect("Insert key"); - let store_key_pair = keystore.read() + let store_key_pair = setup.keystore.read() .ed25519_key_pair(ED25519, &key_pair.public()).expect("Key exists in store"); assert_eq!(key_pair.public(), store_key_pair.public()); @@ -234,29 +214,20 @@ fn should_insert_key() { #[test] fn should_rotate_keys() { - let runtime = runtime::Runtime::new().unwrap(); - let keystore = KeyStore::new(); - let client = Arc::new( - test_client::TestClientBuilder::new().set_keystore(keystore.clone()).build(), - ); - let p = Author { - client: client.clone(), - pool: Arc::new(Pool::new(Default::default(), FullChainApi::new(client))), - subscriptions: Subscriptions::new(Arc::new(runtime.executor())), - keystore: keystore.clone(), - }; + let setup = TestSetup::default(); + let p = setup.author(); let new_public_keys = p.rotate_keys().expect("Rotates the keys"); let session_keys = SessionKeys::decode(&mut &new_public_keys[..]) .expect("SessionKeys decode successfully"); - let ed25519_key_pair = keystore.read().ed25519_key_pair( + let ed25519_key_pair = setup.keystore.read().ed25519_key_pair( ED25519, &session_keys.ed25519.clone().into(), ).expect("ed25519 key exists in store"); - let sr25519_key_pair = keystore.read().sr25519_key_pair( + let sr25519_key_pair = setup.keystore.read().sr25519_key_pair( SR25519, &session_keys.sr25519.clone().into(), ).expect("sr25519 key exists in store"); -- GitLab From 653456962f43bb6872ffcc2917e652b5e0f980db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 22 Oct 2019 18:54:52 +0200 Subject: [PATCH 082/167] Support disabling the addition of the default bootnode (#3888) --- core/cli/src/lib.rs | 2 +- core/cli/src/params.rs | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/core/cli/src/lib.rs b/core/cli/src/lib.rs index e588c5e8f1..51363445dc 100644 --- a/core/cli/src/lib.rs +++ b/core/cli/src/lib.rs @@ -803,7 +803,7 @@ where G: RuntimeGenesis, E: ChainSpecExtension, { - if spec.boot_nodes().is_empty() { + if spec.boot_nodes().is_empty() && !cli.disable_default_bootnode { let base_path = base_path(&cli.shared_params, version); let storage_path = network_path(&base_path, spec.id()); let node_key = node_key_config(cli.node_key_params, &Some(storage_path))?; diff --git a/core/cli/src/params.rs b/core/cli/src/params.rs index e75defec1d..ae1c856622 100644 --- a/core/cli/src/params.rs +++ b/core/cli/src/params.rs @@ -614,6 +614,13 @@ pub struct BuildSpecCmd { #[structopt(long = "raw")] pub raw: bool, + /// Disable adding the default bootnode to the specification. + /// + /// By default the `/ip4/127.0.0.1/tcp/30333/p2p/NODE_PEER_ID` bootnode is added to the + /// specification when no bootnode exists. + #[structopt(long = "disable-default-bootnode")] + pub disable_default_bootnode: bool, + #[allow(missing_docs)] #[structopt(flatten)] pub shared_params: SharedParams, @@ -763,7 +770,7 @@ impl StructOpt for CoreParams where ) ).subcommand( BuildSpecCmd::augment_clap(SubCommand::with_name("build-spec")) - .about("Build a spec.json file, outputing to stdout.") + .about("Build a spec.json file, outputting to stdout.") ) .subcommand( ExportBlocksCmd::augment_clap(SubCommand::with_name("export-blocks")) -- GitLab From d00d3137246bdb7d63fb6ef206957c539685322b Mon Sep 17 00:00:00 2001 From: Weiliang Li Date: Wed, 23 Oct 2019 15:23:47 +0900 Subject: [PATCH 083/167] gossip: futures 03 Receiver (#3832) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * gossip: futures 03 receiver * fix gossip test * use tokio 01 * add comment * Update core/finality-grandpa/src/communication/mod.rs Co-Authored-By: Bastian Köcher * fix format * rename * remove tokio 01 runtime * minor fix * make stable happy --- .../finality-grandpa/src/communication/mod.rs | 30 ++++++++++++------- core/network/src/protocol/consensus_gossip.rs | 30 +++++++++---------- 2 files changed, 35 insertions(+), 25 deletions(-) diff --git a/core/finality-grandpa/src/communication/mod.rs b/core/finality-grandpa/src/communication/mod.rs index ba7bdce336..f2a4dee21e 100644 --- a/core/finality-grandpa/src/communication/mod.rs +++ b/core/finality-grandpa/src/communication/mod.rs @@ -31,6 +31,7 @@ use std::sync::Arc; use futures::prelude::*; use futures::sync::{oneshot, mpsc}; +use futures03::stream::{StreamExt, TryStreamExt}; use grandpa::Message::{Prevote, Precommit, PrimaryPropose}; use grandpa::{voter, voter_set::VoterSet}; use log::{debug, trace}; @@ -100,7 +101,7 @@ mod benefit { /// Intended to be a lightweight handle such as an `Arc`. pub trait Network: Clone + Send + 'static { /// A stream of input messages for a topic. - type In: Stream; + type In: Stream; /// Get a stream of messages for a specific gossip topic. fn messages_for(&self, topic: Block::Hash) -> Self::In; @@ -145,7 +146,9 @@ impl Network for Arc> where S: network::specialization::NetworkSpecialization, H: network::ExHashT, { - type In = NetworkStream; + type In = NetworkStream< + Box + Send + 'static>, + >; fn messages_for(&self, topic: B::Hash) -> Self::In { // Given that one can only communicate with the Substrate network via the `NetworkService` via message-passing, @@ -159,7 +162,11 @@ impl Network for Arc> where // waiting for the oneshot to resolve and from there on acting like a normal message channel. let (tx, rx) = oneshot::channel(); self.with_gossip(move |gossip, _| { - let inner_rx = gossip.messages_for(GRANDPA_ENGINE_ID, topic); + let inner_rx: Box + Send> = Box::new(gossip + .messages_for(GRANDPA_ENGINE_ID, topic) + .map(|x| Ok(x)) + .compat() + ); let _ = tx.send(inner_rx); }); NetworkStream::PollingOneshot(rx) @@ -220,13 +227,16 @@ impl Network for Arc> where /// /// `NetworkStream` combines the two steps into one, requiring a consumer to only poll `NetworkStream` to retrieve /// messages directly. -pub enum NetworkStream { - PollingOneshot(oneshot::Receiver>), - PollingTopicNotifications(mpsc::UnboundedReceiver), +pub enum NetworkStream { + PollingOneshot(oneshot::Receiver), + PollingTopicNotifications(R), } -impl Stream for NetworkStream { - type Item = network_gossip::TopicNotification; +impl Stream for NetworkStream +where + R: Stream, +{ + type Item = R::Item; type Error = (); fn poll(&mut self) -> Poll, Self::Error> { @@ -266,11 +276,11 @@ impl> NetworkBridge { service: N, config: crate::Config, set_state: crate::environment::SharedVoterSetState, - on_exit: impl Future + Clone + Send + 'static, + on_exit: impl Future + Clone + Send + 'static, catch_up_enabled: bool, ) -> ( Self, - impl futures::Future + Send + 'static, + impl Future + Send + 'static, ) { let (validator, report_stream) = GossipValidator::new( diff --git a/core/network/src/protocol/consensus_gossip.rs b/core/network/src/protocol/consensus_gossip.rs index e23df7e1a5..f3d4e536a7 100644 --- a/core/network/src/protocol/consensus_gossip.rs +++ b/core/network/src/protocol/consensus_gossip.rs @@ -48,7 +48,7 @@ use std::sync::Arc; use std::iter; use std::time; use log::{trace, debug}; -use futures::sync::mpsc; +use futures03::channel::mpsc; use lru_cache::LruCache; use libp2p::PeerId; use sr_primitives::traits::{Block as BlockT, Hash, HashFor}; @@ -608,7 +608,7 @@ impl Validator for DiscardAll { #[cfg(test)] mod tests { use sr_primitives::testing::{H256, Block as RawBlock, ExtrinsicWrapper}; - use futures::Stream; + use futures03::executor::block_on_stream; use super::*; @@ -670,7 +670,7 @@ mod tests { let m2 = vec![4, 5, 6]; push_msg!(consensus, prev_hash, m1_hash, m1); - push_msg!(consensus, best_hash, m2_hash, m2.clone()); + push_msg!(consensus, best_hash, m2_hash, m2); consensus.known_messages.insert(m1_hash, ()); consensus.known_messages.insert(m2_hash, ()); @@ -692,8 +692,6 @@ mod tests { #[test] fn message_stream_include_those_sent_before_asking_for_stream() { - use futures::Stream; - let mut consensus = ConsensusGossip::::new(); consensus.register_validator_internal([0, 0, 0, 0], Arc::new(AllowAll)); @@ -701,9 +699,9 @@ mod tests { let topic = HashFor::::hash(&[1,2,3]); consensus.register_message(topic, message.clone()); - let stream = consensus.messages_for([0, 0, 0, 0], topic); + let mut stream = block_on_stream(consensus.messages_for([0, 0, 0, 0], topic)); - assert_eq!(stream.wait().next(), Some(Ok(TopicNotification { message: message.data, sender: None }))); + assert_eq!(stream.next(), Some(TopicNotification { message: message.data, sender: None })); } #[test] @@ -725,16 +723,17 @@ mod tests { let mut consensus = ConsensusGossip::::new(); consensus.register_validator_internal([0, 0, 0, 0], Arc::new(AllowAll)); - let message = ConsensusMessage { data: vec![4, 5, 6], engine_id: [0, 0, 0, 0] }; - let topic = HashFor::::hash(&[1,2,3]); + let data = vec![4, 5, 6]; + let message = ConsensusMessage { data: data.clone(), engine_id: [0, 0, 0, 0] }; + let topic = HashFor::::hash(&[1, 2, 3]); consensus.register_message(topic, message.clone()); - let stream1 = consensus.messages_for([0, 0, 0, 0], topic); - let stream2 = consensus.messages_for([0, 0, 0, 0], topic); + let mut stream1 = block_on_stream(consensus.messages_for([0, 0, 0, 0], topic)); + let mut stream2 = block_on_stream(consensus.messages_for([0, 0, 0, 0], topic)); - assert_eq!(stream1.wait().next(), Some(Ok(TopicNotification { message: message.data.clone(), sender: None }))); - assert_eq!(stream2.wait().next(), Some(Ok(TopicNotification { message: message.data, sender: None }))); + assert_eq!(stream1.next(), Some(TopicNotification { message: data.clone(), sender: None })); + assert_eq!(stream2.next(), Some(TopicNotification { message: data, sender: None })); } #[test] @@ -749,9 +748,10 @@ mod tests { consensus.register_message(topic, msg_a); consensus.register_message(topic, msg_b); - let mut stream = consensus.messages_for([0, 0, 0, 0], topic).wait(); + let mut stream = block_on_stream(consensus.messages_for([0, 0, 0, 0], topic)); + + assert_eq!(stream.next(), Some(TopicNotification { message: vec![1, 2, 3], sender: None })); - assert_eq!(stream.next(), Some(Ok(TopicNotification { message: vec![1, 2, 3], sender: None }))); let _ = consensus.live_message_sinks.remove(&([0, 0, 0, 0], topic)); assert_eq!(stream.next(), None); } -- GitLab From c4e78a3332a872ceafdf2810a9b0e576672a26f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 23 Oct 2019 09:37:41 +0200 Subject: [PATCH 084/167] Fix srml assets compilation with `std` feature (#3892) --- srml/assets/Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/srml/assets/Cargo.toml b/srml/assets/Cargo.toml index 5f22ab3ba3..052a3045b2 100644 --- a/srml/assets/Cargo.toml +++ b/srml/assets/Cargo.toml @@ -27,5 +27,4 @@ std = [ "sr-primitives/std", "support/std", "system/std", - "runtime-io/std", ] -- GitLab From 395cb2d00bf0b091292a937e258e818b88601bb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 23 Oct 2019 10:28:44 +0200 Subject: [PATCH 085/167] Wasm-builder-runner unset `CARGO_TARGET_DIR` and release 1.0.4 (#3893) * Wasm-builder-runner unset `CARGO_TARGET_DIR` and release 1.0.4 `CARGO_TARGET_DIR` needs to be unset or otherwise cargo deadlocks, because cargo always holds an exclusive lock on target dir. * Commit missing version up * Lock file --- Cargo.lock | 14 +++++++------- core/executor/runtime-test/Cargo.toml | 2 +- core/test-runtime/Cargo.toml | 2 +- core/utils/wasm-builder-runner/Cargo.toml | 2 +- core/utils/wasm-builder-runner/src/lib.rs | 7 ++++++- node-template/runtime/Cargo.toml | 2 +- node/runtime/Cargo.toml | 2 +- 7 files changed, 18 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0ad4317dd9..f12014a220 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2511,7 +2511,7 @@ dependencies = [ "substrate-offchain-primitives 2.0.0", "substrate-primitives 2.0.0", "substrate-session 2.0.0", - "substrate-wasm-builder-runner 1.0.3", + "substrate-wasm-builder-runner 1.0.4", ] [[package]] @@ -2572,7 +2572,7 @@ dependencies = [ "substrate-offchain-primitives 2.0.0", "substrate-primitives 2.0.0", "substrate-session 2.0.0", - "substrate-wasm-builder-runner 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "substrate-wasm-builder-runner 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -5484,7 +5484,7 @@ dependencies = [ "sr-sandbox 2.0.0", "sr-std 2.0.0", "substrate-primitives 2.0.0", - "substrate-wasm-builder-runner 1.0.3", + "substrate-wasm-builder-runner 1.0.4", ] [[package]] @@ -5672,7 +5672,7 @@ dependencies = [ "substrate-state-machine 2.0.0", "substrate-test-runtime-client 2.0.0", "substrate-trie 2.0.0", - "substrate-wasm-builder-runner 1.0.3", + "substrate-wasm-builder-runner 1.0.4", "trie-db 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -5754,11 +5754,11 @@ dependencies = [ [[package]] name = "substrate-wasm-builder-runner" -version = "1.0.3" +version = "1.0.4" [[package]] name = "substrate-wasm-builder-runner" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -7148,7 +7148,7 @@ dependencies = [ "checksum strum 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e5d1c33039533f051704951680f1adfd468fd37ac46816ded0d9ee068e60f05f" "checksum strum_macros 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "47cd23f5c7dee395a00fa20135e2ec0fffcdfa151c56182966d7a3261343432e" "checksum substrate-bip39 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3be511be555a3633e71739a79e4ddff6a6aaa6579fa6114182a51d72c3eb93c5" -"checksum substrate-wasm-builder-runner 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "af21b27fad38b212c1919f700cb0def33c88cde14d22e0d1b17d4521f4eb8b40" +"checksum substrate-wasm-builder-runner 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bd48273fe9d7f92c1f7d6c1c537bb01c8068f925b47ad2cd8367e11dc32f8550" "checksum subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" "checksum subtle 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab3af2eb31c42e8f0ccf43548232556c42737e01a96db6e1777b0be108e79799" "checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" diff --git a/core/executor/runtime-test/Cargo.toml b/core/executor/runtime-test/Cargo.toml index 153c5c9a1f..72041218bf 100644 --- a/core/executor/runtime-test/Cargo.toml +++ b/core/executor/runtime-test/Cargo.toml @@ -13,7 +13,7 @@ primitives = { package = "substrate-primitives", path = "../../primitives", def sr-primitives = { package = "sr-primitives", path = "../../sr-primitives", default-features = false } [build-dependencies] -wasm-builder-runner = { package = "substrate-wasm-builder-runner", version = "1.0.2", path = "../../utils/wasm-builder-runner" } +wasm-builder-runner = { package = "substrate-wasm-builder-runner", version = "1.0.4", path = "../../utils/wasm-builder-runner" } [features] default = [ "std" ] diff --git a/core/test-runtime/Cargo.toml b/core/test-runtime/Cargo.toml index fec9128ef5..4e7c3f8bca 100644 --- a/core/test-runtime/Cargo.toml +++ b/core/test-runtime/Cargo.toml @@ -39,7 +39,7 @@ substrate-test-runtime-client = { path = "./client" } state_machine = { package = "substrate-state-machine", path = "../state-machine" } [build-dependencies] -wasm-builder-runner = { package = "substrate-wasm-builder-runner", version = "1.0.2", path = "../utils/wasm-builder-runner" } +wasm-builder-runner = { package = "substrate-wasm-builder-runner", version = "1.0.4", path = "../utils/wasm-builder-runner" } [features] default = [ diff --git a/core/utils/wasm-builder-runner/Cargo.toml b/core/utils/wasm-builder-runner/Cargo.toml index 71cdbd2835..ab8a539054 100644 --- a/core/utils/wasm-builder-runner/Cargo.toml +++ b/core/utils/wasm-builder-runner/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "substrate-wasm-builder-runner" -version = "1.0.3" +version = "1.0.4" authors = ["Parity Technologies "] description = "Runner for substrate-wasm-builder" edition = "2018" diff --git a/core/utils/wasm-builder-runner/src/lib.rs b/core/utils/wasm-builder-runner/src/lib.rs index 1fee4a4fd7..1739c5eff2 100644 --- a/core/utils/wasm-builder-runner/src/lib.rs +++ b/core/utils/wasm-builder-runner/src/lib.rs @@ -227,6 +227,11 @@ fn run_project(project_folder: &Path) { cmd.arg("--release"); } + // Unset the `CARGO_TARGET_DIR` to prevent a cargo deadlock (cargo locks a target dir exclusive). + // The runner project is created in `CARGO_TARGET_DIR` and executing it will create a sub target + // directory inside of `CARGO_TARGET_DIR`. + cmd.env_remove("CARGO_TARGET_DIR"); + if !cmd.status().map(|s| s.success()).unwrap_or(false) { // Don't spam the output with backtraces when a build failed! process::exit(1); @@ -255,7 +260,7 @@ fn check_provide_dummy_wasm_binary() -> bool { fn provide_dummy_wasm_binary(file_path: &Path) { fs::write( file_path, - "pub const WASM_BINARY: &[u8] = &[]; pub const WASM_BINARY_BLOATY: &[u8] = &[];" + "pub const WASM_BINARY: &[u8] = &[]; pub const WASM_BINARY_BLOATY: &[u8] = &[];", ).expect("Writing dummy WASM binary should not fail"); } diff --git a/node-template/runtime/Cargo.toml b/node-template/runtime/Cargo.toml index 5ebf3af6cf..ff2e3eb2b1 100644 --- a/node-template/runtime/Cargo.toml +++ b/node-template/runtime/Cargo.toml @@ -30,7 +30,7 @@ client = { package = "substrate-client", path = "../../core/client", default_fea offchain-primitives = { package = "substrate-offchain-primitives", path = "../../core/offchain/primitives", default-features = false } [build-dependencies] -wasm-builder-runner = { package = "substrate-wasm-builder-runner", version = "1.0.2" } +wasm-builder-runner = { package = "substrate-wasm-builder-runner", version = "1.0.4" } [features] default = ["std"] diff --git a/node/runtime/Cargo.toml b/node/runtime/Cargo.toml index af66c0432f..d65112da24 100644 --- a/node/runtime/Cargo.toml +++ b/node/runtime/Cargo.toml @@ -55,7 +55,7 @@ utility = { package = "srml-utility", path = "../../srml/utility", default-featu transaction-payment = { package = "srml-transaction-payment", path = "../../srml/transaction-payment", default-features = false } [build-dependencies] -wasm-builder-runner = { package = "substrate-wasm-builder-runner", version = "1.0.2", path = "../../core/utils/wasm-builder-runner" } +wasm-builder-runner = { package = "substrate-wasm-builder-runner", version = "1.0.4", path = "../../core/utils/wasm-builder-runner" } [features] default = ["std"] -- GitLab From acf86cd4b0ad4c45dbba57c2ae323531d5b71264 Mon Sep 17 00:00:00 2001 From: Ashley Date: Wed, 23 Oct 2019 11:02:30 +0100 Subject: [PATCH 086/167] Add an OnUnbalanced hook for contract rent payments (#3857) * Add RentPayment trait to runtime * clarify check * improve proof * Clarify further * Simplify RentPayment::on_unbalance calling and get rid of NonZeroRentHook --- node/runtime/src/lib.rs | 3 ++- srml/contracts/src/lib.rs | 3 +++ srml/contracts/src/rent.rs | 6 ++++-- srml/contracts/src/tests.rs | 1 + 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index 472dec02b8..1544ee9a4a 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -85,7 +85,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // implementation changes and behavior does not, then leave spec_version as // is and increment impl_version. spec_version: 181, - impl_version: 182, + impl_version: 183, apis: RUNTIME_API_VERSIONS, }; @@ -412,6 +412,7 @@ impl contracts::Trait for Runtime { type ComputeDispatchFee = contracts::DefaultDispatchFeeComputor; type TrieIdGenerator = contracts::TrieIdFromParentCounter; type GasPayment = (); + type RentPayment = (); type SignedClaimHandicap = contracts::DefaultSignedClaimHandicap; type TombstoneDeposit = TombstoneDeposit; type StorageSizeOffset = contracts::DefaultStorageSizeOffset; diff --git a/srml/contracts/src/lib.rs b/srml/contracts/src/lib.rs index 4346211ab6..8eaef951ba 100644 --- a/srml/contracts/src/lib.rs +++ b/srml/contracts/src/lib.rs @@ -355,6 +355,9 @@ pub trait Trait: system::Trait { /// Handler for the unbalanced reduction when making a gas payment. type GasPayment: OnUnbalanced>; + /// Handler for rent payments. + type RentPayment: OnUnbalanced>; + /// Number of block delay an extrinsic claim surcharge has. /// /// When claim surcharge is called by an extrinsic the rent is checked diff --git a/srml/contracts/src/rent.rs b/srml/contracts/src/rent.rs index 776f804ee7..ecc5f61031 100644 --- a/srml/contracts/src/rent.rs +++ b/srml/contracts/src/rent.rs @@ -17,7 +17,7 @@ use crate::{BalanceOf, ContractInfo, ContractInfoOf, TombstoneContractInfo, Trait, AliveContractInfo}; use sr_primitives::traits::{Bounded, CheckedDiv, CheckedMul, Saturating, Zero, SaturatedConversion}; -use support::traits::{Currency, ExistenceRequirement, Get, WithdrawReason}; +use support::traits::{Currency, ExistenceRequirement, Get, WithdrawReason, OnUnbalanced}; use support::StorageMap; #[derive(PartialEq, Eq, Copy, Clone)] @@ -126,7 +126,7 @@ fn try_evict_or_and_pay_rent( if can_withdraw_rent && (insufficient_rent || pay_rent) { // Collect dues. - let _ = T::Currency::withdraw( + let imbalance = T::Currency::withdraw( account, dues_limited, WithdrawReason::Fee, @@ -137,6 +137,8 @@ fn try_evict_or_and_pay_rent( dues_limited < rent_budget < balance - subsistence < balance - existential_deposit; qed", ); + + T::RentPayment::on_unbalanced(imbalance); } if insufficient_rent || !can_withdraw_rent { diff --git a/srml/contracts/src/tests.rs b/srml/contracts/src/tests.rs index d3b52c334b..7a13a66de2 100644 --- a/srml/contracts/src/tests.rs +++ b/srml/contracts/src/tests.rs @@ -159,6 +159,7 @@ impl Trait for Test { type ComputeDispatchFee = DummyComputeDispatchFee; type TrieIdGenerator = DummyTrieIdGenerator; type GasPayment = (); + type RentPayment = (); type SignedClaimHandicap = SignedClaimHandicap; type TombstoneDeposit = TombstoneDeposit; type StorageSizeOffset = StorageSizeOffset; -- GitLab From a2ef57b517103ed119f1fa5781cafc44b6210bf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 23 Oct 2019 17:17:12 +0200 Subject: [PATCH 087/167] Throw an error if a bootnode is registered with two different peer ids (#3891) * Throw an error if a bootnode is registered with two different peer ids * Rename error * Fix compilation :( * Review feedback --- core/cli/src/lib.rs | 14 ++++++++------ core/network/src/error.rs | 29 +++++++++++++++++++++++++++- core/network/src/service.rs | 38 ++++++++++++++++++++++++++----------- node-template/src/cli.rs | 6 +++--- node-template/src/main.rs | 7 ++----- node/cli/src/lib.rs | 6 +++--- node/src/main.rs | 7 ++----- 7 files changed, 73 insertions(+), 34 deletions(-) diff --git a/core/cli/src/lib.rs b/core/cli/src/lib.rs index 51363445dc..3b4953312a 100644 --- a/core/cli/src/lib.rs +++ b/core/cli/src/lib.rs @@ -269,22 +269,24 @@ pub struct ParseAndPrepareRun<'a, RP> { impl<'a, RP> ParseAndPrepareRun<'a, RP> { /// Runs the command and runs the main client. - pub fn run( + pub fn run( self, spec_factory: S, exit: Exit, run_service: RS, ) -> error::Result<()> - where S: FnOnce(&str) -> Result>, String>, + where + S: FnOnce(&str) -> Result>, String>, + E: Into, RP: StructOpt + Clone, C: Default, G: RuntimeGenesis, - E: ChainSpecExtension, + CE: ChainSpecExtension, Exit: IntoExit, - RS: FnOnce(Exit, RunCmd, RP, Configuration) -> Result<(), String> + RS: FnOnce(Exit, RunCmd, RP, Configuration) -> Result<(), E> { let config = create_run_node_config( - self.params.left.clone(), spec_factory, self.impl_name, self.version + self.params.left.clone(), spec_factory, self.impl_name, self.version, )?; run_service(exit, self.params.left, self.params.right, config).map_err(Into::into) @@ -633,7 +635,7 @@ fn fill_config_keystore_password( } fn create_run_node_config( - cli: RunCmd, spec_factory: S, impl_name: &'static str, version: &VersionInfo + cli: RunCmd, spec_factory: S, impl_name: &'static str, version: &VersionInfo, ) -> error::Result> where C: Default, diff --git a/core/network/src/error.rs b/core/network/src/error.rs index 95a1dc5abe..c3f89e43c1 100644 --- a/core/network/src/error.rs +++ b/core/network/src/error.rs @@ -18,16 +18,42 @@ use client; +use libp2p::{PeerId, Multiaddr}; + +use std::fmt; + /// Result type alias for the network. pub type Result = std::result::Result; /// Error type for the network. -#[derive(Debug, derive_more::Display, derive_more::From)] +#[derive(derive_more::Display, derive_more::From)] pub enum Error { /// Io error Io(std::io::Error), /// Client error Client(client::error::Error), + /// The same bootnode (based on address) is registered with two different peer ids. + #[display( + fmt = "The same bootnode (`{}`) is registered with two different peer ids: `{}` and `{}`", + address, + first_id, + second_id, + )] + DuplicateBootnode { + /// The address of the bootnode. + address: Multiaddr, + /// The first peer id that was found for the bootnode. + first_id: PeerId, + /// The second peer id that was found for the bootnode. + second_id: PeerId, + }, +} + +// Make `Debug` use the `Display` implementation. +impl fmt::Debug for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self, f) + } } impl std::error::Error for Error { @@ -35,6 +61,7 @@ impl std::error::Error for Error { match self { Error::Io(ref err) => Some(err), Error::Client(ref err) => Some(err), + Error::DuplicateBootnode { .. } => None, } } } diff --git a/core/network/src/service.rs b/core/network/src/service.rs index 5e8d41340c..1c44826062 100644 --- a/core/network/src/service.rs +++ b/core/network/src/service.rs @@ -52,14 +52,11 @@ use crate::protocol::specialization::NetworkSpecialization; use crate::protocol::sync::SyncState; /// Minimum Requirements for a Hash within Networking -pub trait ExHashT: - ::std::hash::Hash + Eq + ::std::fmt::Debug + Clone + Send + Sync + 'static -{ -} +pub trait ExHashT: std::hash::Hash + Eq + std::fmt::Debug + Clone + Send + Sync + 'static {} + impl ExHashT for T where - T: ::std::hash::Hash + Eq + ::std::fmt::Debug + Clone + Send + Sync + 'static -{ -} + T: std::hash::Hash + Eq + std::fmt::Debug + Clone + Send + Sync + 'static +{} /// Transaction pool interface pub trait TransactionPool: Send + Sync { @@ -152,6 +149,23 @@ impl, H: ExHashT> NetworkWorker } } + // Check for duplicate bootnodes. + known_addresses.iter() + .try_for_each(|(peer_id, addr)| + if let Some(other) = known_addresses + .iter() + .find(|o| o.1 == *addr && o.0 != *peer_id) + { + Err(Error::DuplicateBootnode { + address: addr.clone(), + first_id: peer_id.clone(), + second_id: other.0.clone(), + }) + } else { + Ok(()) + } + )?; + // Initialize the reserved peers. for reserved in params.network_config.reserved_nodes.iter() { if let Ok((peer_id, addr)) = parse_str_addr(reserved) { @@ -553,8 +567,9 @@ impl, H: ExHashT> NetworkServic } } -impl, H: ExHashT> - ::consensus::SyncOracle for NetworkService { +impl, H: ExHashT> consensus::SyncOracle + for NetworkService +{ fn is_major_syncing(&mut self) -> bool { NetworkService::is_major_syncing(self) } @@ -564,8 +579,9 @@ impl, H: ExHashT> } } -impl<'a, B: BlockT + 'static, S: NetworkSpecialization, H: ExHashT> - ::consensus::SyncOracle for &'a NetworkService { +impl<'a, B: BlockT + 'static, S: NetworkSpecialization, H: ExHashT> consensus::SyncOracle + for &'a NetworkService +{ fn is_major_syncing(&mut self) -> bool { NetworkService::is_major_syncing(self) } diff --git a/node-template/src/cli.rs b/node-template/src/cli.rs index f0b429e0fa..15c1a0486f 100644 --- a/node-template/src/cli.rs +++ b/node-template/src/cli.rs @@ -29,15 +29,15 @@ pub fn run(args: I, exit: E, version: VersionInfo) -> error::Result<()> match config.roles { ServiceRoles::LIGHT => run_until_exit( runtime, - service::new_light(config).map_err(|e| format!("{:?}", e))?, + service::new_light(config)?, exit ), _ => run_until_exit( runtime, - service::new_full(config).map_err(|e| format!("{:?}", e))?, + service::new_full(config)?, exit ), - }.map_err(|e| format!("{:?}", e)) + } }), ParseAndPrepare::BuildSpec(cmd) => cmd.run(load_spec), ParseAndPrepare::ExportBlocks(cmd) => cmd.run_with_builder(|config: Config<_>| diff --git a/node-template/src/main.rs b/node-template/src/main.rs index 024efcc7db..1f286a2237 100644 --- a/node-template/src/main.rs +++ b/node-template/src/main.rs @@ -10,7 +10,7 @@ mod cli; pub use substrate_cli::{VersionInfo, IntoExit, error}; -fn main() { +fn main() -> Result<(), cli::error::Error> { let version = VersionInfo { name: "Substrate Node", commit: env!("VERGEN_SHA_SHORT"), @@ -21,8 +21,5 @@ fn main() { support_url: "support.anonymous.an", }; - if let Err(e) = cli::run(::std::env::args(), cli::Exit, version) { - eprintln!("Fatal error: {}\n\n{:?}", e, e); - std::process::exit(1) - } + cli::run(std::env::args(), cli::Exit, version) } diff --git a/node/cli/src/lib.rs b/node/cli/src/lib.rs index 7eb3bb89c3..d339952ca8 100644 --- a/node/cli/src/lib.rs +++ b/node/cli/src/lib.rs @@ -172,15 +172,15 @@ pub fn run(args: I, exit: E, version: cli::VersionInfo) -> error::Resul match config.roles { ServiceRoles::LIGHT => run_until_exit( runtime, - service::new_light(config).map_err(|e| format!("{:?}", e))?, + service::new_light(config)?, exit ), _ => run_until_exit( runtime, - service::new_full(config).map_err(|e| format!("{:?}", e))?, + service::new_full(config)?, exit ), - }.map_err(|e| format!("{:?}", e)) + } }), ParseAndPrepare::BuildSpec(cmd) => cmd.run(load_spec), ParseAndPrepare::ExportBlocks(cmd) => cmd.run_with_builder(|config: Config<_, _>| diff --git a/node/src/main.rs b/node/src/main.rs index ca4a6b4c60..9f76cf638c 100644 --- a/node/src/main.rs +++ b/node/src/main.rs @@ -43,7 +43,7 @@ impl cli::IntoExit for Exit { } } -fn main() { +fn main() -> Result<(), cli::error::Error> { let version = VersionInfo { name: "Substrate Node", commit: env!("VERGEN_SHA_SHORT"), @@ -54,8 +54,5 @@ fn main() { support_url: "https://github.com/paritytech/substrate/issues/new", }; - if let Err(e) = cli::run(::std::env::args(), Exit, version) { - eprintln!("Fatal error: {}\n\n{:?}", e, e); - std::process::exit(1) - } + cli::run(std::env::args(), Exit, version) } -- GitLab From 772e0ee2d745a0e502cb71be58dc5775b5e53a74 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Wed, 23 Oct 2019 22:04:42 +0200 Subject: [PATCH 088/167] Fix phragmen election to wasm (#3898) * Fix phragmen-election compile to wasm * Fix chain_spec stuff * Fix panic with no term duration --- Cargo.lock | 2 +- node/cli/src/chain_spec.rs | 8 ++--- node/primitives/src/lib.rs | 5 +-- node/runtime/Cargo.toml | 4 +-- node/runtime/src/lib.rs | 34 +++++-------------- node/testing/src/genesis.rs | 2 +- srml/elections-phragmen/src/lib.rs | 53 +++++++++++++++++++++++++++--- 7 files changed, 66 insertions(+), 42 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f12014a220..96c7bfa1e6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2484,7 +2484,7 @@ dependencies = [ "srml-contracts 2.0.0", "srml-contracts-rpc-runtime-api 2.0.0", "srml-democracy 2.0.0", - "srml-elections 2.0.0", + "srml-elections-phragmen 2.0.0", "srml-executive 2.0.0", "srml-finality-tracker 2.0.0", "srml-grandpa 2.0.0", diff --git a/node/cli/src/chain_spec.rs b/node/cli/src/chain_spec.rs index d81591290e..bc9f1e615f 100644 --- a/node/cli/src/chain_spec.rs +++ b/node/cli/src/chain_spec.rs @@ -235,11 +235,11 @@ pub fn testnet_genesis( members: vec![], phantom: Default::default(), }), - elections: Some(ElectionsConfig { - members: vec![], - presentation_duration: 1 * DAYS, + elections_phragmen: Some(ElectionsConfig { + members: endowed_accounts.iter().take(2).cloned().collect(), term_duration: 28 * DAYS, - desired_seats: 0, + desired_members: 4, + desired_runners_up: 1, }), contracts: Some(ContractsConfig { current_schedule: contracts::Schedule { diff --git a/node/primitives/src/lib.rs b/node/primitives/src/lib.rs index 431ba17c00..6b128db4f3 100644 --- a/node/primitives/src/lib.rs +++ b/node/primitives/src/lib.rs @@ -60,9 +60,6 @@ pub type DigestItem = generic::DigestItem; /// Header type. pub type Header = generic::Header; /// Block type. -pub type Block = generic::Block; +pub type Block = generic::Block; /// Block ID. pub type BlockId = generic::BlockId; - -/// Opaque, encoded, unchecked extrinsic. -pub type UncheckedExtrinsic = OpaqueExtrinsic; diff --git a/node/runtime/Cargo.toml b/node/runtime/Cargo.toml index d65112da24..252a7767ea 100644 --- a/node/runtime/Cargo.toml +++ b/node/runtime/Cargo.toml @@ -33,7 +33,7 @@ collective = { package = "srml-collective", path = "../../srml/collective", defa contracts = { package = "srml-contracts", path = "../../srml/contracts", default-features = false } contracts-rpc-runtime-api = { package = "srml-contracts-rpc-runtime-api", path = "../../srml/contracts/rpc/runtime-api/", default-features = false } democracy = { package = "srml-democracy", path = "../../srml/democracy", default-features = false } -elections = { package = "srml-elections", path = "../../srml/elections", default-features = false } +elections-phragmen = { package = "srml-elections-phragmen", path = "../../srml/elections-phragmen", default-features = false } executive = { package = "srml-executive", path = "../../srml/executive", default-features = false } finality-tracker = { package = "srml-finality-tracker", path = "../../srml/finality-tracker", default-features = false } grandpa = { package = "srml-grandpa", path = "../../srml/grandpa", default-features = false } @@ -72,7 +72,7 @@ std = [ "contracts/std", "contracts-rpc-runtime-api/std", "democracy/std", - "elections/std", + "elections-phragmen/std", "executive/std", "finality-tracker/std", "grandpa/std", diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index 1544ee9a4a..a198877552 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -45,7 +45,6 @@ use sr_primitives::traits::{ self, BlakeTwo256, Block as BlockT, NumberFor, StaticLookup, SaturatedConversion, }; use version::RuntimeVersion; -use elections::VoteIndex; #[cfg(any(feature = "std", test))] use version::NativeVersion; use primitives::OpaqueMetadata; @@ -84,8 +83,8 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // and set impl_version to equal spec_version. If only runtime // implementation changes and behavior does not, then leave spec_version as // is and increment impl_version. - spec_version: 181, - impl_version: 183, + spec_version: 182, + impl_version: 182, apis: RUNTIME_API_VERSIONS, }; @@ -324,33 +323,18 @@ impl collective::Trait for Runtime { parameter_types! { pub const CandidacyBond: Balance = 10 * DOLLARS; pub const VotingBond: Balance = 1 * DOLLARS; - pub const VotingFee: Balance = 2 * DOLLARS; - pub const MinimumVotingLock: Balance = 1 * DOLLARS; - pub const PresentSlashPerVoter: Balance = 1 * CENTS; - pub const CarryCount: u32 = 6; - // one additional vote should go by before an inactive voter can be reaped. - pub const InactiveGracePeriod: VoteIndex = 1; - pub const ElectionsVotingPeriod: BlockNumber = 2 * DAYS; - pub const DecayRatio: u32 = 0; } -impl elections::Trait for Runtime { +impl elections_phragmen::Trait for Runtime { type Event = Event; type Currency = Balances; - type BadPresentation = (); - type BadReaper = (); - type BadVoterIndex = (); - type LoserCandidate = (); - type ChangeMembers = Council; + type CurrencyToVote = CurrencyToVoteHandler; type CandidacyBond = CandidacyBond; type VotingBond = VotingBond; - type VotingFee = VotingFee; - type MinimumVotingLock = MinimumVotingLock; - type PresentSlashPerVoter = PresentSlashPerVoter; - type CarryCount = CarryCount; - type InactiveGracePeriod = InactiveGracePeriod; - type VotingPeriod = ElectionsVotingPeriod; - type DecayRatio = DecayRatio; + type LoserCandidate = (); + type BadReport = (); + type KickedMember = (); + type ChangeMembers = Council; } type TechnicalCollective = collective::Instance2; @@ -518,7 +502,7 @@ construct_runtime!( Democracy: democracy::{Module, Call, Storage, Config, Event}, Council: collective::::{Module, Call, Storage, Origin, Event, Config}, TechnicalCommittee: collective::::{Module, Call, Storage, Origin, Event, Config}, - Elections: elections::{Module, Call, Storage, Event, Config}, + Elections: elections_phragmen::{Module, Call, Storage, Event, Config}, TechnicalMembership: membership::::{Module, Call, Storage, Event, Config}, FinalityTracker: finality_tracker::{Module, Call, Inherent}, Grandpa: grandpa::{Module, Call, Storage, Config, Event}, diff --git a/node/testing/src/genesis.rs b/node/testing/src/genesis.rs index 35ff93d1a6..a9f55d86e3 100644 --- a/node/testing/src/genesis.rs +++ b/node/testing/src/genesis.rs @@ -94,7 +94,7 @@ pub fn config(support_changes_trie: bool, code: Option<&[u8]>) -> GenesisConfig collective_Instance1: Some(Default::default()), collective_Instance2: Some(Default::default()), membership_Instance1: Some(Default::default()), - elections: Some(Default::default()), + elections_phragmen: Some(Default::default()), sudo: Some(Default::default()), } } diff --git a/srml/elections-phragmen/src/lib.rs b/srml/elections-phragmen/src/lib.rs index 781d506bd6..f56c5a4ec3 100644 --- a/srml/elections-phragmen/src/lib.rs +++ b/srml/elections-phragmen/src/lib.rs @@ -76,6 +76,7 @@ #![cfg_attr(not(feature = "std"), no_std)] +use rstd::prelude::*; use sr_primitives::{print, traits::{Zero, StaticLookup, Bounded, Convert}}; use sr_primitives::weights::SimpleDispatchInfo; use srml_support::{ @@ -136,7 +137,8 @@ decl_storage! { /// Number of runners_up to keep. pub DesiredRunnersUp get(fn desired_runners_up) config(): u32; /// How long each seat is kept. This defines the next block number at which an election - /// round will happen. + /// round will happen. If set to zero, no elections are ever triggered and the module will + /// be in passive mode. In that case only a member set defined in at genesis can exist. pub TermDuration get(fn term_duration) config(): T::BlockNumber; // ---- State @@ -470,8 +472,10 @@ impl Module { /// Runs phragmen election and cleans all the previous candidate state. The voter state is NOT /// cleaned and voters must themselves submit a transaction to retract. fn end_block(block_number: T::BlockNumber) -> dispatch::Result { - if (block_number % Self::term_duration()).is_zero() { - Self::do_phragmen(); + if !Self::term_duration().is_zero() { + if (block_number % Self::term_duration()).is_zero() { + Self::do_phragmen(); + } } Ok(()) } @@ -701,7 +705,9 @@ mod tests { pub struct ExtBuilder { balance_factor: u64, voter_bond: u64, + term_duration: u64, desired_runners_up: u32, + members: Vec, } impl Default for ExtBuilder { @@ -710,6 +716,8 @@ mod tests { balance_factor: 1, voter_bond: 2, desired_runners_up: 0, + term_duration: 5, + members: vec![], } } } @@ -723,6 +731,14 @@ mod tests { self.desired_runners_up = count; self } + pub fn term_duration(mut self, duration: u64) -> Self { + self.term_duration = duration; + self + } + pub fn members(mut self, members: Vec) -> Self { + self.members = members; + self + } pub fn build(self) -> runtime_io::TestExternalities { VOTING_BOND.with(|v| *v.borrow_mut() = self.voter_bond); GenesisConfig { @@ -738,10 +754,10 @@ mod tests { vesting: vec![], }), elections: Some(elections::GenesisConfig::{ - members: vec![], + members: self.members, desired_members: 2, desired_runners_up: self.desired_runners_up, - term_duration: 5, + term_duration: self.term_duration, }), }.build_storage().unwrap().into() } @@ -781,6 +797,33 @@ mod tests { }); } + #[test] + fn passive_module_should_work() { + ExtBuilder::default() + .term_duration(0) + .members(vec![1, 2, 3]) + .build() + .execute_with(|| + { + System::set_block_number(1); + assert_eq!(Elections::term_duration(), 0); + assert_eq!(Elections::desired_members(), 2); + assert_eq!(Elections::election_rounds(), 0); + + assert_eq!(Elections::members(), vec![1, 2, 3]); + assert_eq!(Elections::runners_up(), vec![]); + + assert_eq!(Elections::candidates(), vec![]); + assert_eq!(all_voters(), vec![]); + + System::set_block_number(5); + assert_ok!(Elections::end_block(System::block_number())); + + assert_eq!(Elections::members(), vec![1, 2, 3]); + assert_eq!(Elections::runners_up(), vec![]); + }); + } + #[test] fn simple_candidate_submission_should_work() { ExtBuilder::default().build().execute_with(|| { -- GitLab From 5c6ce3f1d6f460cba6bc1952a6ae6567144d2237 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Wed, 23 Oct 2019 22:05:05 +0200 Subject: [PATCH 089/167] Remove support for secp256k1 for network keys (#3897) --- core/cli/src/lib.rs | 34 +--------------------------------- core/cli/src/params.rs | 12 ------------ core/network/Cargo.toml | 2 +- core/network/src/config.rs | 28 ++++------------------------ core/network/src/lib.rs | 4 +--- core/network/src/service.rs | 5 +---- 6 files changed, 8 insertions(+), 77 deletions(-) diff --git a/core/cli/src/lib.rs b/core/cli/src/lib.rs index 3b4953312a..b49f686ae6 100644 --- a/core/cli/src/lib.rs +++ b/core/cli/src/lib.rs @@ -68,11 +68,6 @@ use substrate_telemetry::TelemetryEndpoints; /// The maximum number of characters for a node name. const NODE_NAME_MAX_LENGTH: usize = 32; -/// The file name of the node's Secp256k1 secret key inside the chain-specific -/// network config directory, if neither `--node-key` nor `--node-key-file` -/// is specified in combination with `--node-key-type=secp256k1`. -const NODE_KEY_SECP256K1_FILE: &str = "secret"; - /// The file name of the node's Ed25519 secret key inside the chain-specific /// network config directory, if neither `--node-key` nor `--node-key-file` /// is specified in combination with `--node-key-type=ed25519`. @@ -494,14 +489,6 @@ where P: AsRef { match params.node_key_type { - NodeKeyType::Secp256k1 => - params.node_key.as_ref().map(parse_secp256k1_secret).unwrap_or_else(|| - Ok(params.node_key_file - .or_else(|| net_config_file(net_config_dir, NODE_KEY_SECP256K1_FILE)) - .map(network::config::Secret::File) - .unwrap_or(network::config::Secret::New))) - .map(NodeKeyConfig::Secp256k1), - NodeKeyType::Ed25519 => params.node_key.as_ref().map(parse_ed25519_secret).unwrap_or_else(|| Ok(params.node_key_file @@ -524,14 +511,6 @@ fn invalid_node_key(e: impl std::fmt::Display) -> error::Error { error::Error::Input(format!("Invalid node key: {}", e)) } -/// Parse a Secp256k1 secret key from a hex string into a `network::Secret`. -fn parse_secp256k1_secret(hex: &String) -> error::Result { - H256::from_str(hex).map_err(invalid_node_key).and_then(|bytes| - network::config::identity::secp256k1::SecretKey::from_bytes(bytes) - .map(network::config::Secret::Input) - .map_err(invalid_node_key)) -} - /// Parse a Ed25519 secret key from a hex string into a `network::Secret`. fn parse_ed25519_secret(hex: &String) -> error::Result { H256::from_str(&hex).map_err(invalid_node_key).and_then(|bytes| @@ -952,7 +931,7 @@ fn kill_color(s: &str) -> String { mod tests { use super::*; use tempdir::TempDir; - use network::config::identity::{secp256k1, ed25519}; + use network::config::identity::ed25519; #[test] fn tests_node_name_good() { @@ -975,7 +954,6 @@ mod tests { NodeKeyType::variants().into_iter().try_for_each(|t| { let node_key_type = NodeKeyType::from_str(t).unwrap(); let sk = match node_key_type { - NodeKeyType::Secp256k1 => secp256k1::SecretKey::generate().to_bytes().to_vec(), NodeKeyType::Ed25519 => ed25519::SecretKey::generate().as_ref().to_vec() }; let params = NodeKeyParams { @@ -984,9 +962,6 @@ mod tests { node_key_file: None }; node_key_config(params, &net_config_dir).and_then(|c| match c { - NodeKeyConfig::Secp256k1(network::config::Secret::Input(ref ski)) - if node_key_type == NodeKeyType::Secp256k1 && - &sk[..] == ski.to_bytes() => Ok(()), NodeKeyConfig::Ed25519(network::config::Secret::Input(ref ski)) if node_key_type == NodeKeyType::Ed25519 && &sk[..] == ski.as_ref() => Ok(()), @@ -1012,8 +987,6 @@ mod tests { node_key_file: Some(file.clone()) }; node_key_config(params, &net_config_dir).and_then(|c| match c { - NodeKeyConfig::Secp256k1(network::config::Secret::File(ref f)) - if node_key_type == NodeKeyType::Secp256k1 && f == &file => Ok(()), NodeKeyConfig::Ed25519(network::config::Secret::File(ref f)) if node_key_type == NodeKeyType::Ed25519 && f == &file => Ok(()), _ => Err(error::Error::Input("Unexpected node key config".into())) @@ -1046,8 +1019,6 @@ mod tests { let typ = params.node_key_type; node_key_config::(params, &None) .and_then(|c| match c { - NodeKeyConfig::Secp256k1(network::config::Secret::New) - if typ == NodeKeyType::Secp256k1 => Ok(()), NodeKeyConfig::Ed25519(network::config::Secret::New) if typ == NodeKeyType::Ed25519 => Ok(()), _ => Err(error::Error::Input("Unexpected node key config".into())) @@ -1061,9 +1032,6 @@ mod tests { let typ = params.node_key_type; node_key_config(params, &Some(net_config_dir.clone())) .and_then(move |c| match c { - NodeKeyConfig::Secp256k1(network::config::Secret::File(ref f)) - if typ == NodeKeyType::Secp256k1 && - f == &dir.join(NODE_KEY_SECP256K1_FILE) => Ok(()), NodeKeyConfig::Ed25519(network::config::Secret::File(ref f)) if typ == NodeKeyType::Ed25519 && f == &dir.join(NODE_KEY_ED25519_FILE) => Ok(()), diff --git a/core/cli/src/params.rs b/core/cli/src/params.rs index ae1c856622..4480736066 100644 --- a/core/cli/src/params.rs +++ b/core/cli/src/params.rs @@ -150,7 +150,6 @@ arg_enum! { #[allow(missing_docs)] #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum NodeKeyType { - Secp256k1, Ed25519 } } @@ -164,10 +163,6 @@ pub struct NodeKeyParams { /// The value is a string that is parsed according to the choice of /// `--node-key-type` as follows: /// - /// `secp256k1`: - /// The value is parsed as a hex-encoded Secp256k1 32 bytes secret key, - /// i.e. 64 hex characters. - /// /// `ed25519`: /// The value is parsed as a hex-encoded Ed25519 32 bytes secret key, /// i.e. 64 hex characters. @@ -198,10 +193,6 @@ pub struct NodeKeyParams { /// /// The node's secret key determines the corresponding public key and hence the /// node's peer ID in the context of libp2p. - /// - /// NOTE: The current default key type is `secp256k1` for a transition period only - /// but will eventually change to `ed25519` in a future release. To continue using - /// `secp256k1` keys, use `--node-key-type=secp256k1`. #[structopt( long = "node-key-type", value_name = "TYPE", @@ -216,9 +207,6 @@ pub struct NodeKeyParams { /// The contents of the file are parsed according to the choice of `--node-key-type` /// as follows: /// - /// `secp256k1`: - /// The file must contain an unencoded 32 bytes Secp256k1 secret key. - /// /// `ed25519`: /// The file must contain an unencoded 32 bytes Ed25519 secret key. /// diff --git a/core/network/Cargo.toml b/core/network/Cargo.toml index 016ddb8010..71e7d95bfa 100644 --- a/core/network/Cargo.toml +++ b/core/network/Cargo.toml @@ -22,7 +22,7 @@ linked_hash_set = "0.1.3" lru-cache = "0.1.2" rustc-hex = "2.0.1" rand = "0.7.2" -libp2p = { version = "0.12.0", default-features = false, features = ["secp256k1", "libp2p-websocket"] } +libp2p = { version = "0.12.0", default-features = false, features = ["libp2p-websocket"] } fork-tree = { path = "../../core/utils/fork-tree" } consensus = { package = "substrate-consensus-common", path = "../../core/consensus/common" } client = { package = "substrate-client", path = "../../core/client" } diff --git a/core/network/src/config.rs b/core/network/src/config.rs index 0582fcb300..445d4427bd 100644 --- a/core/network/src/config.rs +++ b/core/network/src/config.rs @@ -29,7 +29,7 @@ use bitflags::bitflags; use consensus::{block_validation::BlockAnnounceValidator, import_queue::ImportQueue}; use sr_primitives::traits::{Block as BlockT}; use std::sync::Arc; -use libp2p::identity::{Keypair, secp256k1, ed25519}; +use libp2p::identity::{Keypair, ed25519}; use libp2p::wasm_ext; use libp2p::{PeerId, Multiaddr, multiaddr}; use std::error::Error; @@ -364,15 +364,10 @@ impl NonReservedPeerMode { /// the evaluation of the node key configuration. #[derive(Clone)] pub enum NodeKeyConfig { - /// A Secp256k1 secret key configuration. - Secp256k1(Secret), /// A Ed25519 secret key configuration. Ed25519(Secret) } -/// The options for obtaining a Secp256k1 secret key. -pub type Secp256k1Secret = Secret; - /// The options for obtaining a Ed25519 secret key. pub type Ed25519Secret = Secret; @@ -385,7 +380,6 @@ pub enum Secret { /// it is created with a newly generated secret key `K`. The format /// of the file is determined by `K`: /// - /// * `secp256k1::SecretKey`: An unencoded 32 bytes Secp256k1 secret key. /// * `ed25519::SecretKey`: An unencoded 32 bytes Ed25519 secret key. File(PathBuf), /// Always generate a new secret key `K`. @@ -406,20 +400,6 @@ impl NodeKeyConfig { pub fn into_keypair(self) -> io::Result { use NodeKeyConfig::*; match self { - Secp256k1(Secret::New) => - Ok(Keypair::generate_secp256k1()), - - Secp256k1(Secret::Input(k)) => - Ok(Keypair::Secp256k1(k.into())), - - Secp256k1(Secret::File(f)) => - get_secret(f, - |mut b| secp256k1::SecretKey::from_bytes(&mut b), - secp256k1::SecretKey::generate, - |b| b.to_bytes().to_vec()) - .map(secp256k1::Keypair::from) - .map(Keypair::Secp256k1), - Ed25519(Secret::New) => Ok(Keypair::generate_ed25519()), @@ -526,9 +506,9 @@ mod tests { #[test] fn test_secret_input() { - let sk = secp256k1::SecretKey::generate(); - let kp1 = NodeKeyConfig::Secp256k1(Secret::Input(sk.clone())).into_keypair().unwrap(); - let kp2 = NodeKeyConfig::Secp256k1(Secret::Input(sk)).into_keypair().unwrap(); + let sk = ed25519::SecretKey::generate(); + let kp1 = NodeKeyConfig::Ed25519(Secret::Input(sk.clone())).into_keypair().unwrap(); + let kp2 = NodeKeyConfig::Ed25519(Secret::Input(sk)).into_keypair().unwrap(); assert!(secret_bytes(&kp1) == secret_bytes(&kp2)); } diff --git a/core/network/src/lib.rs b/core/network/src/lib.rs index 7e9fd51a41..d0977d90c9 100644 --- a/core/network/src/lib.rs +++ b/core/network/src/lib.rs @@ -24,9 +24,7 @@ //! # Node identities and addresses //! //! In a decentralized network, each node possesses a network private key and a network public key. -//! In Substrate, the keys are based on the ed25519 curve. As of the writing of this documentation, -//! the secp256k1 curve can also be used, but is deprecated. Our local node's keypair must be -//! passed as part of the network configuration. +//! In Substrate, the keys are based on the ed25519 curve. //! //! From a node's public key, we can derive its *identity*. In Substrate and libp2p, a node's //! identity is represented with the [`PeerId`] struct. All network communications between nodes on diff --git a/core/network/src/service.rs b/core/network/src/service.rs index 1c44826062..48ad51bde3 100644 --- a/core/network/src/service.rs +++ b/core/network/src/service.rs @@ -42,7 +42,7 @@ use sr_primitives::{traits::{Block as BlockT, NumberFor}, ConsensusEngineId}; use crate::{behaviour::{Behaviour, BehaviourOut}, config::{parse_str_addr, parse_addr}}; use crate::{NetworkState, NetworkStateNotConnectedPeer, NetworkStatePeer}; -use crate::{transport, config::NodeKeyConfig, config::NonReservedPeerMode}; +use crate::{transport, config::NonReservedPeerMode}; use crate::config::{Params, TransportConfig}; use crate::error::Error; use crate::protocol::{self, Protocol, Context, CustomMessageOutcome, PeerInfo}; @@ -185,9 +185,6 @@ impl, H: ExHashT> NetworkWorker }; // Private and public keys configuration. - if let NodeKeyConfig::Secp256k1(_) = params.network_config.node_key { - warn!(target: "sub-libp2p", "Secp256k1 keys are deprecated in favour of ed25519"); - } let local_identity = params.network_config.node_key.clone().into_keypair()?; let local_public = local_identity.public(); let local_peer_id = local_public.clone().into_peer_id(); -- GitLab From eda5fe5cf0f8e56d90f8cd913ffcb118362df559 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Wed, 23 Oct 2019 22:05:24 +0200 Subject: [PATCH 090/167] Split the telemetry net status report in two (#3887) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Split the telemetry net status report in two * Update core/service/src/lib.rs Co-Authored-By: Bastian Köcher * Remove clone() * Move code to status_sinks.rs instead * Add basic usage for status_sinks * Update core/service/src/status_sinks.rs Co-Authored-By: Bastian Köcher --- Cargo.lock | 1 + core/cli/src/informant.rs | 13 +-- core/service/Cargo.toml | 1 + core/service/src/builder.rs | 1 + core/service/src/lib.rs | 48 +++++----- core/service/src/status_sinks.rs | 149 +++++++++++++++++++++++++++++++ 6 files changed, 188 insertions(+), 25 deletions(-) create mode 100644 core/service/src/status_sinks.rs diff --git a/Cargo.lock b/Cargo.lock index 96c7bfa1e6..a87da6586c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5539,6 +5539,7 @@ dependencies = [ "substrate-transaction-pool 2.0.0", "sysinfo 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)", "target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/core/cli/src/informant.rs b/core/cli/src/informant.rs index 9d7f04b8f6..f7c23ba479 100644 --- a/core/cli/src/informant.rs +++ b/core/cli/src/informant.rs @@ -22,6 +22,7 @@ use futures03::{StreamExt as _, TryStreamExt as _}; use log::{info, warn}; use sr_primitives::traits::Header; use service::AbstractService; +use std::time::Duration; mod display; @@ -31,11 +32,13 @@ pub fn build(service: &impl AbstractService) -> impl Future { select_chain: Option, network: Arc, /// Sinks to propagate network status updates. - network_status_sinks: Arc>>>, + /// For each element, every time the `Interval` fires we push an element on the sender. + network_status_sinks: Arc>>, transaction_pool: Arc, /// A future that resolves when the service has exited, this is useful to /// make sure any internally spawned futures stop when the service does. @@ -210,7 +211,7 @@ macro_rules! new_impl { let has_bootnodes = !network_params.network_config.boot_nodes.is_empty(); let network_mut = network::NetworkWorker::new(network_params)?; let network = network_mut.service().clone(); - let network_status_sinks = Arc::new(Mutex::new(Vec::new())); + let network_status_sinks = Arc::new(Mutex::new(status_sinks::StatusSinks::new())); let offchain_storage = backend.offchain_storage(); let offchain_workers = match ($config.offchain_worker, offchain_storage) { @@ -296,9 +297,9 @@ macro_rules! new_impl { let client_ = client.clone(); let mut sys = System::new(); let self_pid = get_current_pid().ok(); - let (netstat_tx, netstat_rx) = mpsc::unbounded::<(NetworkStatus<_>, NetworkState)>(); - network_status_sinks.lock().push(netstat_tx); - let tel_task = netstat_rx.for_each(move |(net_status, network_state)| { + let (state_tx, state_rx) = mpsc::unbounded::<(NetworkStatus<_>, NetworkState)>(); + network_status_sinks.lock().push(std::time::Duration::from_millis(5000), state_tx); + let tel_task = state_rx.for_each(move |(net_status, _)| { let info = client_.info(); let best_number = info.chain.best_number.saturated_into::(); let best_hash = info.chain.best_hash; @@ -325,7 +326,6 @@ macro_rules! new_impl { telemetry!( SUBSTRATE_INFO; "system.interval"; - "network_state" => network_state, "peers" => num_peers, "height" => best_number, "best" => ?best_hash, @@ -343,6 +343,19 @@ macro_rules! new_impl { }).select(exit.clone()).then(|_| Ok(())); let _ = to_spawn_tx.unbounded_send(Box::new(tel_task)); + // Periodically send the network state to the telemetry. + let (netstat_tx, netstat_rx) = mpsc::unbounded::<(NetworkStatus<_>, NetworkState)>(); + network_status_sinks.lock().push(std::time::Duration::from_secs(30), netstat_tx); + let tel_task_2 = netstat_rx.for_each(move |(_, network_state)| { + telemetry!( + SUBSTRATE_INFO; + "system.network_state"; + "state" => network_state, + ); + Ok(()) + }).select(exit.clone()).then(|_| Ok(())); + let _ = to_spawn_tx.unbounded_send(Box::new(tel_task_2)); + // RPC let (system_rpc_tx, system_rpc_rx) = futures03::channel::mpsc::unbounded(); let gen_handler = || { @@ -507,7 +520,7 @@ pub trait AbstractService: 'static + Future + fn network(&self) -> Arc>; /// Returns a receiver that periodically receives a status of the network. - fn network_status(&self) -> mpsc::UnboundedReceiver<(NetworkStatus, NetworkState)>; + fn network_status(&self, interval: Duration) -> mpsc::UnboundedReceiver<(NetworkStatus, NetworkState)>; /// Get shared transaction pool instance. fn transaction_pool(&self) -> Arc>; @@ -590,9 +603,9 @@ where self.network.clone() } - fn network_status(&self) -> mpsc::UnboundedReceiver<(NetworkStatus, NetworkState)> { + fn network_status(&self, interval: Duration) -> mpsc::UnboundedReceiver<(NetworkStatus, NetworkState)> { let (sink, stream) = mpsc::unbounded(); - self.network_status_sinks.lock().push(sink); + self.network_status_sinks.lock().push(interval, sink); stream } @@ -666,7 +679,7 @@ fn build_network_future< roles: Roles, mut network: network::NetworkWorker, client: Arc, - status_sinks: Arc, NetworkState)>>>>, + status_sinks: Arc, NetworkState)>>>, rpc_rx: futures03::channel::mpsc::UnboundedReceiver>, should_have_peers: bool, dht_event_tx: Option>, @@ -675,10 +688,6 @@ fn build_network_future< // See https://github.com/paritytech/substrate/issues/3099 let mut rpc_rx = futures03::compat::Compat::new(rpc_rx.map(|v| Ok::<_, ()>(v))); - // Interval at which we send status updates on the status stream. - const STATUS_INTERVAL: Duration = Duration::from_millis(5000); - let mut status_interval = tokio_timer::Interval::new_interval(STATUS_INTERVAL); - let mut imported_blocks_stream = client.import_notification_stream().fuse() .map(|v| Ok::<_, ()>(v)).compat(); let mut finality_notification_stream = client.finality_notification_stream().fuse() @@ -746,7 +755,7 @@ fn build_network_future< } // Interval report for the external API. - while let Ok(Async::Ready(_)) = status_interval.poll() { + status_sinks.lock().poll(|| { let status = NetworkStatus { sync_state: network.sync_state(), best_seen_block: network.best_seen_block(), @@ -757,9 +766,8 @@ fn build_network_future< average_upload_per_sec: network.average_upload_per_sec(), }; let state = network.network_state(); - - status_sinks.lock().retain(|sink| sink.unbounded_send((status.clone(), state.clone())).is_ok()); - } + (status, state) + }); // Main network polling. while let Ok(Async::Ready(Some(Event::Dht(event)))) = network.poll().map_err(|err| { diff --git a/core/service/src/status_sinks.rs b/core/service/src/status_sinks.rs new file mode 100644 index 0000000000..079ecf6353 --- /dev/null +++ b/core/service/src/status_sinks.rs @@ -0,0 +1,149 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +use futures::prelude::*; +use futures::sync::mpsc; +use futures::stream::futures_unordered::FuturesUnordered; +use std::time::{Duration, Instant}; +use tokio_timer::Delay; + +/// Holds a list of `UnboundedSender`s, each associated with a certain time period. Every time the +/// period elapses, we push an element on the sender. +/// +/// Senders are removed only when they are closed. +pub struct StatusSinks { + entries: FuturesUnordered>, +} + +struct YieldAfter { + delay: tokio_timer::Delay, + interval: Duration, + sender: Option>, +} + +impl StatusSinks { + /// Builds a new empty collection. + pub fn new() -> StatusSinks { + StatusSinks { + entries: FuturesUnordered::new(), + } + } + + /// Adds a sender to the collection. + /// + /// The `interval` is the time period between two pushes on the sender. + pub fn push(&mut self, interval: Duration, sender: mpsc::UnboundedSender) { + self.entries.push(YieldAfter { + delay: Delay::new(Instant::now() + interval), + interval, + sender: Some(sender), + }) + } + + /// Processes all the senders. If any sender is ready, calls the `status_grab` function and + /// pushes what it returns to the sender. + /// + /// This function doesn't return anything, but it should be treated as if it implicitly + /// returns `Ok(Async::NotReady)`. In particular, it should be called again when the task + /// is waken up. + /// + /// # Panic + /// + /// Panics if not called within the context of a task. + pub fn poll(&mut self, mut status_grab: impl FnMut() -> T) { + loop { + match self.entries.poll() { + Ok(Async::Ready(Some((sender, interval)))) => { + let status = status_grab(); + if sender.unbounded_send(status).is_ok() { + self.entries.push(YieldAfter { + // Note that since there's a small delay between the moment a task is + // waken up and the moment it is polled, the period is actually not + // `interval` but `interval + `. We ignore this problem in + // practice. + delay: Delay::new(Instant::now() + interval), + interval, + sender: Some(sender), + }); + } + } + Err(()) | + Ok(Async::Ready(None)) | + Ok(Async::NotReady) => break, + } + } + } +} + +impl Future for YieldAfter { + type Item = (mpsc::UnboundedSender, Duration); + type Error = (); + + fn poll(&mut self) -> Poll { + match self.delay.poll() { + Ok(Async::NotReady) => Ok(Async::NotReady), + Ok(Async::Ready(())) => { + let sender = self.sender.take() + .expect("sender is always Some unless the future is finished; qed"); + Ok(Async::Ready((sender, self.interval))) + }, + Err(_) => Err(()), + } + } +} + +#[cfg(test)] +mod tests { + use super::StatusSinks; + use futures::prelude::*; + use futures::sync::mpsc; + use std::time::Duration; + + #[test] + fn basic_usage() { + let mut status_sinks = StatusSinks::new(); + + let (tx1, rx1) = mpsc::unbounded(); + status_sinks.push(Duration::from_millis(200), tx1); + + let (tx2, rx2) = mpsc::unbounded(); + status_sinks.push(Duration::from_millis(500), tx2); + + let mut runtime = tokio::runtime::Runtime::new().unwrap(); + + let mut val_order = 5; + runtime.spawn(futures::future::poll_fn(move || { + status_sinks.poll(|| { val_order += 1; val_order }); + Ok(Async::NotReady) + })); + + let done = rx1 + .into_future() + .and_then(|(item, rest)| { + assert_eq!(item, Some(6)); + rest.into_future() + }) + .and_then(|(item, _)| { + assert_eq!(item, Some(7)); + rx2.into_future() + }) + .map(|(item, _)| { + assert_eq!(item, Some(8)); + }); + + runtime.block_on(done).unwrap(); + } +} -- GitLab From e17836bb4cd5b1203416a980f28c0422c1491022 Mon Sep 17 00:00:00 2001 From: Ryan Bell Date: Thu, 24 Oct 2019 00:29:58 -0700 Subject: [PATCH 091/167] Update README.adoc (#3900) --- README.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.adoc b/README.adoc index 6563340cc6..bb23958bce 100644 --- a/README.adoc +++ b/README.adoc @@ -418,7 +418,7 @@ curl -H 'Content-Type: application/json' --data '{ "jsonrpc":"2.0", "method":"au === Viewing documentation for Substrate packages You can generate documentation for a Substrate Rust package and have it automatically open in your web browser using https://doc.rust-lang.org/rustdoc/what-is-rustdoc.html#using-rustdoc-with-cargo[rustdoc with Cargo], -(of the The Rustdoc Book), by running the the following command: +(of the The Rustdoc Book), by running the following command: ``` cargo doc --package --open -- GitLab From a1226ebdae46ebd27f36f439b633bc809614bd30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= Date: Thu, 24 Oct 2019 09:14:32 +0100 Subject: [PATCH 092/167] node: spawn grandpa voter as essential task (#3899) * node: spawn grandpa voter as essential task * node: stop babe authoring task on exit * node: remove unnecessary future boxing * Apply suggestions from code review --- node-template/src/service.rs | 8 ++++---- node/cli/src/service.rs | 9 ++++++--- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/node-template/src/service.rs b/node-template/src/service.rs index 7934355812..c46928c10e 100644 --- a/node-template/src/service.rs +++ b/node-template/src/service.rs @@ -115,11 +115,11 @@ pub fn new_full(config: Configuration(config: Configuration { // start the lightweight GRANDPA observer - service.spawn_task(Box::new(grandpa::run_grandpa_observer( + service.spawn_task(grandpa::run_grandpa_observer( grandpa_config, grandpa_link, service.network(), service.on_exit(), - )?)); + )?); }, (true, false) => { // start the full GRANDPA voter diff --git a/node/cli/src/service.rs b/node/cli/src/service.rs index 983908c07d..0f4a098f3d 100644 --- a/node/cli/src/service.rs +++ b/node/cli/src/service.rs @@ -175,6 +175,7 @@ macro_rules! new_full { service.network(), dht_event_rx, ); + service.spawn_task(authority_discovery); } @@ -189,12 +190,12 @@ macro_rules! new_full { match (is_authority, disable_grandpa) { (false, false) => { // start the lightweight GRANDPA observer - service.spawn_task(Box::new(grandpa::run_grandpa_observer( + service.spawn_task(grandpa::run_grandpa_observer( config, grandpa_link, service.network(), service.on_exit(), - )?)); + )?); }, (true, false) => { // start the full GRANDPA voter @@ -207,7 +208,9 @@ macro_rules! new_full { telemetry_on_connect: Some(service.telemetry_on_connect_stream()), voting_rule: grandpa::VotingRulesBuilder::default().build(), }; - service.spawn_task(Box::new(grandpa::run_grandpa_voter(grandpa_config)?)); + // the GRANDPA voter task is considered infallible, i.e. + // if it fails we take down the service with it. + service.spawn_essential_task(grandpa::run_grandpa_voter(grandpa_config)?); }, (_, true) => { grandpa::setup_disabled_grandpa( -- GitLab From cc0b1d08d6e0e7e9690947f484c9a1e2265bf05d Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Thu, 24 Oct 2019 10:59:09 +0200 Subject: [PATCH 093/167] Add SECP256k1/ECDSA support for transaction signing (#3861) * Add SECP256k1/ECDSA support for transaction signing. * Refactoring and fixes * Fix for contracts * Avoid breaking runtime host function * Build fixes, make subkey work more generaically. * Fix tests * Dedpulicate a bit of code, remove unneeded code, docs * Bump runtime version * Fix a test and clean up some code. * Derivation can derive seed. * Whitespace * Bump runtime again. * Update core/primitives/src/crypto.rs Co-Authored-By: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update core/primitives/src/ecdsa.rs Co-Authored-By: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Fix AppVerify --- Cargo.lock | 2 + core/application-crypto/src/lib.rs | 13 +- core/application-crypto/src/traits.rs | 1 + core/executor/src/host_interface.rs | 82 ++- core/keyring/src/ed25519.rs | 15 + core/keyring/src/sr25519.rs | 15 + core/primitives/Cargo.toml | 4 + core/primitives/src/crypto.rs | 286 +++++--- core/primitives/src/ecdsa.rs | 608 ++++++++++++++++++ core/primitives/src/ed25519.rs | 20 +- core/primitives/src/hexdisplay.rs | 2 +- core/primitives/src/lib.rs | 1 + core/primitives/src/sr25519.rs | 53 +- core/sr-io/src/lib.rs | 9 +- core/sr-io/with_std.rs | 10 + core/sr-io/without_std.rs | 24 + .../src/generic/unchecked_extrinsic.rs | 22 +- core/sr-primitives/src/lib.rs | 60 +- core/sr-primitives/src/traits.rs | 73 ++- node/cli/src/chain_spec.rs | 67 +- node/cli/src/factory_impl.rs | 13 +- node/cli/src/service.rs | 17 +- node/primitives/src/lib.rs | 9 +- node/runtime/src/lib.rs | 59 +- node/testing/src/keyring.rs | 6 +- srml/system/src/offchain.rs | 71 +- subkey/src/cli.yml | 5 + subkey/src/main.rs | 146 +++-- subkey/src/vanity.rs | 6 +- test-utils/chain-spec-builder/src/main.rs | 6 +- 30 files changed, 1286 insertions(+), 419 deletions(-) create mode 100644 core/primitives/src/ecdsa.rs diff --git a/Cargo.lock b/Cargo.lock index a87da6586c..14f8c87c1a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5366,6 +5366,7 @@ dependencies = [ "hex-literal 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "impl-serde 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libsecp256k1 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -5385,6 +5386,7 @@ dependencies = [ "substrate-primitives-storage 2.0.0", "substrate-serializer 2.0.0", "tiny-bip39 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tiny-keccak 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "twox-hash 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "wasmi 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "zeroize 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/core/application-crypto/src/lib.rs b/core/application-crypto/src/lib.rs index 16eda53238..b4ada5425b 100644 --- a/core/application-crypto/src/lib.rs +++ b/core/application-crypto/src/lib.rs @@ -88,22 +88,13 @@ macro_rules! app_crypto { } fn derive< Iter: Iterator - >(&self, path: Iter) -> Result { - self.0.derive(path).map(Self) + >(&self, path: Iter, seed: Option) -> Result<(Self, Option), Self::DeriveError> { + self.0.derive(path, seed).map(|x| (Self(x.0), x.1)) } 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)) } diff --git a/core/application-crypto/src/traits.rs b/core/application-crypto/src/traits.rs index 49d3a44aee..66e6cd6579 100644 --- a/core/application-crypto/src/traits.rs +++ b/core/application-crypto/src/traits.rs @@ -126,3 +126,4 @@ pub trait RuntimeAppPublic: Sized { /// Verify that the given signature matches the given message using this public key. fn verify>(&self, msg: &M, signature: &Self::Signature) -> bool; } + diff --git a/core/executor/src/host_interface.rs b/core/executor/src/host_interface.rs index e6386ff1ac..7d87d93333 100644 --- a/core/executor/src/host_interface.rs +++ b/core/executor/src/host_interface.rs @@ -41,6 +41,40 @@ macro_rules! debug_trace { pub struct SubstrateExternals; +enum RecoverResult { + Invalid(u32), + Valid(secp256k1::PublicKey), +} + +fn secp256k1_recover( + context: &mut dyn FunctionContext, + msg_data: Pointer, + sig_data: Pointer, +) -> WResult { + let mut sig = [0u8; 65]; + context.read_memory_into(sig_data, &mut sig[..]) + .map_err(|_| "Invalid attempt to get signature in ext_secp256k1_ecdsa_recover")?; + let rs = match secp256k1::Signature::parse_slice(&sig[0..64]) { + Ok(rs) => rs, + _ => return Ok(RecoverResult::Invalid(1)), + }; + + let recovery_id = if sig[64] > 26 { sig[64] - 27 } else { sig[64] } as u8; + let v = match secp256k1::RecoveryId::parse(recovery_id) { + Ok(v) => v, + _ => return Ok(RecoverResult::Invalid(2)), + }; + + let mut msg = [0u8; 32]; + context.read_memory_into(msg_data, &mut msg[..]) + .map_err(|_| "Invalid attempt to get message in ext_secp256k1_ecdsa_recover")?; + + Ok(match secp256k1::recover(&secp256k1::Message::parse(&msg), &rs, &v) { + Ok(pubkey) => RecoverResult::Valid(pubkey), + Err(_) => RecoverResult::Invalid(3), + }) +} + impl_wasm_host_interface! { impl SubstrateExternals where context { ext_malloc(size: WordSize) -> Pointer { @@ -781,33 +815,29 @@ impl_wasm_host_interface! { sig_data: Pointer, pubkey_data: Pointer, ) -> u32 { - let mut sig = [0u8; 65]; - context.read_memory_into(sig_data, &mut sig[..]) - .map_err(|_| "Invalid attempt to get signature in ext_secp256k1_ecdsa_recover")?; - let rs = match secp256k1::Signature::parse_slice(&sig[0..64]) { - Ok(rs) => rs, - _ => return Ok(1), - }; - - let recovery_id = if sig[64] > 26 { sig[64] - 27 } else { sig[64] } as u8; - let v = match secp256k1::RecoveryId::parse(recovery_id) { - Ok(v) => v, - _ => return Ok(2), - }; - - let mut msg = [0u8; 32]; - context.read_memory_into(msg_data, &mut msg[..]) - .map_err(|_| "Invalid attempt to get message in ext_secp256k1_ecdsa_recover")?; - - let pubkey = match secp256k1::recover(&secp256k1::Message::parse(&msg), &rs, &v) { - Ok(pk) => pk, - _ => return Ok(3), - }; - - context.write_memory(pubkey_data, &pubkey.serialize()[1..65]) - .map_err(|_| "Invalid attempt to set pubkey in ext_secp256k1_ecdsa_recover")?; + match secp256k1_recover(context, msg_data, sig_data)? { + RecoverResult::Invalid(c) => Ok(c), + RecoverResult::Valid(pubkey) => { + context.write_memory(pubkey_data, &pubkey.serialize()[1..65]) + .map_err(|_| "Invalid attempt to set pubkey in ext_secp256k1_ecdsa_recover")?; + Ok(0) + } + } + } - Ok(0) + ext_secp256k1_ecdsa_recover_compressed( + msg_data: Pointer, + sig_data: Pointer, + pubkey_data: Pointer, + ) -> u32 { + match secp256k1_recover(context, msg_data, sig_data)? { + RecoverResult::Invalid(c) => Ok(c), + RecoverResult::Valid(pubkey) => { + context.write_memory(pubkey_data, &pubkey.serialize_compressed()[..]) + .map_err(|_| "Invalid attempt to set pubkey in ext_secp256k1_ecdsa_recover")?; + Ok(0) + } + } } ext_is_validator() -> u32 { diff --git a/core/keyring/src/ed25519.rs b/core/keyring/src/ed25519.rs index 56bdb1ce8c..c1a357fc0e 100644 --- a/core/keyring/src/ed25519.rs +++ b/core/keyring/src/ed25519.rs @@ -20,6 +20,7 @@ use std::{collections::HashMap, ops::Deref}; use lazy_static::lazy_static; use primitives::{ed25519::{Pair, Public, Signature}, Pair as PairT, Public as PublicT, H256}; pub use primitives::ed25519; +use sr_primitives::AccountId32; /// Set of test accounts. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, strum_macros::Display, strum_macros::EnumIter)] @@ -39,6 +40,10 @@ impl Keyring { Self::iter().find(|&k| &Public::from(k) == who) } + pub fn from_account_id(who: &AccountId32) -> Option { + Self::iter().find(|&k| &k.to_account_id() == who) + } + pub fn from_raw_public(who: [u8; 32]) -> Option { Self::from_public(&Public::from_raw(who)) } @@ -59,6 +64,10 @@ impl Keyring { Public::from(self).to_raw_vec() } + pub fn to_account_id(self) -> AccountId32 { + self.to_raw_public().into() + } + pub fn sign(self, msg: &[u8]) -> Signature { Pair::from(self).sign(msg) } @@ -119,6 +128,12 @@ impl From for Public { } } +impl From for AccountId32 { + fn from(k: Keyring) -> Self { + k.to_account_id() + } +} + impl From for Pair { fn from(k: Keyring) -> Self { k.pair() diff --git a/core/keyring/src/sr25519.rs b/core/keyring/src/sr25519.rs index bb3aaa6b51..b37b2bdf9b 100644 --- a/core/keyring/src/sr25519.rs +++ b/core/keyring/src/sr25519.rs @@ -21,6 +21,7 @@ use std::ops::Deref; use lazy_static::lazy_static; use primitives::{sr25519::{Pair, Public, Signature}, Pair as PairT, Public as PublicT, H256}; pub use primitives::sr25519; +use sr_primitives::AccountId32; /// Set of test accounts. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, strum_macros::Display, strum_macros::EnumIter)] @@ -40,6 +41,10 @@ impl Keyring { Self::iter().find(|&k| &Public::from(k) == who) } + pub fn from_account_id(who: &AccountId32) -> Option { + Self::iter().find(|&k| &k.to_account_id() == who) + } + pub fn from_raw_public(who: [u8; 32]) -> Option { Self::from_public(&Public::from_raw(who)) } @@ -60,6 +65,10 @@ impl Keyring { Public::from(self).to_raw_vec() } + pub fn to_account_id(self) -> AccountId32 { + self.to_raw_public().into() + } + pub fn sign(self, msg: &[u8]) -> Signature { Pair::from(self).sign(msg) } @@ -114,6 +123,12 @@ lazy_static! { }; } +impl From for AccountId32 { + fn from(k: Keyring) -> Self { + k.to_account_id() + } +} + impl From for Public { fn from(k: Keyring) -> Self { (*PUBLIC_KEYS).get(&k).unwrap().clone() diff --git a/core/primitives/Cargo.toml b/core/primitives/Cargo.toml index 557ce55b88..bc8106de3a 100644 --- a/core/primitives/Cargo.toml +++ b/core/primitives/Cargo.toml @@ -31,6 +31,8 @@ num-traits = { version = "0.2.8", default-features = false } zeroize = "0.10.1" lazy_static = { version = "1.4.0", optional = true } parking_lot = { version = "0.9.0", optional = true } +libsecp256k1 = { version = "0.3.0", optional = true } +tiny-keccak = { version = "1.5.0", optional = true } substrate-debug-derive = { version = "2.0.0", path = "./debug-derive" } externalities = { package = "substrate-externalities", path = "../externalities", optional = true } primitives-storage = { package = "substrate-primitives-storage", path = "storage", default-features = false } @@ -82,6 +84,8 @@ std = [ "schnorrkel", "regex", "num-traits/std", + "libsecp256k1", + "tiny-keccak", "substrate-debug-derive/std", "externalities", "primitives-storage/std", diff --git a/core/primitives/src/crypto.rs b/core/primitives/src/crypto.rs index 588f3bc6e2..b7c70e6224 100644 --- a/core/primitives/src/crypto.rs +++ b/core/primitives/src/crypto.rs @@ -255,7 +255,7 @@ pub enum PublicError { /// Key that can be encoded to/from SS58. #[cfg(feature = "std")] -pub trait Ss58Codec: Sized { +pub trait Ss58Codec: Sized + AsMut<[u8]> + AsRef<[u8]> + Default { /// Some if the string is a properly encoded SS58Check address. fn from_ss58check(s: &str) -> Result { Self::from_ss58check_with_version(s) @@ -269,7 +269,23 @@ pub trait Ss58Codec: Sized { }) } /// Some if the string is a properly encoded SS58Check address. - fn from_ss58check_with_version(s: &str) -> Result<(Self, Ss58AddressFormat), PublicError>; + fn from_ss58check_with_version(s: &str) -> Result<(Self, Ss58AddressFormat), PublicError> { + let mut res = Self::default(); + let len = res.as_mut().len(); + let d = s.from_base58().map_err(|_| PublicError::BadBase58)?; // failure here would be invalid encoding. + if d.len() != len + 3 { + // Invalid length. + return Err(PublicError::BadLength); + } + let ver = d[0].try_into().map_err(|_: ()| PublicError::UnknownVersion)?; + + if d[len + 1..len + 3] != ss58hash(&d[0..len + 1]).as_bytes()[0..2] { + // Invalid checksum. + return Err(PublicError::InvalidChecksum); + } + res.as_mut().copy_from_slice(&d[1..len + 1]); + Ok((res, ver)) + } /// Some if the string is a properly encoded SS58Check address, optionally with /// a derivation path following. fn from_string(s: &str) -> Result { @@ -285,7 +301,13 @@ pub trait Ss58Codec: Sized { } /// Return the ss58-check string for this key. - fn to_ss58check_with_version(&self, version: Ss58AddressFormat) -> String; + fn to_ss58check_with_version(&self, version: Ss58AddressFormat) -> String { + let mut v = vec![version.into()]; + v.extend(self.as_ref()); + let r = ss58hash(&v); + v.extend(&r.as_bytes()[0..2]); + v.to_base58() + } /// Return the ss58-check string for this key. fn to_ss58check(&self) -> String { self.to_ss58check_with_version(*DEFAULT_VERSION.lock()) } /// Some if the string is a properly encoded SS58Check address, optionally with @@ -408,44 +430,28 @@ pub fn set_default_ss58_version(version: Ss58AddressFormat) { } #[cfg(feature = "std")] -impl + AsRef<[u8]> + Default + Derive> Ss58Codec for T { - fn from_ss58check_with_version(s: &str) -> Result<(Self, Ss58AddressFormat), PublicError> { - let mut res = T::default(); - let len = res.as_mut().len(); - let d = s.from_base58().map_err(|_| PublicError::BadBase58)?; // failure here would be invalid encoding. - if d.len() != len + 3 { - // Invalid length. - return Err(PublicError::BadLength); - } - let ver = d[0].try_into().map_err(|_: ()| PublicError::UnknownVersion)?; - - if d[len+1..len+3] != ss58hash(&d[0..len+1]).as_bytes()[0..2] { - // Invalid checksum. - return Err(PublicError::InvalidChecksum); - } - res.as_mut().copy_from_slice(&d[1..len+1]); - Ok((res, ver)) - } - - fn to_ss58check_with_version(&self, version: Ss58AddressFormat) -> String { - let mut v = vec![version.into()]; - v.extend(self.as_ref()); - let r = ss58hash(&v); - v.extend(&r.as_bytes()[0..2]); - v.to_base58() - } - +impl + AsRef<[u8]> + Default + Derive> Ss58Codec for T { fn from_string(s: &str) -> Result { - let re = Regex::new(r"^(?P[\w\d]+)?(?P(//?[^/]+)*)$") + let re = Regex::new(r"^(?P[\w\d ]+)?(?P(//?[^/]+)*)$") .expect("constructed from known-good static value; qed"); let cap = re.captures(s).ok_or(PublicError::InvalidFormat)?; let re_junction = Regex::new(r"/(/?[^/]+)") .expect("constructed from known-good static value; qed"); - let addr = Self::from_ss58check( - cap.name("ss58") - .map(|r| r.as_str()) - .unwrap_or(DEV_ADDRESS) - )?; + let s = cap.name("ss58") + .map(|r| r.as_str()) + .unwrap_or(DEV_ADDRESS); + let addr = if s.starts_with("0x") { + let d = hex::decode(&s[2..]).map_err(|_| PublicError::InvalidFormat)?; + let mut r = Self::default(); + if d.len() == r.as_ref().len() { + r.as_mut().copy_from_slice(&d); + r + } else { + Err(PublicError::BadLength)? + } + } else { + Self::from_ss58check(s)? + }; if cap["path"].is_empty() { Ok(addr) } else { @@ -457,7 +463,7 @@ impl + AsRef<[u8]> + Default + Derive> Ss58Codec for T { } fn from_string_with_version(s: &str) -> Result<(Self, Ss58AddressFormat), PublicError> { - let re = Regex::new(r"^(?P[\w\d]+)?(?P(//?[^/]+)*)$") + let re = Regex::new(r"^(?P[\w\d ]+)?(?P(//?[^/]+)*)$") .expect("constructed from known-good static value; qed"); let cap = re.captures(s).ok_or(PublicError::InvalidFormat)?; let re_junction = Regex::new(r"/(/?[^/]+)") @@ -495,6 +501,103 @@ pub trait Public: AsRef<[u8]> + AsMut<[u8]> + Default + Derive + CryptoType + Pa fn as_slice(&self) -> &[u8] { self.as_ref() } } +/// An opaque 32-byte cryptographic identifier. +#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Default, Encode, Decode)] +pub struct AccountId32([u8; 32]); + +impl UncheckedFrom for AccountId32 { + fn unchecked_from(h: crate::hash::H256) -> Self { + AccountId32(h.into()) + } +} + +#[cfg(feature = "std")] +impl Ss58Codec for AccountId32 {} + +impl AsRef<[u8]> for AccountId32 { + fn as_ref(&self) -> &[u8] { + &self.0[..] + } +} + +impl AsMut<[u8]> for AccountId32 { + fn as_mut(&mut self) -> &mut [u8] { + &mut self.0[..] + } +} + +impl AsRef<[u8; 32]> for AccountId32 { + fn as_ref(&self) -> &[u8; 32] { + &self.0 + } +} + +impl AsMut<[u8; 32]> for AccountId32 { + fn as_mut(&mut self) -> &mut [u8; 32] { + &mut self.0 + } +} + +impl From<[u8; 32]> for AccountId32 { + fn from(x: [u8; 32]) -> AccountId32 { + AccountId32(x) + } +} + +impl<'a> rstd::convert::TryFrom<&'a [u8]> for AccountId32 { + type Error = (); + fn try_from(x: &'a [u8]) -> Result { + if x.len() == 32 { + let mut r = AccountId32::default(); + r.0.copy_from_slice(x); + Ok(r) + } else { + Err(()) + } + } +} + +impl From for [u8; 32] { + fn from(x: AccountId32) -> [u8; 32] { + x.0 + } +} + +#[cfg(feature = "std")] +impl std::fmt::Display for AccountId32 { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{}", self.to_ss58check()) + } +} + +impl rstd::fmt::Debug for AccountId32 { + #[cfg(feature = "std")] + fn fmt(&self, f: &mut rstd::fmt::Formatter) -> rstd::fmt::Result { + let s = self.to_ss58check(); + write!(f, "{} ({}...)", crate::hexdisplay::HexDisplay::from(&self.0), &s[0..8]) + } + + #[cfg(not(feature = "std"))] + fn fmt(&self, _: &mut rstd::fmt::Formatter) -> rstd::fmt::Result { + Ok(()) + } +} + +#[cfg(feature = "std")] +impl serde::Serialize for AccountId32 { + fn serialize(&self, serializer: S) -> Result where S: serde::Serializer { + serializer.serialize_str(&self.to_ss58check()) + } +} + +#[cfg(feature = "std")] +impl<'de> serde::Deserialize<'de> for AccountId32 { + fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de> { + Ss58Codec::from_ss58check(&String::deserialize(deserializer)?) + .map_err(|e| serde::de::Error::custom(format!("{:?}", e))) + } +} + #[cfg(feature = "std")] pub use self::dummy::*; @@ -544,17 +647,10 @@ mod dummy { Ok(Default::default()) } fn derive< - Iter: Iterator - >(&self, _: Iter) -> Result { Ok(Self) } + Iter: Iterator, + >(&self, _: Iter, _: Option) -> Result<(Self, Option), Self::DeriveError> { Ok((Self, None)) } 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>(_: &Self::Signature, _: M, _: &Self::Public) -> bool { true } fn verify_weak, M: AsRef<[u8]>>(_: &[u8], _: M, _: P) -> bool { true } @@ -604,7 +700,10 @@ pub trait Pair: CryptoType + Sized + Clone + Send + Sync + 'static { fn from_phrase(phrase: &str, password: Option<&str>) -> Result<(Self, Self::Seed), SecretStringError>; /// Derive a child key from a series of given junctions. - fn derive>(&self, path: Iter) -> Result; + fn derive>(&self, + path: Iter, + seed: Option, + ) -> Result<(Self, Option), Self::DeriveError>; /// Generate new key pair from the provided `seed`. /// @@ -619,11 +718,6 @@ pub trait Pair: CryptoType + Sized + Clone + Send + Sync + 'static { /// by an attacker then they can also derive your key. fn from_seed_slice(seed: &[u8]) -> Result; - /// Construct a key from a phrase, password and path. - fn from_standard_components< - I: Iterator - >(phrase: &str, password: Option<&str>, path: I) -> Result; - /// Sign a message. fn sign(&self, message: &[u8]) -> Self::Signature; @@ -636,7 +730,9 @@ pub trait Pair: CryptoType + Sized + Clone + Send + Sync + 'static { /// Get the public key. fn public(&self) -> Self::Public; - /// Interprets the string `s` in order to generate a key Pair. + /// Interprets the string `s` in order to generate a key Pair. Returns both the pair and an optional seed, in the + /// case that the pair can be expressed as a direct derivation from a seed (some cases, such as Sr25519 derivations + /// with path components, cannot). /// /// This takes a helper function to do the key generation from a phrase, password and /// junction iterator. @@ -662,31 +758,40 @@ pub trait Pair: CryptoType + Sized + Clone + Send + Sync + 'static { /// be equivalent to no password at all. /// /// `None` is returned if no matches are found. - fn from_string(s: &str, password_override: Option<&str>) -> Result { - let hex_seed = if s.starts_with("0x") { - &s[2..] - } else { - s - }; - - if let Ok(d) = hex::decode(hex_seed) { - if let Ok(r) = Self::from_seed_slice(&d) { - return Ok(r) - } - } - - let re = Regex::new(r"^(?P\w+( \w+)*)?(?P(//?[^/]+)*)(///(?P.*))?$") + fn from_string_with_seed(s: &str, password_override: Option<&str>) -> Result<(Self, Option), SecretStringError> { + let re = Regex::new(r"^(?P[\d\w ]+)?(?P(//?[^/]+)*)(///(?P.*))?$") .expect("constructed from known-good static value; qed"); let cap = re.captures(s).ok_or(SecretStringError::InvalidFormat)?; + let re_junction = Regex::new(r"/(/?[^/]+)") .expect("constructed from known-good static value; qed"); let path = re_junction.captures_iter(&cap["path"]) .map(|f| DeriveJunction::from(&f[1])); - Self::from_standard_components( - cap.name("phrase").map(|r| r.as_str()).unwrap_or(DEV_PHRASE), - password_override.or_else(|| cap.name("password").map(|m| m.as_str())), - path, - ) + + let phrase = cap.name("phrase").map(|r| r.as_str()).unwrap_or(DEV_PHRASE); + let password = password_override.or_else(|| cap.name("password").map(|m| m.as_str())); + + let (root, seed) = if phrase.starts_with("0x") { + hex::decode(&phrase[2..]).ok() + .and_then(|seed_vec| { + let mut seed = Self::Seed::default(); + if seed.as_ref().len() == seed_vec.len() { + seed.as_mut().copy_from_slice(&seed_vec); + Some((Self::from_seed(&seed), seed)) + } else { + None + } + }) + .ok_or(SecretStringError::InvalidSeed)? + } else { + Self::from_phrase(phrase, password) + .map_err(|_| SecretStringError::InvalidPhrase)? + }; + root.derive(path, Some(seed)).map_err(|_| SecretStringError::InvalidPath) + } + + fn from_string(s: &str, password_override: Option<&str>) -> Result { + Self::from_string_with_seed(s, password_override).map(|x| x.0) } /// Return a vec filled with raw data. @@ -846,13 +951,13 @@ mod tests { } impl Pair for TestPair { type Public = TestPublic; - type Seed = [u8; 0]; + type Seed = [u8; 8]; type Signature = [u8; 0]; type DeriveError = (); - fn generate() -> (Self, ::Seed) { (TestPair::Generated, []) } + fn generate() -> (Self, ::Seed) { (TestPair::Generated, [0u8; 8]) } fn generate_with_phrase(_password: Option<&str>) -> (Self, String, ::Seed) { - (TestPair::GeneratedWithPhrase, "".into(), []) + (TestPair::GeneratedWithPhrase, "".into(), [0u8; 8]) } fn from_phrase(phrase: &str, password: Option<&str>) -> Result<(Self, ::Seed), SecretStringError> @@ -860,14 +965,20 @@ mod tests { Ok((TestPair::GeneratedFromPhrase { phrase: phrase.to_owned(), password: password.map(Into::into) - }, [])) + }, [0u8; 8])) } - fn derive>(&self, _path: Iter) - -> Result + fn derive>(&self, path_iter: Iter, _: Option<[u8; 8]>) + -> Result<(Self, Option<[u8; 8]>), Self::DeriveError> { - Err(()) + Ok((match self.clone() { + TestPair::Standard {phrase, password, path} => + TestPair::Standard { phrase, password, path: path.into_iter().chain(path_iter).collect() }, + TestPair::GeneratedFromPhrase {phrase, password} => + TestPair::Standard { phrase, password, path: path_iter.collect() }, + x => if path_iter.count() == 0 { x } else { return Err(()) }, + }, None)) } - fn from_seed(_seed: &::Seed) -> Self { TestPair::Seed(vec![]) } + fn from_seed(_seed: &::Seed) -> Self { TestPair::Seed(_seed.as_ref().to_owned()) } fn sign(&self, _message: &[u8]) -> Self::Signature { [] } fn verify>(_: &Self::Signature, _: M, _: &Self::Public) -> bool { true } fn verify_weak, M: AsRef<[u8]>>( @@ -876,17 +987,6 @@ mod tests { _pubkey: P ) -> bool { true } fn public(&self) -> Self::Public { TestPublic } - fn from_standard_components>( - phrase: &str, - password: Option<&str>, - path: I - ) -> Result { - Ok(TestPair::Standard { - phrase: phrase.to_owned(), - password: password.map(ToOwned::to_owned), - path: path.collect() - }) - } fn from_seed_slice(seed: &[u8]) -> Result { @@ -903,10 +1003,6 @@ mod tests { TestPair::from_string("0x0123456789abcdef", None), Ok(TestPair::Seed(hex!["0123456789abcdef"][..].to_owned())) ); - assert_eq!( - TestPair::from_string("0123456789abcdef", None), - Ok(TestPair::Seed(hex!["0123456789abcdef"][..].to_owned())) - ); } #[test] diff --git a/core/primitives/src/ecdsa.rs b/core/primitives/src/ecdsa.rs new file mode 100644 index 0000000000..abff460c91 --- /dev/null +++ b/core/primitives/src/ecdsa.rs @@ -0,0 +1,608 @@ +// Copyright 2017-2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +// tag::description[] +//! Simple ECDSA API. +// end::description[] + +use rstd::cmp::Ordering; +use codec::{Encode, Decode}; + +#[cfg(feature = "std")] +use std::convert::{TryFrom, TryInto}; +#[cfg(feature = "std")] +use substrate_bip39::seed_from_entropy; +#[cfg(feature = "std")] +use bip39::{Mnemonic, Language, MnemonicType}; +#[cfg(feature = "std")] +use crate::{hashing::blake2_256, crypto::{Pair as TraitPair, DeriveJunction, SecretStringError, Ss58Codec}}; +#[cfg(feature = "std")] +use serde::{de, Serializer, Serialize, Deserializer, Deserialize}; +use crate::crypto::{Public as TraitPublic, UncheckedFrom, CryptoType, Derive}; +#[cfg(feature = "std")] +use secp256k1::{PublicKey, SecretKey}; + +/// A secret seed (which is bytewise essentially equivalent to a SecretKey). +/// +/// We need it as a different type because `Seed` is expected to be AsRef<[u8]>. +#[cfg(feature = "std")] +type Seed = [u8; 32]; + +/// The ECDSA 33-byte compressed public key. +#[derive(Clone, Encode, Decode)] +pub struct Public(pub [u8; 33]); + +impl PartialOrd for Public { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for Public { + fn cmp(&self, other: &Self) -> Ordering { + self.0[..].cmp(&other.0[..]) + } +} + +impl PartialEq for Public { + fn eq(&self, other: &Self) -> bool { + &self.0[..] == &other.0[..] + } +} + +impl Eq for Public {} + +impl Default for Public { + fn default() -> Self { + Public([0u8; 33]) + } +} + +/// A key pair. +#[cfg(feature = "std")] +#[derive(Clone)] +pub struct Pair { + public: PublicKey, + secret: SecretKey, +} + +impl AsRef<[u8; 33]> for Public { + fn as_ref(&self) -> &[u8; 33] { + &self.0 + } +} + +impl AsRef<[u8]> for Public { + fn as_ref(&self) -> &[u8] { + &self.0[..] + } +} + +impl AsMut<[u8]> for Public { + fn as_mut(&mut self) -> &mut [u8] { + &mut self.0[..] + } +} + +impl rstd::convert::TryFrom<&[u8]> for Public { + type Error = (); + + fn try_from(data: &[u8]) -> Result { + if data.len() == 33 { + let mut inner = [0u8; 33]; + inner.copy_from_slice(data); + Ok(Public(inner)) + } else { + Err(()) + } + } +} + +impl From for [u8; 33] { + fn from(x: Public) -> Self { + x.0 + } +} + +#[cfg(feature = "std")] +impl From for Public { + fn from(x: Pair) -> Self { + x.public() + } +} + +impl UncheckedFrom<[u8; 33]> for Public { + fn unchecked_from(x: [u8; 33]) -> Self { + Public(x) + } +} + +#[cfg(feature = "std")] +impl std::fmt::Display for Public { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{}", self.to_ss58check()) + } +} + +#[cfg(feature = "std")] +impl std::fmt::Debug for Public { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + let s = self.to_ss58check(); + write!(f, "{} ({}...)", crate::hexdisplay::HexDisplay::from(&&self.0[..]), &s[0..8]) + } +} + +#[cfg(feature = "std")] +impl Serialize for Public { + fn serialize(&self, serializer: S) -> Result where S: Serializer { + serializer.serialize_str(&self.to_ss58check()) + } +} + +#[cfg(feature = "std")] +impl<'de> Deserialize<'de> for Public { + fn deserialize(deserializer: D) -> Result where D: Deserializer<'de> { + Public::from_ss58check(&String::deserialize(deserializer)?) + .map_err(|e| de::Error::custom(format!("{:?}", e))) + } +} + +#[cfg(feature = "std")] +impl std::hash::Hash for Public { + fn hash(&self, state: &mut H) { + self.0.hash(state); + } +} + +/// A signature (a 512-bit value). +#[derive(Encode, Decode)] +pub struct Signature([u8; 65]); + +impl rstd::convert::TryFrom<&[u8]> for Signature { + type Error = (); + + fn try_from(data: &[u8]) -> Result { + if data.len() == 65 { + let mut inner = [0u8; 65]; + inner.copy_from_slice(data); + Ok(Signature(inner)) + } else { + Err(()) + } + } +} + +impl Clone for Signature { + fn clone(&self) -> Self { + let mut r = [0u8; 65]; + r.copy_from_slice(&self.0[..]); + Signature(r) + } +} + +impl Default for Signature { + fn default() -> Self { + Signature([0u8; 65]) + } +} + +impl PartialEq for Signature { + fn eq(&self, b: &Self) -> bool { + self.0[..] == b.0[..] + } +} + +impl Eq for Signature {} + +impl From for [u8; 65] { + fn from(v: Signature) -> [u8; 65] { + v.0 + } +} + +impl AsRef<[u8; 65]> for Signature { + fn as_ref(&self) -> &[u8; 65] { + &self.0 + } +} + +impl AsRef<[u8]> for Signature { + fn as_ref(&self) -> &[u8] { + &self.0[..] + } +} + +impl AsMut<[u8]> for Signature { + fn as_mut(&mut self) -> &mut [u8] { + &mut self.0[..] + } +} + +#[cfg(feature = "std")] +impl std::fmt::Debug for Signature { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{}", crate::hexdisplay::HexDisplay::from(&self.0)) + } +} + +#[cfg(feature = "std")] +impl std::hash::Hash for Signature { + fn hash(&self, state: &mut H) { + std::hash::Hash::hash(&self.0[..], state); + } +} + +impl Signature { + /// A new instance from the given 65-byte `data`. + /// + /// NOTE: No checking goes on to ensure this is a real signature. Only use it if + /// you are certain that the array actually is a signature. GIGO! + pub fn from_raw(data: [u8; 65]) -> Signature { + Signature(data) + } + + /// Recover the public key from this signature and a message. + #[cfg(feature = "std")] + pub fn recover>(&self, message: M) -> Option { + let message = secp256k1::Message::parse(&blake2_256(message.as_ref())); + let sig: (_, _) = self.try_into().ok()?; + secp256k1::recover(&message, &sig.0, &sig.1).ok() + .map(|recovered| Public(recovered.serialize_compressed())) + } +} + +#[cfg(feature = "std")] +impl From<(secp256k1::Signature, secp256k1::RecoveryId)> for Signature { + fn from(x: (secp256k1::Signature, secp256k1::RecoveryId)) -> Signature { + let mut r = Self::default(); + r.0[0..64].copy_from_slice(&x.0.serialize()[..]); + r.0[64] = x.1.serialize(); + r + } +} + +#[cfg(feature = "std")] +impl<'a> TryFrom<&'a Signature> for (secp256k1::Signature, secp256k1::RecoveryId) { + type Error = (); + fn try_from(x: &'a Signature) -> Result<(secp256k1::Signature, secp256k1::RecoveryId), Self::Error> { + Ok(( + secp256k1::Signature::parse_slice(&x.0[0..64]).expect("hardcoded to 64 bytes; qed"), + secp256k1::RecoveryId::parse(x.0[64]).map_err(|_| ())?, + )) + } +} + +/// An error type for SS58 decoding. +#[cfg(feature = "std")] +#[derive(Clone, Copy, Eq, PartialEq, Debug)] +pub enum PublicError { + /// Bad alphabet. + BadBase58, + /// Bad length. + BadLength, + /// Unknown version. + UnknownVersion, + /// Invalid checksum. + InvalidChecksum, +} + +impl Public { + /// A new instance from the given 33-byte `data`. + /// + /// NOTE: No checking goes on to ensure this is a real public key. Only use it if + /// you are certain that the array actually is a pubkey. GIGO! + pub fn from_raw(data: [u8; 33]) -> Self { + Public(data) + } + + /// Return a slice filled with raw data. + pub fn as_array_ref(&self) -> &[u8; 33] { + self.as_ref() + } +} + +impl TraitPublic for Public { + /// A new instance from the given slice that should be 33 bytes long. + /// + /// NOTE: No checking goes on to ensure this is a real public key. Only use it if + /// you are certain that the array actually is a pubkey. GIGO! + fn from_slice(data: &[u8]) -> Self { + let mut r = [0u8; 33]; + r.copy_from_slice(data); + Public(r) + } +} + +impl Derive for Public {} + +/// Derive a single hard junction. +#[cfg(feature = "std")] +fn derive_hard_junction(secret_seed: &Seed, cc: &[u8; 32]) -> Seed { + ("Secp256k1HDKD", secret_seed, cc).using_encoded(|data| { + let mut res = [0u8; 32]; + res.copy_from_slice(blake2_rfc::blake2b::blake2b(32, &[], data).as_bytes()); + res + }) +} + +/// An error when deriving a key. +#[cfg(feature = "std")] +pub enum DeriveError { + /// A soft key was found in the path (and is unsupported). + SoftKeyInPath, +} + +#[cfg(feature = "std")] +impl TraitPair for Pair { + type Public = Public; + type Seed = Seed; + type Signature = Signature; + type DeriveError = DeriveError; + + /// Generate new secure (random) key pair and provide the recovery phrase. + /// + /// You can recover the same key later with `from_phrase`. + fn generate_with_phrase(password: Option<&str>) -> (Pair, String, Seed) { + let mnemonic = Mnemonic::new(MnemonicType::Words12, Language::English); + let phrase = mnemonic.phrase(); + let (pair, seed) = Self::from_phrase(phrase, password) + .expect("All phrases generated by Mnemonic are valid; qed"); + ( + pair, + phrase.to_owned(), + seed, + ) + } + + /// Generate key pair from given recovery phrase and password. + fn from_phrase(phrase: &str, password: Option<&str>) -> Result<(Pair, Seed), SecretStringError> { + let big_seed = seed_from_entropy( + Mnemonic::from_phrase(phrase, Language::English) + .map_err(|_| SecretStringError::InvalidPhrase)?.entropy(), + password.unwrap_or(""), + ).map_err(|_| SecretStringError::InvalidSeed)?; + let mut seed = Seed::default(); + seed.copy_from_slice(&big_seed[0..32]); + Self::from_seed_slice(&big_seed[0..32]).map(|x| (x, seed)) + } + + /// Make a new key pair from secret seed material. + /// + /// You should never need to use this; generate(), generate_with_phrase + fn from_seed(seed: &Seed) -> Pair { + Self::from_seed_slice(&seed[..]).expect("seed has valid length; qed") + } + + /// Make a new key pair from secret seed material. The slice must be 32 bytes long or it + /// will return `None`. + /// + /// You should never need to use this; generate(), generate_with_phrase + fn from_seed_slice(seed_slice: &[u8]) -> Result { + let secret = SecretKey::parse_slice(seed_slice) + .map_err(|_| SecretStringError::InvalidSeedLength)?; + let public = PublicKey::from_secret_key(&secret); + Ok(Pair{ secret, public }) + } + + /// Derive a child key from a series of given junctions. + fn derive>(&self, + path: Iter, + _seed: Option + ) -> Result<(Pair, Option), DeriveError> { + let mut acc = self.secret.serialize(); + for j in path { + match j { + DeriveJunction::Soft(_cc) => return Err(DeriveError::SoftKeyInPath), + DeriveJunction::Hard(cc) => acc = derive_hard_junction(&acc, &cc), + } + } + Ok((Self::from_seed(&acc), Some(acc))) + } + + /// Get the public key. + fn public(&self) -> Public { + Public(self.public.serialize_compressed()) + } + + /// Sign a message. + fn sign(&self, message: &[u8]) -> Signature { + let message = secp256k1::Message::parse(&blake2_256(message)); + secp256k1::sign(&message, &self.secret).into() + } + + /// Verify a signature on a message. Returns true if the signature is good. + fn verify>(sig: &Self::Signature, message: M, pubkey: &Self::Public) -> bool { + let message = secp256k1::Message::parse(&blake2_256(message.as_ref())); + let sig: (_, _) = match sig.try_into() { Ok(x) => x, _ => return false }; + match secp256k1::recover(&message, &sig.0, &sig.1) { + Ok(actual) => &pubkey.0[..] == &actual.serialize_compressed()[..], + _ => false, + } + } + + /// Verify a signature on a message. Returns true if the signature is good. + /// + /// This doesn't use the type system to ensure that `sig` and `pubkey` are the correct + /// size. Use it only if you're coming from byte buffers and need the speed. + fn verify_weak, M: AsRef<[u8]>>(sig: &[u8], message: M, pubkey: P) -> bool { + let message = secp256k1::Message::parse(&blake2_256(message.as_ref())); + if sig.len() != 65 { return false } + let ri = match secp256k1::RecoveryId::parse(sig[64]) { Ok(x) => x, _ => return false }; + let sig = match secp256k1::Signature::parse_slice(&sig[0..64]) { Ok(x) => x, _ => return false }; + match secp256k1::recover(&message, &sig, &ri) { + Ok(actual) => pubkey.as_ref() == &actual.serialize_compressed()[..], + _ => false, + } + } + + /// Return a vec filled with raw data. + fn to_raw_vec(&self) -> Vec { + self.seed().to_vec() + } +} + +#[cfg(feature = "std")] +impl Pair { + /// Get the seed for this key. + pub fn seed(&self) -> Seed { + self.secret.serialize() + } + + /// Exactly as `from_string` except that if no matches are found then, the the first 32 + /// characters are taken (padded with spaces as necessary) and used as the MiniSecretKey. + pub fn from_legacy_string(s: &str, password_override: Option<&str>) -> Pair { + Self::from_string(s, password_override).unwrap_or_else(|_| { + let mut padded_seed: Seed = [' ' as u8; 32]; + let len = s.len().min(32); + padded_seed[..len].copy_from_slice(&s.as_bytes()[..len]); + Self::from_seed(&padded_seed) + }) + } +} + +impl CryptoType for Public { + #[cfg(feature="std")] + type Pair = Pair; +} + +impl CryptoType for Signature { + #[cfg(feature="std")] + type Pair = Pair; +} + +#[cfg(feature = "std")] +impl CryptoType for Pair { + type Pair = Pair; +} + +#[cfg(test)] +mod test { + use super::*; + use hex_literal::hex; + use crate::crypto::DEV_PHRASE; + + #[test] + fn default_phrase_should_be_used() { + assert_eq!( + Pair::from_string("//Alice///password", None).unwrap().public(), + Pair::from_string(&format!("{}//Alice", DEV_PHRASE), Some("password")).unwrap().public(), + ); + } + + #[test] + fn seed_and_derive_should_work() { + let seed = hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"); + let pair = Pair::from_seed(&seed); + assert_eq!(pair.seed(), seed); + let path = vec![DeriveJunction::Hard([0u8; 32])]; + let derived = pair.derive(path.into_iter(), None).ok().unwrap(); + assert_eq!( + derived.0.seed(), + hex!("b8eefc4937200a8382d00050e050ced2d4ab72cc2ef1b061477afb51564fdd61") + ); + } + + #[test] + fn test_vector_should_work() { + let pair = Pair::from_seed( + &hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60") + ); + let public = pair.public(); + assert_eq!(public, Public::from_raw( + hex!("028db55b05db86c0b1786ca49f095d76344c9e6056b2f02701a7e7f3c20aabfd91") + )); + let message = b""; + let signature = hex!("3dde91174bd9359027be59a428b8146513df80a2a3c7eda2194f64de04a69ab97b753169e94db6ffd50921a2668a48b94ca11e3d32c1ff19cfe88890aa7e8f3c00"); + let signature = Signature::from_raw(signature); + assert!(&pair.sign(&message[..]) == &signature); + assert!(Pair::verify(&signature, &message[..], &public)); + } + + #[test] + fn test_vector_by_string_should_work() { + let pair = Pair::from_string( + "0x9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", + None + ).unwrap(); + let public = pair.public(); + assert_eq!(public, Public::from_raw( + hex!("028db55b05db86c0b1786ca49f095d76344c9e6056b2f02701a7e7f3c20aabfd91") + )); + let message = b""; + let signature = hex!("3dde91174bd9359027be59a428b8146513df80a2a3c7eda2194f64de04a69ab97b753169e94db6ffd50921a2668a48b94ca11e3d32c1ff19cfe88890aa7e8f3c00"); + let signature = Signature::from_raw(signature); + assert!(&pair.sign(&message[..]) == &signature); + assert!(Pair::verify(&signature, &message[..], &public)); + } + + #[test] + fn generated_pair_should_work() { + let (pair, _) = Pair::generate(); + let public = pair.public(); + let message = b"Something important"; + let signature = pair.sign(&message[..]); + assert!(Pair::verify(&signature, &message[..], &public)); + assert!(!Pair::verify(&signature, b"Something else", &public)); + } + + #[test] + fn seeded_pair_should_work() { + let pair = Pair::from_seed(b"12345678901234567890123456789012"); + let public = pair.public(); + assert_eq!(public, Public::from_raw( + hex!("035676109c54b9a16d271abeb4954316a40a32bcce023ac14c8e26e958aa68fba9") + )); + let message = hex!("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000200d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000"); + let signature = pair.sign(&message[..]); + println!("Correct signature: {:?}", signature); + assert!(Pair::verify(&signature, &message[..], &public)); + assert!(!Pair::verify(&signature, "Other message", &public)); + } + + #[test] + fn generate_with_phrase_recovery_possible() { + let (pair1, phrase, _) = Pair::generate_with_phrase(None); + let (pair2, _) = Pair::from_phrase(&phrase, None).unwrap(); + + assert_eq!(pair1.public(), pair2.public()); + } + + #[test] + fn generate_with_password_phrase_recovery_possible() { + let (pair1, phrase, _) = Pair::generate_with_phrase(Some("password")); + let (pair2, _) = Pair::from_phrase(&phrase, Some("password")).unwrap(); + + assert_eq!(pair1.public(), pair2.public()); + } + + #[test] + fn password_does_something() { + let (pair1, phrase, _) = Pair::generate_with_phrase(Some("password")); + let (pair2, _) = Pair::from_phrase(&phrase, None).unwrap(); + + assert_ne!(pair1.public(), pair2.public()); + } + + #[test] + fn ss58check_roundtrip_works() { + let pair = Pair::from_seed(b"12345678901234567890123456789012"); + let public = pair.public(); + let s = public.to_ss58check(); + println!("Correct: {}", s); + let cmp = Public::from_ss58check(&s).unwrap(); + assert_eq!(cmp, public); + } +} diff --git a/core/primitives/src/ed25519.rs b/core/primitives/src/ed25519.rs index ff3b21e160..8c3aa9f89d 100644 --- a/core/primitives/src/ed25519.rs +++ b/core/primitives/src/ed25519.rs @@ -406,7 +406,10 @@ impl TraitPair for Pair { } /// Derive a child key from a series of given junctions. - fn derive>(&self, path: Iter) -> Result { + fn derive>(&self, + path: Iter, + _seed: Option, + ) -> Result<(Pair, Option), DeriveError> { let mut acc = self.0.secret.to_bytes(); for j in path { match j { @@ -414,18 +417,7 @@ impl TraitPair for Pair { DeriveJunction::Hard(cc) => acc = derive_hard_junction(&acc, &cc), } } - Ok(Self::from_seed(&acc)) - } - - /// Generate a key from the phrase, password and derivation path. - fn from_standard_components>( - phrase: &str, - password: Option<&str>, - path: I - ) -> Result { - Self::from_phrase(phrase, password)?.0 - .derive(path) - .map_err(|_| SecretStringError::InvalidPath) + Ok((Self::from_seed(&acc), Some(acc))) } /// Get the public key. @@ -528,7 +520,7 @@ mod test { let pair = Pair::from_seed(&seed); assert_eq!(pair.seed(), &seed); let path = vec![DeriveJunction::Hard([0u8; 32])]; - let derived = pair.derive(path.into_iter()).ok().unwrap(); + let derived = pair.derive(path.into_iter(), None).ok().unwrap().0; assert_eq!( derived.seed(), &hex!("ede3354e133f9c8e337ddd6ee5415ed4b4ffe5fc7d21e933f4930a3730e5b21c") diff --git a/core/primitives/src/hexdisplay.rs b/core/primitives/src/hexdisplay.rs index 6765ce517e..2c8533e25b 100644 --- a/core/primitives/src/hexdisplay.rs +++ b/core/primitives/src/hexdisplay.rs @@ -80,7 +80,7 @@ macro_rules! impl_non_endians { impl_non_endians!([u8; 1], [u8; 2], [u8; 3], [u8; 4], [u8; 5], [u8; 6], [u8; 7], [u8; 8], [u8; 10], [u8; 12], [u8; 14], [u8; 16], [u8; 20], [u8; 24], [u8; 28], [u8; 32], [u8; 40], - [u8; 48], [u8; 56], [u8; 64], [u8; 80], [u8; 96], [u8; 112], [u8; 128]); + [u8; 48], [u8; 56], [u8; 64], [u8; 65], [u8; 80], [u8; 96], [u8; 112], [u8; 128]); /// Format into ASCII + # + hex, suitable for storage key preimages. pub fn ascii_format(asciish: &[u8]) -> String { diff --git a/core/primitives/src/lib.rs b/core/primitives/src/lib.rs index 48d3d998fa..d1b42766a0 100644 --- a/core/primitives/src/lib.rs +++ b/core/primitives/src/lib.rs @@ -59,6 +59,7 @@ pub mod u32_trait; pub mod ed25519; pub mod sr25519; +pub mod ecdsa; pub mod hash; mod hasher; pub mod offchain; diff --git a/core/primitives/src/sr25519.rs b/core/primitives/src/sr25519.rs index f2160b88b7..bb319b8221 100644 --- a/core/primitives/src/sr25519.rs +++ b/core/primitives/src/sr25519.rs @@ -388,8 +388,8 @@ impl AsRef for Pair { /// Derive a single hard junction. #[cfg(feature = "std")] -fn derive_hard_junction(secret: &SecretKey, cc: &[u8; CHAIN_CODE_LENGTH]) -> SecretKey { - secret.hard_derive_mini_secret_key(Some(ChainCode(cc.clone())), b"").0.expand(ExpansionMode::Ed25519) +fn derive_hard_junction(secret: &SecretKey, cc: &[u8; CHAIN_CODE_LENGTH]) -> MiniSecretKey { + secret.hard_derive_mini_secret_key(Some(ChainCode(cc.clone())), b"").0 } /// The raw secret seed, which can be used to recreate the `Pair`. @@ -444,17 +444,6 @@ impl TraitPair for Pair { } } - /// Generate a key from the phrase, password and derivation path. - fn from_standard_components>( - phrase: &str, - password: Option<&str>, - path: I - ) -> Result { - Self::from_phrase(phrase, password)?.0 - .derive(path) - .map_err(|_| SecretStringError::InvalidPath) - } - fn generate_with_phrase(password: Option<&str>) -> (Pair, String, Seed) { let mnemonic = Mnemonic::new(MnemonicType::Words12, Language::English); let phrase = mnemonic.phrase(); @@ -473,13 +462,27 @@ impl TraitPair for Pair { .map(|m| Self::from_entropy(m.entropy(), password)) } - fn derive>(&self, path: Iter) -> Result { + fn derive>(&self, + path: Iter, + seed: Option, + ) -> Result<(Pair, Option), Self::DeriveError> { + let seed = if let Some(s) = seed { + if let Ok(msk) = MiniSecretKey::from_bytes(&s) { + if msk.expand(ExpansionMode::Ed25519) == self.0.secret { + Some(msk) + } else { None } + } else { None } + } else { None }; let init = self.0.secret.clone(); - let result = path.fold(init, |acc, j| match j { - DeriveJunction::Soft(cc) => acc.derived_key_simple(ChainCode(cc), &[]).0, - DeriveJunction::Hard(cc) => derive_hard_junction(&acc, &cc), + let (result, seed) = path.fold((init, seed), |(acc, acc_seed), j| match (j, acc_seed) { + (DeriveJunction::Soft(cc), _) => + (acc.derived_key_simple(ChainCode(cc), &[]).0, None), + (DeriveJunction::Hard(cc), maybe_seed) => { + let seed = derive_hard_junction(&acc, &cc); + (seed.expand(ExpansionMode::Ed25519), maybe_seed.map(|_| seed)) + } }); - Ok(Self(result.into())) + Ok((Self(result.into()), seed.map(|s| MiniSecretKey::to_bytes(&s)))) } fn sign(&self, message: &[u8]) -> Signature { @@ -621,9 +624,9 @@ mod test { let pair = Pair::from_seed(&hex!( "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60" )); - let derive_1 = pair.derive(Some(DeriveJunction::soft(1)).into_iter()).unwrap(); - let derive_1b = pair.derive(Some(DeriveJunction::soft(1)).into_iter()).unwrap(); - let derive_2 = pair.derive(Some(DeriveJunction::soft(2)).into_iter()).unwrap(); + let derive_1 = pair.derive(Some(DeriveJunction::soft(1)).into_iter(), None).unwrap().0; + let derive_1b = pair.derive(Some(DeriveJunction::soft(1)).into_iter(), None).unwrap().0; + let derive_2 = pair.derive(Some(DeriveJunction::soft(2)).into_iter(), None).unwrap().0; assert_eq!(derive_1.public(), derive_1b.public()); assert_ne!(derive_1.public(), derive_2.public()); } @@ -633,9 +636,9 @@ mod test { let pair = Pair::from_seed(&hex!( "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60" )); - let derive_1 = pair.derive(Some(DeriveJunction::hard(1)).into_iter()).unwrap(); - let derive_1b = pair.derive(Some(DeriveJunction::hard(1)).into_iter()).unwrap(); - let derive_2 = pair.derive(Some(DeriveJunction::hard(2)).into_iter()).unwrap(); + let derive_1 = pair.derive(Some(DeriveJunction::hard(1)).into_iter(), None).unwrap().0; + let derive_1b = pair.derive(Some(DeriveJunction::hard(1)).into_iter(), None).unwrap().0; + let derive_2 = pair.derive(Some(DeriveJunction::hard(2)).into_iter(), None).unwrap().0; assert_eq!(derive_1.public(), derive_1b.public()); assert_ne!(derive_1.public(), derive_2.public()); } @@ -646,7 +649,7 @@ mod test { "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60" )); let path = Some(DeriveJunction::soft(1)); - let pair_1 = pair.derive(path.clone().into_iter()).unwrap(); + let pair_1 = pair.derive(path.clone().into_iter(), None).unwrap().0; let public_1 = pair.public().derive(path.into_iter()).unwrap(); assert_eq!(pair_1.public(), public_1); } diff --git a/core/sr-io/src/lib.rs b/core/sr-io/src/lib.rs index b0274286dc..fe5e50b3ed 100644 --- a/core/sr-io/src/lib.rs +++ b/core/sr-io/src/lib.rs @@ -220,15 +220,20 @@ export_api! { /// Verify and recover a SECP256k1 ECDSA signature. /// - `sig` is passed in RSV format. V should be either 0/1 or 27/28. - /// - returns `Err` if the signature is bad, otherwise the 64-byte pubkey (doesn't include the 0x04 prefix). + /// - returns `Err` if the signature is bad, otherwise the 64-byte raw pubkey (doesn't include the 0x04 prefix). fn secp256k1_ecdsa_recover(sig: &[u8; 65], msg: &[u8; 32]) -> Result<[u8; 64], EcdsaVerifyError>; + + /// Verify and recover a SECP256k1 ECDSA signature. + /// - `sig` is passed in RSV format. V should be either 0/1 or 27/28. + /// - returns `Err` if the signature is bad, otherwise the 33-byte compressed pubkey. + fn secp256k1_ecdsa_recover_compressed(sig: &[u8; 65], msg: &[u8; 32]) -> Result<[u8; 33], EcdsaVerifyError>; } } export_api! { pub(crate) trait HashingApi { /// Conduct a 256-bit Keccak hash. - fn keccak_256(data: &[u8]) -> [u8; 32] ; + fn keccak_256(data: &[u8]) -> [u8; 32]; /// Conduct a 128-bit Blake2 hash. fn blake2_128(data: &[u8]) -> [u8; 16]; diff --git a/core/sr-io/with_std.rs b/core/sr-io/with_std.rs index de40115cbe..fdd32124c1 100644 --- a/core/sr-io/with_std.rs +++ b/core/sr-io/with_std.rs @@ -300,6 +300,16 @@ impl CryptoApi for () { res.copy_from_slice(&pubkey.serialize()[1..65]); Ok(res) } + + fn secp256k1_ecdsa_recover_compressed(sig: &[u8; 65], msg: &[u8; 32]) -> Result<[u8; 33], EcdsaVerifyError> { + let rs = secp256k1::Signature::parse_slice(&sig[0..64]) + .map_err(|_| EcdsaVerifyError::BadRS)?; + let v = secp256k1::RecoveryId::parse(if sig[64] > 26 { sig[64] - 27 } else { sig[64] } as u8) + .map_err(|_| EcdsaVerifyError::BadV)?; + let pubkey = secp256k1::recover(&secp256k1::Message::parse(msg), &rs, &v) + .map_err(|_| EcdsaVerifyError::BadSignature)?; + Ok(pubkey.serialize_compressed()) + } } impl HashingApi for () { diff --git a/core/sr-io/without_std.rs b/core/sr-io/without_std.rs index 789098185e..c3f7d62031 100644 --- a/core/sr-io/without_std.rs +++ b/core/sr-io/without_std.rs @@ -394,12 +394,23 @@ pub mod ext { ) -> u32; /// Note: ext_secp256k1_ecdsa_recover returns 0 if the signature is correct, nonzero otherwise. + /// + /// pubkey_data must point to 64 bytes. fn ext_secp256k1_ecdsa_recover( msg_data: *const u8, sig_data: *const u8, pubkey_data: *mut u8, ) -> u32; + /// Note: ext_secp256k1_ecdsa_recover_compressed returns 0 if the signature is correct, nonzero otherwise. + /// + /// pubkey_data must point to 33 bytes. + fn ext_secp256k1_ecdsa_recover_compressed( + msg_data: *const u8, + sig_data: *const u8, + pubkey_data: *mut u8, + ) -> u32; + //================================ // Offchain-worker Context //================================ @@ -971,6 +982,19 @@ impl CryptoApi for () { _ => unreachable!("`ext_secp256k1_ecdsa_recover` only returns 0, 1, 2 or 3; qed"), } } + + fn secp256k1_ecdsa_recover_compressed(sig: &[u8; 65], msg: &[u8; 32]) -> Result<[u8; 33], EcdsaVerifyError> { + let mut pubkey = [0u8; 33]; + match unsafe { + ext_secp256k1_ecdsa_recover_compressed.get()(msg.as_ptr(), sig.as_ptr(), pubkey.as_mut_ptr()) + } { + 0 => Ok(pubkey), + 1 => Err(EcdsaVerifyError::BadRS), + 2 => Err(EcdsaVerifyError::BadV), + 3 => Err(EcdsaVerifyError::BadSignature), + _ => unreachable!("`ext_secp256k1_ecdsa_recover_compressed` only returns 0, 1, 2 or 3; qed"), + } + } } impl OffchainApi for () { diff --git a/core/sr-primitives/src/generic/unchecked_extrinsic.rs b/core/sr-primitives/src/generic/unchecked_extrinsic.rs index d50314f33b..4af8d9a95b 100644 --- a/core/sr-primitives/src/generic/unchecked_extrinsic.rs +++ b/core/sr-primitives/src/generic/unchecked_extrinsic.rs @@ -21,7 +21,7 @@ use rstd::fmt; use runtime_io::blake2_256; use codec::{Decode, Encode, EncodeLike, Input, Error}; use crate::{ - traits::{self, Member, MaybeDisplay, SignedExtension, Checkable, Extrinsic}, + traits::{self, Member, MaybeDisplay, SignedExtension, Checkable, Extrinsic, IdentifyAccount}, generic::CheckedExtrinsic, transaction_validity::{TransactionValidityError, InvalidTransaction}, }; @@ -98,7 +98,8 @@ for where Address: Member + MaybeDisplay, Call: Encode + Member, - Signature: Member + traits::Verify, + Signature: Member + traits::Verify, + ::Signer: IdentifyAccount, Extra: SignedExtension, AccountId: Member + MaybeDisplay, Lookup: traits::Lookup, @@ -284,17 +285,26 @@ mod tests { use super::*; use runtime_io::blake2_256; use crate::codec::{Encode, Decode}; - use crate::traits::{SignedExtension, IdentityLookup}; + use crate::traits::{SignedExtension, IdentifyAccount, IdentityLookup}; use serde::{Serialize, Deserialize}; type TestContext = IdentityLookup; + #[derive(Eq, PartialEq, Clone, Copy, Debug, Serialize, Deserialize, Encode, Decode)] + pub struct TestSigner(pub u64); + impl From for TestSigner { fn from(x: u64) -> Self { Self(x) } } + impl From for u64 { fn from(x: TestSigner) -> Self { x.0 } } + impl IdentifyAccount for TestSigner { + type AccountId = u64; + fn into_account(self) -> u64 { self.into() } + } + #[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize, Encode, Decode)] struct TestSig(u64, Vec); impl traits::Verify for TestSig { - type Signer = u64; - fn verify>(&self, mut msg: L, signer: &Self::Signer) -> bool { - *signer == self.0 && msg.get() == &self.1[..] + type Signer = TestSigner; + fn verify>(&self, mut msg: L, signer: &u64) -> bool { + signer == &self.0 && msg.get() == &self.1[..] } } diff --git a/core/sr-primitives/src/lib.rs b/core/sr-primitives/src/lib.rs index ea295fbea6..84f7bbcff6 100644 --- a/core/sr-primitives/src/lib.rs +++ b/core/sr-primitives/src/lib.rs @@ -42,7 +42,7 @@ pub use runtime_io::{StorageOverlay, ChildrenStorageOverlay}; use rstd::prelude::*; use rstd::convert::TryFrom; -use primitives::{crypto, ed25519, sr25519, hash::{H256, H512}}; +use primitives::{crypto, ed25519, sr25519, ecdsa, hash::{H256, H512}}; use codec::{Encode, Decode}; #[cfg(feature = "std")] @@ -59,7 +59,7 @@ pub mod weights; pub use generic::{DigestItem, Digest}; /// Re-export this since it's part of the API of this crate. -pub use primitives::{TypeId, crypto::{key_types, KeyTypeId, CryptoType}}; +pub use primitives::{TypeId, crypto::{key_types, KeyTypeId, CryptoType, AccountId32}}; pub use app_crypto::RuntimeAppPublic; /// Re-export `RuntimeDebug`, to avoid dependency clutter. @@ -117,6 +117,7 @@ macro_rules! create_runtime_str { #[cfg(feature = "std")] pub use serde::{Serialize, Deserialize, de::DeserializeOwned}; +use crate::traits::IdentifyAccount; /// Complex storage builder stuff. #[cfg(feature = "std")] @@ -175,6 +176,8 @@ pub enum MultiSignature { Ed25519(ed25519::Signature), /// An Sr25519 signature. Sr25519(sr25519::Signature), + /// An ECDSA/SECP256k1 signature. + Ecdsa(ecdsa::Signature), } impl From for MultiSignature { @@ -189,6 +192,12 @@ impl From for MultiSignature { } } +impl From for MultiSignature { + fn from(x: ecdsa::Signature) -> Self { + MultiSignature::Ecdsa(x) + } +} + impl Default for MultiSignature { fn default() -> Self { MultiSignature::Ed25519(Default::default()) @@ -203,6 +212,8 @@ pub enum MultiSigner { Ed25519(ed25519::Public), /// An Sr25519 identity. Sr25519(sr25519::Public), + /// An SECP256k1/ECDSA identity (actually, the Blake2 hash of the pub key). + Ecdsa(ecdsa::Public), } impl Default for MultiSigner { @@ -224,6 +235,18 @@ impl AsRef<[u8]> for MultiSigner { match *self { MultiSigner::Ed25519(ref who) => who.as_ref(), MultiSigner::Sr25519(ref who) => who.as_ref(), + MultiSigner::Ecdsa(ref who) => who.as_ref(), + } + } +} + +impl traits::IdentifyAccount for MultiSigner { + type AccountId = AccountId32; + fn into_account(self) -> AccountId32 { + match self { + MultiSigner::Ed25519(who) => <[u8; 32]>::from(who).into(), + MultiSigner::Sr25519(who) => <[u8; 32]>::from(who).into(), + MultiSigner::Ecdsa(who) => runtime_io::blake2_256(who.as_ref()).into(), } } } @@ -240,23 +263,37 @@ impl From for MultiSigner { } } - #[cfg(feature = "std")] +impl From for MultiSigner { + fn from(x: ecdsa::Public) -> Self { + MultiSigner::Ecdsa(x) + } +} + +#[cfg(feature = "std")] impl std::fmt::Display for MultiSigner { fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { match *self { MultiSigner::Ed25519(ref who) => write!(fmt, "ed25519: {}", who), MultiSigner::Sr25519(ref who) => write!(fmt, "sr25519: {}", who), + MultiSigner::Ecdsa(ref who) => write!(fmt, "ecdsa: {}", who), } } } impl Verify for MultiSignature { type Signer = MultiSigner; - fn verify>(&self, msg: L, signer: &Self::Signer) -> bool { + fn verify>(&self, mut msg: L, signer: &AccountId32) -> bool { + use primitives::crypto::Public; match (self, signer) { - (MultiSignature::Ed25519(ref sig), &MultiSigner::Ed25519(ref who)) => sig.verify(msg, who), - (MultiSignature::Sr25519(ref sig), &MultiSigner::Sr25519(ref who)) => sig.verify(msg, who), - _ => false, + (MultiSignature::Ed25519(ref sig), who) => sig.verify(msg, &ed25519::Public::from_slice(who.as_ref())), + (MultiSignature::Sr25519(ref sig), who) => sig.verify(msg, &sr25519::Public::from_slice(who.as_ref())), + (MultiSignature::Ecdsa(ref sig), who) => { + let m = runtime_io::blake2_256(msg.get()); + match runtime_io::secp256k1_ecdsa_recover_compressed(sig.as_ref(), &m) { + Ok(pubkey) => &runtime_io::blake2_256(pubkey.as_ref()) == >::as_ref(who), + _ => false, + } + } } } } @@ -269,12 +306,13 @@ pub struct AnySignature(H512); impl Verify for AnySignature { type Signer = sr25519::Public; fn verify>(&self, mut msg: L, signer: &sr25519::Public) -> bool { + use primitives::crypto::Public; + let msg = msg.get(); sr25519::Signature::try_from(self.0.as_fixed_bytes().as_ref()) - .map(|s| runtime_io::sr25519_verify(&s, msg.get(), &signer)) + .map(|s| s.verify(msg, signer)) .unwrap_or(false) || ed25519::Signature::try_from(self.0.as_fixed_bytes().as_ref()) - .and_then(|s| ed25519::Public::try_from(signer.0.as_ref()).map(|p| (s, p))) - .map(|(s, p)| runtime_io::ed25519_verify(&s, msg.get(), &p)) + .map(|s| s.verify(msg, &ed25519::Public::from_slice(signer.as_ref()))) .unwrap_or(false) } } @@ -398,7 +436,7 @@ impl From<&'static str> for DispatchError { /// Verify a signature on an encoded value in a lazy manner. This can be /// an optimization if the signature scheme has an "unsigned" escape hash. -pub fn verify_encoded_lazy(sig: &V, item: &T, signer: &V::Signer) -> bool { +pub fn verify_encoded_lazy(sig: &V, item: &T, signer: &::AccountId) -> bool { // The `Lazy` trait expresses something like `X: FnMut &'a T>`. // unfortunately this is a lifetime relationship that can't // be expressed without generic associated types, better unification of HRTBs in type position, diff --git a/core/sr-primitives/src/traits.rs b/core/sr-primitives/src/traits.rs index 0497f094d2..4586a84511 100644 --- a/core/sr-primitives/src/traits.rs +++ b/core/sr-primitives/src/traits.rs @@ -50,46 +50,84 @@ impl<'a> Lazy<[u8]> for &'a [u8] { fn get(&mut self) -> &[u8] { &**self } } +/// Some type that is able to be collapsed into an account ID. It is not possible to recreate the original value from +/// the account ID. +pub trait IdentifyAccount { + /// The account ID that this can be transformed into. + type AccountId; + /// Transform into an account. + fn into_account(self) -> Self::AccountId; +} + +impl IdentifyAccount for primitives::ed25519::Public { + type AccountId = Self; + fn into_account(self) -> Self { self } +} + +impl IdentifyAccount for primitives::sr25519::Public { + type AccountId = Self; + fn into_account(self) -> Self { self } +} + +impl IdentifyAccount for primitives::ecdsa::Public { + type AccountId = Self; + fn into_account(self) -> Self { self } +} + /// Means of signature verification. pub trait Verify { /// Type of the signer. - type Signer; + type Signer: IdentifyAccount; /// Verify a signature. Return `true` if signature is valid for the value. - fn verify>(&self, msg: L, signer: &Self::Signer) -> bool; + fn verify>(&self, msg: L, signer: &::AccountId) -> bool; } impl Verify for primitives::ed25519::Signature { type Signer = primitives::ed25519::Public; - fn verify>(&self, mut msg: L, signer: &Self::Signer) -> bool { + fn verify>(&self, mut msg: L, signer: &primitives::ed25519::Public) -> bool { runtime_io::ed25519_verify(self, msg.get(), signer) } } impl Verify for primitives::sr25519::Signature { type Signer = primitives::sr25519::Public; - fn verify>(&self, mut msg: L, signer: &Self::Signer) -> bool { + fn verify>(&self, mut msg: L, signer: &primitives::sr25519::Public) -> bool { runtime_io::sr25519_verify(self, msg.get(), signer) } } +impl Verify for primitives::ecdsa::Signature { + type Signer = primitives::ecdsa::Public; + fn verify>(&self, mut msg: L, signer: &primitives::ecdsa::Public) -> bool { + match runtime_io::secp256k1_ecdsa_recover_compressed(self.as_ref(), &runtime_io::blake2_256(msg.get())) { + Ok(pubkey) => >::as_ref(signer) == &pubkey[..], + _ => false, + } + } +} + /// Means of signature verification of an application key. pub trait AppVerify { /// Type of the signer. - type Signer; + type AccountId; /// Verify a signature. Return `true` if signature is valid for the value. - fn verify>(&self, msg: L, signer: &Self::Signer) -> bool; + fn verify>(&self, msg: L, signer: &Self::AccountId) -> bool; } impl< S: Verify::Public as app_crypto::AppPublic>::Generic> + From, T: app_crypto::Wraps + app_crypto::AppKey + app_crypto::AppSignature + AsRef + AsMut + From, -> AppVerify for T { - type Signer = ::Public; - fn verify>(&self, msg: L, signer: &Self::Signer) -> bool { +> AppVerify for T where + ::Signer: IdentifyAccount::Signer>, + <::Public as app_crypto::AppPublic>::Generic: + IdentifyAccount::Public as app_crypto::AppPublic>::Generic>, +{ + type AccountId = ::Public; + fn verify>(&self, msg: L, signer: &::Public) -> bool { use app_crypto::IsWrappedBy; let inner: &S = self.as_ref(); - let inner_pubkey = ::Generic::from_ref(&signer); + let inner_pubkey = <::Public as app_crypto::AppPublic>::Generic::from_ref(&signer); Verify::verify(inner, msg, inner_pubkey) } } @@ -1179,6 +1217,21 @@ mod tests { use super::AccountIdConversion; use crate::codec::{Encode, Decode, Input}; + mod t { + use primitives::crypto::KeyTypeId; + use app_crypto::{app_crypto, sr25519}; + app_crypto!(sr25519, KeyTypeId(*b"test")); + } + + #[test] + fn app_verify_works() { + use t::*; + use super::AppVerify; + + let s = Signature::default(); + let _ = s.verify(&[0u8; 100][..], &Public::default()); + } + #[derive(Encode, Decode, Default, PartialEq, Debug)] struct U32Value(u32); impl super::TypeId for U32Value { diff --git a/node/cli/src/chain_spec.rs b/node/cli/src/chain_spec.rs index bc9f1e615f..07f6946baf 100644 --- a/node/cli/src/chain_spec.rs +++ b/node/cli/src/chain_spec.rs @@ -17,7 +17,7 @@ //! Substrate chain configurations. use chain_spec::ChainSpecExtension; -use primitives::{Pair, Public, crypto::UncheckedInto}; +use primitives::{Pair, Public, crypto::UncheckedInto, sr25519}; use serde::{Serialize, Deserialize}; use node_runtime::{ AuthorityDiscoveryConfig, BabeConfig, BalancesConfig, ContractsConfig, CouncilConfig, DemocracyConfig, @@ -32,10 +32,13 @@ use substrate_telemetry::TelemetryEndpoints; use grandpa_primitives::{AuthorityId as GrandpaId}; use babe_primitives::{AuthorityId as BabeId}; use im_online::sr25519::{AuthorityId as ImOnlineId}; -use sr_primitives::Perbill; +use sr_primitives::{traits::Verify, Perbill}; -pub use node_primitives::{AccountId, Balance}; +pub use node_primitives::{AccountId, Balance, Signature}; pub use node_runtime::GenesisConfig; +use sr_primitives::traits::IdentifyAccount; + +type AccountPublic = ::Signer; const STAGING_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/"; @@ -72,9 +75,9 @@ fn staging_testnet_config_genesis() -> GenesisConfig { let initial_authorities: Vec<(AccountId, AccountId, GrandpaId, BabeId, ImOnlineId)> = vec![( // 5Fbsd6WXDGiLTxunqeK5BATNiocfCqu9bS1yArVjCgeBLkVy - hex!["9c7a2ee14e565db0c69f78c7b4cd839fbf52b607d867e9e9c5a79042898a0d12"].unchecked_into(), + hex!["9c7a2ee14e565db0c69f78c7b4cd839fbf52b607d867e9e9c5a79042898a0d12"].into(), // 5EnCiV7wSHeNhjW3FSUwiJNkcc2SBkPLn5Nj93FmbLtBjQUq - hex!["781ead1e2fa9ccb74b44c19d29cb2a7a4b5be3972927ae98cd3877523976a276"].unchecked_into(), + hex!["781ead1e2fa9ccb74b44c19d29cb2a7a4b5be3972927ae98cd3877523976a276"].into(), // 5Fb9ayurnxnaXj56CjmyQLBiadfRCqUbL2VWNbbe1nZU6wiC hex!["9becad03e6dcac03cee07edebca5475314861492cdfc96a2144a67bbe9699332"].unchecked_into(), // 5EZaeQ8djPcq9pheJUhgerXQZt9YaHnMJpiHMRhwQeinqUW8 @@ -83,9 +86,9 @@ fn staging_testnet_config_genesis() -> GenesisConfig { hex!["6e7e4eb42cbd2e0ab4cae8708ce5509580b8c04d11f6758dbf686d50fe9f9106"].unchecked_into(), ),( // 5ERawXCzCWkjVq3xz1W5KGNtVx2VdefvZ62Bw1FEuZW4Vny2 - hex!["68655684472b743e456907b398d3a44c113f189e56d1bbfd55e889e295dfde78"].unchecked_into(), + hex!["68655684472b743e456907b398d3a44c113f189e56d1bbfd55e889e295dfde78"].into(), // 5Gc4vr42hH1uDZc93Nayk5G7i687bAQdHHc9unLuyeawHipF - hex!["c8dc79e36b29395413399edaec3e20fcca7205fb19776ed8ddb25d6f427ec40e"].unchecked_into(), + hex!["c8dc79e36b29395413399edaec3e20fcca7205fb19776ed8ddb25d6f427ec40e"].into(), // 5EockCXN6YkiNCDjpqqnbcqd4ad35nU4RmA1ikM4YeRN4WcE hex!["7932cff431e748892fa48e10c63c17d30f80ca42e4de3921e641249cd7fa3c2f"].unchecked_into(), // 5DhLtiaQd1L1LU9jaNeeu9HJkP6eyg3BwXA7iNMzKm7qqruQ @@ -94,9 +97,9 @@ fn staging_testnet_config_genesis() -> GenesisConfig { hex!["482dbd7297a39fa145c570552249c2ca9dd47e281f0c500c971b59c9dcdcd82e"].unchecked_into(), ),( // 5DyVtKWPidondEu8iHZgi6Ffv9yrJJ1NDNLom3X9cTDi98qp - hex!["547ff0ab649283a7ae01dbc2eb73932eba2fb09075e9485ff369082a2ff38d65"].unchecked_into(), + hex!["547ff0ab649283a7ae01dbc2eb73932eba2fb09075e9485ff369082a2ff38d65"].into(), // 5FeD54vGVNpFX3PndHPXJ2MDakc462vBCD5mgtWRnWYCpZU9 - hex!["9e42241d7cd91d001773b0b616d523dd80e13c6c2cab860b1234ef1b9ffc1526"].unchecked_into(), + hex!["9e42241d7cd91d001773b0b616d523dd80e13c6c2cab860b1234ef1b9ffc1526"].into(), // 5E1jLYfLdUQKrFrtqoKgFrRvxM3oQPMbf6DfcsrugZZ5Bn8d hex!["5633b70b80a6c8bb16270f82cca6d56b27ed7b76c8fd5af2986a25a4788ce440"].unchecked_into(), // 5DhKqkHRkndJu8vq7pi2Q5S3DfftWJHGxbEUNH43b46qNspH @@ -105,9 +108,9 @@ fn staging_testnet_config_genesis() -> GenesisConfig { hex!["482a3389a6cf42d8ed83888cfd920fec738ea30f97e44699ada7323f08c3380a"].unchecked_into(), ),( // 5HYZnKWe5FVZQ33ZRJK1rG3WaLMztxWrrNDb1JRwaHHVWyP9 - hex!["f26cdb14b5aec7b2789fd5ca80f979cef3761897ae1f37ffb3e154cbcc1c2663"].unchecked_into(), + hex!["f26cdb14b5aec7b2789fd5ca80f979cef3761897ae1f37ffb3e154cbcc1c2663"].into(), // 5EPQdAQ39WQNLCRjWsCk5jErsCitHiY5ZmjfWzzbXDoAoYbn - hex!["66bc1e5d275da50b72b15de072a2468a5ad414919ca9054d2695767cf650012f"].unchecked_into(), + hex!["66bc1e5d275da50b72b15de072a2468a5ad414919ca9054d2695767cf650012f"].into(), // 5DMa31Hd5u1dwoRKgC4uvqyrdK45RHv3CpwvpUC1EzuwDit4 hex!["3919132b851ef0fd2dae42a7e734fe547af5a6b809006100f48944d7fae8e8ef"].unchecked_into(), // 5C4vDQxA8LTck2xJEy4Yg1hM9qjDt4LvTQaMo4Y8ne43aU6x @@ -120,7 +123,7 @@ fn staging_testnet_config_genesis() -> GenesisConfig { let root_key: AccountId = hex![ // 5Ff3iXP75ruzroPWRP2FYBHWnmGGBSb63857BgnzCoXNxfPo "9ee5e5bdc0ec239eb164f865ecc345ce4c88e76ee002e0f7e318097347471809" - ].unchecked_into(); + ].into(); let endowed_accounts: Vec = vec![root_key.clone()]; @@ -154,12 +157,18 @@ pub fn get_from_seed(seed: &str) -> ::Pu .public() } +/// Helper function to generate an account ID from seed +pub fn get_account_id_from_seed(seed: &str) -> AccountId where + AccountPublic: From<::Public> +{ + AccountPublic::from(get_from_seed::(seed)).into_account() +} /// Helper function to generate stash, controller and session key from seed pub fn get_authority_keys_from_seed(seed: &str) -> (AccountId, AccountId, GrandpaId, BabeId, ImOnlineId) { ( - get_from_seed::(&format!("{}//stash", seed)), - get_from_seed::(seed), + get_account_id_from_seed::(&format!("{}//stash", seed)), + get_account_id_from_seed::(seed), get_from_seed::(seed), get_from_seed::(seed), get_from_seed::(seed), @@ -175,18 +184,18 @@ pub fn testnet_genesis( ) -> GenesisConfig { let endowed_accounts: Vec = endowed_accounts.unwrap_or_else(|| { vec![ - get_from_seed::("Alice"), - get_from_seed::("Bob"), - get_from_seed::("Charlie"), - get_from_seed::("Dave"), - get_from_seed::("Eve"), - get_from_seed::("Ferdie"), - get_from_seed::("Alice//stash"), - get_from_seed::("Bob//stash"), - get_from_seed::("Charlie//stash"), - get_from_seed::("Dave//stash"), - get_from_seed::("Eve//stash"), - get_from_seed::("Ferdie//stash"), + get_account_id_from_seed::("Alice"), + get_account_id_from_seed::("Bob"), + get_account_id_from_seed::("Charlie"), + get_account_id_from_seed::("Dave"), + get_account_id_from_seed::("Eve"), + get_account_id_from_seed::("Ferdie"), + get_account_id_from_seed::("Alice//stash"), + get_account_id_from_seed::("Bob//stash"), + get_account_id_from_seed::("Charlie//stash"), + get_account_id_from_seed::("Dave//stash"), + get_account_id_from_seed::("Eve//stash"), + get_account_id_from_seed::("Ferdie//stash"), ] }); @@ -272,7 +281,7 @@ fn development_config_genesis() -> GenesisConfig { vec![ get_authority_keys_from_seed("Alice"), ], - get_from_seed::("Alice"), + get_account_id_from_seed::("Alice"), None, true, ) @@ -298,7 +307,7 @@ fn local_testnet_genesis() -> GenesisConfig { get_authority_keys_from_seed("Alice"), get_authority_keys_from_seed("Bob"), ], - get_from_seed::("Alice"), + get_account_id_from_seed::("Alice"), None, false, ) @@ -330,7 +339,7 @@ pub(crate) mod tests { vec![ get_authority_keys_from_seed("Alice"), ], - get_from_seed::("Alice"), + get_account_id_from_seed::("Alice"), None, false, ) diff --git a/node/cli/src/factory_impl.rs b/node/cli/src/factory_impl.rs index 84c24f2af0..48fb7b237f 100644 --- a/node/cli/src/factory_impl.rs +++ b/node/cli/src/factory_impl.rs @@ -25,16 +25,21 @@ use codec::{Encode, Decode}; use keyring::sr25519::Keyring; use node_runtime::{ Call, CheckedExtrinsic, UncheckedExtrinsic, SignedExtra, BalancesCall, ExistentialDeposit, - MinimumPeriod, + MinimumPeriod }; +use node_primitives::Signature; use primitives::{sr25519, crypto::Pair}; -use sr_primitives::{generic::Era, traits::{Block as BlockT, Header as HeaderT, SignedExtension}}; +use sr_primitives::{ + generic::Era, traits::{Block as BlockT, Header as HeaderT, SignedExtension, Verify, IdentifyAccount} +}; use transaction_factory::RuntimeAdapter; use transaction_factory::modes::Mode; use inherents::InherentData; use timestamp; use finality_tracker; +type AccountPublic = ::Signer; + pub struct FactoryState { block_no: N, @@ -167,7 +172,7 @@ impl RuntimeAdapter for FactoryState { } fn master_account_id() -> Self::AccountId { - Keyring::Alice.pair().public() + Keyring::Alice.to_account_id() } fn master_account_secret() -> Self::Secret { @@ -177,7 +182,7 @@ impl RuntimeAdapter for FactoryState { /// Generates a random `AccountId` from `seed`. fn gen_random_account_id(seed: &Self::Number) -> Self::AccountId { let pair: sr25519::Pair = sr25519::Pair::from_seed(&gen_seed_bytes(*seed)); - pair.public().into() + AccountPublic::from(pair.public()).into_account() } /// Generates a random `Secret` from `seed`. diff --git a/node/cli/src/service.rs b/node/cli/src/service.rs index 0f4a098f3d..03d31c4392 100644 --- a/node/cli/src/service.rs +++ b/node/cli/src/service.rs @@ -330,17 +330,15 @@ mod tests { use consensus_common::{ Environment, Proposer, BlockImportParams, BlockOrigin, ForkChoiceStrategy, BlockImport, }; - use node_primitives::{Block, DigestItem}; - use node_runtime::{BalancesCall, Call, UncheckedExtrinsic}; + use node_primitives::{Block, DigestItem, Signature}; + use node_runtime::{BalancesCall, Call, UncheckedExtrinsic, Address}; use node_runtime::constants::{currency::CENTS, time::SLOT_DURATION}; use codec::{Encode, Decode}; - use primitives::{ - crypto::Pair as CryptoPair, - sr25519::Public as AddressPublic, H256, - }; + use primitives::{crypto::Pair as CryptoPair, H256}; use sr_primitives::{ generic::{BlockId, Era, Digest, SignedPayload}, traits::Block as BlockT, + traits::Verify, OpaqueExtrinsic, }; use timestamp; @@ -348,6 +346,9 @@ mod tests { use keyring::AccountKeyring; use substrate_service::{AbstractService, Roles}; use crate::service::new_full; + use sr_primitives::traits::IdentifyAccount; + + type AccountPublic = ::Signer; #[cfg(feature = "rhd")] fn test_sync() { @@ -518,8 +519,8 @@ mod tests { }, |service, _| { let amount = 5 * CENTS; - let to = AddressPublic::from_raw(bob.public().0); - let from = AddressPublic::from_raw(charlie.public().0); + let to: Address = AccountPublic::from(bob.public()).into_account().into(); + let from: Address = AccountPublic::from(charlie.public()).into_account().into(); let genesis_hash = service.client().block_hash(0).unwrap().unwrap(); let best_block_id = BlockId::number(service.client().info().chain.best_number); let version = service.client().runtime_version_at(&best_block_id).unwrap().spec_version; diff --git a/node/primitives/src/lib.rs b/node/primitives/src/lib.rs index 6b128db4f3..b6a5ec0565 100644 --- a/node/primitives/src/lib.rs +++ b/node/primitives/src/lib.rs @@ -21,21 +21,20 @@ #![cfg_attr(not(feature = "std"), no_std)] use sr_primitives::{ - generic, traits::{Verify, BlakeTwo256}, OpaqueExtrinsic, AnySignature + generic, traits::{Verify, BlakeTwo256, IdentifyAccount}, OpaqueExtrinsic, MultiSignature }; /// An index to a block. pub type BlockNumber = u32; /// Alias to 512-bit hash when used in the context of a transaction signature on the chain. -pub type Signature = AnySignature; +pub type Signature = MultiSignature; /// Some way of identifying an account on the chain. We intentionally make it equivalent /// to the public key of our transaction signing scheme. -pub type AccountId = ::Signer; +pub type AccountId = <::Signer as IdentifyAccount>::AccountId; -/// The type for looking up accounts. We don't expect more than 4 billion of them, but you -/// never know... +/// The type for looking up accounts. We don't expect more than 4 billion of them. pub type AccountIndex = u32; /// Balance of an account. diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index a198877552..d7008dd893 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -42,7 +42,7 @@ use sr_primitives::curve::PiecewiseLinear; use sr_primitives::transaction_validity::TransactionValidity; use sr_primitives::weights::Weight; use sr_primitives::traits::{ - self, BlakeTwo256, Block as BlockT, NumberFor, StaticLookup, SaturatedConversion, + BlakeTwo256, Block as BlockT, NumberFor, StaticLookup, }; use version::RuntimeVersion; #[cfg(any(feature = "std", test))] @@ -83,8 +83,8 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // and set impl_version to equal spec_version. If only runtime // implementation changes and behavior does not, then leave spec_version as // is and increment impl_version. - spec_version: 182, - impl_version: 182, + spec_version: 183, + impl_version: 183, apis: RUNTIME_API_VERSIONS, }; @@ -455,34 +455,6 @@ impl finality_tracker::Trait for Runtime { type ReportLatency = ReportLatency; } -impl system::offchain::CreateTransaction for Runtime { - type Signature = Signature; - - fn create_transaction>( - call: Call, - account: AccountId, - index: Index, - ) -> Option<(Call, ::SignaturePayload)> { - let period = 1 << 8; - let current_block = System::block_number().saturated_into::(); - let tip = 0; - let extra: SignedExtra = ( - system::CheckVersion::::new(), - system::CheckGenesis::::new(), - system::CheckEra::::from(generic::Era::mortal(period, current_block)), - system::CheckNonce::::from(index), - system::CheckWeight::::new(), - transaction_payment::ChargeTransactionPayment::::from(tip), - Default::default(), - ); - let raw_payload = SignedPayload::new(call, extra).ok()?; - let signature = F::sign(account.clone(), &raw_payload)?; - let address = Indices::unlookup(account); - let (call, extra, _) = raw_payload.deconstruct(); - Some((call, (address, signature, extra))) - } -} - construct_runtime!( pub enum Runtime where Block = Block, @@ -693,28 +665,3 @@ impl_runtime_apis! { } } } - -#[cfg(test)] -mod tests { - use super::*; - use sr_primitives::app_crypto::RuntimeAppPublic; - use system::offchain::SubmitSignedTransaction; - - fn is_submit_signed_transaction(_arg: T) where - T: SubmitSignedTransaction< - Runtime, - Call, - Extrinsic=UncheckedExtrinsic, - CreateTransaction=Runtime, - Signer=Signer, - >, - Signer: RuntimeAppPublic + From, - Signer::Signature: Into, - {} - - #[test] - fn validate_bounds() { - let x = SubmitTransaction::default(); - is_submit_signed_transaction(x); - } -} diff --git a/node/testing/src/keyring.rs b/node/testing/src/keyring.rs index 853ca0ef6d..ca44a53880 100644 --- a/node/testing/src/keyring.rs +++ b/node/testing/src/keyring.rs @@ -23,9 +23,7 @@ use sr_primitives::generic::Era; use codec::Encode; /// Alice's account id. -pub fn alice() -> AccountId { - AccountKeyring::Alice.into() -} +pub fn alice() -> AccountId { AccountKeyring::Alice.into() } /// Bob's account id. pub fn bob() -> AccountId { @@ -82,7 +80,7 @@ pub fn sign(xt: CheckedExtrinsic, version: u32, genesis_hash: [u8; 32]) -> Unche match xt.signed { Some((signed, extra)) => { let payload = (xt.function, extra.clone(), version, genesis_hash, genesis_hash); - let key = AccountKeyring::from_public(&signed).unwrap(); + let key = AccountKeyring::from_account_id(&signed).unwrap(); let signature = payload.using_encoded(|b| { if b.len() > 256 { key.sign(&sr_io::blake2_256(b)) diff --git a/srml/system/src/offchain.rs b/srml/system/src/offchain.rs index e234c74c08..468c88af39 100644 --- a/srml/system/src/offchain.rs +++ b/srml/system/src/offchain.rs @@ -21,71 +21,24 @@ use sr_primitives::app_crypto::RuntimeAppPublic; use sr_primitives::traits::Extrinsic as ExtrinsicT; /// A trait responsible for signing a payload using given account. -pub trait Signer { +pub trait Signer { /// Sign any encodable payload with given account and produce a signature. /// /// Returns `Some` if signing succeeded and `None` in case the `account` couldn't be used. - fn sign(account: Account, payload: &Payload) -> Option; + fn sign(public: Public, payload: &Payload) -> Option; } -impl Signer for AppPublic where - AppPublic: RuntimeAppPublic + From, +impl Signer for AppPublic where + AppPublic: RuntimeAppPublic + From, AppPublic::Signature: Into, { - fn sign(account: Account, raw_payload: &Payload) -> Option { + fn sign(public: Public, raw_payload: &Payload) -> Option { raw_payload.using_encoded(|payload| { - AppPublic::from(account).sign(&payload).map(Into::into) + AppPublic::from(public).sign(&payload).map(Into::into) }) } } -/// Creates runtime-specific signed transaction. -pub trait CreateTransaction { - type Signature; - - /// Attempt to create signed extrinsic data that encodes call from given account. - /// - /// Runtime implementation is free to construct the payload to sign and the signature - /// in any way it wants. - /// Returns `None` if signed extrinsic could not be created (either because signing failed - /// or because of any other runtime-specific reason). - fn create_transaction>( - call: Extrinsic::Call, - account: T::AccountId, - nonce: T::Index, - ) -> Option<(Extrinsic::Call, Extrinsic::SignaturePayload)>; -} - -/// A trait to sign and submit transactions in offchain calls. -pub trait SubmitSignedTransaction { - /// Unchecked extrinsic type. - type Extrinsic: ExtrinsicT + codec::Encode; - - /// A runtime-specific type to produce signed data for the extrinsic. - type CreateTransaction: CreateTransaction; - - /// A type used to sign transactions created using `CreateTransaction`. - type Signer: Signer< - T::AccountId, - >::Signature, - >; - - /// Sign given call and submit it to the transaction pool. - /// - /// Returns `Ok` if the transaction was submitted correctly - /// and `Err` if the key for given `id` was not found or the - /// transaction was rejected from the pool. - fn sign_and_submit(call: impl Into, id: T::AccountId) -> Result<(), ()> { - let call = call.into(); - let expected = >::account_nonce(&id); - let (call, signature_data) = Self::CreateTransaction - ::create_transaction::(call, id, expected) - .ok_or(())?; - let xt = Self::Extrinsic::new(call, Some(signature_data)).ok_or(())?; - runtime_io::submit_transaction(xt.encode()) - } -} - /// A trait to submit unsigned transactions in offchain calls. pub trait SubmitUnsignedTransaction { /// Unchecked extrinsic type. @@ -114,18 +67,6 @@ impl Default for TransactionSubmitter { } } -/// A blanket implementation to simplify creation of transaction signer & submitter in the runtime. -impl SubmitSignedTransaction for TransactionSubmitter where - T: crate::Trait, - C: CreateTransaction, - S: Signer>::Signature>, - E: ExtrinsicT + codec::Encode, -{ - type Extrinsic = E; - type CreateTransaction = C; - type Signer = S; -} - /// A blanket impl to use the same submitter for usigned transactions as well. impl SubmitUnsignedTransaction for TransactionSubmitter where T: crate::Trait, diff --git a/subkey/src/cli.yml b/subkey/src/cli.yml index aa6c6d4a57..5d8cd11b1e 100644 --- a/subkey/src/cli.yml +++ b/subkey/src/cli.yml @@ -12,6 +12,11 @@ args: long: sr25519 help: Use Schnorr/Ristretto x25519/BIP39 cryptography takes_value: false + - secp256k1: + short: k + long: secp256k1 + help: Use SECP256k1/ECDSA/BIP39 cryptography + takes_value: false - password: short: p long: password diff --git a/subkey/src/main.rs b/subkey/src/main.rs index 2596513ab2..1b537580f5 100644 --- a/subkey/src/main.rs +++ b/subkey/src/main.rs @@ -22,15 +22,15 @@ use bip39::{Language, Mnemonic, MnemonicType}; use clap::{load_yaml, App, ArgMatches}; use codec::{Decode, Encode}; use hex_literal::hex; -use node_primitives::{Balance, Hash, Index}; +use node_primitives::{Balance, Hash, Index, AccountId, Signature}; use node_runtime::{BalancesCall, Call, Runtime, SignedPayload, UncheckedExtrinsic, VERSION}; use primitives::{ crypto::{set_default_ss58_version, Ss58AddressFormat, Ss58Codec}, - ed25519, sr25519, Pair, Public, H256, hexdisplay::HexDisplay, + ed25519, sr25519, ecdsa, Pair, Public, H256, hexdisplay::HexDisplay, }; -use sr_primitives::generic::Era; +use sr_primitives::{traits::{IdentifyAccount, Verify}, generic::Era}; use std::{ - convert::TryInto, + convert::{TryInto, TryFrom}, io::{stdin, Read}, str::FromStr, }; @@ -43,8 +43,10 @@ trait Crypto: Sized { fn pair_from_suri(suri: &str, password: Option<&str>) -> Self::Pair { Self::Pair::from_string(suri, password).expect("Invalid phrase") } - fn ss58_from_pair(pair: &Self::Pair) -> String { - pair.public().to_ss58check() + fn ss58_from_pair(pair: &Self::Pair) -> String where + ::Public: PublicT, + { + pair.public().into_runtime().into_account().to_ss58check() } fn public_from_pair(pair: &Self::Pair) -> Self::Public { pair.public() @@ -58,28 +60,43 @@ trait Crypto: Sized { { if let Ok((pair, seed)) = Self::Pair::from_phrase(uri, password) { let public_key = Self::public_from_pair(&pair); - println!("Secret phrase `{}` is account:\n Secret seed: {}\n Public key (hex): {}\n Address (SS58): {}", + println!("Secret phrase `{}` is account:\n \ + Secret seed: {}\n \ + Public key (hex): {}\n \ + Account ID: {}\n \ + SS58 Address: {}", uri, format_seed::(seed), - format_public_key::(public_key), + format_public_key::(public_key.clone()), + format_account_id::(public_key), Self::ss58_from_pair(&pair) ); - } else if let Ok(pair) = Self::Pair::from_string(uri, password) { + } else if let Ok((pair, seed)) = Self::Pair::from_string_with_seed(uri, password) { let public_key = Self::public_from_pair(&pair); - println!( - "Secret Key URI `{}` is account:\n Public key (hex): {}\n Address (SS58): {}", + println!("Secret Key URI `{}` is account:\n \ + Secret seed: {}\n \ + Public key (hex): {}\n \ + Account ID: {}\n \ + SS58 Address: {}", uri, - format_public_key::(public_key), + if let Some(seed) = seed { format_seed::(seed) } else { "n/a".into() }, + format_public_key::(public_key.clone()), + format_account_id::(public_key), Self::ss58_from_pair(&pair) ); } else if let Ok((public_key, v)) = ::Public::from_string_with_version(uri) { let v = network_override.unwrap_or(v); - println!("Public Key URI `{}` is account:\n Network ID/version: {}\n Public key (hex): {}\n Address (SS58): {}", + println!("Public Key URI `{}` is account:\n \ + Network ID/version: {}\n \ + Public key (hex): {}\n \ + Account ID: {}\n \ + SS58 Address: {}", uri, String::from(v), format_public_key::(public_key.clone()), + format_account_id::(public_key.clone()), public_key.to_ss58check_with_version(v) ); } else { @@ -106,17 +123,37 @@ impl Crypto for Sr25519 { type Public = sr25519::Public; } +struct Ecdsa; + +impl Crypto for Ecdsa { + type Pair = ecdsa::Pair; + type Public = ecdsa::Public; +} + type SignatureOf = <::Pair as Pair>::Signature; type PublicOf = <::Pair as Pair>::Public; type SeedOf = <::Pair as Pair>::Seed; +type AccountPublic = ::Signer; -trait SignatureT: AsRef<[u8]> + AsMut<[u8]> + Default {} -trait PublicT: Sized + AsRef<[u8]> + Ss58Codec {} +trait SignatureT: AsRef<[u8]> + AsMut<[u8]> + Default { + /// Converts the signature into a runtime account signature, if possible. If not possible, bombs out. + fn into_runtime(self) -> Signature { + panic!("This cryptography isn't supported for this runtime.") + } +} +trait PublicT: Sized + AsRef<[u8]> + Ss58Codec { + /// Converts the public key into a runtime account public key, if possible. If not possible, bombs out. + fn into_runtime(self) -> AccountPublic { + panic!("This cryptography isn't supported for this runtime.") + } +} -impl SignatureT for sr25519::Signature {} -impl SignatureT for ed25519::Signature {} -impl PublicT for sr25519::Public {} -impl PublicT for ed25519::Public {} +impl SignatureT for sr25519::Signature { fn into_runtime(self) -> Signature { self.into() } } +impl SignatureT for ed25519::Signature { fn into_runtime(self) -> Signature { self.into() } } +impl SignatureT for ecdsa::Signature { fn into_runtime(self) -> Signature { self.into() } } +impl PublicT for sr25519::Public { fn into_runtime(self) -> AccountPublic { self.into() } } +impl PublicT for ed25519::Public { fn into_runtime(self) -> AccountPublic { self.into() } } +impl PublicT for ecdsa::Public { fn into_runtime(self) -> AccountPublic { self.into() } } fn main() { let yaml = load_yaml!("cli.yml"); @@ -125,10 +162,12 @@ fn main() { .get_matches(); if matches.is_present("ed25519") { - execute::(matches) - } else { - execute::(matches) + return execute::(matches) } + if matches.is_present("secp256k1") { + return execute::(matches) + } + return execute::(matches) } fn execute(matches: ArgMatches) @@ -165,7 +204,7 @@ where ("verify", Some(matches)) => { let should_decode = matches.is_present("hex"); let message = read_message_from_stdin(should_decode); - let is_valid_signature = do_verify::(matches, message, password); + let is_valid_signature = do_verify::(matches, message); if is_valid_signature { println!("Signature verifies correctly."); } else { @@ -182,20 +221,20 @@ where C::print_from_uri(&formated_seed, None, maybe_network); } ("transfer", Some(matches)) => { - let signer = read_pair::(matches.value_of("from"), password); + let signer = read_pair::(matches.value_of("from"), password); let index = read_required_parameter::(matches, "index"); let genesis_hash = read_genesis_hash(matches); - let to = read_public_key::(matches.value_of("to"), password); + let to: AccountId = read_account_id(matches.value_of("to")); let amount = read_required_parameter::(matches, "amount"); let function = Call::Balances(BalancesCall::transfer(to.into(), amount)); - let extrinsic = create_extrinsic(function, index, signer, genesis_hash); + let extrinsic = create_extrinsic::(function, index, signer, genesis_hash); print_extrinsic(extrinsic); } ("sign-transaction", Some(matches)) => { - let signer = read_pair::(matches.value_of("suri"), password); + let signer = read_pair::(matches.value_of("suri"), password); let index = read_required_parameter::(matches, "nonce"); let genesis_hash = read_genesis_hash(matches); @@ -205,7 +244,7 @@ where .and_then(|x| Decode::decode(&mut &x[..]).ok()) .unwrap(); - let extrinsic = create_extrinsic(function, index, signer, genesis_hash); + let extrinsic = create_extrinsic::(function, index, signer, genesis_hash); print_extrinsic(extrinsic); } @@ -236,13 +275,13 @@ where format_signature::(&signature) } -fn do_verify(matches: &ArgMatches, message: Vec, password: Option<&str>) -> bool +fn do_verify(matches: &ArgMatches, message: Vec) -> bool where SignatureOf: SignatureT, PublicOf: PublicT, { let signature = read_signature::(matches); - let pubkey = read_public_key::(matches.value_of("uri"), password); + let pubkey = read_public_key::(matches.value_of("uri")); <::Pair as Pair>::verify(&signature, &message, &pubkey) } @@ -305,9 +344,7 @@ where signature } -fn read_public_key(matched_uri: Option<&str>, password: Option<&str>) -> PublicOf -where - SignatureOf: SignatureT, +fn read_public_key(matched_uri: Option<&str>) -> PublicOf where PublicOf: PublicT, { let uri = matched_uri.expect("parameter is required; thus it can't be None; qed"); @@ -319,13 +356,28 @@ where if let Ok(pubkey_vec) = hex::decode(uri) { ::Public::from_slice(pubkey_vec.as_slice()) } else { - ::Pair::from_string(uri, password) + ::Public::from_string(uri) .ok() - .map(|p| p.public()) .expect("Invalid URI; expecting either a secret URI or a public URI.") } } +fn read_account_id(matched_uri: Option<&str>) -> AccountId { + let uri = matched_uri.expect("parameter is required; thus it can't be None; qed"); + let uri = if uri.starts_with("0x") { + &uri[2..] + } else { + uri + }; + if let Ok(data_vec) = hex::decode(uri) { + AccountId::try_from(data_vec.as_slice()) + .expect("Invalid hex length for account ID; should be 32 bytes") + } else { + AccountId::from_ss58check(uri).ok() + .expect("Invalid SS58-check address given for account ID.") + } +} + fn read_pair( matched_suri: Option<&str>, password: Option<&str>, @@ -350,12 +402,21 @@ fn format_public_key(public_key: PublicOf) -> String { format!("0x{}", HexDisplay::from(&public_key.as_ref())) } -fn create_extrinsic( +fn format_account_id(public_key: PublicOf) -> String where + PublicOf: PublicT, +{ + format!("0x{}", HexDisplay::from(&public_key.into_runtime().into_account().as_ref())) +} + +fn create_extrinsic( function: Call, index: Index, - signer: ::Pair, + signer: C::Pair, genesis_hash: H256, -) -> UncheckedExtrinsic { +) -> UncheckedExtrinsic where + PublicOf: PublicT, + SignatureOf: SignatureT, +{ let extra = |i: Index, f: Balance| { ( system::CheckVersion::::new(), @@ -380,13 +441,14 @@ fn create_extrinsic( (), ), ); - let signature = raw_payload.using_encoded(|payload| signer.sign(payload)); + let signature = raw_payload.using_encoded(|payload| signer.sign(payload)).into_runtime(); + let signer = signer.public().into_runtime(); let (function, extra, _) = raw_payload.deconstruct(); UncheckedExtrinsic::new_signed( function, - signer.public().into(), - signature.into(), + signer.into_account().into(), + signature, extra, ) } @@ -439,7 +501,7 @@ mod tests { let matches = App::from_yaml(yaml).get_matches_from(arg_vec); let matches = matches.subcommand().1.unwrap(); - assert!(do_verify::(matches, message, password)); + assert!(do_verify::(matches, message)); } #[test] diff --git a/subkey/src/vanity.rs b/subkey/src/vanity.rs index b612bc470f..835001a0aa 100644 --- a/subkey/src/vanity.rs +++ b/subkey/src/vanity.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -use super::Crypto; +use super::{PublicOf, PublicT, Crypto}; use primitives::Pair; use rand::{rngs::OsRng, RngCore}; @@ -62,7 +62,9 @@ fn calculate_score(_desired: &str, key: &str) -> usize { 0 } -pub(super) fn generate_key(desired: &str) -> Result, &str> { +pub(super) fn generate_key(desired: &str) -> Result, &str> where + PublicOf: PublicT, +{ if desired.is_empty() { return Err("Pattern must not be empty"); } diff --git a/test-utils/chain-spec-builder/src/main.rs b/test-utils/chain-spec-builder/src/main.rs index 22c5253b06..8fdd282345 100644 --- a/test-utils/chain-spec-builder/src/main.rs +++ b/test-utils/chain-spec-builder/src/main.rs @@ -22,7 +22,7 @@ use structopt::StructOpt; use keystore::{Store as Keystore}; use node_cli::chain_spec::{self, AccountId}; -use primitives::{crypto::{Public, Ss58Codec}, traits::BareCryptoStore}; +use primitives::{sr25519, crypto::{Public, Ss58Codec}, traits::BareCryptoStore}; /// A utility to easily create a testnet chain spec definition with a given set /// of authorities and endowed accounts and/or generate random accounts. @@ -237,11 +237,11 @@ fn main() -> Result<(), String> { } let endowed_accounts = endowed_seeds.iter().map(|seed| { - chain_spec::get_from_seed::(seed) + chain_spec::get_account_id_from_seed::(seed) .to_ss58check() }).collect(); - let sudo_account = chain_spec::get_from_seed::(&sudo_seed) + let sudo_account = chain_spec::get_account_id_from_seed::(&sudo_seed) .to_ss58check(); (authority_seeds, endowed_accounts, sudo_account) -- GitLab From 7cc598c2d454606b8aabe4ca18c2b1bb5ad59fb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= Date: Thu, 24 Oct 2019 13:29:09 +0100 Subject: [PATCH 094/167] node-template: remove unnecessary on_exit guard (#3903) --- node-template/src/service.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/node-template/src/service.rs b/node-template/src/service.rs index c46928c10e..46c0124cb4 100644 --- a/node-template/src/service.rs +++ b/node-template/src/service.rs @@ -115,8 +115,6 @@ pub fn new_full(config: Configuration Date: Thu, 24 Oct 2019 15:03:52 +0200 Subject: [PATCH 095/167] Better Parameterisation for Fee system (#3823) * Better fee parameters * Fix build * Better runtime tests * Price to Weight ratio as type parameter (#3856) * Price to Weight ration as type parameter * Kian feedback * Some renames. * Fix executor tests * Getting Closer. * Phantom Data * Actually fix executor tests. * Fix tests. * Remove todo * Fix build --- Cargo.lock | 1 + core/sr-arithmetic/src/biguint.rs | 2 +- core/sr-arithmetic/src/fixed64.rs | 6 + node/executor/src/lib.rs | 11 +- node/runtime/Cargo.toml | 3 + node/runtime/src/constants.rs | 16 -- node/runtime/src/impls.rs | 322 +++++++++++++++------------- node/runtime/src/lib.rs | 12 +- srml/system/src/lib.rs | 27 ++- srml/transaction-payment/src/lib.rs | 6 +- 10 files changed, 217 insertions(+), 189 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 14f8c87c1a..c3c3e66c12 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2472,6 +2472,7 @@ dependencies = [ "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-io 2.0.0", "sr-primitives 2.0.0", "sr-staking-primitives 2.0.0", "sr-std 2.0.0", diff --git a/core/sr-arithmetic/src/biguint.rs b/core/sr-arithmetic/src/biguint.rs index b7d93c2f0d..c0836e09b3 100644 --- a/core/sr-arithmetic/src/biguint.rs +++ b/core/sr-arithmetic/src/biguint.rs @@ -21,7 +21,7 @@ use rstd::{cmp::Ordering, ops, prelude::*, cell::RefCell, convert::TryFrom}; // A sensible value for this would be half of the dword size of the host machine. Since the // runtime is compiled to 32bit webassembly, using 32 and 64 for single and double respectively -// should yield the most performance. TODO #3745 we could benchmark this and verify. +// should yield the most performance. /// Representation of a single limb. pub type Single = u32; /// Representation of two limbs. diff --git a/core/sr-arithmetic/src/fixed64.rs b/core/sr-arithmetic/src/fixed64.rs index 3bac75898e..bd58e36940 100644 --- a/core/sr-arithmetic/src/fixed64.rs +++ b/core/sr-arithmetic/src/fixed64.rs @@ -48,6 +48,12 @@ impl Fixed64 { DIV } + /// Consume self and return the inner value. + /// + /// This should only be used for testing. + #[cfg(any(feature = "std", test))] + pub fn into_inner(self) -> i64 { self.0 } + /// Raw constructor. Equal to `parts / 1_000_000_000`. pub fn from_parts(parts: i64) -> Self { Self(parts) diff --git a/node/executor/src/lib.rs b/node/executor/src/lib.rs index 3c97b3cd11..39727d1d55 100644 --- a/node/executor/src/lib.rs +++ b/node/executor/src/lib.rs @@ -38,9 +38,7 @@ mod tests { use super::Executor; use {balances, contracts, indices, system, timestamp}; use codec::{Encode, Decode, Joiner}; - use runtime_support::{ - Hashable, StorageValue, StorageMap, traits::Currency, - }; + use runtime_support::{Hashable, StorageValue, StorageMap, traits::Currency}; use state_machine::TestExternalities as CoreTestExternalities; use primitives::{ Blake2Hasher, NeverNativeValue, NativeOrEncoded, map, @@ -57,8 +55,9 @@ mod tests { use node_runtime::{ Header, Block, UncheckedExtrinsic, CheckedExtrinsic, Call, Runtime, Balances, BuildStorage, System, TransactionPayment, Event, TransferFee, TransactionBaseFee, TransactionByteFee, - constants::currency::*, impls::WeightToFee, + WeightFeeCoefficient, constants::currency::*, }; + use node_runtime::impls::LinearWeightToFee; use node_primitives::{Balance, Hash, BlockNumber}; use node_testing::keyring::*; use wabt; @@ -501,8 +500,6 @@ mod tests { ).0.unwrap(); t.execute_with(|| { - // NOTE: fees differ slightly in tests that execute more than one block due to the - // weight update. Hence, using `assert_eq_error_rate`. assert_eq!( Balances::total_balance(&alice()), alice_last_known_balance - 10 * DOLLARS - transfer_fee(&xt(), fm), @@ -1069,7 +1066,7 @@ mod tests { balance_alice -= length_fee; let weight = default_transfer_call().get_dispatch_info().weight; - let weight_fee = WeightToFee::convert(weight); + let weight_fee = LinearWeightToFee::::convert(weight); // we know that weight to fee multiplier is effect-less in block 1. assert_eq!(weight_fee as Balance, MILLICENTS); diff --git a/node/runtime/Cargo.toml b/node/runtime/Cargo.toml index 252a7767ea..5a6a2b6772 100644 --- a/node/runtime/Cargo.toml +++ b/node/runtime/Cargo.toml @@ -57,6 +57,9 @@ transaction-payment = { package = "srml-transaction-payment", path = "../../srml [build-dependencies] wasm-builder-runner = { package = "substrate-wasm-builder-runner", version = "1.0.4", path = "../../core/utils/wasm-builder-runner" } +[dev-dependencies] +runtime_io = { package = "sr-io", path = "../../core/sr-io" } + [features] default = ["std"] std = [ diff --git a/node/runtime/src/constants.rs b/node/runtime/src/constants.rs index ca57bdc8ba..fba4c7ac79 100644 --- a/node/runtime/src/constants.rs +++ b/node/runtime/src/constants.rs @@ -66,19 +66,3 @@ pub mod time { pub const HOURS: BlockNumber = MINUTES * 60; pub const DAYS: BlockNumber = HOURS * 24; } - -// CRITICAL NOTE: The system module maintains two constants: a _maximum_ block weight and a _ratio_ -// of it yielding the portion which is accessible to normal transactions (reserving the rest for -// operational ones). `TARGET_BLOCK_FULLNESS` is entirely independent and the system module is not -// aware of if, nor should it care about it. This constant simply denotes on which ratio of the -// _maximum_ block weight we tweak the fees. It does NOT care about the type of the dispatch. -// -// For the system to be configured in a sane way, `TARGET_BLOCK_FULLNESS` should always be less than -// the ratio that `system` module uses to find normal transaction quota. -/// Fee-related. -pub mod fee { - pub use sr_primitives::Perbill; - - /// The block saturation level. Fees will be updates based on this value. - pub const TARGET_BLOCK_FULLNESS: Perbill = Perbill::from_percent(25); -} diff --git a/node/runtime/src/impls.rs b/node/runtime/src/impls.rs index 2193845020..2e9bd38c8f 100644 --- a/node/runtime/src/impls.rs +++ b/node/runtime/src/impls.rs @@ -19,10 +19,9 @@ use node_primitives::Balance; use sr_primitives::weights::Weight; use sr_primitives::traits::{Convert, Saturating}; -use sr_primitives::Fixed64; -use support::traits::{OnUnbalanced, Currency}; -use crate::{Balances, Authorship, MaximumBlockWeight, NegativeImbalance}; -use crate::constants::fee::TARGET_BLOCK_FULLNESS; +use sr_primitives::{Fixed64, Perbill}; +use support::traits::{OnUnbalanced, Currency, Get}; +use crate::{Balances, System, Authorship, MaximumBlockWeight, NegativeImbalance}; pub struct Author; impl OnUnbalanced for Author { @@ -47,48 +46,34 @@ impl Convert for CurrencyToVoteHandler { fn convert(x: u128) -> Balance { x * Self::factor() } } -/// Handles converting a weight scalar to a fee value, based on the scale and granularity of the -/// node's balance type. -/// -/// This should typically create a mapping between the following ranges: -/// - [0, system::MaximumBlockWeight] -/// - [Balance::min, Balance::max] -/// -/// Yet, it can be used for any other sort of change to weight-fee. Some examples being: -/// - Setting it to `0` will essentially disable the weight fee. -/// - Setting it to `1` will cause the literal `#[weight = x]` values to be charged. -/// -/// By default, substrate node will have a weight range of [0, 1_000_000_000]. -pub struct WeightToFee; -impl Convert for WeightToFee { - fn convert(x: Weight) -> Balance { +/// Convert from weight to balance via a simple coefficient multiplication +/// The associated type C encapsulates a constant in units of balance per weight +pub struct LinearWeightToFee(rstd::marker::PhantomData); + +impl> Convert for LinearWeightToFee { + fn convert(w: Weight) -> Balance { // substrate-node a weight of 10_000 (smallest non-zero weight) to be mapped to 10^7 units of // fees, hence: - Balance::from(x).saturating_mul(1_000) + let coefficient = C::get(); + Balance::from(w).saturating_mul(coefficient) } } -/// A struct that updates the weight multiplier based on the saturation level of the previous block. -/// This should typically be called once per-block. +/// Update the given multiplier based on the following formula /// -/// This assumes that weight is a numeric value in the u32 range. -/// -/// Given `TARGET_BLOCK_FULLNESS = 1/2`, a block saturation greater than 1/2 will cause the system -/// fees to slightly grow and the opposite for block saturations less than 1/2. -/// -/// Formula: -/// diff = (target_weight - current_block_weight) +/// diff = (target_weight - previous_block_weight) /// v = 0.00004 /// next_weight = weight * (1 + (v . diff) + (v . diff)^2 / 2) /// +/// Where `target_weight` must be given as the `Get` implementation of the `T` generic type. /// https://research.web3.foundation/en/latest/polkadot/Token%20Economics/#relay-chain-transaction-fees -pub struct FeeMultiplierUpdateHandler; +pub struct TargetedFeeAdjustment(rstd::marker::PhantomData); -impl Convert<(Weight, Fixed64), Fixed64> for FeeMultiplierUpdateHandler { - fn convert(previous_state: (Weight, Fixed64)) -> Fixed64 { - let (block_weight, multiplier) = previous_state; +impl> Convert for TargetedFeeAdjustment { + fn convert(multiplier: Fixed64) -> Fixed64 { + let block_weight = System::all_extrinsics_weight(); let max_weight = MaximumBlockWeight::get(); - let target_weight = (TARGET_BLOCK_FULLNESS * max_weight) as u128; + let target_weight = (T::get() * max_weight) as u128; let block_weight = block_weight as u128; // determines if the first_term is positive @@ -100,8 +85,8 @@ impl Convert<(Weight, Fixed64), Fixed64> for FeeMultiplierUpdateHandler { // 0.00004 = 4/100_000 = 40_000/10^9 let v = Fixed64::from_rational(4, 100_000); - // 0.00004^2 = 16/10^10 ~= 2/10^9. Taking the future /2 into account, then it is just 1 parts - // from a billionth. + // 0.00004^2 = 16/10^10 ~= 2/10^9. Taking the future /2 into account, then it is just 1 + // parts from a billionth. let v_squared_2 = Fixed64::from_rational(1, 1_000_000_000); let first_term = v.saturating_mul(diff); @@ -132,15 +117,16 @@ impl Convert<(Weight, Fixed64), Fixed64> for FeeMultiplierUpdateHandler { mod tests { use super::*; use sr_primitives::weights::Weight; + use sr_primitives::assert_eq_error_rate; use crate::{MaximumBlockWeight, AvailableBlockRatio, Runtime}; - use crate::constants::currency::*; + use crate::{constants::currency::*, TransactionPayment, TargetBlockFullness}; fn max() -> Weight { MaximumBlockWeight::get() } fn target() -> Weight { - TARGET_BLOCK_FULLNESS * max() + TargetBlockFullness::get() * max() } // poc reference implementation. @@ -155,50 +141,68 @@ mod tests { // Current saturation in terms of weight let s = block_weight; - let fm = (v * (s/m - ss/m)) + (v.powi(2) * (s/m - ss/m).powi(2)) / 2.0; - let addition_fm = Fixed64::from_parts((fm * 1_000_000_000_f32) as i64); + let fm = v * (s/m - ss/m) + v.powi(2) * (s/m - ss/m).powi(2) / 2.0; + let addition_fm = Fixed64::from_parts((fm * 1_000_000_000_f32).round() as i64); previous.saturating_add(addition_fm) } - fn fm(parts: i64) -> Fixed64 { + fn feemul(parts: i64) -> Fixed64 { Fixed64::from_parts(parts) } + fn run_with_system_weight(w: Weight, assertions: F) where F: Fn() -> () { + let mut t: runtime_io::TestExternalities = + system::GenesisConfig::default().build_storage::().unwrap().into(); + t.execute_with(|| { + System::set_block_limits(w, 0); + assertions() + }); + } + #[test] fn fee_multiplier_update_poc_works() { let fm = Fixed64::from_rational(0, 1); let test_set = vec![ - // TODO: this has a rounding error and fails. - // (0, fm.clone()), + (0, fm.clone()), (100, fm.clone()), (target(), fm.clone()), (max() / 2, fm.clone()), (max(), fm.clone()), ]; test_set.into_iter().for_each(|(w, fm)| { - assert_eq!( - fee_multiplier_update(w, fm), - FeeMultiplierUpdateHandler::convert((w, fm)), - "failed for weight {} and prev fm {:?}", - w, - fm, - ); + run_with_system_weight(w, || { + assert_eq_error_rate!( + fee_multiplier_update(w, fm).into_inner(), + TargetedFeeAdjustment::::convert(fm).into_inner(), + 5, + ); + }) }) } #[test] fn empty_chain_simulation() { // just a few txs per_block. - let block_weight = 1000; - let mut fm = Fixed64::default(); - let mut iterations: u64 = 0; - loop { - let next = FeeMultiplierUpdateHandler::convert((block_weight, fm)); - fm = next; - if fm == Fixed64::from_rational(-1, 1) { break; } - iterations += 1; - } - println!("iteration {}, new fm = {:?}. Weight fee is now zero", iterations, fm); + let block_weight = 0; + run_with_system_weight(block_weight, || { + let mut fm = Fixed64::default(); + let mut iterations: u64 = 0; + loop { + let next = TargetedFeeAdjustment::::convert(fm); + fm = next; + if fm == Fixed64::from_rational(-1, 1) { break; } + iterations += 1; + } + println!("iteration {}, new fm = {:?}. Weight fee is now zero", iterations, fm); + assert!(iterations > 50_000, "This assertion is just a warning; Don't panic. \ + Current substrate/polkadot node are configured with a _slow adjusting fee_ \ + mechanism. Hence, it is really unlikely that fees collapse to zero even on an \ + empty chain in less than at least of couple of thousands of empty blocks. But this \ + simulation indicates that fees collapsed to zero after {} almost-empty blocks. \ + Check it", + iterations, + ); + }) } #[test] @@ -207,100 +211,116 @@ mod tests { // `cargo test congested_chain_simulation -- --nocapture` to get some insight. // almost full. The entire quota of normal transactions is taken. - let block_weight = AvailableBlockRatio::get() * max(); - - // default minimum substrate weight - let tx_weight = 10_000u32; - - // initial value of system - let mut fm = Fixed64::default(); - assert_eq!(fm, Fixed64::from_parts(0)); - - let mut iterations: u64 = 0; - loop { - let next = FeeMultiplierUpdateHandler::convert((block_weight, fm)); - if fm == next { break; } - fm = next; - iterations += 1; - let fee = ::WeightToFee::convert(tx_weight); - let adjusted_fee = fm.saturated_multiply_accumulate(fee); - println!( - "iteration {}, new fm = {:?}. Fee at this point is: \ - {} units, {} millicents, {} cents, {} dollars", - iterations, - fm, - adjusted_fee, - adjusted_fee / MILLICENTS, - adjusted_fee / CENTS, - adjusted_fee / DOLLARS - ); - } + let block_weight = AvailableBlockRatio::get() * max() - 100; + + // Default substrate minimum. + let tx_weight = 10_000; + + run_with_system_weight(block_weight, || { + // initial value configured on module + let mut fm = Fixed64::default(); + assert_eq!(fm, TransactionPayment::next_fee_multiplier()); + + let mut iterations: u64 = 0; + loop { + let next = TargetedFeeAdjustment::::convert(fm); + // if no change, panic. This should never happen in this case. + if fm == next { panic!("The fee should ever increase"); } + fm = next; + iterations += 1; + let fee = ::WeightToFee::convert(tx_weight); + let adjusted_fee = fm.saturated_multiply_accumulate(fee); + println!( + "iteration {}, new fm = {:?}. Fee at this point is: {} units / {} millicents, \ + {} cents, {} dollars", + iterations, + fm, + adjusted_fee, + adjusted_fee / MILLICENTS, + adjusted_fee / CENTS, + adjusted_fee / DOLLARS, + ); + } + }); } #[test] fn stateless_weight_mul() { - // Light block. Fee is reduced a little. - assert_eq!( - FeeMultiplierUpdateHandler::convert((target() / 4, Fixed64::default())), - fm(-7500) - ); - // a bit more. Fee is decreased less, meaning that the fee increases as the block grows. - assert_eq!( - FeeMultiplierUpdateHandler::convert((target() / 2, Fixed64::default())), - fm(-5000) - ); - // ideal. Original fee. No changes. - assert_eq!( - FeeMultiplierUpdateHandler::convert((target(), Fixed64::default())), - fm(0) - ); - // // More than ideal. Fee is increased. - assert_eq!( - FeeMultiplierUpdateHandler::convert(((target() * 2), Fixed64::default())), - fm(10000) - ); + run_with_system_weight(target() / 4, || { + // Light block. Fee is reduced a little. + assert_eq!( + TargetedFeeAdjustment::::convert(Fixed64::default()), + feemul(-7500), + ); + }); + run_with_system_weight(target() / 2, || { + // a bit more. Fee is decreased less, meaning that the fee increases as the block grows. + assert_eq!( + TargetedFeeAdjustment::::convert(Fixed64::default()), + feemul(-5000), + ); + + }); + run_with_system_weight(target(), || { + // ideal. Original fee. No changes. + assert_eq!( + TargetedFeeAdjustment::::convert(Fixed64::default()), + feemul(0), + ); + }); + run_with_system_weight(target() * 2, || { + // // More than ideal. Fee is increased. + assert_eq!( + TargetedFeeAdjustment::::convert(Fixed64::default()), + feemul(10000), + ); + }); } #[test] fn stateful_weight_mul_grow_to_infinity() { - assert_eq!( - FeeMultiplierUpdateHandler::convert((target() * 2, Fixed64::default())), - fm(10000) - ); - assert_eq!( - FeeMultiplierUpdateHandler::convert((target() * 2, fm(10000))), - fm(20000) - ); - assert_eq!( - FeeMultiplierUpdateHandler::convert((target() * 2, fm(20000))), - fm(30000) - ); - // ... - assert_eq!( - FeeMultiplierUpdateHandler::convert((target() * 2, fm(1_000_000_000))), - fm(1_000_000_000 + 10000) - ); + run_with_system_weight(target() * 2, || { + assert_eq!( + TargetedFeeAdjustment::::convert(Fixed64::default()), + feemul(10000) + ); + assert_eq!( + TargetedFeeAdjustment::::convert(feemul(10000)), + feemul(20000) + ); + assert_eq!( + TargetedFeeAdjustment::::convert(feemul(20000)), + feemul(30000) + ); + // ... + assert_eq!( + TargetedFeeAdjustment::::convert(feemul(1_000_000_000)), + feemul(1_000_000_000 + 10000) + ); + }); } #[test] fn stateful_weight_mil_collapse_to_minus_one() { - assert_eq!( - FeeMultiplierUpdateHandler::convert((0, Fixed64::default())), - fm(-10000) - ); - assert_eq!( - FeeMultiplierUpdateHandler::convert((0, fm(-10000))), - fm(-20000) - ); - assert_eq!( - FeeMultiplierUpdateHandler::convert((0, fm(-20000))), - fm(-30000) - ); - // ... - assert_eq!( - FeeMultiplierUpdateHandler::convert((0, fm(1_000_000_000 * -1))), - fm(-1_000_000_000) - ); + run_with_system_weight(0, || { + assert_eq!( + TargetedFeeAdjustment::::convert(Fixed64::default()), + feemul(-10000) + ); + assert_eq!( + TargetedFeeAdjustment::::convert(feemul(-10000)), + feemul(-20000) + ); + assert_eq!( + TargetedFeeAdjustment::::convert(feemul(-20000)), + feemul(-30000) + ); + // ... + assert_eq!( + TargetedFeeAdjustment::::convert(feemul(1_000_000_000 * -1)), + feemul(-1_000_000_000) + ); + }) } #[test] @@ -309,6 +329,7 @@ mod tests { let mb = kb * kb; let max_fm = Fixed64::from_natural(i64::max_value()); + // check that for all values it can compute, correctly. vec![ 0, 1, @@ -322,7 +343,11 @@ mod tests { Weight::max_value() / 2, Weight::max_value() ].into_iter().for_each(|i| { - FeeMultiplierUpdateHandler::convert((i, Fixed64::default())); + run_with_system_weight(i, || { + let next = TargetedFeeAdjustment::::convert(Fixed64::default()); + let truth = fee_multiplier_update(i, Fixed64::default()); + assert_eq_error_rate!(truth.into_inner(), next.into_inner(), 5); + }); }); // Some values that are all above the target and will cause an increase. @@ -330,12 +355,11 @@ mod tests { vec![t + 100, t * 2, t * 4] .into_iter() .for_each(|i| { - let fm = FeeMultiplierUpdateHandler::convert(( - i, - max_fm - )); - // won't grow. The convert saturates everything. - assert_eq!(fm, max_fm); + run_with_system_weight(i, || { + let fm = TargetedFeeAdjustment::::convert(max_fm); + // won't grow. The convert saturates everything. + assert_eq!(fm, max_fm); + }) }); } } diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index d7008dd893..9097dd22a3 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -64,7 +64,7 @@ pub use staking::StakerStatus; /// Implementations of some helper traits passed into runtime modules as associated types. pub mod impls; -use impls::{CurrencyToVoteHandler, FeeMultiplierUpdateHandler, Author, WeightToFee}; +use impls::{CurrencyToVoteHandler, Author, LinearWeightToFee, TargetedFeeAdjustment}; /// Constant values used within the runtime. pub mod constants; @@ -109,9 +109,9 @@ pub type DealWithFees = SplitTwoWays< parameter_types! { pub const BlockHashCount: BlockNumber = 250; pub const MaximumBlockWeight: Weight = 1_000_000_000; - pub const AvailableBlockRatio: Perbill = Perbill::from_percent(75); pub const MaximumBlockLength: u32 = 5 * 1024 * 1024; pub const Version: RuntimeVersion = VERSION; + pub const AvailableBlockRatio: Perbill = Perbill::from_percent(75); } impl system::Trait for Runtime { @@ -176,6 +176,10 @@ impl balances::Trait for Runtime { parameter_types! { pub const TransactionBaseFee: Balance = 1 * CENTS; pub const TransactionByteFee: Balance = 10 * MILLICENTS; + // setting this to zero will disable the weight fee. + pub const WeightFeeCoefficient: Balance = 1_000; + // for a sane configuration, this should always be less than `AvailableBlockRatio`. + pub const TargetBlockFullness: Perbill = Perbill::from_percent(25); } impl transaction_payment::Trait for Runtime { @@ -183,8 +187,8 @@ impl transaction_payment::Trait for Runtime { type OnTransactionPayment = DealWithFees; type TransactionBaseFee = TransactionBaseFee; type TransactionByteFee = TransactionByteFee; - type WeightToFee = WeightToFee; - type FeeMultiplierUpdate = FeeMultiplierUpdateHandler; + type WeightToFee = LinearWeightToFee; + type FeeMultiplierUpdate = TargetedFeeAdjustment; } parameter_types! { diff --git a/srml/system/src/lib.rs b/srml/system/src/lib.rs index c9dcca53cb..87c38096ab 100644 --- a/srml/system/src/lib.rs +++ b/srml/system/src/lib.rs @@ -157,15 +157,17 @@ pub fn extrinsics_data_root(xts: Vec>) -> H::Output { pub trait Trait: 'static + Eq + Clone { /// The aggregated `Origin` type used by dispatchable calls. - type Origin: Into, Self::Origin>> + From>; + type Origin: + Into, Self::Origin>> + From>; /// The aggregated `Call` type. type Call: Debug; - /// Account index (aka nonce) type. This stores the number of previous transactions associated with a sender - /// account. + /// Account index (aka nonce) type. This stores the number of previous transactions associated + /// with a sender account. type Index: - Parameter + Member + MaybeSerialize + Debug + Default + MaybeDisplay + SimpleArithmetic + Copy; + Parameter + Member + MaybeSerialize + Debug + Default + MaybeDisplay + SimpleArithmetic + + Copy; /// The block number type used by the runtime. type BlockNumber: @@ -181,13 +183,15 @@ pub trait Trait: 'static + Eq + Clone { type Hashing: Hash; /// The user account identifier type for the runtime. - type AccountId: Parameter + Member + MaybeSerializeDeserialize + Debug + MaybeDisplay + Ord + Default; + type AccountId: Parameter + Member + MaybeSerializeDeserialize + Debug + MaybeDisplay + Ord + + Default; /// Converting trait to take a source type and convert to `AccountId`. /// - /// Used to define the type and conversion mechanism for referencing accounts in transactions. It's perfectly - /// reasonable for this to be an identity conversion (with the source type being `AccountId`), but other modules - /// (e.g. Indices module) may provide more functional/efficient alternatives. + /// Used to define the type and conversion mechanism for referencing accounts in transactions. + /// It's perfectly reasonable for this to be an identity conversion (with the source type being + /// `AccountId`), but other modules (e.g. Indices module) may provide more functional/efficient + /// alternatives. type Lookup: StaticLookup; /// The block header. @@ -701,6 +705,13 @@ impl Module { >::put(n); } + /// Set the current block weight. This should only be used in some integration tests. + #[cfg(any(feature = "std", test))] + pub fn set_block_limits(weight: Weight, len: usize) { + AllExtrinsicsWeight::put(weight); + AllExtrinsicsLen::put(len as u32); + } + /// Return the chain's current runtime version. pub fn runtime_version() -> RuntimeVersion { T::Version::get() } diff --git a/srml/transaction-payment/src/lib.rs b/srml/transaction-payment/src/lib.rs index ab120322f6..5ad5c650af 100644 --- a/srml/transaction-payment/src/lib.rs +++ b/srml/transaction-payment/src/lib.rs @@ -70,8 +70,7 @@ pub trait Trait: system::Trait { type WeightToFee: Convert>; /// Update the multiplier of the next block, based on the previous block's weight. - // TODO: maybe this does not need previous weight and can just read it - type FeeMultiplierUpdate: Convert<(Weight, Multiplier), Multiplier>; + type FeeMultiplierUpdate: Convert; } decl_storage! { @@ -89,9 +88,8 @@ decl_module! { const TransactionByteFee: BalanceOf = T::TransactionByteFee::get(); fn on_finalize() { - let current_weight = >::all_extrinsics_weight(); NextFeeMultiplier::mutate(|fm| { - *fm = T::FeeMultiplierUpdate::convert((current_weight, *fm)) + *fm = T::FeeMultiplierUpdate::convert(*fm) }); } } -- GitLab From 626699a992c5d30a482b235c7f952e3193ed3f25 Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Thu, 24 Oct 2019 15:11:24 +0200 Subject: [PATCH 096/167] Bump transaction version (#3904) --- core/sr-primitives/src/generic/unchecked_extrinsic.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/sr-primitives/src/generic/unchecked_extrinsic.rs b/core/sr-primitives/src/generic/unchecked_extrinsic.rs index 4af8d9a95b..c7bff1f4c8 100644 --- a/core/sr-primitives/src/generic/unchecked_extrinsic.rs +++ b/core/sr-primitives/src/generic/unchecked_extrinsic.rs @@ -25,7 +25,7 @@ use crate::{ generic::CheckedExtrinsic, transaction_validity::{TransactionValidityError, InvalidTransaction}, }; -const TRANSACTION_VERSION: u8 = 3; +const TRANSACTION_VERSION: u8 = 4; /// A extrinsic right from the external world. This is unchecked and so /// can contain a signature. -- GitLab From fa7864e7055b39bc57e4db306b29e09c01baffba Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Thu, 24 Oct 2019 15:11:38 +0200 Subject: [PATCH 097/167] Service builder clean-up (#3906) * Rename NewService to Service * Move new_impl! macro to builder module * Inline new_impl! * Minor cleanup * Inline the offchain_workers() function * Fix indentation level * Inline start_rpc * Remove RpcBuilder trait --- core/service/src/builder.rs | 632 ++++++++++++++++++++++-------------- core/service/src/lib.rs | 343 +------------------ node/cli/src/service.rs | 4 +- 3 files changed, 400 insertions(+), 579 deletions(-) diff --git a/core/service/src/builder.rs b/core/service/src/builder.rs index cf91d1b267..b2a6cc731a 100644 --- a/core/service/src/builder.rs +++ b/core/service/src/builder.rs @@ -14,9 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -use crate::{NewService, NetworkStatus, NetworkState, error::{self, Error}, DEFAULT_PROTOCOL_ID}; +use crate::{Service, NetworkStatus, NetworkState, error::{self, Error}, DEFAULT_PROTOCOL_ID}; use crate::{SpawnTaskHandle, start_rpc_servers, build_network_future, TransactionPoolAdapter}; -use crate::TaskExecutor; use crate::status_sinks; use crate::config::Configuration; use client::{ @@ -33,13 +32,13 @@ use futures03::{ FutureExt as _, TryFutureExt as _, StreamExt as _, TryStreamExt as _, }; -use keystore::{Store as Keystore, KeyStorePtr}; +use keystore::{Store as Keystore}; use log::{info, warn}; use network::{FinalityProofProvider, OnDemand, NetworkService, NetworkStateInfo, DhtEvent}; use network::{config::BoxFinalityProofRequestBuilder, specialization::NetworkSpecialization}; use parking_lot::{Mutex, RwLock}; use primitives::{Blake2Hasher, H256, Hasher}; -use rpc::{self, system::SystemInfo}; +use rpc; use sr_primitives::generic::BlockId; use sr_primitives::traits::{ Block as BlockT, Extrinsic, ProvideRuntimeApi, NumberFor, One, Zero, Header, SaturatedConversion @@ -69,7 +68,7 @@ use transaction_pool::txpool::{self, ChainApi, Pool as TransactionPool}; /// generics is done when you call `build`. /// pub struct ServiceBuilder + TNetP, TExPool, TRpc, Backend> { config: Configuration, client: Arc, @@ -83,7 +82,7 @@ pub struct ServiceBuilder, rpc_extensions: TRpc, - rpc_builder: TRpcB, + remote_backend: Option>>, dht_event_tx: Option>, marker: PhantomData<(TBl, TRtApi)>, } @@ -134,7 +133,7 @@ type TLightCallExecutor = client::light::call_executor::GenesisC >, >; -impl ServiceBuilder<(), (), TCfg, TGen, TCSExt, (), (), (), (), (), (), (), (), (), (), ()> +impl ServiceBuilder<(), (), TCfg, TGen, TCSExt, (), (), (), (), (), (), (), (), (), ()> where TGen: RuntimeGenesis, TCSExt: Extension { /// Start the service builder with a configuration. pub fn new_full, TRtApi, TExecDisp: NativeExecutionDispatch>( @@ -154,7 +153,6 @@ where TGen: RuntimeGenesis, TCSExt: Extension { (), (), (), - FullRpcBuilder, TFullBackend, >, Error> { let keystore = Keystore::open(config.keystore_path.clone(), config.keystore_password.clone())?; @@ -190,8 +188,6 @@ where TGen: RuntimeGenesis, TCSExt: Extension { let client = Arc::new(client); - let rpc_builder = FullRpcBuilder { client: client.clone() }; - Ok(ServiceBuilder { config, client, @@ -205,7 +201,7 @@ where TGen: RuntimeGenesis, TCSExt: Extension { network_protocol: (), transaction_pool: Arc::new(()), rpc_extensions: Default::default(), - rpc_builder, + remote_backend: None, dht_event_tx: None, marker: PhantomData, }) @@ -229,7 +225,6 @@ where TGen: RuntimeGenesis, TCSExt: Extension { (), (), (), - LightRpcBuilder, TLightBackend, >, Error> { let keystore = Keystore::open(config.keystore_path.clone(), config.keystore_password.clone())?; @@ -259,11 +254,6 @@ where TGen: RuntimeGenesis, TCSExt: Extension { &config.chain_spec, executor, )?); - let rpc_builder = LightRpcBuilder { - client: client.clone(), - remote_blockchain, - fetcher: fetcher.clone(), - }; Ok(ServiceBuilder { config, @@ -278,16 +268,16 @@ where TGen: RuntimeGenesis, TCSExt: Extension { network_protocol: (), transaction_pool: Arc::new(()), rpc_extensions: Default::default(), - rpc_builder, + remote_backend: Some(remote_blockchain), dht_event_tx: None, marker: PhantomData, }) } } -impl +impl ServiceBuilder { + TNetP, TExPool, TRpc, Backend> { /// Returns a reference to the client that was stored in this builder. pub fn client(&self) -> &Arc { @@ -311,7 +301,7 @@ impl, &Arc ) -> Result, Error> ) -> Result, Error> { + TNetP, TExPool, TRpc, Backend>, Error> { let select_chain = select_chain_builder(&self.config, &self.backend)?; Ok(ServiceBuilder { @@ -327,7 +317,7 @@ impl, &Arc) -> Result ) -> Result, Error> { + TNetP, TExPool, TRpc, Backend>, Error> { self.with_opt_select_chain(|cfg, b| builder(cfg, b).map(Option::Some)) } @@ -348,7 +338,7 @@ impl, Arc, Option, Arc) -> Result ) -> Result, Error> + TNetP, TExPool, TRpc, Backend>, Error> where TSc: Clone { let import_queue = builder( &self.config, @@ -370,7 +360,7 @@ impl) -> Result ) -> Result, Error> { + UNetP, TExPool, TRpc, Backend>, Error> { let network_protocol = network_protocol_builder(&self.config)?; Ok(ServiceBuilder { @@ -397,7 +387,7 @@ impl, Error> { let finality_proof_provider = builder(self.client.clone(), self.backend.clone())?; @@ -440,7 +429,7 @@ impl, Error> { self.with_opt_finality_proof_provider(|client, backend| build(client, backend).map(Option::Some)) @@ -483,7 +471,7 @@ impl, ) -> Result<(UImpQu, Option), Error> ) -> Result, Error> + TNetP, TExPool, TRpc, Backend>, Error> where TSc: Clone, TFchr: Clone { let (import_queue, fprb) = builder( &self.config, @@ -507,7 +495,7 @@ impl, ) -> Result<(UImpQu, UFprb), Error> ) -> Result, Error> + TNetP, TExPool, TRpc, Backend>, Error> where TSc: Clone, TFchr: Clone { self.with_import_queue_and_opt_fprb(|cfg, cl, b, f, sc, tx| builder(cfg, cl, b, f, sc, tx) @@ -538,7 +526,7 @@ impl) -> Result ) -> Result, Error> { + TNetP, UExPool, TRpc, Backend>, Error> { let transaction_pool = transaction_pool_builder(self.config.transaction_pool.clone(), self.client.clone())?; Ok(ServiceBuilder { @@ -554,7 +542,7 @@ impl, Arc) -> URpc ) -> Result, Error> { + TNetP, TExPool, URpc, Backend>, Error> { let rpc_extensions = rpc_ext_builder(self.client.clone(), self.transaction_pool.clone()); Ok(ServiceBuilder { @@ -581,114 +569,36 @@ impl, - ) -> Result, Error> { - Ok(ServiceBuilder { - config: self.config, - client: self.client, - backend: self.backend, - keystore: self.keystore, - fetcher: self.fetcher, - select_chain: self.select_chain, - import_queue: self.import_queue, - finality_proof_request_builder: self.finality_proof_request_builder, - finality_proof_provider: self.finality_proof_provider, - network_protocol: self.network_protocol, - transaction_pool: self.transaction_pool, - rpc_extensions: self.rpc_extensions, - rpc_builder: self.rpc_builder, - dht_event_tx: Some(dht_event_tx), - marker: self.marker, - }) - } -} - -/// RPC handlers builder. -pub trait RpcBuilder { - /// Build chain RPC handler. - fn build_chain(&self, subscriptions: rpc::Subscriptions) -> rpc::chain::Chain; - /// Build state RPC handler. - fn build_state(&self, subscriptions: rpc::Subscriptions) -> rpc::state::State; -} - -/// RPC handlers builder for full nodes. -pub struct FullRpcBuilder { - client: Arc>, -} - -impl RpcBuilder, TFullCallExecutor, TRtApi> - for - FullRpcBuilder - where - TBl: BlockT, - TRtApi: 'static + Send + Sync, - TExecDisp: 'static + NativeExecutionDispatch, - TFullClient: ProvideRuntimeApi, - as ProvideRuntimeApi>::Api: runtime_api::Metadata, -{ - fn build_chain( - &self, - subscriptions: rpc::Subscriptions, - ) -> rpc::chain::Chain, TFullCallExecutor, TBl, TRtApi> { - rpc::chain::new_full(self.client.clone(), subscriptions) - } - - fn build_state( - &self, - subscriptions: rpc::Subscriptions, - ) -> rpc::state::State, TFullCallExecutor, TBl, TRtApi> { - rpc::state::new_full(self.client.clone(), subscriptions) - } -} - -/// RPC handlers builder for light nodes. -pub struct LightRpcBuilder, TRtApi, TExecDisp> { - client: Arc>, - remote_blockchain: Arc>, - fetcher: Arc>, -} - -impl RpcBuilder, TLightCallExecutor, TRtApi> - for - LightRpcBuilder - where - TBl: BlockT, - TRtApi: 'static + Send + Sync, - TExecDisp: 'static + NativeExecutionDispatch, -{ - fn build_chain( - &self, - subscriptions: rpc::Subscriptions, - ) -> rpc::chain::Chain, TLightCallExecutor, TBl, TRtApi> { - rpc::chain::new_light( - self.client.clone(), - subscriptions, - self.remote_blockchain.clone(), - self.fetcher.clone(), - ) - } - - fn build_state( - &self, - subscriptions: rpc::Subscriptions, - ) -> rpc::state::State, TLightCallExecutor, TBl, TRtApi> { - rpc::state::new_light( - self.client.clone(), - subscriptions, - self.remote_blockchain.clone(), - self.fetcher.clone(), - ) + /// Adds a dht event sender to builder to be used by the network to send dht events to the authority discovery + /// module. + pub fn with_dht_event_tx( + self, + dht_event_tx: mpsc::Sender, + ) -> Result, Error> { + Ok(ServiceBuilder { + config: self.config, + client: self.client, + backend: self.backend, + keystore: self.keystore, + fetcher: self.fetcher, + select_chain: self.select_chain, + import_queue: self.import_queue, + finality_proof_request_builder: self.finality_proof_request_builder, + finality_proof_provider: self.finality_proof_provider, + network_protocol: self.network_protocol, + transaction_pool: self.transaction_pool, + rpc_extensions: self.rpc_extensions, + remote_backend: self.remote_backend, + dht_event_tx: Some(dht_event_tx), + marker: self.marker, + }) } } @@ -736,10 +646,10 @@ pub trait ServiceBuilderRevert { impl< TBl, TRtApi, TCfg, TGen, TCSExt, TBackend, TExec, TFchr, TSc, TImpQu, TFprb, TFpp, TNetP, - TExPool, TRpc, TRpcB, Backend + TExPool, TRpc, Backend > ServiceBuilderImport for ServiceBuilder< TBl, TRtApi, TCfg, TGen, TCSExt, Client, - TFchr, TSc, TImpQu, TFprb, TFpp, TNetP, TExPool, TRpc, TRpcB, Backend + TFchr, TSc, TImpQu, TFprb, TFpp, TNetP, TExPool, TRpc, Backend > where TBl: BlockT::Out>, TBackend: 'static + client::backend::Backend + Send, @@ -759,9 +669,9 @@ impl< } } -impl +impl ServiceBuilderExport for ServiceBuilder, - TFchr, TSc, TImpQu, TFprb, TFpp, TNetP, TExPool, TRpc, TRpcB, TBackend> + TFchr, TSc, TImpQu, TFprb, TFpp, TNetP, TExPool, TRpc, TBackend> where TBl: BlockT::Out>, TBackend: 'static + client::backend::Backend + Send, @@ -782,9 +692,9 @@ where } } -impl +impl ServiceBuilderRevert for ServiceBuilder, - TFchr, TSc, TImpQu, TFprb, TFpp, TNetP, TExPool, TRpc, TRpcB, TBackend> + TFchr, TSc, TImpQu, TFprb, TFpp, TNetP, TExPool, TRpc, TBackend> where TBl: BlockT::Out>, TBackend: 'static + client::backend::Backend + Send, @@ -801,7 +711,7 @@ where } } -impl +impl ServiceBuilder< TBl, TRtApi, @@ -817,7 +727,6 @@ ServiceBuilder< TNetP, TransactionPool, TRpc, - TRpcB, TBackend, > where Client: ProvideRuntimeApi, @@ -838,10 +747,9 @@ ServiceBuilder< TNetP: NetworkSpecialization, TExPoolApi: 'static + ChainApi::Hash>, TRpc: rpc::RpcExtension + Clone, - TRpcB: RpcBuilder, { /// Builds the service. - pub fn build(self) -> Result Result, TSc, @@ -858,7 +766,7 @@ ServiceBuilder< marker: _, mut config, client, - fetcher, + fetcher: on_demand, backend, keystore, select_chain, @@ -868,8 +776,8 @@ ServiceBuilder< network_protocol, transaction_pool, rpc_extensions, + remote_backend, dht_event_tx, - rpc_builder, } = self; session::generate_initial_session_keys( @@ -877,74 +785,344 @@ ServiceBuilder< config.dev_key_seed.clone().map(|s| vec![s]).unwrap_or_default() )?; - new_impl!( - TBl, - config, - move |_| -> Result<_, Error> { - Ok(( - client, - fetcher, - backend, - keystore, - select_chain, - import_queue, - finality_proof_request_builder, - finality_proof_provider, - network_protocol, - transaction_pool, - rpc_extensions, - dht_event_tx, - )) + let (signal, exit) = exit_future::signal(); + + // List of asynchronous tasks to spawn. We collect them, then spawn them all at once. + let (to_spawn_tx, to_spawn_rx) = + mpsc::unbounded:: + Send>>(); + + let import_queue = Box::new(import_queue); + let chain_info = client.info().chain; + + let version = config.full_version(); + info!("Highest known block at #{}", chain_info.best_number); + telemetry!( + SUBSTRATE_INFO; + "node.start"; + "height" => chain_info.best_number.saturated_into::(), + "best" => ?chain_info.best_hash + ); + + let transaction_pool_adapter = Arc::new(TransactionPoolAdapter { + imports_external_transactions: !config.roles.is_light(), + pool: transaction_pool.clone(), + client: client.clone(), + executor: Arc::new(SpawnTaskHandle { sender: to_spawn_tx.clone(), on_exit: exit.clone() }), + }); + + let protocol_id = { + let protocol_id_full = match config.chain_spec.protocol_id() { + Some(pid) => pid, + None => { + warn!("Using default protocol ID {:?} because none is configured in the \ + chain specs", DEFAULT_PROTOCOL_ID + ); + DEFAULT_PROTOCOL_ID + } + }.as_bytes(); + network::config::ProtocolId::from(protocol_id_full) + }; + + let block_announce_validator = + Box::new(consensus_common::block_validation::DefaultBlockAnnounceValidator::new(client.clone())); + + let network_params = network::config::Params { + roles: config.roles, + network_config: config.network.clone(), + chain: client.clone(), + finality_proof_provider, + finality_proof_request_builder, + on_demand: on_demand.clone(), + transaction_pool: transaction_pool_adapter.clone() as _, + import_queue, + protocol_id, + specialization: network_protocol, + block_announce_validator, + }; + + let has_bootnodes = !network_params.network_config.boot_nodes.is_empty(); + let network_mut = network::NetworkWorker::new(network_params)?; + let network = network_mut.service().clone(); + let network_status_sinks = Arc::new(Mutex::new(status_sinks::StatusSinks::new())); + + let offchain_storage = backend.offchain_storage(); + let offchain_workers = match (config.offchain_worker, offchain_storage) { + (true, Some(db)) => { + Some(Arc::new(offchain::OffchainWorkers::new(client.clone(), db))) + }, + (true, None) => { + log::warn!("Offchain workers disabled, due to lack of offchain storage support in backend."); + None }, - |h, c, tx, r| maintain_transaction_pool(h, c, tx, r), - |n, o, p, ns, v| offchain_workers(n, o, p, ns, v), - |c, ssb, si, te, tp, ext, ks| start_rpc(&rpc_builder, c, ssb, si, te, tp, ext, ks), + _ => None, + }; + + { + // block notifications + let txpool = Arc::downgrade(&transaction_pool); + let wclient = Arc::downgrade(&client); + let offchain = offchain_workers.as_ref().map(Arc::downgrade); + let to_spawn_tx_ = to_spawn_tx.clone(); + let network_state_info: Arc = network.clone(); + let is_validator = config.roles.is_authority(); + + let events = client.import_notification_stream() + .map(|v| Ok::<_, ()>(v)).compat() + .for_each(move |notification| { + let number = *notification.header.number(); + let txpool = txpool.upgrade(); + + if let (Some(txpool), Some(client)) = (txpool.as_ref(), wclient.upgrade()) { + let future = maintain_transaction_pool( + &BlockId::hash(notification.hash), + &client, + &*txpool, + ¬ification.retracted, + ).map_err(|e| warn!("Pool error processing new block: {:?}", e))?; + let _ = to_spawn_tx_.unbounded_send(future); + } + + let offchain = offchain.as_ref().and_then(|o| o.upgrade()); + if let (Some(txpool), Some(offchain)) = (txpool, offchain) { + let future = offchain.on_block_imported(&number, &txpool, network_state_info.clone(), is_validator) + .map(|()| Ok(())); + let _ = to_spawn_tx_.unbounded_send(Box::new(Compat::new(future))); + } + + Ok(()) + }) + .select(exit.clone()) + .then(|_| Ok(())); + let _ = to_spawn_tx.unbounded_send(Box::new(events)); + } + + { + // extrinsic notifications + let network = Arc::downgrade(&network); + let transaction_pool_ = transaction_pool.clone(); + let events = transaction_pool.import_notification_stream() + .map(|v| Ok::<_, ()>(v)).compat() + .for_each(move |_| { + if let Some(network) = network.upgrade() { + network.trigger_repropagate(); + } + let status = transaction_pool_.status(); + telemetry!(SUBSTRATE_INFO; "txpool.import"; + "ready" => status.ready, + "future" => status.future + ); + Ok(()) + }) + .select(exit.clone()) + .then(|_| Ok(())); + + let _ = to_spawn_tx.unbounded_send(Box::new(events)); + } + + // Periodically notify the telemetry. + let transaction_pool_ = transaction_pool.clone(); + let client_ = client.clone(); + let mut sys = System::new(); + let self_pid = get_current_pid().ok(); + let (state_tx, state_rx) = mpsc::unbounded::<(NetworkStatus<_>, NetworkState)>(); + network_status_sinks.lock().push(std::time::Duration::from_millis(5000), state_tx); + let tel_task = state_rx.for_each(move |(net_status, _)| { + let info = client_.info(); + let best_number = info.chain.best_number.saturated_into::(); + let best_hash = info.chain.best_hash; + let num_peers = net_status.num_connected_peers; + let txpool_status = transaction_pool_.status(); + let finalized_number: u64 = info.chain.finalized_number.saturated_into::(); + let bandwidth_download = net_status.average_download_per_sec; + let bandwidth_upload = net_status.average_upload_per_sec; + + let used_state_cache_size = match info.used_state_cache_size { + Some(size) => size, + None => 0, + }; + + // get cpu usage and memory usage of this process + let (cpu_usage, memory) = if let Some(self_pid) = self_pid { + if sys.refresh_process(self_pid) { + let proc = sys.get_process(self_pid) + .expect("Above refresh_process succeeds, this should be Some(), qed"); + (proc.cpu_usage(), proc.memory()) + } else { (0.0, 0) } + } else { (0.0, 0) }; + + telemetry!( + SUBSTRATE_INFO; + "system.interval"; + "peers" => num_peers, + "height" => best_number, + "best" => ?best_hash, + "txcount" => txpool_status.ready, + "cpu" => cpu_usage, + "memory" => memory, + "finalized_height" => finalized_number, + "finalized_hash" => ?info.chain.finalized_hash, + "bandwidth_download" => bandwidth_download, + "bandwidth_upload" => bandwidth_upload, + "used_state_cache_size" => used_state_cache_size, + ); + + Ok(()) + }).select(exit.clone()).then(|_| Ok(())); + let _ = to_spawn_tx.unbounded_send(Box::new(tel_task)); + + // Periodically send the network state to the telemetry. + let (netstat_tx, netstat_rx) = mpsc::unbounded::<(NetworkStatus<_>, NetworkState)>(); + network_status_sinks.lock().push(std::time::Duration::from_secs(30), netstat_tx); + let tel_task_2 = netstat_rx.for_each(move |(_, network_state)| { + telemetry!( + SUBSTRATE_INFO; + "system.network_state"; + "state" => network_state, + ); + Ok(()) + }).select(exit.clone()).then(|_| Ok(())); + let _ = to_spawn_tx.unbounded_send(Box::new(tel_task_2)); + + // RPC + let (system_rpc_tx, system_rpc_rx) = futures03::channel::mpsc::unbounded(); + let gen_handler = || { + use rpc::{chain, state, author, system}; + + let system_info = rpc::system::SystemInfo { + chain_name: config.chain_spec.name().into(), + impl_name: config.impl_name.into(), + impl_version: config.impl_version.into(), + properties: config.chain_spec.properties().clone(), + }; + + let subscriptions = rpc::Subscriptions::new(Arc::new(SpawnTaskHandle { + sender: to_spawn_tx.clone(), + on_exit: exit.clone() + })); + + let (chain, state) = if let (Some(remote_backend), Some(on_demand)) = + (remote_backend.as_ref(), on_demand.as_ref()) { + // Light clients + let chain = rpc::chain::new_light( + client.clone(), + subscriptions.clone(), + remote_backend.clone(), + on_demand.clone() + ); + let state = rpc::state::new_light( + client.clone(), + subscriptions.clone(), + remote_backend.clone(), + on_demand.clone() + ); + (chain, state) + + } else { + // Full nodes + let chain = rpc::chain::new_full(client.clone(), subscriptions.clone()); + let state = rpc::state::new_full(client.clone(), subscriptions.clone()); + (chain, state) + }; + + let author = rpc::author::Author::new( + client.clone(), + transaction_pool.clone(), + subscriptions, + keystore.clone(), + ); + let system = system::System::new(system_info, system_rpc_tx.clone()); + + rpc_servers::rpc_handler(( + state::StateApi::to_delegate(state), + chain::ChainApi::to_delegate(chain), + author::AuthorApi::to_delegate(author), + system::SystemApi::to_delegate(system), + rpc_extensions.clone(), + )) + }; + let rpc_handlers = gen_handler(); + let rpc = start_rpc_servers(&config, gen_handler)?; + + + let _ = to_spawn_tx.unbounded_send(Box::new(build_network_future( + config.roles, + network_mut, + client.clone(), + network_status_sinks.clone(), + system_rpc_rx, + has_bootnodes, + dht_event_tx, ) + .map_err(|_| ()) + .select(exit.clone()) + .then(|_| Ok(())))); + + let telemetry_connection_sinks: Arc>>> = Default::default(); + + // Telemetry + let telemetry = config.telemetry_endpoints.clone().map(|endpoints| { + let is_authority = config.roles.is_authority(); + let network_id = network.local_peer_id().to_base58(); + let name = config.name.clone(); + let impl_name = config.impl_name.to_owned(); + let version = version.clone(); + let chain_name = config.chain_spec.name().to_owned(); + let telemetry_connection_sinks_ = telemetry_connection_sinks.clone(); + let telemetry = tel::init_telemetry(tel::TelemetryConfig { + endpoints, + wasm_external_transport: config.telemetry_external_transport.take(), + }); + let future = telemetry.clone() + .map(|ev| Ok::<_, ()>(ev)) + .compat() + .for_each(move |event| { + // Safe-guard in case we add more events in the future. + let tel::TelemetryEvent::Connected = event; + + telemetry!(SUBSTRATE_INFO; "system.connected"; + "name" => name.clone(), + "implementation" => impl_name.clone(), + "version" => version.clone(), + "config" => "", + "chain" => chain_name.clone(), + "authority" => is_authority, + "network_id" => network_id.clone() + ); + + telemetry_connection_sinks_.lock().retain(|sink| { + sink.unbounded_send(()).is_ok() + }); + Ok(()) + }); + let _ = to_spawn_tx.unbounded_send(Box::new(future + .select(exit.clone()) + .then(|_| Ok(())))); + telemetry + }); + + Ok(Service { + client, + network, + network_status_sinks, + select_chain, + transaction_pool, + exit, + signal: Some(signal), + essential_failed: Arc::new(AtomicBool::new(false)), + to_spawn_tx, + to_spawn_rx, + to_poll: Vec::new(), + rpc_handlers, + _rpc: rpc, + _telemetry: telemetry, + _offchain_workers: offchain_workers, + _telemetry_on_connect_sinks: telemetry_connection_sinks.clone(), + keystore, + marker: PhantomData::, + }) } } -pub(crate) fn start_rpc( - rpc_builder: &RpcB, - client: Arc>, - system_send_back: futures03::channel::mpsc::UnboundedSender>, - rpc_system_info: SystemInfo, - task_executor: TaskExecutor, - transaction_pool: Arc>, - rpc_extensions: impl rpc::RpcExtension, - keystore: KeyStorePtr, -) -> rpc_servers::RpcHandler -where - Block: BlockT::Out>, - Backend: client::backend::Backend + 'static, - Client: ProvideRuntimeApi, - as ProvideRuntimeApi>::Api: - runtime_api::Metadata + session::SessionKeys, - Api: Send + Sync + 'static, - Executor: client::CallExecutor + Send + Sync + Clone + 'static, - PoolApi: txpool::ChainApi + 'static, - RpcB: RpcBuilder, -{ - use rpc::{chain, state, author, system}; - let subscriptions = rpc::Subscriptions::new(task_executor); - let chain = rpc_builder.build_chain(subscriptions.clone()); - let state = rpc_builder.build_state(subscriptions.clone()); - let author = rpc::author::Author::new( - client, - transaction_pool, - subscriptions, - keystore, - ); - let system = system::System::new(rpc_system_info, system_send_back); - - rpc_servers::rpc_handler(( - state::StateApi::to_delegate(state), - chain::ChainApi::to_delegate(chain), - author::AuthorApi::to_delegate(author), - system::SystemApi::to_delegate(system), - rpc_extensions, - )) -} - pub(crate) fn maintain_transaction_pool( id: &BlockId, client: &Arc>, @@ -997,32 +1175,6 @@ pub(crate) fn maintain_transaction_pool( }) } -pub(crate) fn offchain_workers( - number: &NumberFor, - offchain: &offchain::OffchainWorkers< - Client, - >::OffchainStorage, - Block - >, - pool: &Arc>, - network_state: &Arc, - is_validator: bool, -) -> error::Result + Send>> -where - Block: BlockT::Out>, - Backend: client::backend::Backend + 'static, - Api: 'static, - >::OffchainStorage: 'static, - Client: ProvideRuntimeApi + Send + Sync, - as ProvideRuntimeApi>::Api: offchain::OffchainWorkerApi, - Executor: client::CallExecutor + 'static, - PoolApi: txpool::ChainApi + 'static, -{ - let future = offchain.on_block_imported(number, pool, network_state.clone(), is_validator) - .map(|()| Ok(())); - Ok(Box::new(Compat::new(future))) -} - #[cfg(test)] mod tests { use super::*; diff --git a/core/service/src/lib.rs b/core/service/src/lib.rs index 334a001a48..3057b8ce4d 100644 --- a/core/service/src/lib.rs +++ b/core/service/src/lib.rs @@ -24,6 +24,7 @@ pub mod config; pub mod chain_ops; pub mod error; +mod builder; mod status_sinks; use std::io; @@ -71,7 +72,7 @@ pub use futures::future::Executor; const DEFAULT_PROTOCOL_ID: &str = "sup"; /// Substrate service. -pub struct NewService { +pub struct Service { client: Arc, select_chain: Option, network: Arc, @@ -129,338 +130,6 @@ impl Executor + Send>> for SpawnTaskHandle } } -macro_rules! new_impl { - ( - $block:ty, - $config:ident, - $build_components:expr, - $maintain_transaction_pool:expr, - $offchain_workers:expr, - $start_rpc:expr, - ) => {{ - let (signal, exit) = exit_future::signal(); - - // List of asynchronous tasks to spawn. We collect them, then spawn them all at once. - let (to_spawn_tx, to_spawn_rx) = - mpsc::unbounded:: + Send>>(); - - // Create all the components. - let ( - client, - on_demand, - backend, - keystore, - select_chain, - import_queue, - finality_proof_request_builder, - finality_proof_provider, - network_protocol, - transaction_pool, - rpc_extensions, - dht_event_tx, - ) = $build_components(&$config)?; - let import_queue = Box::new(import_queue); - let chain_info = client.info().chain; - - let version = $config.full_version(); - info!("Highest known block at #{}", chain_info.best_number); - telemetry!( - SUBSTRATE_INFO; - "node.start"; - "height" => chain_info.best_number.saturated_into::(), - "best" => ?chain_info.best_hash - ); - - let transaction_pool_adapter = Arc::new(TransactionPoolAdapter { - imports_external_transactions: !$config.roles.is_light(), - pool: transaction_pool.clone(), - client: client.clone(), - executor: Arc::new(SpawnTaskHandle { sender: to_spawn_tx.clone(), on_exit: exit.clone() }), - }); - - let protocol_id = { - let protocol_id_full = match $config.chain_spec.protocol_id() { - Some(pid) => pid, - None => { - warn!("Using default protocol ID {:?} because none is configured in the \ - chain specs", DEFAULT_PROTOCOL_ID - ); - DEFAULT_PROTOCOL_ID - } - }.as_bytes(); - network::config::ProtocolId::from(protocol_id_full) - }; - - let block_announce_validator = - Box::new(consensus_common::block_validation::DefaultBlockAnnounceValidator::new(client.clone())); - - let network_params = network::config::Params { - roles: $config.roles, - network_config: $config.network.clone(), - chain: client.clone(), - finality_proof_provider, - finality_proof_request_builder, - on_demand, - transaction_pool: transaction_pool_adapter.clone() as _, - import_queue, - protocol_id, - specialization: network_protocol, - block_announce_validator, - }; - - let has_bootnodes = !network_params.network_config.boot_nodes.is_empty(); - let network_mut = network::NetworkWorker::new(network_params)?; - let network = network_mut.service().clone(); - let network_status_sinks = Arc::new(Mutex::new(status_sinks::StatusSinks::new())); - - let offchain_storage = backend.offchain_storage(); - let offchain_workers = match ($config.offchain_worker, offchain_storage) { - (true, Some(db)) => { - Some(Arc::new(offchain::OffchainWorkers::new(client.clone(), db))) - }, - (true, None) => { - log::warn!("Offchain workers disabled, due to lack of offchain storage support in backend."); - None - }, - _ => None, - }; - - { - // block notifications - let txpool = Arc::downgrade(&transaction_pool); - let wclient = Arc::downgrade(&client); - let offchain = offchain_workers.as_ref().map(Arc::downgrade); - let to_spawn_tx_ = to_spawn_tx.clone(); - let network_state_info: Arc = network.clone(); - let is_validator = $config.roles.is_authority(); - - let events = client.import_notification_stream() - .map(|v| Ok::<_, ()>(v)).compat() - .for_each(move |notification| { - let number = *notification.header.number(); - let txpool = txpool.upgrade(); - - if let (Some(txpool), Some(client)) = (txpool.as_ref(), wclient.upgrade()) { - let future = $maintain_transaction_pool( - &BlockId::hash(notification.hash), - &client, - &*txpool, - ¬ification.retracted, - ).map_err(|e| warn!("Pool error processing new block: {:?}", e))?; - let _ = to_spawn_tx_.unbounded_send(future); - } - - let offchain = offchain.as_ref().and_then(|o| o.upgrade()); - if let (Some(txpool), Some(offchain)) = (txpool, offchain) { - let future = $offchain_workers( - &number, - &offchain, - &txpool, - &network_state_info, - is_validator, - ).map_err(|e| warn!("Offchain workers error processing new block: {:?}", e))?; - let _ = to_spawn_tx_.unbounded_send(future); - } - - Ok(()) - }) - .select(exit.clone()) - .then(|_| Ok(())); - let _ = to_spawn_tx.unbounded_send(Box::new(events)); - } - - { - // extrinsic notifications - let network = Arc::downgrade(&network); - let transaction_pool_ = transaction_pool.clone(); - let events = transaction_pool.import_notification_stream() - .map(|v| Ok::<_, ()>(v)).compat() - .for_each(move |_| { - if let Some(network) = network.upgrade() { - network.trigger_repropagate(); - } - let status = transaction_pool_.status(); - telemetry!(SUBSTRATE_INFO; "txpool.import"; - "ready" => status.ready, - "future" => status.future - ); - Ok(()) - }) - .select(exit.clone()) - .then(|_| Ok(())); - - let _ = to_spawn_tx.unbounded_send(Box::new(events)); - } - - // Periodically notify the telemetry. - let transaction_pool_ = transaction_pool.clone(); - let client_ = client.clone(); - let mut sys = System::new(); - let self_pid = get_current_pid().ok(); - let (state_tx, state_rx) = mpsc::unbounded::<(NetworkStatus<_>, NetworkState)>(); - network_status_sinks.lock().push(std::time::Duration::from_millis(5000), state_tx); - let tel_task = state_rx.for_each(move |(net_status, _)| { - let info = client_.info(); - let best_number = info.chain.best_number.saturated_into::(); - let best_hash = info.chain.best_hash; - let num_peers = net_status.num_connected_peers; - let txpool_status = transaction_pool_.status(); - let finalized_number: u64 = info.chain.finalized_number.saturated_into::(); - let bandwidth_download = net_status.average_download_per_sec; - let bandwidth_upload = net_status.average_upload_per_sec; - - let used_state_cache_size = match info.used_state_cache_size { - Some(size) => size, - None => 0, - }; - - // get cpu usage and memory usage of this process - let (cpu_usage, memory) = if let Some(self_pid) = self_pid { - if sys.refresh_process(self_pid) { - let proc = sys.get_process(self_pid) - .expect("Above refresh_process succeeds, this should be Some(), qed"); - (proc.cpu_usage(), proc.memory()) - } else { (0.0, 0) } - } else { (0.0, 0) }; - - telemetry!( - SUBSTRATE_INFO; - "system.interval"; - "peers" => num_peers, - "height" => best_number, - "best" => ?best_hash, - "txcount" => txpool_status.ready, - "cpu" => cpu_usage, - "memory" => memory, - "finalized_height" => finalized_number, - "finalized_hash" => ?info.chain.finalized_hash, - "bandwidth_download" => bandwidth_download, - "bandwidth_upload" => bandwidth_upload, - "used_state_cache_size" => used_state_cache_size, - ); - - Ok(()) - }).select(exit.clone()).then(|_| Ok(())); - let _ = to_spawn_tx.unbounded_send(Box::new(tel_task)); - - // Periodically send the network state to the telemetry. - let (netstat_tx, netstat_rx) = mpsc::unbounded::<(NetworkStatus<_>, NetworkState)>(); - network_status_sinks.lock().push(std::time::Duration::from_secs(30), netstat_tx); - let tel_task_2 = netstat_rx.for_each(move |(_, network_state)| { - telemetry!( - SUBSTRATE_INFO; - "system.network_state"; - "state" => network_state, - ); - Ok(()) - }).select(exit.clone()).then(|_| Ok(())); - let _ = to_spawn_tx.unbounded_send(Box::new(tel_task_2)); - - // RPC - let (system_rpc_tx, system_rpc_rx) = futures03::channel::mpsc::unbounded(); - let gen_handler = || { - let system_info = rpc::system::SystemInfo { - chain_name: $config.chain_spec.name().into(), - impl_name: $config.impl_name.into(), - impl_version: $config.impl_version.into(), - properties: $config.chain_spec.properties().clone(), - }; - $start_rpc( - client.clone(), - //light_components.clone(), - system_rpc_tx.clone(), - system_info.clone(), - Arc::new(SpawnTaskHandle { sender: to_spawn_tx.clone(), on_exit: exit.clone() }), - transaction_pool.clone(), - rpc_extensions.clone(), - keystore.clone(), - ) - }; - let rpc_handlers = gen_handler(); - let rpc = start_rpc_servers(&$config, gen_handler)?; - - - let _ = to_spawn_tx.unbounded_send(Box::new(build_network_future( - $config.roles, - network_mut, - client.clone(), - network_status_sinks.clone(), - system_rpc_rx, - has_bootnodes, - dht_event_tx, - ) - .map_err(|_| ()) - .select(exit.clone()) - .then(|_| Ok(())))); - - let telemetry_connection_sinks: Arc>>> = Default::default(); - - // Telemetry - let telemetry = $config.telemetry_endpoints.clone().map(|endpoints| { - let is_authority = $config.roles.is_authority(); - let network_id = network.local_peer_id().to_base58(); - let name = $config.name.clone(); - let impl_name = $config.impl_name.to_owned(); - let version = version.clone(); - let chain_name = $config.chain_spec.name().to_owned(); - let telemetry_connection_sinks_ = telemetry_connection_sinks.clone(); - let telemetry = tel::init_telemetry(tel::TelemetryConfig { - endpoints, - wasm_external_transport: $config.telemetry_external_transport.take(), - }); - let future = telemetry.clone() - .map(|ev| Ok::<_, ()>(ev)) - .compat() - .for_each(move |event| { - // Safe-guard in case we add more events in the future. - let tel::TelemetryEvent::Connected = event; - - telemetry!(SUBSTRATE_INFO; "system.connected"; - "name" => name.clone(), - "implementation" => impl_name.clone(), - "version" => version.clone(), - "config" => "", - "chain" => chain_name.clone(), - "authority" => is_authority, - "network_id" => network_id.clone() - ); - - telemetry_connection_sinks_.lock().retain(|sink| { - sink.unbounded_send(()).is_ok() - }); - Ok(()) - }); - let _ = to_spawn_tx.unbounded_send(Box::new(future - .select(exit.clone()) - .then(|_| Ok(())))); - telemetry - }); - - Ok(NewService { - client, - network, - network_status_sinks, - select_chain, - transaction_pool, - exit, - signal: Some(signal), - essential_failed: Arc::new(AtomicBool::new(false)), - to_spawn_tx, - to_spawn_rx, - to_poll: Vec::new(), - rpc_handlers, - _rpc: rpc, - _telemetry: telemetry, - _offchain_workers: offchain_workers, - _telemetry_on_connect_sinks: telemetry_connection_sinks.clone(), - keystore, - marker: PhantomData::<$block>, - }) - }} -} - -mod builder; - /// Abstraction over a Substrate service. pub trait AbstractService: 'static + Future + Executor + Send>> + Send { @@ -530,7 +199,7 @@ pub trait AbstractService: 'static + Future + } impl AbstractService for - NewService, TSc, NetworkStatus, + Service, TSc, NetworkStatus, NetworkService, TransactionPool, TOc> where TBl: BlockT, @@ -619,7 +288,7 @@ where } impl Future for - NewService + Service { type Item = (); type Error = Error; @@ -652,7 +321,7 @@ impl Future for } impl Executor + Send>> for - NewService + Service { fn execute( &self, @@ -819,7 +488,7 @@ pub struct NetworkStatus { } impl Drop for - NewService + Service { fn drop(&mut self) { debug!(target: "service", "Substrate service shutdown"); diff --git a/node/cli/src/service.rs b/node/cli/src/service.rs index 03d31c4392..78b978b72b 100644 --- a/node/cli/src/service.rs +++ b/node/cli/src/service.rs @@ -33,7 +33,7 @@ use transaction_pool::{self, txpool::{Pool as TransactionPool}}; use inherents::InherentDataProviders; use network::construct_simple_protocol; -use substrate_service::{NewService, NetworkStatus}; +use substrate_service::{Service, NetworkStatus}; use client::{Client, LocalCallExecutor}; use client_db::Backend; use sr_primitives::traits::Block as BlockT; @@ -248,7 +248,7 @@ pub type NodeConfiguration = Configuration(config: NodeConfiguration) -> Result< - NewService< + Service< ConcreteBlock, ConcreteClient, LongestChain, -- GitLab From 5bd69ac2c12f4160ee345200f367ed909df5aae1 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Thu, 24 Oct 2019 17:01:14 +0200 Subject: [PATCH 098/167] core/finality-grandpa: Request block sync from network after import timeout (#3800) * core/finality-grandpa: Pass Grandpa msg sender up to UntilImported * core/finality-grandpa: Track senders to maybe later request blocks * core/finality-grandpa: Make BlockStatus pub only within crate * core/finality-grandpa: Abstract NetworkBridge with BlockSyncRequester * core/finality-grandpa: Pass BlockSyncRequester to UntilImported * core/finality-grandpa: Track block number of pending within UntilImported * core/finality-grandpa: Request block sync on long wait * core/finality-grandpa: Adjust unit tests to previous changes * core/finality-grandpa: Fix line length * core/finality-grandpa: Add comment explaining in & out vote combination * core/finality-grandpa: Log after, not before, timeout expired The UntilImported component should log whenever waiting for a specific block to be imported surpassed a defined constant timeout. Without this patch the code would log whenever the current time was below the timeout. * core/finality-grandpa: Collect senders as HashSet for deduplication * Revert "core/finality-grandpa: Track senders to maybe later request blocks" This reverts commit 61ac9dd715612d5fdbf7b8f00b84e450f282ade0. * Revert "core/finality-grandpa: Pass Grandpa msg sender up to UntilImported" This reverts commit afdc9646a6c314f99a9d19242f1878f85980e70d. * core/network/sync: Ask for block from all peers if none provided When requesting an explicit fork sync, try to sync from all known peers, when no specific peers were provided. * core/network/sync: Request specific fork sync from peers ahead or on par When making an explicit fork sync request without specifying any peers, make sure to only request it from the locally known peers that are either ahead or on a par compared to the block number we are looking for. * grandpa: fix tests * grandpa: fix warnings * grandpa: add test for block sync request on until_imported * grandpa: rename Environment field inner to client * grandpa: fix minor nits * grandpa: minor nits in until_imported * grandpa: copy docs for set_sync_fork_request * grandpa: remove stale TODO on UntilImported --- .../finality-grandpa/src/communication/mod.rs | 27 ++- .../src/communication/tests.rs | 4 + core/finality-grandpa/src/environment.rs | 27 +-- core/finality-grandpa/src/lib.rs | 45 ++-- core/finality-grandpa/src/tests.rs | 2 +- core/finality-grandpa/src/until_imported.rs | 195 +++++++++++++++--- core/network/src/protocol/sync.rs | 24 ++- 7 files changed, 258 insertions(+), 66 deletions(-) diff --git a/core/finality-grandpa/src/communication/mod.rs b/core/finality-grandpa/src/communication/mod.rs index f2a4dee21e..6f43b1106a 100644 --- a/core/finality-grandpa/src/communication/mod.rs +++ b/core/finality-grandpa/src/communication/mod.rs @@ -39,7 +39,7 @@ use network::{consensus_gossip as network_gossip, NetworkService}; use network_gossip::ConsensusMessage; use codec::{Encode, Decode}; use primitives::Pair; -use sr_primitives::traits::{Block as BlockT, Hash as HashT, Header as HeaderT}; +use sr_primitives::traits::{Block as BlockT, Hash as HashT, Header as HeaderT, NumberFor}; use substrate_telemetry::{telemetry, CONSENSUS_DEBUG, CONSENSUS_INFO}; use tokio_executor::Executor; @@ -129,6 +129,14 @@ pub trait Network: Clone + Send + 'static { /// Inform peers that a block with given hash should be downloaded. fn announce(&self, block: Block::Hash, associated_data: Vec); + + /// Notifies the sync service to try and sync the given block from the given + /// peers. + /// + /// If the given vector of peers is empty then the underlying implementation + /// should make a best effort to fetch the block from any peers it is + /// connected to (NOTE: this assumption will change in the future #3629). + fn set_sync_fork_request(&self, peers: Vec, hash: Block::Hash, number: NumberFor); } /// Create a unique topic for a round and set-id combo. @@ -216,6 +224,10 @@ impl Network for Arc> where fn announce(&self, block: B::Hash, associated_data: Vec) { self.announce_block(block, associated_data) } + + fn set_sync_fork_request(&self, peers: Vec, hash: B::Hash, number: NumberFor) { + NetworkService::set_sync_fork_request(self, peers, hash, number) + } } /// A stream used by NetworkBridge in its implementation of Network. Given a oneshot that eventually returns a channel @@ -468,6 +480,9 @@ impl> NetworkBridge { format!("Failed to receive on unbounded receiver for round {}", round.0) )); + // Combine incoming votes from external GRANDPA nodes with outgoing + // votes from our own GRANDPA voter to have a single + // vote-import-pipeline. let incoming = incoming.select(out_rx); (incoming, outgoing) @@ -514,6 +529,16 @@ impl> NetworkBridge { (incoming, outgoing) } + + /// Notifies the sync service to try and sync the given block from the given + /// peers. + /// + /// If the given vector of peers is empty then the underlying implementation + /// should make a best effort to fetch the block from any peers it is + /// connected to (NOTE: this assumption will change in the future #3629). + pub(crate) fn set_sync_fork_request(&self, peers: Vec, hash: B::Hash, number: NumberFor) { + self.service.set_sync_fork_request(peers, hash, number) + } } fn incoming_global>( diff --git a/core/finality-grandpa/src/communication/tests.rs b/core/finality-grandpa/src/communication/tests.rs index 14e54511fb..7b91b2ef0a 100644 --- a/core/finality-grandpa/src/communication/tests.rs +++ b/core/finality-grandpa/src/communication/tests.rs @@ -25,6 +25,7 @@ use tokio::runtime::current_thread; use std::sync::Arc; use keyring::Ed25519Keyring; use codec::Encode; +use sr_primitives::traits::NumberFor; use crate::environment::SharedVoterSetState; use super::gossip::{self, GossipValidator}; @@ -91,6 +92,9 @@ impl super::Network for TestNetwork { fn announce(&self, block: Hash, _associated_data: Vec) { let _ = self.sender.unbounded_send(Event::Announce(block)); } + + /// Notify the sync service to try syncing the given chain. + fn set_sync_fork_request(&self, _peers: Vec, _hash: Hash, _number: NumberFor) {} } impl network_gossip::ValidatorContext for TestNetwork { diff --git a/core/finality-grandpa/src/environment.rs b/core/finality-grandpa/src/environment.rs index ee146c4608..149b00e80f 100644 --- a/core/finality-grandpa/src/environment.rs +++ b/core/finality-grandpa/src/environment.rs @@ -370,7 +370,7 @@ impl SharedVoterSetState { /// The environment we run GRANDPA in. pub(crate) struct Environment, RA, SC, VR> { - pub(crate) inner: Arc>, + pub(crate) client: Arc>, pub(crate) select_chain: SC, pub(crate) voters: Arc>, pub(crate) config: Config, @@ -413,7 +413,7 @@ where NumberFor: BlockNumberOps, { fn ancestry(&self, base: Block::Hash, block: Block::Hash) -> Result, GrandpaError> { - ancestry(&self.inner, base, block) + ancestry(&self.client, base, block) } fn best_chain_containing(&self, block: Block::Hash) -> Option<(Block::Hash, NumberFor)> { @@ -434,7 +434,7 @@ where match self.select_chain.finality_target(block, None) { Ok(Some(best_hash)) => { - let base_header = self.inner.header(&BlockId::Hash(block)).ok()? + let base_header = self.client.header(&BlockId::Hash(block)).ok()? .expect("Header known to exist after `best_containing` call; qed"); if let Some(limit) = limit { @@ -449,7 +449,7 @@ where } } - let best_header = self.inner.header(&BlockId::Hash(best_hash)).ok()? + let best_header = self.client.header(&BlockId::Hash(best_hash)).ok()? .expect("Header known to exist after `best_containing` call; qed"); // check if our vote is currently being limited due to a pending change @@ -473,7 +473,7 @@ where break; } - target_header = self.inner.header(&BlockId::Hash(*target_header.parent_hash())).ok()? + target_header = self.client.header(&BlockId::Hash(*target_header.parent_hash())).ok()? .expect("Header known to exist after `best_containing` call; qed"); } @@ -492,7 +492,7 @@ where // authority set limit filter, which can be considered a // mandatory/implicit voting rule. self.voting_rule - .restrict_vote(&*self.inner, &base_header, &best_header, target_header) + .restrict_vote(&*self.client, &base_header, &best_header, target_header) .or(Some((target_header.hash(), *target_header.number()))) }, Ok(None) => { @@ -601,8 +601,9 @@ where // schedule incoming messages from the network to be held until // corresponding blocks are imported. let incoming = Box::new(UntilVoteTargetImported::new( - self.inner.import_notification_stream(), - self.inner.clone(), + self.client.import_notification_stream(), + self.network.clone(), + self.client.clone(), incoming, "round", ).map_err(Into::into)); @@ -650,7 +651,7 @@ where current_rounds, }; - crate::aux_schema::write_voter_set_state(&*self.inner, &set_state)?; + crate::aux_schema::write_voter_set_state(&*self.client, &set_state)?; Ok(Some(set_state)) })?; @@ -691,7 +692,7 @@ where current_rounds, }; - crate::aux_schema::write_voter_set_state(&*self.inner, &set_state)?; + crate::aux_schema::write_voter_set_state(&*self.client, &set_state)?; Ok(Some(set_state)) })?; @@ -742,7 +743,7 @@ where current_rounds, }; - crate::aux_schema::write_voter_set_state(&*self.inner, &set_state)?; + crate::aux_schema::write_voter_set_state(&*self.client, &set_state)?; Ok(Some(set_state)) })?; @@ -800,7 +801,7 @@ where current_rounds, }; - crate::aux_schema::write_voter_set_state(&*self.inner, &set_state)?; + crate::aux_schema::write_voter_set_state(&*self.client, &set_state)?; Ok(Some(set_state)) })?; @@ -816,7 +817,7 @@ where commit: Commit, ) -> Result<(), Self::Error> { finalize_block( - &*self.inner, + &*self.client, &self.authority_set, &self.consensus_changes, Some(self.config.justification_period.into()), diff --git a/core/finality-grandpa/src/lib.rs b/core/finality-grandpa/src/lib.rs index 9d1e3f563f..63eddfd3f3 100644 --- a/core/finality-grandpa/src/lib.rs +++ b/core/finality-grandpa/src/lib.rs @@ -22,11 +22,11 @@ //! //! # Usage //! -//! First, create a block-import wrapper with the `block_import` function. -//! The GRANDPA worker needs to be linked together with this block import object, -//! so a `LinkHalf` is returned as well. All blocks imported (from network or consensus or otherwise) -//! must pass through this wrapper, otherwise consensus is likely to break in -//! unexpected ways. +//! First, create a block-import wrapper with the `block_import` function. The +//! GRANDPA worker needs to be linked together with this block import object, so +//! a `LinkHalf` is returned as well. All blocks imported (from network or +//! consensus or otherwise) must pass through this wrapper, otherwise consensus +//! is likely to break in unexpected ways. //! //! Next, use the `LinkHalf` and a local configuration to `run_grandpa_voter`. //! This requires a `Network` implementation. The returned future should be @@ -242,7 +242,7 @@ impl From for Error { } /// Something which can determine if a block is known. -pub trait BlockStatus { +pub(crate) trait BlockStatus { /// Return `Ok(Some(number))` or `Ok(None)` depending on whether the block /// is definitely known and has been imported. /// If an unexpected error occurs, return that. @@ -261,6 +261,26 @@ impl, RA> BlockStatus for Arc { + /// Notifies the sync service to try and sync the given block from the given + /// peers. + /// + /// If the given vector of peers is empty then the underlying implementation + /// should make a best effort to fetch the block from any peers it is + /// connected to (NOTE: this assumption will change in the future #3629). + fn set_sync_fork_request(&self, peers: Vec, hash: Block::Hash, number: NumberFor); +} + +impl BlockSyncRequester for NetworkBridge where + Block: BlockT, + N: communication::Network, +{ + fn set_sync_fork_request(&self, peers: Vec, hash: Block::Hash, number: NumberFor) { + NetworkBridge::set_sync_fork_request(self, peers, hash, number) + } +} + /// A new authority set along with the canonical block it changed at. #[derive(Debug)] pub(crate) struct NewAuthoritySet { @@ -429,6 +449,7 @@ fn global_communication, B, E, N, RA>( // block commit and catch up messages until relevant blocks are imported. let global_in = UntilGlobalMessageBlocksImported::new( client.import_notification_stream(), + network.clone(), client.clone(), global_in, "global", @@ -617,7 +638,7 @@ where let voters = persistent_data.authority_set.current_authorities(); let env = Arc::new(Environment { - inner: client, + client, select_chain, voting_rule, voters: Arc::new(voters), @@ -656,7 +677,7 @@ where "authority_id" => authority_id.to_string(), ); - let chain_info = self.env.inner.info(); + let chain_info = self.env.client.info(); telemetry!(CONSENSUS_INFO; "afg.authority_set"; "number" => ?chain_info.chain.finalized_number, "hash" => ?chain_info.chain.finalized_hash, @@ -680,7 +701,7 @@ where let global_comms = global_communication( self.env.set_id, &self.env.voters, - &self.env.inner, + &self.env.client, &self.env.network, &self.env.config.keystore, ); @@ -728,7 +749,7 @@ where (new.canon_hash, new.canon_number), ); - aux_schema::write_voter_set_state(&*self.env.inner, &set_state)?; + aux_schema::write_voter_set_state(&*self.env.client, &set_state)?; Ok(Some(set_state)) })?; @@ -737,7 +758,7 @@ where set_id: new.set_id, voter_set_state: self.env.voter_set_state.clone(), // Fields below are simply transferred and not updated. - inner: self.env.inner.clone(), + client: self.env.client.clone(), select_chain: self.env.select_chain.clone(), config: self.env.config.clone(), authority_set: self.env.authority_set.clone(), @@ -757,7 +778,7 @@ where let completed_rounds = voter_set_state.completed_rounds(); let set_state = VoterSetState::Paused { completed_rounds }; - aux_schema::write_voter_set_state(&*self.env.inner, &set_state)?; + aux_schema::write_voter_set_state(&*self.env.client, &set_state)?; Ok(Some(set_state)) })?; diff --git a/core/finality-grandpa/src/tests.rs b/core/finality-grandpa/src/tests.rs index 7f4a0d053a..8c0047e38b 100644 --- a/core/finality-grandpa/src/tests.rs +++ b/core/finality-grandpa/src/tests.rs @@ -1556,7 +1556,7 @@ fn grandpa_environment_respects_voting_rules() { authority_set: authority_set.clone(), config: config.clone(), consensus_changes: consensus_changes.clone(), - inner: link.client.clone(), + client: link.client.clone(), select_chain: link.select_chain.clone(), set_id: authority_set.set_id(), voter_set_state: set_state.clone(), diff --git a/core/finality-grandpa/src/until_imported.rs b/core/finality-grandpa/src/until_imported.rs index 119ecf95c5..5fca476a82 100644 --- a/core/finality-grandpa/src/until_imported.rs +++ b/core/finality-grandpa/src/until_imported.rs @@ -20,7 +20,13 @@ //! //! This is used for votes and commit messages currently. -use super::{BlockStatus, CommunicationIn, Error, SignedMessage}; +use super::{ + BlockStatus as BlockStatusT, + BlockSyncRequester as BlockSyncRequesterT, + CommunicationIn, + Error, + SignedMessage, +}; use log::{debug, warn}; use client::{BlockImportNotification, ImportNotifications}; @@ -54,8 +60,8 @@ pub(crate) trait BlockUntilImported: Sized { wait: Wait, ready: Ready, ) -> Result<(), Error> where - S: BlockStatus, - Wait: FnMut(Block::Hash, Self), + S: BlockStatusT, + Wait: FnMut(Block::Hash, NumberFor, Self), Ready: FnMut(Self::Blocked); /// called when the wait has completed. The canonical number is passed through @@ -64,23 +70,31 @@ pub(crate) trait BlockUntilImported: Sized { } /// Buffering imported messages until blocks with given hashes are imported. -pub(crate) struct UntilImported> { +pub(crate) struct UntilImported> { import_notifications: Fuse, Error = ()> + Send>>, - status_check: Status, + block_sync_requester: BlockSyncRequester, + status_check: BlockStatus, inner: Fuse, ready: VecDeque, check_pending: Interval, - pending: HashMap)>, + /// Mapping block hashes to their block number, the point in time it was + /// first encountered (Instant) and a list of GRANDPA messages referencing + /// the block hash. + pending: HashMap, Instant, Vec)>, identifier: &'static str, } -impl UntilImported - where Status: BlockStatus, M: BlockUntilImported +impl UntilImported where + Block: BlockT, + BlockStatus: BlockStatusT, + M: BlockUntilImported, + I: Stream, { /// Create a new `UntilImported` wrapper. pub(crate) fn new( import_notifications: ImportNotifications, - status_check: Status, + block_sync_requester: BlockSyncRequester, + status_check: BlockStatus, stream: I, identifier: &'static str, ) -> Self { @@ -98,6 +112,7 @@ impl UntilImported let stream = import_notifications.map::<_, fn(_) -> _>(|v| Ok::<_, ()>(v)).compat(); Box::new(stream) as Box + Send> }.fuse(), + block_sync_requester, status_check, inner: stream.fuse(), ready: VecDeque::new(), @@ -108,8 +123,10 @@ impl UntilImported } } -impl Stream for UntilImported where - Status: BlockStatus, +impl Stream for UntilImported where + Block: BlockT, + BStatus: BlockStatusT, + BSyncRequester: BlockSyncRequesterT, I: Stream, M: BlockUntilImported, { @@ -128,10 +145,10 @@ impl Stream for UntilImported M::schedule_wait( input, &self.status_check, - |target_hash, wait| pending + |target_hash, target_number, wait| pending .entry(target_hash) - .or_insert_with(|| (Instant::now(), Vec::new())) - .1 + .or_insert_with(|| (target_number, Instant::now(), Vec::new())) + .2 .push(wait), |ready_item| ready.push_back(ready_item), )?; @@ -146,7 +163,7 @@ impl Stream for UntilImported Ok(Async::Ready(None)) => return Ok(Async::Ready(None)), Ok(Async::Ready(Some(notification))) => { // new block imported. queue up all messages tied to that hash. - if let Some((_, messages)) = self.pending.remove(¬ification.hash) { + if let Some((_, _, messages)) = self.pending.remove(¬ification.hash) { let canon_number = notification.header.number().clone(); let ready_messages = messages.into_iter() .filter_map(|m| m.wait_completed(canon_number)); @@ -165,28 +182,38 @@ impl Stream for UntilImported if update_interval { let mut known_keys = Vec::new(); - for (&block_hash, &mut (ref mut last_log, ref v)) in &mut self.pending { + for (&block_hash, &mut (block_number, ref mut last_log, ref v)) in &mut self.pending { if let Some(number) = self.status_check.block_number(block_hash)? { known_keys.push((block_hash, number)); } else { let next_log = *last_log + LOG_PENDING_INTERVAL; - if Instant::now() <= next_log { + if Instant::now() >= next_log { debug!( target: "afg", "Waiting to import block {} before {} {} messages can be imported. \ + Requesting network sync service to retrieve block from. \ Possible fork?", block_hash, v.len(), self.identifier, ); + // NOTE: when sending an empty vec of peers the + // underlying should make a best effort to sync the + // block from any peers it knows about. + self.block_sync_requester.set_sync_fork_request( + vec![], + block_hash, + block_number, + ); + *last_log = next_log; } } } for (known_hash, canon_number) in known_keys { - if let Some((_, pending_messages)) = self.pending.remove(&known_hash) { + if let Some((_, _, pending_messages)) = self.pending.remove(&known_hash) { let ready_messages = pending_messages.into_iter() .filter_map(|m| m.wait_completed(canon_number)); @@ -220,14 +247,14 @@ fn warn_authority_wrong_target(hash: H, id: AuthorityId) impl BlockUntilImported for SignedMessage { type Blocked = Self; - fn schedule_wait( + fn schedule_wait( msg: Self::Blocked, - status_check: &S, + status_check: &BlockStatus, mut wait: Wait, mut ready: Ready, ) -> Result<(), Error> where - S: BlockStatus, - Wait: FnMut(Block::Hash, Self), + BlockStatus: BlockStatusT, + Wait: FnMut(Block::Hash, NumberFor, Self), Ready: FnMut(Self::Blocked), { let (&target_hash, target_number) = msg.target(); @@ -239,7 +266,7 @@ impl BlockUntilImported for SignedMessage { ready(msg); } } else { - wait(target_hash, msg) + wait(target_hash, target_number, msg) } Ok(()) @@ -259,7 +286,13 @@ impl BlockUntilImported for SignedMessage { /// Helper type definition for the stream which waits until vote targets for /// signed messages are imported. -pub(crate) type UntilVoteTargetImported = UntilImported>; +pub(crate) type UntilVoteTargetImported = UntilImported< + Block, + BlockStatus, + BlockSyncRequester, + I, + SignedMessage, +>; /// This blocks a global message import, i.e. a commit or catch up messages, /// until all blocks referenced in its votes are known. @@ -274,14 +307,14 @@ pub(crate) struct BlockGlobalMessage { impl BlockUntilImported for BlockGlobalMessage { type Blocked = CommunicationIn; - fn schedule_wait( + fn schedule_wait( input: Self::Blocked, - status_check: &S, + status_check: &BlockStatus, mut wait: Wait, mut ready: Ready, ) -> Result<(), Error> where - S: BlockStatus, - Wait: FnMut(Block::Hash, Self), + BlockStatus: BlockStatusT, + Wait: FnMut(Block::Hash, NumberFor, Self), Ready: FnMut(Self::Blocked), { use std::collections::hash_map::Entry; @@ -383,7 +416,7 @@ impl BlockUntilImported for BlockGlobalMessage { // if this is taking a long time. for (hash, is_known) in checked_hashes { if let KnownOrUnknown::Unknown(target_number) = is_known { - wait(hash, BlockGlobalMessage { + wait(hash, target_number, BlockGlobalMessage { inner: locked_global.clone(), target_number, }) @@ -425,9 +458,10 @@ impl BlockUntilImported for BlockGlobalMessage { /// A stream which gates off incoming global messages, i.e. commit and catch up /// messages, until all referenced block hashes have been imported. -pub(crate) type UntilGlobalMessageBlocksImported = UntilImported< +pub(crate) type UntilGlobalMessageBlocksImported = UntilImported< Block, - Status, + BlockStatus, + BlockSyncRequester, I, BlockGlobalMessage, >; @@ -485,12 +519,31 @@ mod tests { inner: Arc>>, } - impl BlockStatus for TestBlockStatus { + impl BlockStatusT for TestBlockStatus { fn block_number(&self, hash: Hash) -> Result, Error> { Ok(self.inner.lock().get(&hash).map(|x| x.clone())) } } + #[derive(Clone)] + struct TestBlockSyncRequester { + requests: Arc)>>>, + } + + impl Default for TestBlockSyncRequester { + fn default() -> Self { + TestBlockSyncRequester { + requests: Arc::new(Mutex::new(Vec::new())), + } + } + } + + impl BlockSyncRequesterT for TestBlockSyncRequester { + fn set_sync_fork_request(&self, _peers: Vec, hash: Hash, number: NumberFor) { + self.requests.lock().push((hash, number)); + } + } + fn make_header(number: u64) -> Header { Header::new( number, @@ -535,6 +588,7 @@ mod tests { let until_imported = UntilGlobalMessageBlocksImported::new( import_notifications, + TestBlockSyncRequester::default(), block_status, global_rx.map_err(|_| panic!("should never error")), "global", @@ -561,6 +615,7 @@ mod tests { let until_imported = UntilGlobalMessageBlocksImported::new( import_notifications, + TestBlockSyncRequester::default(), block_status, global_rx.map_err(|_| panic!("should never error")), "global", @@ -806,4 +861,80 @@ mod tests { unapply_catch_up(unknown_catch_up()), ); } + + #[test] + fn request_block_sync_for_needed_blocks() { + let (chain_state, import_notifications) = TestChainState::new(); + let block_status = chain_state.block_status(); + + let (global_tx, global_rx) = futures::sync::mpsc::unbounded(); + + let block_sync_requester = TestBlockSyncRequester::default(); + + let until_imported = UntilGlobalMessageBlocksImported::new( + import_notifications, + block_sync_requester.clone(), + block_status, + global_rx.map_err(|_| panic!("should never error")), + "global", + ); + + let h1 = make_header(5); + let h2 = make_header(6); + let h3 = make_header(7); + + // we create a commit message, with precommits for blocks 6 and 7 which + // we haven't imported. + let unknown_commit = CompactCommit:: { + target_hash: h1.hash(), + target_number: 5, + precommits: vec![ + Precommit { + target_hash: h2.hash(), + target_number: 6, + }, + Precommit { + target_hash: h3.hash(), + target_number: 7, + }, + ], + auth_data: Vec::new(), // not used + }; + + let unknown_commit = || voter::CommunicationIn::Commit( + 0, + unknown_commit.clone(), + voter::Callback::Blank, + ); + + // we send the commit message and spawn the until_imported stream + global_tx.unbounded_send(unknown_commit()).unwrap(); + + let mut runtime = Runtime::new().unwrap(); + runtime.spawn(until_imported.into_future().map(|_| ()).map_err(|_| ())); + + // assert that we will make sync requests + let assert = futures::future::poll_fn::<(), (), _>(|| { + let block_sync_requests = block_sync_requester.requests.lock(); + + // we request blocks targeted by the precommits that aren't imported + if block_sync_requests.contains(&(h2.hash(), *h2.number())) && + block_sync_requests.contains(&(h3.hash(), *h3.number())) + { + return Ok(Async::Ready(())); + } + + Ok(Async::NotReady) + }); + + // the `until_imported` stream doesn't request the blocks immediately, + // but it should request them after a small timeout + let timeout = Delay::new(Instant::now() + Duration::from_secs(60)); + let test = assert.select2(timeout).map(|res| match res { + Either::A(_) => {}, + Either::B(_) => panic!("timed out waiting for block sync request"), + }).map_err(|_| ()); + + runtime.block_on(test).unwrap(); + } } diff --git a/core/network/src/protocol/sync.rs b/core/network/src/protocol/sync.rs index bd8a9fe27f..4f08c942de 100644 --- a/core/network/src/protocol/sync.rs +++ b/core/network/src/protocol/sync.rs @@ -456,14 +456,24 @@ impl ChainSync { /// Request syncing for the given block from given set of peers. // The implementation is similar to on_block_announce with unknown parent hash. - pub fn set_sync_fork_request(&mut self, peers: Vec, hash: &B::Hash, number: NumberFor) { + pub fn set_sync_fork_request(&mut self, mut peers: Vec, hash: &B::Hash, number: NumberFor) { if peers.is_empty() { - if let Some(_) = self.fork_targets.remove(hash) { - debug!(target: "sync", "Cleared sync request for block {:?} with {:?}", hash, peers); - } - return; + debug!( + target: "sync", + "Explicit sync request for block {:?} with no peers specified. \ + Syncing from all connected peers {:?} instead.", + hash, peers, + ); + + peers = self.peers.iter() + // Only request blocks from peers who are ahead or on a par. + .filter(|(_, peer)| peer.best_number >= number) + .map(|(id, _)| id.clone()) + .collect(); + } else { + debug!(target: "sync", "Explicit sync request for block {:?} with {:?}", hash, peers); } - debug!(target: "sync", "Explicit sync request for block {:?} with {:?}", hash, peers); + if self.is_known(&hash) { debug!(target: "sync", "Refusing to sync known hash {:?}", hash); return; @@ -1074,7 +1084,7 @@ impl ChainSync { parent_hash: Some(header.parent_hash().clone()), peers: Default::default(), }) - .peers.insert(who); + .peers.insert(who); } OnBlockAnnounce::Nothing -- GitLab From 81618967efc309fbbdd8dec3e8c28b21027861d1 Mon Sep 17 00:00:00 2001 From: thiolliere Date: Thu, 24 Oct 2019 17:26:26 +0200 Subject: [PATCH 099/167] Fix treasury kept and spend when emptied (#3880) * Now construct_runtime must include treasury config so account is created at genesis. * if it doesn't though it is ok, account will be created when the amount put is more than existential deposit. --- node/cli/src/chain_spec.rs | 1 + node/runtime/src/lib.rs | 6 +-- node/testing/src/genesis.rs | 1 + srml/treasury/src/lib.rs | 102 +++++++++++++++++++++++++++++++++--- 4 files changed, 99 insertions(+), 11 deletions(-) diff --git a/node/cli/src/chain_spec.rs b/node/cli/src/chain_spec.rs index 07f6946baf..721fdbaf99 100644 --- a/node/cli/src/chain_spec.rs +++ b/node/cli/src/chain_spec.rs @@ -273,6 +273,7 @@ pub fn testnet_genesis( authorities: vec![], }), membership_Instance1: Some(Default::default()), + treasury: Some(Default::default()), } } diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index 9097dd22a3..c43777773d 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -83,8 +83,8 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // and set impl_version to equal spec_version. If only runtime // implementation changes and behavior does not, then leave spec_version as // is and increment impl_version. - spec_version: 183, - impl_version: 183, + spec_version: 184, + impl_version: 184, apis: RUNTIME_API_VERSIONS, }; @@ -482,7 +482,7 @@ construct_runtime!( TechnicalMembership: membership::::{Module, Call, Storage, Event, Config}, FinalityTracker: finality_tracker::{Module, Call, Inherent}, Grandpa: grandpa::{Module, Call, Storage, Config, Event}, - Treasury: treasury::{Module, Call, Storage, Event}, + Treasury: treasury::{Module, Call, Storage, Config, Event}, Contracts: contracts, Sudo: sudo, ImOnline: im_online::{Module, Call, Storage, Event, ValidateUnsigned, Config}, diff --git a/node/testing/src/genesis.rs b/node/testing/src/genesis.rs index a9f55d86e3..5220d1774b 100644 --- a/node/testing/src/genesis.rs +++ b/node/testing/src/genesis.rs @@ -96,5 +96,6 @@ pub fn config(support_changes_trie: bool, code: Option<&[u8]>) -> GenesisConfig membership_Instance1: Some(Default::default()), elections_phragmen: Some(Default::default()), sudo: Some(Default::default()), + treasury: Some(Default::default()), } } diff --git a/srml/treasury/src/lib.rs b/srml/treasury/src/lib.rs index 08e2f729ab..48b56e438e 100644 --- a/srml/treasury/src/lib.rs +++ b/srml/treasury/src/lib.rs @@ -77,7 +77,7 @@ use support::traits::{ }; use sr_primitives::{Permill, Perbill, ModuleId}; use sr_primitives::traits::{ - Zero, EnsureOrigin, StaticLookup, AccountIdConversion, CheckedSub + Zero, EnsureOrigin, StaticLookup, AccountIdConversion, CheckedSub, Saturating }; use sr_primitives::weights::SimpleDispatchInfo; use codec::{Encode, Decode}; @@ -233,6 +233,15 @@ decl_storage! { /// Proposal indices that have been approved but not yet awarded. Approvals get(fn approvals): Vec; } + add_extra_genesis { + build(|_config| { + // Create Treasury account + let _ = T::Currency::make_free_balance_be( + &>::account_id(), + T::Currency::minimum_balance(), + ); + }); + } } decl_event!( @@ -311,6 +320,10 @@ impl Module { Self::deposit_event(RawEvent::Burnt(burn)) } + // Must never be an error, but better to be safe. + // proof: budget_remaining is account free balance minus ED; + // Thus we can't spend more than account free balance minus ED; + // Thus account is kept alive; qed; if let Err(problem) = T::Currency::settle( &Self::account_id(), imbalance, @@ -325,21 +338,32 @@ impl Module { Self::deposit_event(RawEvent::Rollover(budget_remaining)); } + /// Return the amount of money in the pot. + // The existential deposit is not part of the pot so treasury account never gets deleted. fn pot() -> BalanceOf { T::Currency::free_balance(&Self::account_id()) + // Must never be less than 0 but better be safe. + .saturating_sub(T::Currency::minimum_balance()) } } impl OnUnbalanced> for Module { fn on_unbalanced(amount: NegativeImbalanceOf) { - T::Currency::resolve_creating(&Self::account_id(), amount); + // Must resolve into existing but better to be safe. + let _ = T::Currency::resolve_creating(&Self::account_id(), amount); } } +/// Mint extra funds for the treasury to keep the ratio of portion to total_issuance equal +/// pre dilution and post-dilution. +/// +/// i.e. +/// ```nocompile +/// portion / total_issuance_before_dilution == +/// (portion + minted) / (total_issuance_before_dilution + minted_to_treasury + minted) +/// ``` impl OnDilution> for Module { fn on_dilution(minted: BalanceOf, portion: BalanceOf) { - // Mint extra funds for the treasury to keep the ratio of portion to total_issuance equal - // pre dilution and post-dilution. if !minted.is_zero() && !portion.is_zero() { let total_issuance = T::Currency::total_issuance(); if let Some(funding) = total_issuance.checked_sub(&portion) { @@ -391,7 +415,7 @@ mod tests { type Version = (); } parameter_types! { - pub const ExistentialDeposit: u64 = 0; + pub const ExistentialDeposit: u64 = 1; pub const TransferFee: u64 = 0; pub const CreationFee: u64 = 0; } @@ -430,9 +454,11 @@ mod tests { fn new_test_ext() -> runtime_io::TestExternalities { let mut t = system::GenesisConfig::default().build_storage::().unwrap(); balances::GenesisConfig::{ - balances: vec![(0, 100), (1, 99), (2, 1)], + // Total issuance will be 200 with treasury account initialized at ED. + balances: vec![(0, 100), (1, 98), (2, 1)], vesting: vec![], }.assimilate_storage(&mut t).unwrap(); + GenesisConfig::default().assimilate_storage::(&mut t).unwrap(); t.into() } @@ -600,17 +626,77 @@ mod tests { fn pot_underflow_should_not_diminish() { new_test_ext().execute_with(|| { Treasury::on_dilution(100, 100); + assert_eq!(Treasury::pot(), 100); assert_ok!(Treasury::propose_spend(Origin::signed(0), 150, 3)); assert_ok!(Treasury::approve_proposal(Origin::ROOT, 0)); >::on_finalize(2); + assert_eq!(Treasury::pot(), 100); // Pot hasn't changed + + Treasury::on_dilution(100, 100); + >::on_finalize(4); + assert_eq!(Balances::free_balance(&3), 150); // Fund has been spent + assert_eq!(Treasury::pot(), 75); // Pot has finally changed + }); + } + + // Treasury account doesn't get deleted if amount approved to spend is all its free balance. + // i.e. pot should not include existential deposit needed for account survival. + #[test] + fn treasury_account_doesnt_get_deleted() { + new_test_ext().execute_with(|| { + Treasury::on_dilution(100, 100); assert_eq!(Treasury::pot(), 100); + let treasury_balance = Balances::free_balance(&Treasury::account_id()); + + assert_ok!(Treasury::propose_spend(Origin::signed(0), treasury_balance, 3)); + assert_ok!(Treasury::approve_proposal(Origin::ROOT, 0)); + + >::on_finalize(2); + assert_eq!(Treasury::pot(), 100); // Pot hasn't changed + + assert_ok!(Treasury::propose_spend(Origin::signed(0), Treasury::pot(), 3)); + assert_ok!(Treasury::approve_proposal(Origin::ROOT, 1)); + + >::on_finalize(4); + assert_eq!(Treasury::pot(), 0); // Pot is emptied + assert_eq!(Balances::free_balance(&Treasury::account_id()), 1); // but the account is still there + }); + } + + // In case treasury account is not existing then it works fine. + // This is usefull for chain that will just update runtime. + #[test] + fn inexisting_account_works() { + let mut t = system::GenesisConfig::default().build_storage::().unwrap(); + balances::GenesisConfig::{ + balances: vec![(0, 100), (1, 99), (2, 1)], + vesting: vec![], + }.assimilate_storage(&mut t).unwrap(); + // Treasury genesis config is not build thus treasury account does not exist + let mut t: runtime_io::TestExternalities = t.into(); + + t.execute_with(|| { + assert_eq!(Balances::free_balance(&Treasury::account_id()), 0); // Account does not exist + assert_eq!(Treasury::pot(), 0); // Pot is empty + + assert_ok!(Treasury::propose_spend(Origin::signed(0), 99, 3)); + assert_ok!(Treasury::approve_proposal(Origin::ROOT, 0)); + assert_ok!(Treasury::propose_spend(Origin::signed(0), 1, 3)); + assert_ok!(Treasury::approve_proposal(Origin::ROOT, 1)); + >::on_finalize(2); + assert_eq!(Treasury::pot(), 0); // Pot hasn't changed + assert_eq!(Balances::free_balance(&3), 0); // Balance of `3` hasn't changed Treasury::on_dilution(100, 100); + assert_eq!(Treasury::pot(), 99); // Pot now contains funds + assert_eq!(Balances::free_balance(&Treasury::account_id()), 100); // Account does exist + >::on_finalize(4); - assert_eq!(Balances::free_balance(&3), 150); - assert_eq!(Treasury::pot(), 75); + + assert_eq!(Treasury::pot(), 0); // Pot has changed + assert_eq!(Balances::free_balance(&3), 99); // Balance of `3` has changed }); } } -- GitLab From c6524464feb7c88d35e73e5e3a9f7fde90763d97 Mon Sep 17 00:00:00 2001 From: Joshy Orndorff Date: Fri, 25 Oct 2019 00:25:33 -0400 Subject: [PATCH 100/167] Change dependency name "node-template-runtime" -> "runtime" (#3910) --- node-template/Cargo.toml | 2 +- node-template/src/chain_spec.rs | 2 +- node-template/src/service.rs | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/node-template/Cargo.toml b/node-template/Cargo.toml index 2c01655dc2..bb61c2c2ca 100644 --- a/node-template/Cargo.toml +++ b/node-template/Cargo.toml @@ -33,7 +33,7 @@ grandpa = { package = "substrate-finality-grandpa", path = "../core/finality-gra 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" } +runtime = { package = "node-template-runtime", path = "runtime" } [build-dependencies] vergen = "3.0.4" diff --git a/node-template/src/chain_spec.rs b/node-template/src/chain_spec.rs index 2996f5414a..b8f7fef35e 100644 --- a/node-template/src/chain_spec.rs +++ b/node-template/src/chain_spec.rs @@ -1,5 +1,5 @@ use primitives::{Pair, Public}; -use node_template_runtime::{ +use runtime::{ AccountId, AuraConfig, BalancesConfig, GenesisConfig, GrandpaConfig, SudoConfig, IndicesConfig, SystemConfig, WASM_BINARY, }; diff --git a/node-template/src/service.rs b/node-template/src/service.rs index 46c0124cb4..203e311df9 100644 --- a/node-template/src/service.rs +++ b/node-template/src/service.rs @@ -4,7 +4,7 @@ use std::sync::Arc; use std::time::Duration; use substrate_client::LongestChain; use futures::prelude::*; -use node_template_runtime::{self, GenesisConfig, opaque::Block, RuntimeApi}; +use runtime::{self, GenesisConfig, opaque::Block, RuntimeApi}; use substrate_service::{error::{Error as ServiceError}, AbstractService, Configuration, ServiceBuilder}; use transaction_pool::{self, txpool::{Pool as TransactionPool}}; use inherents::InherentDataProviders; @@ -17,8 +17,8 @@ use grandpa::{self, FinalityProofProvider as GrandpaFinalityProofProvider}; // Our native executor instance. native_executor_instance!( pub Executor, - node_template_runtime::api::dispatch, - node_template_runtime::native_version, + runtime::api::dispatch, + runtime::native_version, ); construct_simple_protocol! { @@ -36,7 +36,7 @@ macro_rules! new_full_start { let inherent_data_providers = inherents::InherentDataProviders::new(); let builder = substrate_service::ServiceBuilder::new_full::< - node_template_runtime::opaque::Block, node_template_runtime::RuntimeApi, crate::service::Executor + runtime::opaque::Block, runtime::RuntimeApi, crate::service::Executor >($config)? .with_select_chain(|_config, backend| { Ok(substrate_client::LongestChain::new(backend.clone())) @@ -49,7 +49,7 @@ macro_rules! new_full_start { .ok_or_else(|| substrate_service::Error::SelectChainRequired)?; let (grandpa_block_import, grandpa_link) = - grandpa::block_import::<_, _, _, node_template_runtime::RuntimeApi, _, _>( + grandpa::block_import::<_, _, _, runtime::RuntimeApi, _, _>( client.clone(), &*client, select_chain )?; -- GitLab From 4ff62401ccd29881b4120c90b7767e58b99f5ae8 Mon Sep 17 00:00:00 2001 From: Jim Posen Date: Fri, 25 Oct 2019 11:44:57 +0200 Subject: [PATCH 101/167] support: BuildStorage methods to take self reference (#3884) * support: BuildStorage methods to take self reference. There is no reason to consume the GenesisConfig when using it to initialize a new storage backend. Instead, build_storage and assimilate_storage now operator on self references. * Bump node runtime impl_version. --- core/chain-spec/src/chain_spec.rs | 8 +++---- core/sr-primitives/src/lib.rs | 24 +++++++++---------- node/runtime/src/lib.rs | 2 +- .../src/storage/genesis_config/builder_def.rs | 4 ++-- .../src/storage/genesis_config/mod.rs | 6 ++--- 5 files changed, 21 insertions(+), 23 deletions(-) diff --git a/core/chain-spec/src/chain_spec.rs b/core/chain-spec/src/chain_spec.rs index 8d72effc7b..0f69654b9e 100644 --- a/core/chain-spec/src/chain_spec.rs +++ b/core/chain-spec/src/chain_spec.rs @@ -71,7 +71,7 @@ impl GenesisSource { } impl<'a, G: RuntimeGenesis, E> BuildStorage for &'a ChainSpec { - fn build_storage(self) -> Result<(StorageOverlay, ChildrenStorageOverlay), String> { + fn build_storage(&self) -> Result<(StorageOverlay, ChildrenStorageOverlay), String> { match self.genesis.resolve()? { Genesis::Runtime(gc) => gc.build_storage(), Genesis::Raw(map, children_map) => Ok(( @@ -85,7 +85,7 @@ impl<'a, G: RuntimeGenesis, E> BuildStorage for &'a ChainSpec { } fn assimilate_storage( - self, + &self, _: &mut (StorageOverlay, ChildrenStorageOverlay) ) -> Result<(), String> { Err("`assimilate_storage` not implemented for `ChainSpec`.".into()) @@ -289,11 +289,11 @@ mod tests { impl BuildStorage for Genesis { fn assimilate_storage( - self, + &self, storage: &mut (StorageOverlay, ChildrenStorageOverlay), ) -> Result<(), String> { storage.0.extend( - self.0.into_iter().map(|(a, b)| (a.into_bytes(), b.into_bytes())) + self.0.iter().map(|(a, b)| (a.clone().into_bytes(), b.clone().into_bytes())) ); Ok(()) } diff --git a/core/sr-primitives/src/lib.rs b/core/sr-primitives/src/lib.rs index 84f7bbcff6..624e224ef1 100644 --- a/core/sr-primitives/src/lib.rs +++ b/core/sr-primitives/src/lib.rs @@ -123,14 +123,14 @@ use crate::traits::IdentifyAccount; #[cfg(feature = "std")] pub trait BuildStorage: Sized { /// Build the storage out of this builder. - fn build_storage(self) -> Result<(StorageOverlay, ChildrenStorageOverlay), String> { + fn build_storage(&self) -> Result<(StorageOverlay, ChildrenStorageOverlay), String> { let mut storage = (Default::default(), Default::default()); self.assimilate_storage(&mut storage)?; Ok(storage) } /// Assimilate the storage for this module into pre-existing overlays. fn assimilate_storage( - self, + &self, storage: &mut (StorageOverlay, ChildrenStorageOverlay), ) -> Result<(), String>; } @@ -140,26 +140,24 @@ pub trait BuildStorage: Sized { pub trait BuildModuleGenesisStorage: Sized { /// Create the module genesis storage into the given `storage` and `child_storage`. fn build_module_genesis_storage( - self, + &self, storage: &mut (StorageOverlay, ChildrenStorageOverlay), ) -> Result<(), String>; } #[cfg(feature = "std")] impl BuildStorage for (StorageOverlay, ChildrenStorageOverlay) { - fn build_storage(self) -> Result<(StorageOverlay, ChildrenStorageOverlay), String> { - Ok(self) - } fn assimilate_storage( - self, + &self, storage: &mut (StorageOverlay, ChildrenStorageOverlay), )-> Result<(), String> { - storage.0.extend(self.0); - for (k, other_map) in self.1.into_iter() { + storage.0.extend(self.0.iter().map(|(k, v)| (k.clone(), v.clone()))); + for (k, other_map) in self.1.iter() { + let k = k.clone(); if let Some(map) = storage.1.get_mut(&k) { - map.extend(other_map); + map.extend(other_map.iter().map(|(k, v)| (k.clone(), v.clone()))); } else { - storage.1.insert(k, other_map); + storage.1.insert(k, other_map.clone()); } } Ok(()) @@ -522,11 +520,11 @@ macro_rules! impl_outer_config { #[cfg(any(feature = "std", test))] impl $crate::BuildStorage for $main { fn assimilate_storage( - self, + &self, storage: &mut ($crate::StorageOverlay, $crate::ChildrenStorageOverlay), ) -> std::result::Result<(), String> { $( - if let Some(extra) = self.[< $snake $(_ $instance )? >] { + if let Some(ref extra) = self.[< $snake $(_ $instance )? >] { $crate::impl_outer_config! { @CALL_FN $concrete; diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index c43777773d..fefc1144ac 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -84,7 +84,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // implementation changes and behavior does not, then leave spec_version as // is and increment impl_version. spec_version: 184, - impl_version: 184, + impl_version: 185, apis: RUNTIME_API_VERSIONS, }; diff --git a/srml/support/procedural/src/storage/genesis_config/builder_def.rs b/srml/support/procedural/src/storage/genesis_config/builder_def.rs index 60f094e9fe..fc425e4a6d 100644 --- a/srml/support/procedural/src/storage/genesis_config/builder_def.rs +++ b/srml/support/procedural/src/storage/genesis_config/builder_def.rs @@ -51,7 +51,7 @@ impl BuilderDef { is_generic |= ext::expr_contains_ident(&builder, &def.module_runtime_generic); is_generic |= line.is_generic; - data = Some(quote_spanned!(builder.span() => &(#builder)(&self))); + data = Some(quote_spanned!(builder.span() => &(#builder)(self))); } else if let Some(config) = &line.config { is_generic |= line.is_generic; @@ -98,7 +98,7 @@ impl BuilderDef { blocks.push(quote_spanned! { builder.span() => let extra_genesis_builder: fn(&Self) = #builder; - extra_genesis_builder(&self); + extra_genesis_builder(self); }); } diff --git a/srml/support/procedural/src/storage/genesis_config/mod.rs b/srml/support/procedural/src/storage/genesis_config/mod.rs index 57de1e34a8..2d4d4af386 100644 --- a/srml/support/procedural/src/storage/genesis_config/mod.rs +++ b/srml/support/procedural/src/storage/genesis_config/mod.rs @@ -138,7 +138,7 @@ fn impl_build_storage( quote!{ #[cfg(feature = "std")] impl#genesis_impl GenesisConfig#genesis_struct #genesis_where_clause { - pub fn build_storage #fn_generic (self) -> std::result::Result< + pub fn build_storage #fn_generic (&self) -> std::result::Result< ( #scrate::sr_primitives::StorageOverlay, #scrate::sr_primitives::ChildrenStorageOverlay, @@ -152,7 +152,7 @@ fn impl_build_storage( /// Assimilate the storage for this module into pre-existing overlays. pub fn assimilate_storage #fn_generic ( - self, + &self, tuple_storage: &mut ( #scrate::sr_primitives::StorageOverlay, #scrate::sr_primitives::ChildrenStorageOverlay, @@ -170,7 +170,7 @@ fn impl_build_storage( #where_clause { fn build_module_genesis_storage( - self, + &self, storage: &mut ( #scrate::sr_primitives::StorageOverlay, #scrate::sr_primitives::ChildrenStorageOverlay, -- GitLab From 706defecb954ff45234fdb82e08a9e50eda76c82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Fri, 25 Oct 2019 12:24:58 +0200 Subject: [PATCH 102/167] Bring back `SubmitSignedTransaction` trait. (#3908) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Bring back SubmitSignedTransaction. * Fix long lines. * Add missing docs. * Update core/primitives/src/crypto.rs Co-Authored-By: Bastian Köcher * Update node/runtime/src/lib.rs Co-Authored-By: Bastian Köcher * Update core/primitives/src/crypto.rs Co-Authored-By: Bastian Köcher --- core/primitives/src/crypto.rs | 3 + core/sr-primitives/src/lib.rs | 21 +++++++ node/runtime/src/lib.rs | 53 +++++++++++++++++- srml/im-online/src/lib.rs | 12 ---- srml/system/src/offchain.rs | 102 ++++++++++++++++++++++++++++++++-- 5 files changed, 173 insertions(+), 18 deletions(-) diff --git a/core/primitives/src/crypto.rs b/core/primitives/src/crypto.rs index b7c70e6224..6e46793432 100644 --- a/core/primitives/src/crypto.rs +++ b/core/primitives/src/crypto.rs @@ -790,6 +790,9 @@ pub trait Pair: CryptoType + Sized + Clone + Send + Sync + 'static { root.derive(path, Some(seed)).map_err(|_| SecretStringError::InvalidPath) } + /// Interprets the string `s` in order to generate a key pair. + /// + /// See [`from_string_with_seed`](Self::from_string_with_seed) for more extensive documentation. fn from_string(s: &str, password_override: Option<&str>) -> Result { Self::from_string_with_seed(s, password_override).map(|x| x.0) } diff --git a/core/sr-primitives/src/lib.rs b/core/sr-primitives/src/lib.rs index 624e224ef1..4341e3543a 100644 --- a/core/sr-primitives/src/lib.rs +++ b/core/sr-primitives/src/lib.rs @@ -255,18 +255,39 @@ impl From for MultiSigner { } } +impl TryFrom for ed25519::Public { + type Error = (); + fn try_from(m: MultiSigner) -> Result { + if let MultiSigner::Ed25519(x) = m { Ok(x) } else { Err(()) } + } +} + impl From for MultiSigner { fn from(x: sr25519::Public) -> Self { MultiSigner::Sr25519(x) } } +impl TryFrom for sr25519::Public { + type Error = (); + fn try_from(m: MultiSigner) -> Result { + if let MultiSigner::Sr25519(x) = m { Ok(x) } else { Err(()) } + } +} + impl From for MultiSigner { fn from(x: ecdsa::Public) -> Self { MultiSigner::Ecdsa(x) } } +impl TryFrom for ecdsa::Public { + type Error = (); + fn try_from(m: MultiSigner) -> Result { + if let MultiSigner::Ecdsa(x) = m { Ok(x) } else { Err(()) } + } +} + #[cfg(feature = "std")] impl std::fmt::Display for MultiSigner { fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index fefc1144ac..3b72ff40fa 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -42,7 +42,7 @@ use sr_primitives::curve::PiecewiseLinear; use sr_primitives::transaction_validity::TransactionValidity; use sr_primitives::weights::Weight; use sr_primitives::traits::{ - BlakeTwo256, Block as BlockT, NumberFor, StaticLookup, + self, BlakeTwo256, Block as BlockT, NumberFor, StaticLookup, SaturatedConversion, }; use version::RuntimeVersion; #[cfg(any(feature = "std", test))] @@ -459,6 +459,36 @@ impl finality_tracker::Trait for Runtime { type ReportLatency = ReportLatency; } +impl system::offchain::CreateTransaction for Runtime { + type Public = ::Signer; + type Signature = Signature; + + fn create_transaction>( + call: Call, + public: Self::Public, + account: AccountId, + index: Index, + ) -> Option<(Call, ::SignaturePayload)> { + let period = 1 << 8; + let current_block = System::block_number().saturated_into::(); + let tip = 0; + let extra: SignedExtra = ( + system::CheckVersion::::new(), + system::CheckGenesis::::new(), + system::CheckEra::::from(generic::Era::mortal(period, current_block)), + system::CheckNonce::::from(index), + system::CheckWeight::::new(), + transaction_payment::ChargeTransactionPayment::::from(tip), + Default::default(), + ); + let raw_payload = SignedPayload::new(call, extra).ok()?; + let signature = F::sign(public, &raw_payload)?; + let address = Indices::unlookup(account); + let (call, extra, _) = raw_payload.deconstruct(); + Some((call, (address, signature, extra))) + } +} + construct_runtime!( pub enum Runtime where Block = Block, @@ -669,3 +699,24 @@ impl_runtime_apis! { } } } +#[cfg(test)] +mod tests { + use super::*; + use system::offchain::SubmitSignedTransaction; + + fn is_submit_signed_transaction(_arg: T) where + T: SubmitSignedTransaction< + Runtime, + Call, + Extrinsic=UncheckedExtrinsic, + CreateTransaction=Runtime, + Signer=ImOnlineId, + >, + {} + + #[test] + fn validate_bounds() { + let x = SubmitTransaction::default(); + is_submit_signed_transaction(x); + } +} diff --git a/srml/im-online/src/lib.rs b/srml/im-online/src/lib.rs index 202507bef9..82b866d32b 100644 --- a/srml/im-online/src/lib.rs +++ b/srml/im-online/src/lib.rs @@ -96,12 +96,6 @@ pub mod sr25519 { mod app_sr25519 { use app_crypto::{app_crypto, key_types::IM_ONLINE, sr25519}; app_crypto!(sr25519, IM_ONLINE); - - impl From for sr_primitives::AnySignature { - fn from(sig: Signature) -> Self { - sr25519::Signature::from(sig).into() - } - } } /// An i'm online keypair using sr25519 as its crypto. @@ -119,12 +113,6 @@ pub mod ed25519 { mod app_ed25519 { use app_crypto::{app_crypto, key_types::IM_ONLINE, ed25519}; app_crypto!(ed25519, IM_ONLINE); - - impl From for sr_primitives::AnySignature { - fn from(sig: Signature) -> Self { - ed25519::Signature::from(sig).into() - } - } } /// An i'm online keypair using ed25519 as its crypto. diff --git a/srml/system/src/offchain.rs b/srml/system/src/offchain.rs index 468c88af39..11f7e234f7 100644 --- a/srml/system/src/offchain.rs +++ b/srml/system/src/offchain.rs @@ -17,8 +17,8 @@ //! Module helpers for offchain calls. use codec::Encode; -use sr_primitives::app_crypto::RuntimeAppPublic; -use sr_primitives::traits::Extrinsic as ExtrinsicT; +use sr_primitives::app_crypto::{self, RuntimeAppPublic}; +use sr_primitives::traits::{Extrinsic as ExtrinsicT, IdentifyAccount}; /// A trait responsible for signing a payload using given account. pub trait Signer { @@ -28,17 +28,96 @@ pub trait Signer { fn sign(public: Public, payload: &Payload) -> Option; } +/// A `Signer` implementation for any `AppPublic` type. +/// +/// This implementation additionaly supports conversion to/from multi-signature/multi-signer +/// wrappers. +/// If the wrapped crypto doesn't match `AppPublic`s crypto `None` is returned. impl Signer for AppPublic where - AppPublic: RuntimeAppPublic + From, - AppPublic::Signature: Into, + AppPublic: RuntimeAppPublic + + app_crypto::AppPublic + + From<::Generic>, + ::Signature: app_crypto::AppSignature, + Signature: From< + <::Signature as app_crypto::AppSignature>::Generic + >, + Public: rstd::convert::TryInto<::Generic> { fn sign(public: Public, raw_payload: &Payload) -> Option { raw_payload.using_encoded(|payload| { - AppPublic::from(public).sign(&payload).map(Into::into) + let public = public.try_into().ok()?; + AppPublic::from(public).sign(&payload) + .map( + <::Signature as app_crypto::AppSignature> + ::Generic::from + ) + .map(Signature::from) }) } } +/// Creates runtime-specific signed transaction. +pub trait CreateTransaction { + /// A `Public` key representing a particular `AccountId`. + type Public; + /// A `Signature` generated by the `Signer`. + type Signature; + + /// Attempt to create signed extrinsic data that encodes call from given account. + /// + /// Runtime implementation is free to construct the payload to sign and the signature + /// in any way it wants. + /// Returns `None` if signed extrinsic could not be created (either because signing failed + /// or because of any other runtime-specific reason). + fn create_transaction>( + call: Extrinsic::Call, + public: Self::Public, + account: T::AccountId, + nonce: T::Index, + ) -> Option<(Extrinsic::Call, Extrinsic::SignaturePayload)>; +} + +type PublicOf = < + >::CreateTransaction as CreateTransaction< + T, + >::Extrinsic, + > +>::Public; + +/// A trait to sign and submit transactions in offchain calls. +pub trait SubmitSignedTransaction +where + PublicOf: IdentifyAccount + Clone, +{ + /// Unchecked extrinsic type. + type Extrinsic: ExtrinsicT + codec::Encode; + + /// A runtime-specific type to produce signed data for the extrinsic. + type CreateTransaction: CreateTransaction; + + /// A type used to sign transactions created using `CreateTransaction`. + type Signer: Signer< + PublicOf, + >::Signature, + >; + + /// Sign given call and submit it to the transaction pool. + /// + /// Returns `Ok` if the transaction was submitted correctly + /// and `Err` if the key for given `id` was not found or the + /// transaction was rejected from the pool. + fn sign_and_submit(call: impl Into, public: PublicOf) -> Result<(), ()> { + let call = call.into(); + let id = public.clone().into_account(); + let expected = >::account_nonce(&id); + let (call, signature_data) = Self::CreateTransaction + ::create_transaction::(call, public, id, expected) + .ok_or(())?; + let xt = Self::Extrinsic::new(call, Some(signature_data)).ok_or(())?; + runtime_io::submit_transaction(xt.encode()) + } +} + /// A trait to submit unsigned transactions in offchain calls. pub trait SubmitUnsignedTransaction { /// Unchecked extrinsic type. @@ -67,6 +146,19 @@ impl Default for TransactionSubmitter { } } +/// A blanket implementation to simplify creation of transaction signer & submitter in the runtime. +impl SubmitSignedTransaction for TransactionSubmitter where + T: crate::Trait, + C: CreateTransaction, + S: Signer<>::Public, >::Signature>, + E: ExtrinsicT + codec::Encode, + >::Public: IdentifyAccount + Clone, +{ + type Extrinsic = E; + type CreateTransaction = C; + type Signer = S; +} + /// A blanket impl to use the same submitter for usigned transactions as well. impl SubmitUnsignedTransaction for TransactionSubmitter where T: crate::Trait, -- GitLab From cc5294b72a1b3bc85b17068504a5748ffc2d3b63 Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Fri, 25 Oct 2019 14:22:25 +0200 Subject: [PATCH 103/167] Remove MintedForSpending (now unused) (#3917) --- node/runtime/src/lib.rs | 1 - srml/treasury/src/lib.rs | 4 ---- 2 files changed, 5 deletions(-) diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index 3b72ff40fa..6d596b197d 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -370,7 +370,6 @@ impl treasury::Trait for Runtime { type ApproveOrigin = collective::EnsureMembers<_4, AccountId, CouncilCollective>; type RejectOrigin = collective::EnsureMembers<_2, AccountId, CouncilCollective>; type Event = Event; - type MintedForSpending = (); type ProposalRejection = (); type ProposalBond = ProposalBond; type ProposalBondMinimum = ProposalBondMinimum; diff --git a/srml/treasury/src/lib.rs b/srml/treasury/src/lib.rs index 48b56e438e..668dcaca32 100644 --- a/srml/treasury/src/lib.rs +++ b/srml/treasury/src/lib.rs @@ -102,9 +102,6 @@ pub trait Trait: system::Trait { /// The overarching event type. type Event: From> + Into<::Event>; - /// Handler for the unbalanced increase when minting cash from the "Pot". - type MintedForSpending: OnUnbalanced>; - /// Handler for the unbalanced decrease when slashing for a rejected proposal. type ProposalRejection: OnUnbalanced>; @@ -441,7 +438,6 @@ mod tests { type ApproveOrigin = system::EnsureRoot; type RejectOrigin = system::EnsureRoot; type Event = (); - type MintedForSpending = (); type ProposalRejection = (); type ProposalBond = ProposalBond; type ProposalBondMinimum = ProposalBondMinimum; -- GitLab From b2973634e024626d2cf32cab56601aabfce34090 Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Fri, 25 Oct 2019 15:14:49 +0200 Subject: [PATCH 104/167] Add force_unstake to staking as root operation. (#3918) * Add force_unstake to staking as root operation. * Bump runtime * Tests * Update srml/staking/src/lib.rs Co-Authored-By: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- node/runtime/src/lib.rs | 2 +- srml/staking/src/lib.rs | 11 +++++++++++ srml/staking/src/tests.rs | 22 ++++++++++++++++++++++ 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index 6d596b197d..2c02a8be17 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -83,7 +83,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // and set impl_version to equal spec_version. If only runtime // implementation changes and behavior does not, then leave spec_version as // is and increment impl_version. - spec_version: 184, + spec_version: 185, impl_version: 185, apis: RUNTIME_API_VERSIONS, }; diff --git a/srml/staking/src/lib.rs b/srml/staking/src/lib.rs index e7d7c073a1..e5c0277f57 100644 --- a/srml/staking/src/lib.rs +++ b/srml/staking/src/lib.rs @@ -993,6 +993,17 @@ decl_module! { ensure_root(origin)?; >::put(validators); } + + /// Force a current staker to become completely unstaked, immediately. + #[weight = sr_primitives::SimpleDispatchInfo::FreeOperational] + fn force_unstake(origin, stash: T::AccountId) { + ensure_root(origin)?; + + // remove the lock. + T::Currency::remove_lock(STAKING_ID, &stash); + // remove all staking-related information. + Self::kill_stash(&stash); + } } } diff --git a/srml/staking/src/tests.rs b/srml/staking/src/tests.rs index 2cb7981154..2b82176457 100644 --- a/srml/staking/src/tests.rs +++ b/srml/staking/src/tests.rs @@ -22,6 +22,28 @@ use sr_primitives::{assert_eq_error_rate, traits::OnInitialize}; use sr_staking_primitives::offence::{OffenceDetails, OnOffenceHandler}; use support::{assert_ok, assert_noop, assert_eq_uvec, traits::{Currency, ReservableCurrency}}; +#[test] +fn force_unstake_works() { + // Verifies initial conditions of mock + ExtBuilder::default().build().execute_with(|| { + // Account 11 is stashed and locked, and account 10 is the controller + assert_eq!(Staking::bonded(&11), Some(10)); + // Cant transfer + assert_noop!( + Balances::transfer(Origin::signed(11), 1, 10), + "account liquidity restrictions prevent withdrawal" + ); + // Force unstake requires root. + assert_noop!(Staking::force_unstake(Origin::signed(11), 11), "RequireRootOrigin"); + // We now force them to unstake + assert_ok!(Staking::force_unstake(Origin::ROOT, 11)); + // No longer bonded. + assert_eq!(Staking::bonded(&11), None); + // Transfer works. + assert_ok!(Balances::transfer(Origin::signed(11), 1, 10)); + }); +} + #[test] fn basic_setup_works() { // Verifies initial conditions of mock -- GitLab From dac3ab2e4690fd33132e01af0501ce277721fd0f Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Fri, 25 Oct 2019 15:17:55 +0200 Subject: [PATCH 105/167] Telemetry timeout (#3916) * telemetry worker: add connection timeout * restructure * only add timeout when writing data * don't overwrite an existing delay * set timeout only around writing data * address comments * dedicated error enum * remove whitespace * move timeout to inside struct * fix timeout * remove prints * move polling * address comment * Implement * More work --- core/telemetry/src/worker/node.rs | 107 +++++++++++++++++++++--------- 1 file changed, 77 insertions(+), 30 deletions(-) diff --git a/core/telemetry/src/worker/node.rs b/core/telemetry/src/worker/node.rs index 11b1f2a81e..0f606e4063 100644 --- a/core/telemetry/src/worker/node.rs +++ b/core/telemetry/src/worker/node.rs @@ -58,6 +58,8 @@ struct NodeSocketConnected { pending: VecDeque, /// If true, we need to flush the sink. need_flush: bool, + /// A timeout for the socket to write data. + timeout: Option, } /// Event that can happen with this node. @@ -66,7 +68,16 @@ pub enum NodeEvent { /// We are now connected to this node. Connected, /// We are now disconnected from this node. - Disconnected(TSinkErr), + Disconnected(ConnectionError), +} + +/// Reason for disconnecting from a node. +#[derive(Debug)] +pub enum ConnectionError { + /// The connection timed-out. + Timeout, + /// The sink errored. + Sink(TSinkErr), } impl Node { @@ -116,10 +127,12 @@ where TTrans: Clone + Unpin, TTrans::Dial: Unpin, let mut socket = mem::replace(&mut self.socket, NodeSocket::Poisoned); self.socket = loop { match socket { - NodeSocket::Connected(mut conn) => + NodeSocket::Connected(mut conn) => { match NodeSocketConnected::poll(Pin::new(&mut conn), cx, &self.addr) { - Poll::Ready(Ok(v)) => match v {} - Poll::Pending => break NodeSocket::Connected(conn), + Poll::Ready(Ok(v)) => match v {}, + Poll::Pending => { + break NodeSocket::Connected(conn) + }, Poll::Ready(Err(err)) => { warn!(target: "telemetry", "Disconnected from {}: {:?}", self.addr, err); let timeout = gen_rand_reconnect_delay(); @@ -127,10 +140,16 @@ where TTrans: Clone + Unpin, TTrans::Dial: Unpin, return Poll::Ready(NodeEvent::Disconnected(err)) } } + } NodeSocket::Dialing(mut s) => match Future::poll(Pin::new(&mut s), cx) { Poll::Ready(Ok(sink)) => { debug!(target: "telemetry", "Connected to {}", self.addr); - let conn = NodeSocketConnected { sink, pending: VecDeque::new(), need_flush: false }; + let conn = NodeSocketConnected { + sink, + pending: VecDeque::new(), + need_flush: false, + timeout: None, + }; self.socket = NodeSocket::Connected(conn); return Poll::Ready(NodeEvent::Connected) }, @@ -189,18 +208,15 @@ where TTrans::Output: Sink fn poll( mut self: Pin<&mut Self>, cx: &mut Context, - my_addr: &Multiaddr - ) -> Poll> { - loop { - if let Some(item) = self.pending.pop_front() { - if let Poll::Pending = Sink::poll_ready(Pin::new(&mut self.sink), cx) { - self.pending.push_front(item); - return Poll::Pending - } + my_addr: &Multiaddr, + ) -> Poll>> { + while let Some(item) = self.pending.pop_front() { + if let Poll::Ready(_) = Sink::poll_ready(Pin::new(&mut self.sink), cx) { let item_len = item.len(); if let Err(err) = Sink::start_send(Pin::new(&mut self.sink), item) { - return Poll::Ready(Err(err)) + self.timeout = None; + return Poll::Ready(Err(ConnectionError::Sink(err))) } trace!( target: "telemetry", "Successfully sent {:?} bytes message to {}", @@ -208,28 +224,59 @@ where TTrans::Output: Sink ); self.need_flush = true; - } else if self.need_flush { - match Sink::poll_flush(Pin::new(&mut self.sink), cx) { - Poll::Pending => return Poll::Pending, - Poll::Ready(Err(err)) => return Poll::Ready(Err(err)), - Poll::Ready(Ok(())) => self.need_flush = false, + } else { + self.pending.push_front(item); + if self.timeout.is_none() { + self.timeout = Some(Delay::new(Duration::from_secs(10))); } + break; + } + } - } else { - match Stream::poll_next(Pin::new(&mut self.sink), cx) { - Poll::Ready(Some(Ok(_))) => { - // We poll the telemetry `Stream` because the underlying implementation relies on - // this in order to answer PINGs. - // We don't do anything with incoming messages, however. - }, - Poll::Ready(Some(Err(err))) => { - return Poll::Ready(Err(err)) - }, - Poll::Pending | Poll::Ready(None) => break, + if self.need_flush { + match Sink::poll_flush(Pin::new(&mut self.sink), cx) { + Poll::Pending => { + if self.timeout.is_none() { + self.timeout = Some(Delay::new(Duration::from_secs(10))); + } + }, + Poll::Ready(Err(err)) => { + self.timeout = None; + return Poll::Ready(Err(ConnectionError::Sink(err))) + }, + Poll::Ready(Ok(())) => { + self.timeout = None; + self.need_flush = false; + }, + } + } + + if let Some(timeout) = self.timeout.as_mut() { + match Future::poll(Pin::new(timeout), cx) { + Poll::Pending => {}, + Poll::Ready(Err(err)) => { + self.timeout = None; + warn!(target: "telemetry", "Connection timeout error for {} {:?}", my_addr, err); + } + Poll::Ready(Ok(_)) => { + self.timeout = None; + return Poll::Ready(Err(ConnectionError::Timeout)) } } } + match Stream::poll_next(Pin::new(&mut self.sink), cx) { + Poll::Ready(Some(Ok(_))) => { + // We poll the telemetry `Stream` because the underlying implementation relies on + // this in order to answer PINGs. + // We don't do anything with incoming messages, however. + }, + Poll::Ready(Some(Err(err))) => { + return Poll::Ready(Err(ConnectionError::Sink(err))) + }, + Poll::Pending | Poll::Ready(None) => {}, + } + Poll::Pending } } -- GitLab From d4e22ed5493d434a5a4835fdd1dde71f0c094f8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Fri, 25 Oct 2019 15:18:20 +0200 Subject: [PATCH 106/167] Adds function `to_substrate_wasm_fn_return_value` (#3905) * Adds function `to_substrate_wasm_fn_return_value` Instead of replicating this piece of code over and over again, just move it to a function that does it. * Feedback * Comment --- Cargo.lock | 62 +++++++++++++++++-- core/client/src/runtime_api.rs | 3 + core/primitives/src/lib.rs | 22 +++++++ core/primitives/src/testing.rs | 19 +----- core/sr-api-macros/Cargo.toml | 11 +++- core/sr-api-macros/src/impl_runtime_apis.rs | 14 ++--- core/sr-api-macros/tests/decl_and_impl.rs | 7 --- .../ui/impl_incorrect_method_signature.rs | 16 ++++- .../ui/impl_incorrect_method_signature.stderr | 34 +++++++++- .../ui/impl_two_traits_with_same_name.rs | 2 + .../ui/impl_two_traits_with_same_name.stderr | 28 +++------ ...ype_reference_in_impl_runtime_apis_call.rs | 16 ++++- ...reference_in_impl_runtime_apis_call.stderr | 25 ++++++-- 13 files changed, 187 insertions(+), 72 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c3c3e66c12..f169f7b24e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -539,6 +539,30 @@ dependencies = [ "walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "criterion" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", + "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", + "criterion-plot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "csv 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_os 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_xoshiro 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", + "tinytemplate 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "criterion-plot" version = "0.3.1" @@ -549,6 +573,15 @@ dependencies = [ "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "criterion-plot" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "crossbeam-channel" version = "0.3.9" @@ -3318,6 +3351,15 @@ dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rand_os" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rand_pcg" version = "0.1.2" @@ -3344,6 +3386,14 @@ dependencies = [ "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rand_xoshiro" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rayon" version = "1.2.0" @@ -3491,7 +3541,7 @@ dependencies = [ [[package]] name = "rustversion" -version = "0.1.4" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3825,12 +3875,12 @@ name = "sr-api-macros" version = "2.0.0" dependencies = [ "blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", - "criterion 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "criterion 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro-crate 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "rustversion 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "rustversion 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", "sr-version 2.0.0", "substrate-client 2.0.0", @@ -6829,7 +6879,9 @@ dependencies = [ "checksum core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b" "checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" "checksum criterion 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "0363053954f3e679645fc443321ca128b7b950a6fe288cf5f9335cc22ee58394" +"checksum criterion 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "938703e165481c8d612ea3479ac8342e5615185db37765162e762ec3523e2fc6" "checksum criterion-plot 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "76f9212ddf2f4a9eb2d401635190600656a1f88a932ef53d06e7fa4c7e02fb8e" +"checksum criterion-plot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "eccdc6ce8bbe352ca89025bee672aa6d24f4eb8c53e3a8b5d1bc58011da072a2" "checksum crossbeam-channel 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c8ec7fcd21571dc78f96cc96243cab8d8f035247c3efd16c687be154c3fa9efa" "checksum crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b18cd2e169ad86297e6bc0ad9aa679aee9daa4f19e8163860faf7c164e4f5a71" "checksum crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fedcd6772e37f3da2a9af9bf12ebe046c0dfe657992377b4df982a2b54cd37a9" @@ -7084,9 +7136,11 @@ dependencies = [ "checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" "checksum rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" "checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" +"checksum rand_os 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a788ae3edb696cfcba1c19bfd388cc4b8c21f8a408432b199c072825084da58a" "checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" "checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" "checksum rand_xoshiro 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "03b418169fb9c46533f326efd6eed2576699c44ca92d3052a066214a8d828929" +"checksum rand_xoshiro 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0e18c91676f670f6f0312764c759405f13afb98d5d73819840cf72a518487bff" "checksum rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "83a27732a533a1be0a0035a111fe76db89ad312f6f0347004c220c57f209a123" "checksum rayon-core 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "98dcf634205083b17d0861252431eb2acbfb698ab7478a2d20de07954f47ec7b" "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" @@ -7104,7 +7158,7 @@ dependencies = [ "checksum rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "403bb3a286107a04825a5f82e1270acc1e14028d3d554d7a1e08914549575ab8" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum rustls 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f271e3552cd835fa28c541c34a7e8fdd8cdff09d77fe4eb8f6c42e87a11b096e" -"checksum rustversion 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b48139cfc215c6cc70d43c6c555a59e723c3b5adb26a4cfa09f815a5ae5871e8" +"checksum rustversion 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c48f91977f4ef3be5358c15d131d3f663f6b4d7a112555bf3bf52ad23b6659e5" "checksum rw-stream-sink 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9cbe61c20455d3015b2bb7be39e1872310283b8e5a52f5b242b0ac7581fe78" "checksum ryu 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "19d2271fa48eaf61e53cc88b4ad9adcbafa2d512c531e7fadb6dc11a4d3656c5" "checksum safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7f7bf422d23a88c16d5090d455f182bc99c60af4df6a345c63428acf5129e347" diff --git a/core/client/src/runtime_api.rs b/core/client/src/runtime_api.rs index a5700951e9..68b49e5910 100644 --- a/core/client/src/runtime_api.rs +++ b/core/client/src/runtime_api.rs @@ -23,6 +23,9 @@ pub use state_machine::OverlayedChanges; #[cfg(feature = "std")] pub use primitives::NativeOrEncoded; #[doc(hidden)] +#[cfg(not(feature = "std"))] +pub use primitives::to_substrate_wasm_fn_return_value; +#[doc(hidden)] pub use sr_primitives::{ traits::{ Block as BlockT, GetNodeBlockType, GetRuntimeBlockType, diff --git a/core/primitives/src/lib.rs b/core/primitives/src/lib.rs index d1b42766a0..02f28c797c 100644 --- a/core/primitives/src/lib.rs +++ b/core/primitives/src/lib.rs @@ -287,3 +287,25 @@ impl From for log::Level { } } } + +/// Encodes the given value into a buffer and returns the pointer and the length as a single `u64`. +/// +/// When Substrate calls into Wasm it expects a fixed signature for functions exported +/// from the Wasm blob. The return value of this signature is always a `u64`. +/// This `u64` stores the pointer to the encoded return value and the length of this encoded value. +/// The low `32bits` are reserved for the pointer, followed by `32bit` for the length. +#[cfg(not(feature = "std"))] +pub fn to_substrate_wasm_fn_return_value(value: &impl Encode) -> u64 { + let encoded = value.encode(); + + let ptr = encoded.as_ptr() as u64; + let length = encoded.len() as u64; + let res = ptr | (length << 32); + + // Leak the output vector to avoid it being freed. + // This is fine in a WASM context since the heap + // will be discarded after the call. + rstd::mem::forget(encoded); + + res +} diff --git a/core/primitives/src/testing.rs b/core/primitives/src/testing.rs index 92a09ff044..e5d301008e 100644 --- a/core/primitives/src/testing.rs +++ b/core/primitives/src/testing.rs @@ -196,15 +196,7 @@ macro_rules! wasm_export_functions { $( $fn_impl )* } - // We need to return *something* - let output = Vec::::new(); - let res = output.as_ptr() as u64 + ((output.len() as u64) << 32); - - // Leak the output vector to avoid it being freed. - // This is fine in a WASM context since the heap - // will be discarded after the call. - $crate::rstd::mem::forget(output); - res + $crate::to_substrate_wasm_fn_return_value(&()) } }; (@IMPL @@ -232,14 +224,7 @@ macro_rules! wasm_export_functions { $( $fn_impl )* }; - let output = $crate::Encode::encode(&output); - let res = output.as_ptr() as u64 + ((output.len() as u64) << 32); - - // Leak the output vector to avoid it being freed. - // This is fine in a WASM context since the heap - // will be discarded after the call. - $crate::rstd::mem::forget(output); - res + $crate::to_substrate_wasm_fn_return_value(&output) } }; } diff --git a/core/sr-api-macros/Cargo.toml b/core/sr-api-macros/Cargo.toml index 6f02e30409..022536136b 100644 --- a/core/sr-api-macros/Cargo.toml +++ b/core/sr-api-macros/Cargo.toml @@ -21,12 +21,17 @@ state_machine = { package = "substrate-state-machine", path = "../state-machine" sr-primitives = { path = "../sr-primitives" } sr-version = { path = "../sr-version" } primitives = { package = "substrate-primitives", path = "../primitives" } -criterion = "0.2.11" +criterion = "0.3.0" consensus_common = { package = "substrate-consensus-common", path = "../consensus/common" } codec = { package = "parity-scale-codec", version = "1.0.0" } -trybuild = "1.0.14" -rustversion = "0.1.4" +trybuild = "1.0.17" +rustversion = "1.0.0" [[bench]] name = "bench" harness = false + +# We actually don't need the `std` feature in this crate, but the tests require it. +[features] +default = [ "std" ] +std = [] diff --git a/core/sr-api-macros/src/impl_runtime_apis.rs b/core/sr-api-macros/src/impl_runtime_apis.rs index fb154aa112..28eb5c6072 100644 --- a/core/sr-api-macros/src/impl_runtime_apis.rs +++ b/core/sr-api-macros/src/impl_runtime_apis.rs @@ -83,8 +83,7 @@ fn generate_impl_call( )* #[allow(deprecated)] - let output = <#runtime as #impl_trait>::#fn_name(#( #pborrow #pnames2 ),*); - #c::runtime_api::Encode::encode(&output) + <#runtime as #impl_trait>::#fn_name(#( #pborrow #pnames2 ),*) ) ) } @@ -175,11 +174,12 @@ fn generate_impl_calls( /// Generate the dispatch function that is used in native to call into the runtime. fn generate_dispatch_function(impls: &[ItemImpl]) -> Result { let data = Ident::new("data", Span::call_site()); + let c = generate_crate_access(HIDDEN_INCLUDES_ID); let impl_calls = generate_impl_calls(impls, &data)? .into_iter() .map(|(trait_, fn_name, impl_)| { let name = prefix_function_with_trait(&trait_, &fn_name); - quote!( #name => Some({ #impl_ }), ) + quote!( #name => Some(#c::runtime_api::Encode::encode(&{ #impl_ })), ) }); Ok(quote!( @@ -218,13 +218,7 @@ fn generate_wasm_interface(impls: &[ItemImpl]) -> Result { }; let output = { #impl_ }; - let res = output.as_ptr() as u64 + ((output.len() as u64) << 32); - - // Leak the output vector to avoid it being freed. - // This is fine in a WASM context since the heap - // will be discarded after the call. - #c::runtime_api::mem::forget(output); - res + #c::runtime_api::to_substrate_wasm_fn_return_value(&output) } ) }); diff --git a/core/sr-api-macros/tests/decl_and_impl.rs b/core/sr-api-macros/tests/decl_and_impl.rs index 36091d1f85..a539d83822 100644 --- a/core/sr-api-macros/tests/decl_and_impl.rs +++ b/core/sr-api-macros/tests/decl_and_impl.rs @@ -93,13 +93,6 @@ fn test_client_side_function_signature() { RuntimeApiImpl::::same_name_before_version_2; } -#[test] -fn test_runtime_side_function_signature() { - let _api_same_name: fn(input_data: *mut u8, input_len: usize) -> u64 = api::Api_same_name; - let _api_with_version_same_name: fn(input_data: *mut u8, input_len: usize) -> u64 = - api::ApiWithCustomVersion_same_name; -} - #[test] fn check_runtime_api_info() { assert_eq!(&Api::::ID, &runtime_decl_for_Api::ID); diff --git a/core/sr-api-macros/tests/ui/impl_incorrect_method_signature.rs b/core/sr-api-macros/tests/ui/impl_incorrect_method_signature.rs index 774d017c19..b85431f3ba 100644 --- a/core/sr-api-macros/tests/ui/impl_incorrect_method_signature.rs +++ b/core/sr-api-macros/tests/ui/impl_incorrect_method_signature.rs @@ -1,6 +1,6 @@ -use sr_primitives::traits::GetNodeBlockType; +use sr_primitives::traits::{GetNodeBlockType, Block as BlockT}; use test_client::runtime::Block; -use client::{decl_runtime_apis, impl_runtime_apis}; +use client::{decl_runtime_apis, impl_runtime_apis, runtime_api}; /// The declaration of the `Runtime` type and the implementation of the `GetNodeBlockType` /// trait are done by the `construct_runtime!` macro in a real runtime. @@ -19,6 +19,18 @@ impl_runtime_apis! { impl self::Api for Runtime { fn test(data: String) {} } + + impl runtime_api::Core for Runtime { + fn version() -> runtime_api::RuntimeVersion { + unimplemented!() + } + fn execute_block(_: Block) { + unimplemented!() + } + fn initialize_block(_: &::Header) { + unimplemented!() + } + } } fn main() {} diff --git a/core/sr-api-macros/tests/ui/impl_incorrect_method_signature.stderr b/core/sr-api-macros/tests/ui/impl_incorrect_method_signature.stderr index 15434a52ba..025ca60c48 100644 --- a/core/sr-api-macros/tests/ui/impl_incorrect_method_signature.stderr +++ b/core/sr-api-macros/tests/ui/impl_incorrect_method_signature.stderr @@ -10,6 +10,37 @@ error[E0053]: method `test` has an incompatible type for trait = note: expected type `fn(u64)` found type `fn(std::string::String)` +error[E0053]: method `Api_test_runtime_api_impl` has an incompatible type for trait + --> $DIR/impl_incorrect_method_signature.rs:18:1 + | +12 | / decl_runtime_apis! { +13 | | pub trait Api { +14 | | fn test(data: u64); +15 | | } +16 | | } + | |_- type in trait +17 | +18 | impl_runtime_apis! { + | ^^^^^^^^^^^^^^^^^^ expected u64, found struct `std::string::String` + | + = note: expected type `fn(&RuntimeApiImpl, &sr_primitives::generic::block::BlockId, substrate_test_runtime::Extrinsic>>, sr_api_hidden_includes_DECL_RUNTIME_APIS::sr_api_client::runtime_api::ExecutionContext, std::option::Option, std::vec::Vec) -> std::result::Result, sr_api_hidden_includes_DECL_RUNTIME_APIS::sr_api_client::error::Error>` + found type `fn(&RuntimeApiImpl, &sr_primitives::generic::block::BlockId, substrate_test_runtime::Extrinsic>>, sr_api_hidden_includes_DECL_RUNTIME_APIS::sr_api_client::runtime_api::ExecutionContext, std::option::Option, std::vec::Vec) -> std::result::Result, sr_api_hidden_includes_DECL_RUNTIME_APIS::sr_api_client::error::Error>` + +error[E0308]: mismatched types + --> $DIR/impl_incorrect_method_signature.rs:18:1 + | +18 | / impl_runtime_apis! { +19 | | impl self::Api for Runtime { +20 | | fn test(data: String) {} +21 | | } +... | +33 | | } +34 | | } + | |_^ expected u64, found struct `std::string::String` + | + = note: expected type `u64` + found type `std::string::String` + error[E0308]: mismatched types --> $DIR/impl_incorrect_method_signature.rs:20:11 | @@ -18,6 +49,3 @@ error[E0308]: mismatched types | = note: expected type `u64` found type `std::string::String` - -Some errors have detailed explanations: E0053, E0308. -For more information about an error, try `rustc --explain E0053`. diff --git a/core/sr-api-macros/tests/ui/impl_two_traits_with_same_name.rs b/core/sr-api-macros/tests/ui/impl_two_traits_with_same_name.rs index acca97a73d..1664bec577 100644 --- a/core/sr-api-macros/tests/ui/impl_two_traits_with_same_name.rs +++ b/core/sr-api-macros/tests/ui/impl_two_traits_with_same_name.rs @@ -16,6 +16,8 @@ decl_runtime_apis! { } mod second { + use super::*; + decl_runtime_apis! { pub trait Api { fn test2(data: u64); diff --git a/core/sr-api-macros/tests/ui/impl_two_traits_with_same_name.stderr b/core/sr-api-macros/tests/ui/impl_two_traits_with_same_name.stderr index 355db2864b..4c37b6b716 100644 --- a/core/sr-api-macros/tests/ui/impl_two_traits_with_same_name.stderr +++ b/core/sr-api-macros/tests/ui/impl_two_traits_with_same_name.stderr @@ -1,25 +1,17 @@ error: Two traits with the same name detected! The trait name is used to generate its ID. Please rename one trait at the declaration! - --> $DIR/impl_two_traits_with_same_name.rs:31:15 + --> $DIR/impl_two_traits_with_same_name.rs:33:15 | -31 | impl second::Api for Runtime { +33 | impl second::Api for Runtime { | ^^^ -error: cannot find macro `decl_runtime_apis!` in this scope - --> $DIR/impl_two_traits_with_same_name.rs:19:2 +error[E0277]: the trait bound `RuntimeApiImpl: sr_api_hidden_includes_DECL_RUNTIME_APIS::sr_api_client::runtime_api::Core, substrate_test_runtime::Extrinsic>>` is not satisfied + --> $DIR/impl_two_traits_with_same_name.rs:29:7 | -19 | decl_runtime_apis! { - | ^^^^^^^^^^^^^^^^^ +29 | impl self::Api for Runtime { + | ^^^^^^^^^^^^^^^^ the trait `sr_api_hidden_includes_DECL_RUNTIME_APIS::sr_api_client::runtime_api::Core, substrate_test_runtime::Extrinsic>>` is not implemented for `RuntimeApiImpl` -error[E0433]: failed to resolve: could not find `runtime_decl_for_Api` in `second` - --> $DIR/impl_two_traits_with_same_name.rs:26:1 +error[E0277]: the trait bound `RuntimeApiImpl: sr_api_hidden_includes_DECL_RUNTIME_APIS::sr_api_client::runtime_api::Core, substrate_test_runtime::Extrinsic>>` is not satisfied + --> $DIR/impl_two_traits_with_same_name.rs:33:7 | -26 | / impl_runtime_apis! { -27 | | impl self::Api for Runtime { -28 | | fn test(data: u64) {} -29 | | } -... | -33 | | } -34 | | } - | |_^ could not find `runtime_decl_for_Api` in `second` - -For more information about this error, try `rustc --explain E0433`. +33 | impl second::Api for Runtime { + | ^^^^^^^^^^^^^^^^^^ the trait `sr_api_hidden_includes_DECL_RUNTIME_APIS::sr_api_client::runtime_api::Core, substrate_test_runtime::Extrinsic>>` is not implemented for `RuntimeApiImpl` diff --git a/core/sr-api-macros/tests/ui/type_reference_in_impl_runtime_apis_call.rs b/core/sr-api-macros/tests/ui/type_reference_in_impl_runtime_apis_call.rs index 0e7dc56951..20f114c6bb 100644 --- a/core/sr-api-macros/tests/ui/type_reference_in_impl_runtime_apis_call.rs +++ b/core/sr-api-macros/tests/ui/type_reference_in_impl_runtime_apis_call.rs @@ -1,6 +1,6 @@ -use sr_primitives::traits::GetNodeBlockType; +use sr_primitives::traits::{GetNodeBlockType, Block as BlockT}; use test_client::runtime::Block; -use client::{decl_runtime_apis, impl_runtime_apis}; +use client::{decl_runtime_apis, impl_runtime_apis, runtime_api}; /// The declaration of the `Runtime` type and the implementation of the `GetNodeBlockType` /// trait are done by the `construct_runtime!` macro in a real runtime. @@ -21,6 +21,18 @@ impl_runtime_apis! { unimplemented!() } } + + impl runtime_api::Core for Runtime { + fn version() -> runtime_api::RuntimeVersion { + unimplemented!() + } + fn execute_block(_: Block) { + unimplemented!() + } + fn initialize_block(_: &::Header) { + unimplemented!() + } + } } fn main() {} diff --git a/core/sr-api-macros/tests/ui/type_reference_in_impl_runtime_apis_call.stderr b/core/sr-api-macros/tests/ui/type_reference_in_impl_runtime_apis_call.stderr index 9bfc04c8db..f3abaddd6e 100644 --- a/core/sr-api-macros/tests/ui/type_reference_in_impl_runtime_apis_call.stderr +++ b/core/sr-api-macros/tests/ui/type_reference_in_impl_runtime_apis_call.stderr @@ -10,6 +10,22 @@ error[E0053]: method `test` has an incompatible type for trait = note: expected type `fn(u64)` found type `fn(&u64)` +error[E0053]: method `Api_test_runtime_api_impl` has an incompatible type for trait + --> $DIR/type_reference_in_impl_runtime_apis_call.rs:18:1 + | +12 | / decl_runtime_apis! { +13 | | pub trait Api { +14 | | fn test(data: u64); +15 | | } +16 | | } + | |_- type in trait +17 | +18 | impl_runtime_apis! { + | ^^^^^^^^^^^^^^^^^^ expected u64, found &u64 + | + = note: expected type `fn(&RuntimeApiImpl, &sr_primitives::generic::block::BlockId, substrate_test_runtime::Extrinsic>>, sr_api_hidden_includes_DECL_RUNTIME_APIS::sr_api_client::runtime_api::ExecutionContext, std::option::Option, std::vec::Vec) -> std::result::Result, sr_api_hidden_includes_DECL_RUNTIME_APIS::sr_api_client::error::Error>` + found type `fn(&RuntimeApiImpl, &sr_primitives::generic::block::BlockId, substrate_test_runtime::Extrinsic>>, sr_api_hidden_includes_DECL_RUNTIME_APIS::sr_api_client::runtime_api::ExecutionContext, std::option::Option<&u64>, std::vec::Vec) -> std::result::Result, sr_api_hidden_includes_DECL_RUNTIME_APIS::sr_api_client::error::Error>` + error[E0308]: mismatched types --> $DIR/type_reference_in_impl_runtime_apis_call.rs:18:1 | @@ -17,13 +33,10 @@ error[E0308]: mismatched types 19 | | impl self::Api for Runtime { 20 | | fn test(data: &u64) { 21 | | unimplemented!() -22 | | } -23 | | } -24 | | } +... | +35 | | } +36 | | } | |_^ expected u64, found &u64 | = note: expected type `u64` found type `&u64` - -Some errors have detailed explanations: E0053, E0308. -For more information about an error, try `rustc --explain E0053`. -- GitLab From 74fd1cf1c2d7c67a2fff31abe79d2b7c36481981 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 25 Oct 2019 15:19:36 +0200 Subject: [PATCH 107/167] Emergency build fix on previous PR. --- srml/staking/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/srml/staking/src/lib.rs b/srml/staking/src/lib.rs index e5c0277f57..f6d123bd13 100644 --- a/srml/staking/src/lib.rs +++ b/srml/staking/src/lib.rs @@ -995,7 +995,7 @@ decl_module! { } /// Force a current staker to become completely unstaked, immediately. - #[weight = sr_primitives::SimpleDispatchInfo::FreeOperational] + #[weight = SimpleDispatchInfo::FreeOperational] fn force_unstake(origin, stash: T::AccountId) { ensure_root(origin)?; -- GitLab From ee4d5dd70b68a64faacca379b00b73f2cfee6074 Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Fri, 25 Oct 2019 18:04:32 +0200 Subject: [PATCH 108/167] Correct docs. (#3919) --- srml/democracy/src/lib.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/srml/democracy/src/lib.rs b/srml/democracy/src/lib.rs index f1f10a7319..545666e493 100644 --- a/srml/democracy/src/lib.rs +++ b/srml/democracy/src/lib.rs @@ -486,9 +486,10 @@ decl_module! { /// but it is not a majority-carries referendum then it fails. /// /// - `proposal_hash`: The hash of the current external proposal. - /// - `voting_period`: The period that is allowed for voting on this proposal. + /// - `voting_period`: The period that is allowed for voting on this proposal. Increased to + /// `EmergencyVotingPeriod` if too low. /// - `delay`: The number of block after voting has ended in approval and this should be - /// enacted. Increased to `EmergencyVotingPeriod` if too low. + /// enacted. This doesn't have a minimum amount. #[weight = SimpleDispatchInfo::FixedNormal(200_000)] fn fast_track(origin, proposal_hash: T::Hash, -- GitLab From a7fe15eda21c5e44ee50e6ccb6a46b0411624557 Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Sun, 27 Oct 2019 12:53:41 +0100 Subject: [PATCH 109/167] runtime: Account nicknames (#3930) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add Nicknames module for accounts. * Integrate into node. * Fix build * Update srml/nicks/src/lib.rs Co-Authored-By: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Bump runtime * Improve weight docs * Docs. * Apply suggestions from code review Co-Authored-By: Bastian Köcher --- Cargo.lock | 16 ++ Cargo.toml | 1 + node/runtime/Cargo.toml | 2 + node/runtime/src/lib.rs | 23 ++- srml/nicks/Cargo.toml | 30 ++++ srml/nicks/src/lib.rs | 331 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 400 insertions(+), 3 deletions(-) create mode 100644 srml/nicks/Cargo.toml create mode 100644 srml/nicks/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index f169f7b24e..1796a68b4b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2525,6 +2525,7 @@ dependencies = [ "srml-im-online 0.1.0", "srml-indices 2.0.0", "srml-membership 2.0.0", + "srml-nicks 2.0.0", "srml-offences 1.0.0", "srml-randomness-collective-flip 2.0.0", "srml-session 2.0.0", @@ -4350,6 +4351,21 @@ dependencies = [ "substrate-primitives 2.0.0", ] +[[package]] +name = "srml-nicks" +version = "2.0.0" +dependencies = [ + "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-io 2.0.0", + "sr-primitives 2.0.0", + "sr-std 2.0.0", + "srml-balances 2.0.0", + "srml-support 2.0.0", + "srml-system 2.0.0", + "substrate-primitives 2.0.0", +] + [[package]] name = "srml-offences" version = "1.0.0" diff --git a/Cargo.toml b/Cargo.toml index 8d3d04c4d0..2c1e361fc9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -96,6 +96,7 @@ members = [ "srml/indices", "srml/membership", "srml/metadata", + "srml/nicks", "srml/offences", "srml/randomness-collective-flip", "srml/scored-pool", diff --git a/node/runtime/Cargo.toml b/node/runtime/Cargo.toml index 5a6a2b6772..9169f26dc3 100644 --- a/node/runtime/Cargo.toml +++ b/node/runtime/Cargo.toml @@ -40,6 +40,7 @@ grandpa = { package = "srml-grandpa", path = "../../srml/grandpa", default-featu im-online = { package = "srml-im-online", path = "../../srml/im-online", default-features = false } indices = { package = "srml-indices", path = "../../srml/indices", default-features = false } membership = { package = "srml-membership", path = "../../srml/membership", default-features = false } +nicks = { package = "srml-nicks", path = "../../srml/nicks", default-features = false } offences = { package = "srml-offences", path = "../../srml/offences", default-features = false } randomness-collective-flip = { package = "srml-randomness-collective-flip", path = "../../srml/randomness-collective-flip", default-features = false } session = { package = "srml-session", path = "../../srml/session", default-features = false, features = ["historical"] } @@ -82,6 +83,7 @@ std = [ "im-online/std", "indices/std", "membership/std", + "nicks/std", "node-primitives/std", "offchain-primitives/std", "offences/std", diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index 2c02a8be17..fe97f806fc 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -83,8 +83,8 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // and set impl_version to equal spec_version. If only runtime // implementation changes and behavior does not, then leave spec_version as // is and increment impl_version. - spec_version: 185, - impl_version: 185, + spec_version: 186, + impl_version: 186, apis: RUNTIME_API_VERSIONS, }; @@ -440,7 +440,7 @@ impl offences::Trait for Runtime { } impl authority_discovery::Trait for Runtime { - type AuthorityId = BabeId; + type AuthorityId = BabeId; } impl grandpa::Trait for Runtime { @@ -458,6 +458,22 @@ impl finality_tracker::Trait for Runtime { type ReportLatency = ReportLatency; } +parameter_types! { + pub const ReservationFee: Balance = 1 * DOLLARS; + pub const MinLength: usize = 3; + pub const MaxLength: usize = 16; +} + +impl nicks::Trait for Runtime { + type Event = Event; + type Currency = Balances; + type ReservationFee = ReservationFee; + type Slashed = Treasury; + type KillOrigin = collective::EnsureMember; + type MinLength = MinLength; + type MaxLength = MaxLength; +} + impl system::offchain::CreateTransaction for Runtime { type Public = ::Signer; type Signature = Signature; @@ -518,6 +534,7 @@ construct_runtime!( AuthorityDiscovery: authority_discovery::{Module, Call, Config}, Offences: offences::{Module, Call, Storage, Event}, RandomnessCollectiveFlip: randomness_collective_flip::{Module, Call, Storage}, + Nicks: nicks::{Module, Call, Storage, Event}, } ); diff --git a/srml/nicks/Cargo.toml b/srml/nicks/Cargo.toml new file mode 100644 index 0000000000..4b8fabe9ef --- /dev/null +++ b/srml/nicks/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "srml-nicks" +version = "2.0.0" +authors = ["Parity Technologies "] +edition = "2018" + +[dependencies] +serde = { version = "1.0.101", optional = true } +codec = { package = "parity-scale-codec", version = "1.0.0", default-features = false, features = ["derive"] } +rstd = { package = "sr-std", path = "../../core/sr-std", default-features = false } +runtime-io = { package = "sr-io", path = "../../core/sr-io", default-features = false } +sr-primitives = { path = "../../core/sr-primitives", default-features = false } +support = { package = "srml-support", path = "../support", default-features = false } +system = { package = "srml-system", path = "../system", default-features = false } + +[dev-dependencies] +primitives = { package = "substrate-primitives", path = "../../core/primitives" } +balances = { package = "srml-balances", path = "../balances", default-features = false } + +[features] +default = ["std"] +std = [ + "serde", + "codec/std", + "rstd/std", + "runtime-io/std", + "sr-primitives/std", + "support/std", + "system/std", +] diff --git a/srml/nicks/src/lib.rs b/srml/nicks/src/lib.rs new file mode 100644 index 0000000000..894f7100f8 --- /dev/null +++ b/srml/nicks/src/lib.rs @@ -0,0 +1,331 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +//! # Nicks Module +//! +//! - [`nicks::Trait`](./trait.Trait.html) +//! - [`Call`](./enum.Call.html) +//! +//! ## Overview +//! +//! Nicks is a trivial module for keeping track of account names on-chain. It makes no effort to +//! create a name hierarchy, be a DNS replacement or provide reverse lookups. +//! +//! ## Interface +//! +//! ### Dispatchable Functions +//! +//! * `set_name` - Set the associated name of an account; a small deposit is reserved if not already +//! taken. +//! * `clear_name` - Remove an account's associated name; the deposit is returned. +//! * `kill_name` - Forcibly remove the associated name; the deposit is lost. +//! +//! [`Call`]: ./enum.Call.html +//! [`Trait`]: ./trait.Trait.html + +#![cfg_attr(not(feature = "std"), no_std)] + +use rstd::prelude::*; +use sr_primitives::{ + traits::{StaticLookup, EnsureOrigin}, weights::SimpleDispatchInfo, +}; +use support::{ + decl_module, decl_event, decl_storage, ensure, traits::{ + Currency, ReservableCurrency, OnUnbalanced, Get + }, +}; +use system::{ensure_signed, ensure_root}; + +type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; +type NegativeImbalanceOf = <::Currency as Currency<::AccountId>>::NegativeImbalance; + +pub trait Trait: system::Trait { + /// The overarching event type. + type Event: From> + Into<::Event>; + + /// The currency trait. + type Currency: ReservableCurrency; + + /// Reservation fee. + type ReservationFee: Get>; + + /// What to do with slashed funds. + type Slashed: OnUnbalanced>; + + /// The origin which may forcibly remove a name. Root can always do this. + type KillOrigin: EnsureOrigin; + + /// The minimum length a name may be. + type MinLength: Get; + + /// The maximum length a name may be. + type MaxLength: Get; +} + +decl_storage! { + trait Store for Module as Sudo { + /// The lookup table for names. + NameOf: map T::AccountId => Option<(Vec, BalanceOf)>; + } +} + +decl_event!( + pub enum Event where AccountId = ::AccountId, Balance = BalanceOf { + /// A name was set. + NameSet(AccountId), + /// A name was changed. + NameChanged(AccountId), + /// A name was cleared, and the given balance returned. + NameCleared(AccountId, Balance), + /// A name was removed and the given balance slashed. + NameKilled(AccountId, Balance), + } +); + +decl_module! { + // Simple declaration of the `Module` type. Lets the macro know what it's working on. + pub struct Module for enum Call where origin: T::Origin { + fn deposit_event() = default; + + /// Set an account's name. The name should be a UTF-8-encoded string by convention, though + /// we don't check it. + /// + /// The name may not be more than `T::MaxLength` bytes, nor less than `T::MinLength` bytes. + /// + /// If the account doesn't already have a name, then a fee of `ReservationFee` is reserved + /// in the account. + /// + /// The dispatch origin for this call must be _Signed_. + /// + /// # + /// - O(1). + /// - At most one balance operation. + /// - One storage read/write. + /// - One event. + /// # + #[weight = SimpleDispatchInfo::FixedNormal(50_000)] + fn set_name(origin, name: Vec) { + let sender = ensure_signed(origin)?; + + ensure!(name.len() >= T::MinLength::get(), "Name too short"); + ensure!(name.len() <= T::MaxLength::get(), "Name too long"); + + let deposit = if let Some((_, deposit)) = >::get(&sender) { + Self::deposit_event(RawEvent::NameSet(sender.clone())); + deposit + } else { + let deposit = T::ReservationFee::get(); + T::Currency::reserve(&sender, deposit.clone())?; + Self::deposit_event(RawEvent::NameChanged(sender.clone())); + deposit + }; + + >::insert(&sender, (name, deposit)); + } + + /// Clear an account's name and return the deposit. Fails if the account was not named. + /// + /// The dispatch origin for this call must be _Signed_. + /// + /// # + /// - O(1). + /// - One balance operation. + /// - One storage read/write. + /// - One event. + /// # + fn clear_name(origin) { + let sender = ensure_signed(origin)?; + + let deposit = >::take(&sender).ok_or("Not named")?.1; + + let _ = T::Currency::unreserve(&sender, deposit.clone()); + + Self::deposit_event(RawEvent::NameCleared(sender, deposit)); + } + + /// Remove an account's name and take charge of the deposit. + /// + /// Fails if `who` has not been named. The deposit is dealt with through `T::Slashed` + /// imbalance handler. + /// + /// The dispatch origin for this call must be _Root_ or match `T::KillOrigin`. + /// + /// # + /// - O(1). + /// - One unbalanced handler (probably a balance transfer) + /// - One storage read/write. + /// - One event. + /// # + #[weight = SimpleDispatchInfo::FreeOperational] + fn kill_name(origin, target: ::Source) { + T::KillOrigin::try_origin(origin) + .map(|_| ()) + .or_else(ensure_root) + .map_err(|_| "bad origin")?; + + // Figure out who we're meant to be clearing. + let target = T::Lookup::lookup(target)?; + // Grab their deposit (and check that they have one). + let deposit = >::take(&target).ok_or("Not named")?.1; + // Slash their deposit from them. + T::Slashed::on_unbalanced(T::Currency::slash_reserved(&target, deposit.clone()).0); + + Self::deposit_event(RawEvent::NameKilled(target, deposit)); + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + use support::{assert_ok, assert_noop, impl_outer_origin, parameter_types}; + use primitives::H256; + use system::EnsureSignedBy; + // The testing primitives are very useful for avoiding having to work with signatures + // or public keys. `u64` is used as the `AccountId` and no `Signature`s are required. + use sr_primitives::{ + Perbill, testing::Header, traits::{BlakeTwo256, IdentityLookup}, + }; + + impl_outer_origin! { + pub enum Origin for Test {} + } + + // For testing the module, we construct most of a mock runtime. This means + // first constructing a configuration type (`Test`) which `impl`s each of the + // configuration traits of modules we want to use. + #[derive(Clone, Eq, PartialEq)] + pub struct Test; + parameter_types! { + pub const BlockHashCount: u64 = 250; + pub const MaximumBlockWeight: u32 = 1024; + pub const MaximumBlockLength: u32 = 2 * 1024; + pub const AvailableBlockRatio: Perbill = Perbill::one(); + } + impl system::Trait for Test { + type Origin = Origin; + type Index = u64; + type BlockNumber = u64; + type Hash = H256; + type Call = (); + type Hashing = BlakeTwo256; + type AccountId = u64; + type Lookup = IdentityLookup; + type Header = Header; + type Event = (); + type BlockHashCount = BlockHashCount; + type MaximumBlockWeight = MaximumBlockWeight; + type MaximumBlockLength = MaximumBlockLength; + type AvailableBlockRatio = AvailableBlockRatio; + type Version = (); + } + parameter_types! { + pub const ExistentialDeposit: u64 = 0; + pub const TransferFee: u64 = 0; + pub const CreationFee: u64 = 0; + } + impl balances::Trait for Test { + type Balance = u64; + type OnFreeBalanceZero = (); + type OnNewAccount = (); + type Event = (); + type TransferPayment = (); + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type TransferFee = TransferFee; + type CreationFee = CreationFee; + } + parameter_types! { + pub const ReservationFee: u64 = 2; + pub const MinLength: usize = 3; + pub const MaxLength: usize = 16; + pub const One: u64 = 1; + } + impl Trait for Test { + type Event = (); + type Currency = Balances; + type ReservationFee = ReservationFee; + type Slashed = (); + type KillOrigin = EnsureSignedBy; + type MinLength = MinLength; + type MaxLength = MaxLength; + } + type Balances = balances::Module; + type Nicks = Module; + + // This function basically just builds a genesis storage key/value store according to + // our desired mockup. + fn new_test_ext() -> runtime_io::TestExternalities { + let mut t = system::GenesisConfig::default().build_storage::().unwrap(); + // We use default for brevity, but you can configure as desired if needed. + balances::GenesisConfig:: { + balances: vec![ + (1, 10), + (2, 10), + ], + vesting: vec![], + }.assimilate_storage(&mut t).unwrap(); + t.into() + } + + #[test] + fn kill_names_should_work() { + new_test_ext().execute_with(|| { + assert_ok!(Nicks::set_name(Origin::signed(2), b"Dave".to_vec())); + assert_eq!(Balances::total_balance(&2), 10); + assert_ok!(Nicks::kill_name(Origin::signed(1), 2)); + assert_eq!(Balances::total_balance(&2), 8); + assert_eq!(>::get(2), None); + }); + } + + #[test] + fn normal_operation_should_work() { + new_test_ext().execute_with(|| { + assert_ok!(Nicks::set_name(Origin::signed(1), b"Gav".to_vec())); + assert_eq!(Balances::reserved_balance(&1), 2); + assert_eq!(Balances::free_balance(&1), 8); + assert_eq!(>::get(1).unwrap().0, b"Gav".to_vec()); + + assert_ok!(Nicks::set_name(Origin::signed(1), b"Gavin".to_vec())); + assert_eq!(Balances::reserved_balance(&1), 2); + assert_eq!(Balances::free_balance(&1), 8); + assert_eq!(>::get(1).unwrap().0, b"Gavin".to_vec()); + + assert_ok!(Nicks::clear_name(Origin::signed(1))); + assert_eq!(Balances::reserved_balance(&1), 0); + assert_eq!(Balances::free_balance(&1), 10); + }); + } + + #[test] + fn error_catching_should_work() { + new_test_ext().execute_with(|| { + assert_noop!(Nicks::clear_name(Origin::signed(1)), "Not named"); + + assert_noop!(Nicks::set_name(Origin::signed(3), b"Dave".to_vec()), "not enough free funds"); + + assert_noop!(Nicks::set_name(Origin::signed(1), b"Ga".to_vec()), "Name too short"); + assert_noop!( + Nicks::set_name(Origin::signed(1), b"Gavin James Wood, Esquire".to_vec()), + "Name too long" + ); + assert_ok!(Nicks::set_name(Origin::signed(1), b"Dave".to_vec())); + assert_noop!(Nicks::kill_name(Origin::signed(2), 1), "bad origin"); + }); + } +} -- GitLab From b60dec32932935238cfb4f1b2def5123145c466f Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Sun, 27 Oct 2019 14:53:52 +0300 Subject: [PATCH 110/167] Fix missing doc comments. (#3929) --- core/rpc-servers/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/rpc-servers/src/lib.rs b/core/rpc-servers/src/lib.rs index 3f408f6684..8d39386f93 100644 --- a/core/rpc-servers/src/lib.rs +++ b/core/rpc-servers/src/lib.rs @@ -60,7 +60,9 @@ pub fn rpc_handler( mod inner { use super::*; + /// Type alias for http server pub type HttpServer = http::Server; + /// Type alias for ws server pub type WsServer = ws::Server; /// Start HTTP server listening on given address. -- GitLab From 857b951aaa02d2d5fa6b88b74a09275726521751 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= Date: Sun, 27 Oct 2019 11:54:08 +0000 Subject: [PATCH 111/167] grandpa: always try to import available block justifcation (#3928) * grandpa: always try to import justifications in blocks * grandpa: export useful types * grandpa: add test for justification import on regular blocks * grandpa: expand comment in test --- .../finality-grandpa/src/communication/mod.rs | 2 +- core/finality-grandpa/src/import.rs | 14 ++-- core/finality-grandpa/src/justification.rs | 2 +- core/finality-grandpa/src/lib.rs | 1 + core/finality-grandpa/src/tests.rs | 81 +++++++++++++++++++ 5 files changed, 90 insertions(+), 10 deletions(-) diff --git a/core/finality-grandpa/src/communication/mod.rs b/core/finality-grandpa/src/communication/mod.rs index 6f43b1106a..9a6a40fb8d 100644 --- a/core/finality-grandpa/src/communication/mod.rs +++ b/core/finality-grandpa/src/communication/mod.rs @@ -683,7 +683,7 @@ impl> Clone for NetworkBridge { } } -fn localized_payload(round: RoundNumber, set_id: SetIdNumber, message: &E) -> Vec { +pub(crate) fn localized_payload(round: RoundNumber, set_id: SetIdNumber, message: &E) -> Vec { (message, round, set_id).encode() } diff --git a/core/finality-grandpa/src/import.rs b/core/finality-grandpa/src/import.rs index 758f6f18db..8fbe0791e8 100644 --- a/core/finality-grandpa/src/import.rs +++ b/core/finality-grandpa/src/import.rs @@ -465,17 +465,15 @@ impl, RA, SC> BlockImport _ => {}, } - if !needs_justification && !enacts_consensus_change { - return Ok(ImportResult::Imported(imported_aux)); - } - match justification { Some(justification) => { self.import_justification(hash, number, justification, needs_justification).unwrap_or_else(|err| { - debug!(target: "finality", "Imported block #{} that enacts authority set change with \ - invalid justification: {:?}, requesting justification from peers.", number, err); - imported_aux.bad_justification = true; - imported_aux.needs_justification = true; + if needs_justification || enacts_consensus_change { + debug!(target: "finality", "Imported block #{} that enacts authority set change with \ + invalid justification: {:?}, requesting justification from peers.", number, err); + imported_aux.bad_justification = true; + imported_aux.needs_justification = true; + } }); }, None => { diff --git a/core/finality-grandpa/src/justification.rs b/core/finality-grandpa/src/justification.rs index b4de8ff058..f5965df3e1 100644 --- a/core/finality-grandpa/src/justification.rs +++ b/core/finality-grandpa/src/justification.rs @@ -39,7 +39,7 @@ use crate::communication; /// This is meant to be stored in the db and passed around the network to other /// nodes, and are used by syncing nodes to prove authority set handoffs. #[derive(Encode, Decode)] -pub(crate) struct GrandpaJustification { +pub struct GrandpaJustification { round: u64, pub(crate) commit: Commit, votes_ancestries: Vec, diff --git a/core/finality-grandpa/src/lib.rs b/core/finality-grandpa/src/lib.rs index 63eddfd3f3..68019dc8eb 100644 --- a/core/finality-grandpa/src/lib.rs +++ b/core/finality-grandpa/src/lib.rs @@ -96,6 +96,7 @@ mod voting_rule; pub use communication::Network; pub use finality_proof::FinalityProofProvider; +pub use justification::GrandpaJustification; pub use light_import::light_block_import; pub use observer::run_grandpa_observer; pub use voting_rule::{ diff --git a/core/finality-grandpa/src/tests.rs b/core/finality-grandpa/src/tests.rs index 8c0047e38b..2767c14b27 100644 --- a/core/finality-grandpa/src/tests.rs +++ b/core/finality-grandpa/src/tests.rs @@ -1627,3 +1627,84 @@ fn grandpa_environment_respects_voting_rules() { 19, ); } + +#[test] +fn imports_justification_for_regular_blocks_on_import() { + // NOTE: this is a regression test since initially we would only import + // justifications for authority change blocks, and would discard any + // existing justification otherwise. + let peers = &[Ed25519Keyring::Alice]; + let voters = make_ids(peers); + let api = TestApi::new(voters); + let mut net = GrandpaTestNet::new(api.clone(), 1); + + let client = net.peer(0).client().clone(); + let (mut block_import, ..) = net.make_block_import(client.clone()); + + let full_client = client.as_full().expect("only full clients are used in test"); + let builder = full_client.new_block_at(&BlockId::Number(0), Default::default()).unwrap(); + let block = builder.bake().unwrap(); + + let block_hash = block.hash(); + + // create a valid justification, with one precommit targeting the block + let justification = { + let round = 1; + let set_id = 0; + + let precommit = grandpa::Precommit { + target_hash: block_hash, + target_number: *block.header.number(), + }; + + let msg = grandpa::Message::Precommit(precommit.clone()); + let encoded = communication::localized_payload(round, set_id, &msg); + let signature = peers[0].sign(&encoded[..]).into(); + + let precommit = grandpa::SignedPrecommit { + precommit, + signature, + id: peers[0].public().into(), + }; + + let commit = grandpa::Commit { + target_hash: block_hash, + target_number: *block.header.number(), + precommits: vec![precommit], + }; + + GrandpaJustification::from_commit( + &full_client, + round, + commit, + ).unwrap() + }; + + // we import the block with justification attached + let block = BlockImportParams { + origin: BlockOrigin::File, + header: block.header, + justification: Some(justification.encode()), + post_digests: Vec::new(), + body: Some(block.extrinsics), + finalized: false, + auxiliary: Vec::new(), + fork_choice: ForkChoiceStrategy::LongestChain, + }; + + assert_eq!( + block_import.import_block(block, HashMap::new()).unwrap(), + ImportResult::Imported(ImportedAux { + needs_justification: false, + clear_justification_requests: false, + bad_justification: false, + is_new_best: true, + ..Default::default() + }), + ); + + // the justification should be imported and available from the client + assert!( + client.justification(&BlockId::Hash(block_hash)).unwrap().is_some(), + ); +} -- GitLab From 6537f8bf87ff6461a8b1825b48961acfa1eaca3a Mon Sep 17 00:00:00 2001 From: Xiliang Chen Date: Mon, 28 Oct 2019 00:54:41 +1300 Subject: [PATCH 112/167] Fix node-template (#3924) * fix node-template Use MultiSignature to maintain compatibility with substrate-node Reset version to 1 Remove unused const * fix chain_spec * line width --- Cargo.lock | 1 + node-template/Cargo.toml | 1 + node-template/runtime/src/lib.rs | 25 +++++++------- node-template/src/chain_spec.rs | 56 +++++++++++++++++++------------- node-template/src/service.rs | 1 - node/cli/src/chain_spec.rs | 3 +- 6 files changed, 47 insertions(+), 40 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1796a68b4b..909fbb769e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2562,6 +2562,7 @@ dependencies = [ "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 2.0.0", + "sr-primitives 2.0.0", "substrate-basic-authorship 2.0.0", "substrate-cli 2.0.0", "substrate-client 2.0.0", diff --git a/node-template/Cargo.toml b/node-template/Cargo.toml index bb61c2c2ca..ba8c4caaf8 100644 --- a/node-template/Cargo.toml +++ b/node-template/Cargo.toml @@ -34,6 +34,7 @@ grandpa-primitives = { package = "substrate-finality-grandpa-primitives", path = substrate-client = { path = "../core/client" } basic-authorship = { package = "substrate-basic-authorship", path = "../core/basic-authorship" } runtime = { package = "node-template-runtime", path = "runtime" } +sr-primitives = { path = "../core/sr-primitives" } [build-dependencies] vergen = "3.0.4" diff --git a/node-template/runtime/src/lib.rs b/node-template/runtime/src/lib.rs index acc5143ffe..b803e18417 100644 --- a/node-template/runtime/src/lib.rs +++ b/node-template/runtime/src/lib.rs @@ -12,9 +12,11 @@ use rstd::prelude::*; use primitives::{OpaqueMetadata, crypto::key_types}; use sr_primitives::{ ApplyResult, transaction_validity::TransactionValidity, generic, create_runtime_str, - impl_opaque_keys, AnySignature + impl_opaque_keys, MultiSignature +}; +use sr_primitives::traits::{ + NumberFor, BlakeTwo256, Block as BlockT, StaticLookup, Verify, ConvertInto, IdentifyAccount }; -use sr_primitives::traits::{NumberFor, BlakeTwo256, Block as BlockT, StaticLookup, Verify, ConvertInto}; use sr_primitives::weights::Weight; use client::{ block_builder::api::{CheckInherentsResult, InherentData, self as block_builder_api}, @@ -39,11 +41,11 @@ pub use support::{StorageValue, construct_runtime, parameter_types, traits::Rand pub type BlockNumber = u32; /// Alias to 512-bit hash when used in the context of a transaction signature on the chain. -pub type Signature = AnySignature; +pub type Signature = MultiSignature; /// Some way of identifying an account on the chain. We intentionally make it equivalent /// to the public key of our transaction signing scheme. -pub type AccountId = ::Signer; +pub type AccountId = <::Signer as IdentifyAccount>::AccountId; /// The type for looking up accounts. We don't expect more than 4 billion of them, but you /// never know... @@ -94,9 +96,9 @@ pub mod opaque { pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("node-template"), impl_name: create_runtime_str!("node-template"), - authoring_version: 3, - spec_version: 4, - impl_version: 4, + authoring_version: 1, + spec_version: 1, + impl_version: 1, apis: RUNTIME_API_VERSIONS, }; @@ -104,16 +106,11 @@ pub const MILLISECS_PER_BLOCK: u64 = 6000; pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK; -pub const EPOCH_DURATION_IN_BLOCKS: u32 = 10 * MINUTES; - // These time units are defined in number of blocks. pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber); pub const HOURS: BlockNumber = MINUTES * 60; pub const DAYS: BlockNumber = HOURS * 24; -// 1 in 4 blocks (on average, not counting collisions) will be primary babe blocks. -pub const PRIMARY_PROBABILITY: (u64, u64) = (1, 4); - /// The version infromation used to identify this runtime when compiled natively. #[cfg(feature = "std")] pub fn native_version() -> NativeVersion { @@ -175,7 +172,7 @@ impl grandpa::Trait for Runtime { impl indices::Trait for Runtime { /// The type for recording indexing into the account enumeration. If this ever overflows, there /// will be problems! - type AccountIndex = u32; + type AccountIndex = AccountIndex; /// Use the standard means of resolving an index hint from an id. type ResolveHint = indices::SimpleResolveHint; /// Determine whether an account is dead. @@ -346,7 +343,7 @@ impl_runtime_apis! { fn slot_duration() -> u64 { Aura::slot_duration() } - + fn authorities() -> Vec { Aura::authorities() } diff --git a/node-template/src/chain_spec.rs b/node-template/src/chain_spec.rs index b8f7fef35e..8d43e67304 100644 --- a/node-template/src/chain_spec.rs +++ b/node-template/src/chain_spec.rs @@ -1,11 +1,12 @@ -use primitives::{Pair, Public}; +use primitives::{Pair, Public, sr25519}; use runtime::{ AccountId, AuraConfig, BalancesConfig, GenesisConfig, GrandpaConfig, - SudoConfig, IndicesConfig, SystemConfig, WASM_BINARY, + SudoConfig, IndicesConfig, SystemConfig, WASM_BINARY, Signature }; use aura_primitives::sr25519::{AuthorityId as AuraId}; use grandpa_primitives::{AuthorityId as GrandpaId}; use substrate_service; +use sr_primitives::traits::{Verify, IdentifyAccount}; // Note this is the URL for the telemetry server //const STAGING_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/"; @@ -31,8 +32,17 @@ pub fn get_from_seed(seed: &str) -> ::Pu .public() } +type AccountPublic = ::Signer; + +/// Helper function to generate an account ID from seed +pub fn get_account_id_from_seed(seed: &str) -> AccountId where + AccountPublic: From<::Public> +{ + AccountPublic::from(get_from_seed::(seed)).into_account() +} + /// Helper function to generate an authority key for Aura -pub fn get_authority_keys_from_seed(s: &str) -> (AuraId, GrandpaId) { +pub fn get_authority_keys_from_seed(s: &str) -> (AuraId, GrandpaId) { ( get_from_seed::(s), get_from_seed::(s), @@ -49,12 +59,12 @@ impl Alternative { || testnet_genesis(vec![ get_authority_keys_from_seed("Alice"), ], - get_from_seed::("Alice"), + get_account_id_from_seed::("Alice"), vec![ - get_from_seed::("Alice"), - get_from_seed::("Bob"), - get_from_seed::("Alice//stash"), - get_from_seed::("Bob//stash"), + get_account_id_from_seed::("Alice"), + get_account_id_from_seed::("Bob"), + get_account_id_from_seed::("Alice//stash"), + get_account_id_from_seed::("Bob//stash"), ], true), vec![], @@ -69,21 +79,21 @@ impl Alternative { || testnet_genesis(vec![ get_authority_keys_from_seed("Alice"), get_authority_keys_from_seed("Bob"), - ], - get_from_seed::("Alice"), + ], + get_account_id_from_seed::("Alice"), vec![ - get_from_seed::("Alice"), - get_from_seed::("Bob"), - get_from_seed::("Charlie"), - get_from_seed::("Dave"), - get_from_seed::("Eve"), - get_from_seed::("Ferdie"), - get_from_seed::("Alice//stash"), - get_from_seed::("Bob//stash"), - get_from_seed::("Charlie//stash"), - get_from_seed::("Dave//stash"), - get_from_seed::("Eve//stash"), - get_from_seed::("Ferdie//stash"), + get_account_id_from_seed::("Alice"), + get_account_id_from_seed::("Bob"), + get_account_id_from_seed::("Charlie"), + get_account_id_from_seed::("Dave"), + get_account_id_from_seed::("Eve"), + get_account_id_from_seed::("Ferdie"), + get_account_id_from_seed::("Alice//stash"), + get_account_id_from_seed::("Bob//stash"), + get_account_id_from_seed::("Charlie//stash"), + get_account_id_from_seed::("Dave//stash"), + get_account_id_from_seed::("Eve//stash"), + get_account_id_from_seed::("Ferdie//stash"), ], true), vec![], @@ -105,7 +115,7 @@ impl Alternative { } fn testnet_genesis(initial_authorities: Vec<(AuraId, GrandpaId)>, - root_key: AccountId, + root_key: AccountId, endowed_accounts: Vec, _enable_println: bool) -> GenesisConfig { GenesisConfig { diff --git a/node-template/src/service.rs b/node-template/src/service.rs index 203e311df9..8972cffa96 100644 --- a/node-template/src/service.rs +++ b/node-template/src/service.rs @@ -3,7 +3,6 @@ use std::sync::Arc; use std::time::Duration; use substrate_client::LongestChain; -use futures::prelude::*; use runtime::{self, GenesisConfig, opaque::Block, RuntimeApi}; use substrate_service::{error::{Error as ServiceError}, AbstractService, Configuration, ServiceBuilder}; use transaction_pool::{self, txpool::{Pool as TransactionPool}}; diff --git a/node/cli/src/chain_spec.rs b/node/cli/src/chain_spec.rs index 721fdbaf99..360421bda1 100644 --- a/node/cli/src/chain_spec.rs +++ b/node/cli/src/chain_spec.rs @@ -32,11 +32,10 @@ use substrate_telemetry::TelemetryEndpoints; use grandpa_primitives::{AuthorityId as GrandpaId}; use babe_primitives::{AuthorityId as BabeId}; use im_online::sr25519::{AuthorityId as ImOnlineId}; -use sr_primitives::{traits::Verify, Perbill}; +use sr_primitives::{Perbill, traits::{Verify, IdentifyAccount}}; pub use node_primitives::{AccountId, Balance, Signature}; pub use node_runtime::GenesisConfig; -use sr_primitives::traits::IdentifyAccount; type AccountPublic = ::Signer; -- GitLab From a57c72bedf0767a50333e1c58e5445150df0d917 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Sun, 27 Oct 2019 14:55:44 +0300 Subject: [PATCH 113/167] Watch existing extrinsics RPC (#3873) * Transaction pool watch intristics. * Track extrinsic rpc methods. * Test for pool watcher. * Track extrinsic rpc test. * Fix rpc naming. * review fixes * Update jsonrpc and use une subcription. * Naming and dependencies. --- Cargo.lock | 95 +++++++++---------- core/rpc-servers/Cargo.toml | 8 +- core/rpc/Cargo.toml | 4 +- core/rpc/api/Cargo.toml | 8 +- core/rpc/api/src/author/mod.rs | 14 ++- core/rpc/src/author/mod.rs | 17 ++++ core/rpc/src/author/tests.rs | 51 +++++++++- core/transaction-pool/graph/src/pool.rs | 44 ++++++++- .../graph/src/validated_pool.rs | 7 +- core/transaction-pool/graph/src/watcher.rs | 1 - node/cli/Cargo.toml | 2 +- node/rpc-client/Cargo.toml | 2 +- node/rpc/Cargo.toml | 2 +- srml/contracts/rpc/Cargo.toml | 6 +- srml/system/rpc/Cargo.toml | 6 +- 15 files changed, 194 insertions(+), 73 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 909fbb769e..46b03ed3c0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1507,14 +1507,14 @@ dependencies = [ [[package]] name = "jsonrpc-client-transports" -version = "13.2.0" +version = "14.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.12.35 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-core 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-pubsub 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-pubsub 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1525,7 +1525,7 @@ dependencies = [ [[package]] name = "jsonrpc-core" -version = "13.2.0" +version = "14.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1537,31 +1537,31 @@ dependencies = [ [[package]] name = "jsonrpc-core-client" -version = "13.2.0" +version = "14.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "jsonrpc-client-transports 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-client-transports 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "jsonrpc-derive" -version = "13.2.0" +version = "14.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro-crate 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "jsonrpc-http-server" -version = "13.2.0" +version = "14.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "hyper 0.12.35 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-core 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-server-utils 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-server-utils 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1570,10 +1570,10 @@ dependencies = [ [[package]] name = "jsonrpc-pubsub" -version = "13.2.0" +version = "14.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "jsonrpc-core 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1581,15 +1581,14 @@ dependencies = [ [[package]] name = "jsonrpc-server-utils" -version = "13.2.0" +version = "14.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "globset 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-core 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "unicase 2.5.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1597,11 +1596,11 @@ dependencies = [ [[package]] name = "jsonrpc-ws-server" -version = "13.2.0" +version = "14.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "jsonrpc-core 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-server-utils 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-server-utils 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2381,7 +2380,7 @@ dependencies = [ "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "futures-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", "hex-literal 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-core 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "node-executor 2.0.0", "node-primitives 2.0.0", @@ -2473,7 +2472,7 @@ dependencies = [ name = "node-rpc" version = "2.0.0" dependencies = [ - "jsonrpc-core 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "node-primitives 2.0.0", "sr-primitives 2.0.0", "srml-contracts-rpc 2.0.0", @@ -2489,7 +2488,7 @@ dependencies = [ "env_logger 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.12.35 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-core-client 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core-client 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "node-primitives 2.0.0", "substrate-rpc 2.0.0", @@ -4139,9 +4138,9 @@ dependencies = [ name = "srml-contracts-rpc" version = "2.0.0" dependencies = [ - "jsonrpc-core 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-core-client 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-derive 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core-client 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-derive 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", @@ -4572,9 +4571,9 @@ version = "2.0.0" dependencies = [ "env_logger 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "futures-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-core 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-core-client 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-derive 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core-client 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-derive 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", @@ -5478,8 +5477,8 @@ dependencies = [ "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "futures-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", "hash-db 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-core 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-pubsub 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-pubsub 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -5508,10 +5507,10 @@ version = "2.0.0" dependencies = [ "derive_more 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "futures-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-core 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-core-client 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-derive 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-pubsub 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core-client 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-derive 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-pubsub 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -5535,10 +5534,10 @@ dependencies = [ name = "substrate-rpc-servers" version = "2.0.0" dependencies = [ - "jsonrpc-core 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-http-server 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-pubsub 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-ws-server 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-http-server 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-pubsub 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-ws-server 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", @@ -7003,14 +7002,14 @@ dependencies = [ "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" "checksum jobserver 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "f2b1d42ef453b30b7387e113da1c83ab1605d90c5b4e0eb8e96d016ed3b8c160" "checksum js-sys 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)" = "2cc9a97d7cec30128fd8b28a7c1f9df1c001ceb9b441e2b755e24130a6b43c79" -"checksum jsonrpc-client-transports 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8dbf2466adbf6d5b4e618857f22be40b1e1cc6ed79d72751324358f6b539b06d" -"checksum jsonrpc-core 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "91d767c183a7e58618a609499d359ce3820700b3ebb4823a18c343b4a2a41a0d" -"checksum jsonrpc-core-client 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "161dc223549fa6fe4a4eda675de2d1d3cff5a7164e5c031cdf1e22c734700f8b" -"checksum jsonrpc-derive 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4a76285ebba4515680fbfe4b62498ccb2a932384c8732eed68351b02fb7ae475" -"checksum jsonrpc-http-server 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "601fcc7bec888c7cbc7fd124d3d6744d72c0ebb540eca6fe2261b71f9cff6320" -"checksum jsonrpc-pubsub 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "64e0fb0664d8ce287e826940dafbb45379443c595bdd71d93655f3c8f25fd992" -"checksum jsonrpc-server-utils 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4d415f51d016a4682878e19dd03e8c0b61cd4394912d7cd3dc48d4f19f061a4e" -"checksum jsonrpc-ws-server 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4699433c1ac006d7df178b4c29c191e5bb6d81e2dca18c5c804a094592900101" +"checksum jsonrpc-client-transports 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d389a085cb2184604dff060390cadb8cba1f063c7fd0ad710272c163c88b9f20" +"checksum jsonrpc-core 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "34651edf3417637cc45e70ed0182ecfa9ced0b7e8131805fccf7400d989845ca" +"checksum jsonrpc-core-client 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9dbaec1d57271ff952f24ca79d37d716cfd749c855b058d9aa5f053a6b8ae4ef" +"checksum jsonrpc-derive 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d5d5c31575cc70a8b21542599028472c80a9248394aeea4d8918a045a0ab08a3" +"checksum jsonrpc-http-server 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "aa54c4c2d88cb5e04b251a5031ba0f2ee8c6ef30970e31228955b89a80c3b611" +"checksum jsonrpc-pubsub 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3ee1b8da0b9219a231c4b7cbc7110bfdb457cbcd8d90a6224d0b3cab8aae8443" +"checksum jsonrpc-server-utils 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "87bc3c0a9a282211b2ec14abb3e977de33016bbec495332e9f7be858de7c5117" +"checksum jsonrpc-ws-server 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "af36a129cef77a9db8028ac7552d927e1bb7b6928cd96b23dd25cc38bff974ab" "checksum keccak 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" "checksum keccak-hasher 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3468207deea1359a0e921591ae9b4c928733d94eb9d6a2eeda994cfd59f42cf8" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" diff --git a/core/rpc-servers/Cargo.toml b/core/rpc-servers/Cargo.toml index 80e16bc5ae..60d5fa3ae0 100644 --- a/core/rpc-servers/Cargo.toml +++ b/core/rpc-servers/Cargo.toml @@ -5,13 +5,13 @@ authors = ["Parity Technologies "] edition = "2018" [dependencies] -jsonrpc-core = "13.2.0" -pubsub = { package = "jsonrpc-pubsub", version = "13.2.0" } +jsonrpc-core = "14.0" +pubsub = { package = "jsonrpc-pubsub", version = "14.0" } log = "0.4.8" serde = "1.0.101" serde_json = "1.0.41" sr-primitives = { path = "../sr-primitives" } [target.'cfg(not(target_os = "unknown"))'.dependencies] -http = { package = "jsonrpc-http-server", version = "13.2.0" } -ws = { package = "jsonrpc-ws-server", version = "13.2.0" } +http = { package = "jsonrpc-http-server", version = "14.0" } +ws = { package = "jsonrpc-ws-server", version = "14.0" } diff --git a/core/rpc/Cargo.toml b/core/rpc/Cargo.toml index 85998feb1b..124cd90e75 100644 --- a/core/rpc/Cargo.toml +++ b/core/rpc/Cargo.toml @@ -9,10 +9,10 @@ api = { package = "substrate-rpc-api", path = "./api" } client = { package = "substrate-client", path = "../client" } codec = { package = "parity-scale-codec", version = "1.0.0" } futures03 = { package = "futures-preview", version = "0.3.0-alpha.19", features = ["compat"] } -jsonrpc-pubsub = "13.1.0" +jsonrpc-pubsub = "14.0" log = "0.4.8" primitives = { package = "substrate-primitives", path = "../primitives" } -rpc = { package = "jsonrpc-core", version = "13.0.0" } +rpc = { package = "jsonrpc-core", version = "14.0" } runtime_version = { package = "sr-version", path = "../sr-version" } serde_json = "1.0.41" session = { package = "substrate-session", path = "../session" } diff --git a/core/rpc/api/Cargo.toml b/core/rpc/api/Cargo.toml index bccafc2a85..e40b94a32f 100644 --- a/core/rpc/api/Cargo.toml +++ b/core/rpc/api/Cargo.toml @@ -8,10 +8,10 @@ edition = "2018" codec = { package = "parity-scale-codec", version = "1.0.0" } derive_more = "0.15.0" futures03 = { package = "futures-preview", version = "0.3.0-alpha.19", features = ["compat"] } -jsonrpc-core = "13.2.0" -jsonrpc-core-client = "13.2.0" -jsonrpc-derive = "13.2.0" -jsonrpc-pubsub = "13.2.0" +jsonrpc-core = "14.0" +jsonrpc-core-client = "14.0" +jsonrpc-derive = "14.0" +jsonrpc-pubsub = "14.0" log = "0.4.8" parking_lot = "0.9.0" primitives = { package = "substrate-primitives", path = "../../primitives" } diff --git a/core/rpc/api/src/author/mod.rs b/core/rpc/api/src/author/mod.rs index 4ea96cb3c6..3501a30501 100644 --- a/core/rpc/api/src/author/mod.rs +++ b/core/rpc/api/src/author/mod.rs @@ -67,7 +67,7 @@ pub trait AuthorApi { subscribe, name = "author_submitAndWatchExtrinsic" )] - fn watch_extrinsic(&self, + fn submit_and_watch_extrinsic(&self, metadata: Self::Metadata, subscriber: Subscriber>, bytes: Bytes @@ -83,4 +83,16 @@ pub trait AuthorApi { metadata: Option, id: SubscriptionId ) -> Result; + + /// Watch multiple extrinsics (own or from network) + #[pubsub( + subscription = "author_extrinsicUpdate", + subscribe, + name = "author_watchExtrinsic" + )] + fn watch_extrinsic(&self, + metadata: Self::Metadata, + subscriber: Subscriber>, + hash: Hash, + ); } diff --git a/core/rpc/src/author/mod.rs b/core/rpc/src/author/mod.rs index 82122dcf3d..5c7dca9e01 100644 --- a/core/rpc/src/author/mod.rs +++ b/core/rpc/src/author/mod.rs @@ -153,6 +153,23 @@ impl AuthorApi, BlockHash

> for Author whe } fn watch_extrinsic(&self, + _metadata: Self::Metadata, + subscriber: Subscriber, BlockHash

>>, + hash: ExHash

, + ) { + let watcher = self.pool.watch(hash).into_stream().map(|v| Ok::<_, ()>(Ok(v))); + let subscriptions = self.subscriptions.clone(); + + subscriptions.add(subscriber, + move |sink| { + sink.sink_map_err(|_| unimplemented!()) + .send_all(Compat::new(watcher)) + .map(|_| ()) + } + ); + } + + fn submit_and_watch_extrinsic(&self, _metadata: Self::Metadata, subscriber: Subscriber, BlockHash

>>, xt: Bytes diff --git a/core/rpc/src/author/tests.rs b/core/rpc/src/author/tests.rs index 5ae044ff49..8f7eb67e7c 100644 --- a/core/rpc/src/author/tests.rs +++ b/core/rpc/src/author/tests.rs @@ -115,7 +115,7 @@ fn should_watch_extrinsic() { let (subscriber, id_rx, data) = jsonrpc_pubsub::typed::Subscriber::new_test("test"); // when - p.watch_extrinsic(Default::default(), subscriber, uxt(AccountKeyring::Alice, 0).encode().into()); + p.submit_and_watch_extrinsic(Default::default(), subscriber, uxt(AccountKeyring::Alice, 0).encode().into()); // then assert_eq!(setup.runtime.block_on(id_rx), Ok(Ok(1.into()))); @@ -142,6 +142,53 @@ fn should_watch_extrinsic() { ); } + +#[test] +fn should_watch_existing_extrinsic() { + // Initial setup is 1 submitted extrinsic + let mut runtime = runtime::Runtime::new().unwrap(); + let client = Arc::new(test_client::new()); + let pool = Arc::new(Pool::new(Default::default(), FullChainApi::new(client.clone()))); + let keystore = KeyStore::new(); + let p = Author { + client, + pool: pool.clone(), + subscriptions: Subscriptions::new(Arc::new(runtime.executor())), + keystore: keystore.clone(), + }; + let (subscriber, id_rx, data) = jsonrpc_pubsub::typed::Subscriber::new_test("test"); + + let xt = uxt(AccountKeyring::Alice, 0).encode(); + let xt_hash: H256 = blake2_256(&xt).into(); + p.submit_extrinsic(xt.into()).wait().expect("Failed to submit extrinsic"); + + // Then we track it + p.watch_extrinsic(Default::default(), subscriber, xt_hash.into()); + assert_eq!(runtime.block_on(id_rx), Ok(Ok(1.into()))); + + // Add replacement + let replacement = { + let tx = Transfer { + amount: 5, + nonce: 0, + from: AccountKeyring::Alice.into(), + to: Default::default(), + }; + tx.into_signed_tx() + }.encode(); + let replacement_hash = blake2_256(&replacement); + AuthorApi::submit_extrinsic(&p, replacement.into()).wait().unwrap(); + + // And check if the tracked one received usurped event + assert_eq!( + runtime.block_on(data.into_future()).unwrap().0, + Some(format!( + r#"{{"jsonrpc":"2.0","method":"test","params":{{"result":{{"usurped":"0x{}"}},"subscription":1}}}}"#, + HexDisplay::from(&replacement_hash)) + ) + ); +} + #[test] fn should_return_watch_validation_error() { //given @@ -151,7 +198,7 @@ fn should_return_watch_validation_error() { let (subscriber, id_rx, _data) = jsonrpc_pubsub::typed::Subscriber::new_test("test"); // when - p.watch_extrinsic(Default::default(), subscriber, uxt(AccountKeyring::Alice, 179).encode().into()); + p.submit_and_watch_extrinsic(Default::default(), subscriber, uxt(AccountKeyring::Alice, 179).encode().into()); // then let res = setup.runtime.block_on(id_rx).unwrap(); diff --git a/core/transaction-pool/graph/src/pool.rs b/core/transaction-pool/graph/src/pool.rs index 621aeabda8..4e6db54c38 100644 --- a/core/transaction-pool/graph/src/pool.rs +++ b/core/transaction-pool/graph/src/pool.rs @@ -165,6 +165,17 @@ impl Pool { ) } + /// Watch existing transaction + /// + /// Get notified when some existing transaction is finished verifying or gets finalized + /// in a new block. + pub fn watch( + &self, + hash: ExHash, + ) -> Watcher, BlockHash> { + self.validated_pool.watch(hash) + } + /// Prunes ready transactions. /// /// Used to clear the pool from transactions that were part of recently imported block. @@ -783,7 +794,6 @@ mod tests { // when pool.validated_pool.remove_invalid(&[*watcher.hash()]); - // then let mut stream = futures::executor::block_on_stream(watcher.into_stream()); assert_eq!(stream.next(), Some(watcher::Status::Ready)); @@ -907,5 +917,37 @@ mod tests { assert_eq!(pool.status().ready, 1); assert_eq!(pool.status().future, 0); } + + #[test] + fn should_watch_existing() { + let limit = Limit { + count: 1, + total_bytes: 1000, + }; + let pool = Pool::new(Options { + ready: limit.clone(), + future: limit.clone(), + }, TestApi::default()); + + let xt = uxt(Transfer { + from: AccountId::from_h256(H256::from_low_u64_be(1)), + to: AccountId::from_h256(H256::from_low_u64_be(2)), + amount: 5, + nonce: 0, + }); + let hash = block_on(pool.submit_one(&BlockId::Number(0), xt)).expect("Failed to submit"); + assert_eq!(pool.status().ready, 1); + + let watcher = pool.watch(hash); + block_on(pool.prune_tags(&BlockId::Number(2), vec![], vec![hash])) + .expect("Failed to prune tags"); + + let mut stream = futures::executor::block_on_stream( + watcher.into_stream() + ); + + assert_eq!(stream.next(), Some(watcher::Status::Finalized(H256::from_low_u64_be(2).into()))); + assert_eq!(stream.next(), None); + } } } diff --git a/core/transaction-pool/graph/src/validated_pool.rs b/core/transaction-pool/graph/src/validated_pool.rs index 9bf1012628..6020092e0f 100644 --- a/core/transaction-pool/graph/src/validated_pool.rs +++ b/core/transaction-pool/graph/src/validated_pool.rs @@ -171,7 +171,7 @@ impl ValidatedPool { match tx { ValidatedTransaction::Valid(tx) => { let hash = self.api.hash_and_length(&tx.data).0; - let watcher = self.listener.write().create_watcher(hash); + let watcher = self.watch(hash); self.submit(std::iter::once(ValidatedTransaction::Valid(tx))) .pop() .expect("One extrinsic passed; one result returned; qed") @@ -182,6 +182,11 @@ impl ValidatedPool { } } + /// Watch some existing transaction with known hash. + pub fn watch(&self, hash: ExHash) -> Watcher, BlockHash> { + self.listener.write().create_watcher(hash) + } + /// For each extrinsic, returns tags that it provides (if known), or None (if it is unknown). pub fn extrinsics_tags(&self, extrinsics: &[ExtrinsicFor]) -> (Vec>, Vec>>) { let hashes = extrinsics.iter().map(|extrinsic| self.api.hash_and_length(extrinsic).0).collect::>(); diff --git a/core/transaction-pool/graph/src/watcher.rs b/core/transaction-pool/graph/src/watcher.rs index 11d6b9f407..ed10dd3ab6 100644 --- a/core/transaction-pool/graph/src/watcher.rs +++ b/core/transaction-pool/graph/src/watcher.rs @@ -130,7 +130,6 @@ impl Sender { self.send(Status::Broadcast(peers)) } - /// Returns true if the are no more listeners for this extrinsic or it was finalized. pub fn is_done(&self) -> bool { self.finalized || self.receivers.is_empty() diff --git a/node/cli/Cargo.toml b/node/cli/Cargo.toml index 5fa92360d6..b8fd63c38a 100644 --- a/node/cli/Cargo.toml +++ b/node/cli/Cargo.toml @@ -11,7 +11,7 @@ log = "0.4.8" tokio = "0.1.22" futures = "0.1.29" exit-future = "0.1.4" -jsonrpc-core = "13.2.0" +jsonrpc-core = "14.0" cli = { package = "substrate-cli", path = "../../core/cli" } codec = { package = "parity-scale-codec", version = "1.0.0" } sr-io = { path = "../../core/sr-io" } diff --git a/node/rpc-client/Cargo.toml b/node/rpc-client/Cargo.toml index e377f89359..7fd50c5e35 100644 --- a/node/rpc-client/Cargo.toml +++ b/node/rpc-client/Cargo.toml @@ -8,7 +8,7 @@ edition = "2018" env_logger = "0.7.0" futures = "0.1.29" hyper = "0.12.35" -jsonrpc-core-client = { version = "13.1.0", features = ["http", "ws"] } +jsonrpc-core-client = { version = "14.0", features = ["http", "ws"] } log = "0.4.8" node-primitives = { path = "../primitives" } substrate-rpc = { path = "../../core/rpc", version = "2.0.0" } diff --git a/node/rpc/Cargo.toml b/node/rpc/Cargo.toml index 5d2ca81e0f..9cc5bfe1e6 100644 --- a/node/rpc/Cargo.toml +++ b/node/rpc/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" [dependencies] client = { package = "substrate-client", path = "../../core/client" } -jsonrpc-core = "13.2.0" +jsonrpc-core = "14.0" node-primitives = { path = "../primitives" } sr-primitives = { path = "../../core/sr-primitives" } srml-contracts-rpc = { path = "../../srml/contracts/rpc/" } diff --git a/srml/contracts/rpc/Cargo.toml b/srml/contracts/rpc/Cargo.toml index 90bf34bec1..e516d93d63 100644 --- a/srml/contracts/rpc/Cargo.toml +++ b/srml/contracts/rpc/Cargo.toml @@ -7,9 +7,9 @@ edition = "2018" [dependencies] client = { package = "substrate-client", path = "../../../core/client" } codec = { package = "parity-scale-codec", version = "1.0.0" } -jsonrpc-core = "13.2.0" -jsonrpc-core-client = "13.2.0" -jsonrpc-derive = "13.2.0" +jsonrpc-core = "14.0" +jsonrpc-core-client = "14.0" +jsonrpc-derive = "14.0" primitives = { package = "substrate-primitives", path = "../../../core/primitives" } rpc-primitives = { package = "substrate-rpc-primitives", path = "../../../core/rpc/primitives" } serde = { version = "1.0.101", features = ["derive"] } diff --git a/srml/system/rpc/Cargo.toml b/srml/system/rpc/Cargo.toml index 04856a817f..e3193c2018 100644 --- a/srml/system/rpc/Cargo.toml +++ b/srml/system/rpc/Cargo.toml @@ -7,9 +7,9 @@ edition = "2018" [dependencies] client = { package = "substrate-client", path = "../../../core/client" } codec = { package = "parity-scale-codec", version = "1.0.0" } -jsonrpc-core = "13.2.0" -jsonrpc-core-client = "13.2.0" -jsonrpc-derive = "13.2.0" +jsonrpc-core = "14.0" +jsonrpc-core-client = "14.0" +jsonrpc-derive = "14.0" log = "0.4.8" serde = { version = "1.0.101", features = ["derive"] } sr-primitives = { path = "../../../core/sr-primitives" } -- GitLab From 37189e0e9b5ef2a02fac17892ac21279f1ed74a7 Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Sun, 27 Oct 2019 13:19:06 +0100 Subject: [PATCH 114/167] Revert "Watch existing extrinsics RPC (#3873)" (#3931) This reverts commit a57c72bedf0767a50333e1c58e5445150df0d917. --- Cargo.lock | 95 ++++++++++--------- core/rpc-servers/Cargo.toml | 8 +- core/rpc/Cargo.toml | 4 +- core/rpc/api/Cargo.toml | 8 +- core/rpc/api/src/author/mod.rs | 14 +-- core/rpc/src/author/mod.rs | 17 ---- core/rpc/src/author/tests.rs | 51 +--------- core/transaction-pool/graph/src/pool.rs | 44 +-------- .../graph/src/validated_pool.rs | 7 +- core/transaction-pool/graph/src/watcher.rs | 1 + node/cli/Cargo.toml | 2 +- node/rpc-client/Cargo.toml | 2 +- node/rpc/Cargo.toml | 2 +- srml/contracts/rpc/Cargo.toml | 6 +- srml/system/rpc/Cargo.toml | 6 +- 15 files changed, 73 insertions(+), 194 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 46b03ed3c0..909fbb769e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1507,14 +1507,14 @@ dependencies = [ [[package]] name = "jsonrpc-client-transports" -version = "14.0.3" +version = "13.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.12.35 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-core 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-pubsub 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-pubsub 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1525,7 +1525,7 @@ dependencies = [ [[package]] name = "jsonrpc-core" -version = "14.0.3" +version = "13.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1537,31 +1537,31 @@ dependencies = [ [[package]] name = "jsonrpc-core-client" -version = "14.0.3" +version = "13.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "jsonrpc-client-transports 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-client-transports 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "jsonrpc-derive" -version = "14.0.3" +version = "13.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro-crate 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "jsonrpc-http-server" -version = "14.0.3" +version = "13.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "hyper 0.12.35 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-core 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-server-utils 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-server-utils 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1570,10 +1570,10 @@ dependencies = [ [[package]] name = "jsonrpc-pubsub" -version = "14.0.3" +version = "13.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "jsonrpc-core 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1581,14 +1581,15 @@ dependencies = [ [[package]] name = "jsonrpc-server-utils" -version = "14.0.3" +version = "13.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "globset 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-core 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "unicase 2.5.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1596,11 +1597,11 @@ dependencies = [ [[package]] name = "jsonrpc-ws-server" -version = "14.0.3" +version = "13.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "jsonrpc-core 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-server-utils 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-server-utils 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2380,7 +2381,7 @@ dependencies = [ "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "futures-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", "hex-literal 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-core 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "node-executor 2.0.0", "node-primitives 2.0.0", @@ -2472,7 +2473,7 @@ dependencies = [ name = "node-rpc" version = "2.0.0" dependencies = [ - "jsonrpc-core 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "node-primitives 2.0.0", "sr-primitives 2.0.0", "srml-contracts-rpc 2.0.0", @@ -2488,7 +2489,7 @@ dependencies = [ "env_logger 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.12.35 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-core-client 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core-client 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "node-primitives 2.0.0", "substrate-rpc 2.0.0", @@ -4138,9 +4139,9 @@ dependencies = [ name = "srml-contracts-rpc" version = "2.0.0" dependencies = [ - "jsonrpc-core 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-core-client 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-derive 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core-client 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-derive 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", @@ -4571,9 +4572,9 @@ version = "2.0.0" dependencies = [ "env_logger 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "futures-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-core 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-core-client 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-derive 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core-client 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-derive 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", @@ -5477,8 +5478,8 @@ dependencies = [ "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "futures-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", "hash-db 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-core 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-pubsub 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-pubsub 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -5507,10 +5508,10 @@ version = "2.0.0" dependencies = [ "derive_more 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "futures-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-core 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-core-client 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-derive 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-pubsub 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core-client 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-derive 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-pubsub 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -5534,10 +5535,10 @@ dependencies = [ name = "substrate-rpc-servers" version = "2.0.0" dependencies = [ - "jsonrpc-core 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-http-server 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-pubsub 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-ws-server 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-http-server 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-pubsub 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-ws-server 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", @@ -7002,14 +7003,14 @@ dependencies = [ "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" "checksum jobserver 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "f2b1d42ef453b30b7387e113da1c83ab1605d90c5b4e0eb8e96d016ed3b8c160" "checksum js-sys 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)" = "2cc9a97d7cec30128fd8b28a7c1f9df1c001ceb9b441e2b755e24130a6b43c79" -"checksum jsonrpc-client-transports 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d389a085cb2184604dff060390cadb8cba1f063c7fd0ad710272c163c88b9f20" -"checksum jsonrpc-core 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "34651edf3417637cc45e70ed0182ecfa9ced0b7e8131805fccf7400d989845ca" -"checksum jsonrpc-core-client 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9dbaec1d57271ff952f24ca79d37d716cfd749c855b058d9aa5f053a6b8ae4ef" -"checksum jsonrpc-derive 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d5d5c31575cc70a8b21542599028472c80a9248394aeea4d8918a045a0ab08a3" -"checksum jsonrpc-http-server 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "aa54c4c2d88cb5e04b251a5031ba0f2ee8c6ef30970e31228955b89a80c3b611" -"checksum jsonrpc-pubsub 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3ee1b8da0b9219a231c4b7cbc7110bfdb457cbcd8d90a6224d0b3cab8aae8443" -"checksum jsonrpc-server-utils 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "87bc3c0a9a282211b2ec14abb3e977de33016bbec495332e9f7be858de7c5117" -"checksum jsonrpc-ws-server 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "af36a129cef77a9db8028ac7552d927e1bb7b6928cd96b23dd25cc38bff974ab" +"checksum jsonrpc-client-transports 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8dbf2466adbf6d5b4e618857f22be40b1e1cc6ed79d72751324358f6b539b06d" +"checksum jsonrpc-core 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "91d767c183a7e58618a609499d359ce3820700b3ebb4823a18c343b4a2a41a0d" +"checksum jsonrpc-core-client 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "161dc223549fa6fe4a4eda675de2d1d3cff5a7164e5c031cdf1e22c734700f8b" +"checksum jsonrpc-derive 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4a76285ebba4515680fbfe4b62498ccb2a932384c8732eed68351b02fb7ae475" +"checksum jsonrpc-http-server 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "601fcc7bec888c7cbc7fd124d3d6744d72c0ebb540eca6fe2261b71f9cff6320" +"checksum jsonrpc-pubsub 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "64e0fb0664d8ce287e826940dafbb45379443c595bdd71d93655f3c8f25fd992" +"checksum jsonrpc-server-utils 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4d415f51d016a4682878e19dd03e8c0b61cd4394912d7cd3dc48d4f19f061a4e" +"checksum jsonrpc-ws-server 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4699433c1ac006d7df178b4c29c191e5bb6d81e2dca18c5c804a094592900101" "checksum keccak 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" "checksum keccak-hasher 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3468207deea1359a0e921591ae9b4c928733d94eb9d6a2eeda994cfd59f42cf8" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" diff --git a/core/rpc-servers/Cargo.toml b/core/rpc-servers/Cargo.toml index 60d5fa3ae0..80e16bc5ae 100644 --- a/core/rpc-servers/Cargo.toml +++ b/core/rpc-servers/Cargo.toml @@ -5,13 +5,13 @@ authors = ["Parity Technologies "] edition = "2018" [dependencies] -jsonrpc-core = "14.0" -pubsub = { package = "jsonrpc-pubsub", version = "14.0" } +jsonrpc-core = "13.2.0" +pubsub = { package = "jsonrpc-pubsub", version = "13.2.0" } log = "0.4.8" serde = "1.0.101" serde_json = "1.0.41" sr-primitives = { path = "../sr-primitives" } [target.'cfg(not(target_os = "unknown"))'.dependencies] -http = { package = "jsonrpc-http-server", version = "14.0" } -ws = { package = "jsonrpc-ws-server", version = "14.0" } +http = { package = "jsonrpc-http-server", version = "13.2.0" } +ws = { package = "jsonrpc-ws-server", version = "13.2.0" } diff --git a/core/rpc/Cargo.toml b/core/rpc/Cargo.toml index 124cd90e75..85998feb1b 100644 --- a/core/rpc/Cargo.toml +++ b/core/rpc/Cargo.toml @@ -9,10 +9,10 @@ api = { package = "substrate-rpc-api", path = "./api" } client = { package = "substrate-client", path = "../client" } codec = { package = "parity-scale-codec", version = "1.0.0" } futures03 = { package = "futures-preview", version = "0.3.0-alpha.19", features = ["compat"] } -jsonrpc-pubsub = "14.0" +jsonrpc-pubsub = "13.1.0" log = "0.4.8" primitives = { package = "substrate-primitives", path = "../primitives" } -rpc = { package = "jsonrpc-core", version = "14.0" } +rpc = { package = "jsonrpc-core", version = "13.0.0" } runtime_version = { package = "sr-version", path = "../sr-version" } serde_json = "1.0.41" session = { package = "substrate-session", path = "../session" } diff --git a/core/rpc/api/Cargo.toml b/core/rpc/api/Cargo.toml index e40b94a32f..bccafc2a85 100644 --- a/core/rpc/api/Cargo.toml +++ b/core/rpc/api/Cargo.toml @@ -8,10 +8,10 @@ edition = "2018" codec = { package = "parity-scale-codec", version = "1.0.0" } derive_more = "0.15.0" futures03 = { package = "futures-preview", version = "0.3.0-alpha.19", features = ["compat"] } -jsonrpc-core = "14.0" -jsonrpc-core-client = "14.0" -jsonrpc-derive = "14.0" -jsonrpc-pubsub = "14.0" +jsonrpc-core = "13.2.0" +jsonrpc-core-client = "13.2.0" +jsonrpc-derive = "13.2.0" +jsonrpc-pubsub = "13.2.0" log = "0.4.8" parking_lot = "0.9.0" primitives = { package = "substrate-primitives", path = "../../primitives" } diff --git a/core/rpc/api/src/author/mod.rs b/core/rpc/api/src/author/mod.rs index 3501a30501..4ea96cb3c6 100644 --- a/core/rpc/api/src/author/mod.rs +++ b/core/rpc/api/src/author/mod.rs @@ -67,7 +67,7 @@ pub trait AuthorApi { subscribe, name = "author_submitAndWatchExtrinsic" )] - fn submit_and_watch_extrinsic(&self, + fn watch_extrinsic(&self, metadata: Self::Metadata, subscriber: Subscriber>, bytes: Bytes @@ -83,16 +83,4 @@ pub trait AuthorApi { metadata: Option, id: SubscriptionId ) -> Result; - - /// Watch multiple extrinsics (own or from network) - #[pubsub( - subscription = "author_extrinsicUpdate", - subscribe, - name = "author_watchExtrinsic" - )] - fn watch_extrinsic(&self, - metadata: Self::Metadata, - subscriber: Subscriber>, - hash: Hash, - ); } diff --git a/core/rpc/src/author/mod.rs b/core/rpc/src/author/mod.rs index 5c7dca9e01..82122dcf3d 100644 --- a/core/rpc/src/author/mod.rs +++ b/core/rpc/src/author/mod.rs @@ -153,23 +153,6 @@ impl AuthorApi, BlockHash

> for Author whe } fn watch_extrinsic(&self, - _metadata: Self::Metadata, - subscriber: Subscriber, BlockHash

>>, - hash: ExHash

, - ) { - let watcher = self.pool.watch(hash).into_stream().map(|v| Ok::<_, ()>(Ok(v))); - let subscriptions = self.subscriptions.clone(); - - subscriptions.add(subscriber, - move |sink| { - sink.sink_map_err(|_| unimplemented!()) - .send_all(Compat::new(watcher)) - .map(|_| ()) - } - ); - } - - fn submit_and_watch_extrinsic(&self, _metadata: Self::Metadata, subscriber: Subscriber, BlockHash

>>, xt: Bytes diff --git a/core/rpc/src/author/tests.rs b/core/rpc/src/author/tests.rs index 8f7eb67e7c..5ae044ff49 100644 --- a/core/rpc/src/author/tests.rs +++ b/core/rpc/src/author/tests.rs @@ -115,7 +115,7 @@ fn should_watch_extrinsic() { let (subscriber, id_rx, data) = jsonrpc_pubsub::typed::Subscriber::new_test("test"); // when - p.submit_and_watch_extrinsic(Default::default(), subscriber, uxt(AccountKeyring::Alice, 0).encode().into()); + p.watch_extrinsic(Default::default(), subscriber, uxt(AccountKeyring::Alice, 0).encode().into()); // then assert_eq!(setup.runtime.block_on(id_rx), Ok(Ok(1.into()))); @@ -142,53 +142,6 @@ fn should_watch_extrinsic() { ); } - -#[test] -fn should_watch_existing_extrinsic() { - // Initial setup is 1 submitted extrinsic - let mut runtime = runtime::Runtime::new().unwrap(); - let client = Arc::new(test_client::new()); - let pool = Arc::new(Pool::new(Default::default(), FullChainApi::new(client.clone()))); - let keystore = KeyStore::new(); - let p = Author { - client, - pool: pool.clone(), - subscriptions: Subscriptions::new(Arc::new(runtime.executor())), - keystore: keystore.clone(), - }; - let (subscriber, id_rx, data) = jsonrpc_pubsub::typed::Subscriber::new_test("test"); - - let xt = uxt(AccountKeyring::Alice, 0).encode(); - let xt_hash: H256 = blake2_256(&xt).into(); - p.submit_extrinsic(xt.into()).wait().expect("Failed to submit extrinsic"); - - // Then we track it - p.watch_extrinsic(Default::default(), subscriber, xt_hash.into()); - assert_eq!(runtime.block_on(id_rx), Ok(Ok(1.into()))); - - // Add replacement - let replacement = { - let tx = Transfer { - amount: 5, - nonce: 0, - from: AccountKeyring::Alice.into(), - to: Default::default(), - }; - tx.into_signed_tx() - }.encode(); - let replacement_hash = blake2_256(&replacement); - AuthorApi::submit_extrinsic(&p, replacement.into()).wait().unwrap(); - - // And check if the tracked one received usurped event - assert_eq!( - runtime.block_on(data.into_future()).unwrap().0, - Some(format!( - r#"{{"jsonrpc":"2.0","method":"test","params":{{"result":{{"usurped":"0x{}"}},"subscription":1}}}}"#, - HexDisplay::from(&replacement_hash)) - ) - ); -} - #[test] fn should_return_watch_validation_error() { //given @@ -198,7 +151,7 @@ fn should_return_watch_validation_error() { let (subscriber, id_rx, _data) = jsonrpc_pubsub::typed::Subscriber::new_test("test"); // when - p.submit_and_watch_extrinsic(Default::default(), subscriber, uxt(AccountKeyring::Alice, 179).encode().into()); + p.watch_extrinsic(Default::default(), subscriber, uxt(AccountKeyring::Alice, 179).encode().into()); // then let res = setup.runtime.block_on(id_rx).unwrap(); diff --git a/core/transaction-pool/graph/src/pool.rs b/core/transaction-pool/graph/src/pool.rs index 4e6db54c38..621aeabda8 100644 --- a/core/transaction-pool/graph/src/pool.rs +++ b/core/transaction-pool/graph/src/pool.rs @@ -165,17 +165,6 @@ impl Pool { ) } - /// Watch existing transaction - /// - /// Get notified when some existing transaction is finished verifying or gets finalized - /// in a new block. - pub fn watch( - &self, - hash: ExHash, - ) -> Watcher, BlockHash> { - self.validated_pool.watch(hash) - } - /// Prunes ready transactions. /// /// Used to clear the pool from transactions that were part of recently imported block. @@ -794,6 +783,7 @@ mod tests { // when pool.validated_pool.remove_invalid(&[*watcher.hash()]); + // then let mut stream = futures::executor::block_on_stream(watcher.into_stream()); assert_eq!(stream.next(), Some(watcher::Status::Ready)); @@ -917,37 +907,5 @@ mod tests { assert_eq!(pool.status().ready, 1); assert_eq!(pool.status().future, 0); } - - #[test] - fn should_watch_existing() { - let limit = Limit { - count: 1, - total_bytes: 1000, - }; - let pool = Pool::new(Options { - ready: limit.clone(), - future: limit.clone(), - }, TestApi::default()); - - let xt = uxt(Transfer { - from: AccountId::from_h256(H256::from_low_u64_be(1)), - to: AccountId::from_h256(H256::from_low_u64_be(2)), - amount: 5, - nonce: 0, - }); - let hash = block_on(pool.submit_one(&BlockId::Number(0), xt)).expect("Failed to submit"); - assert_eq!(pool.status().ready, 1); - - let watcher = pool.watch(hash); - block_on(pool.prune_tags(&BlockId::Number(2), vec![], vec![hash])) - .expect("Failed to prune tags"); - - let mut stream = futures::executor::block_on_stream( - watcher.into_stream() - ); - - assert_eq!(stream.next(), Some(watcher::Status::Finalized(H256::from_low_u64_be(2).into()))); - assert_eq!(stream.next(), None); - } } } diff --git a/core/transaction-pool/graph/src/validated_pool.rs b/core/transaction-pool/graph/src/validated_pool.rs index 6020092e0f..9bf1012628 100644 --- a/core/transaction-pool/graph/src/validated_pool.rs +++ b/core/transaction-pool/graph/src/validated_pool.rs @@ -171,7 +171,7 @@ impl ValidatedPool { match tx { ValidatedTransaction::Valid(tx) => { let hash = self.api.hash_and_length(&tx.data).0; - let watcher = self.watch(hash); + let watcher = self.listener.write().create_watcher(hash); self.submit(std::iter::once(ValidatedTransaction::Valid(tx))) .pop() .expect("One extrinsic passed; one result returned; qed") @@ -182,11 +182,6 @@ impl ValidatedPool { } } - /// Watch some existing transaction with known hash. - pub fn watch(&self, hash: ExHash) -> Watcher, BlockHash> { - self.listener.write().create_watcher(hash) - } - /// For each extrinsic, returns tags that it provides (if known), or None (if it is unknown). pub fn extrinsics_tags(&self, extrinsics: &[ExtrinsicFor]) -> (Vec>, Vec>>) { let hashes = extrinsics.iter().map(|extrinsic| self.api.hash_and_length(extrinsic).0).collect::>(); diff --git a/core/transaction-pool/graph/src/watcher.rs b/core/transaction-pool/graph/src/watcher.rs index ed10dd3ab6..11d6b9f407 100644 --- a/core/transaction-pool/graph/src/watcher.rs +++ b/core/transaction-pool/graph/src/watcher.rs @@ -130,6 +130,7 @@ impl Sender { self.send(Status::Broadcast(peers)) } + /// Returns true if the are no more listeners for this extrinsic or it was finalized. pub fn is_done(&self) -> bool { self.finalized || self.receivers.is_empty() diff --git a/node/cli/Cargo.toml b/node/cli/Cargo.toml index b8fd63c38a..5fa92360d6 100644 --- a/node/cli/Cargo.toml +++ b/node/cli/Cargo.toml @@ -11,7 +11,7 @@ log = "0.4.8" tokio = "0.1.22" futures = "0.1.29" exit-future = "0.1.4" -jsonrpc-core = "14.0" +jsonrpc-core = "13.2.0" cli = { package = "substrate-cli", path = "../../core/cli" } codec = { package = "parity-scale-codec", version = "1.0.0" } sr-io = { path = "../../core/sr-io" } diff --git a/node/rpc-client/Cargo.toml b/node/rpc-client/Cargo.toml index 7fd50c5e35..e377f89359 100644 --- a/node/rpc-client/Cargo.toml +++ b/node/rpc-client/Cargo.toml @@ -8,7 +8,7 @@ edition = "2018" env_logger = "0.7.0" futures = "0.1.29" hyper = "0.12.35" -jsonrpc-core-client = { version = "14.0", features = ["http", "ws"] } +jsonrpc-core-client = { version = "13.1.0", features = ["http", "ws"] } log = "0.4.8" node-primitives = { path = "../primitives" } substrate-rpc = { path = "../../core/rpc", version = "2.0.0" } diff --git a/node/rpc/Cargo.toml b/node/rpc/Cargo.toml index 9cc5bfe1e6..5d2ca81e0f 100644 --- a/node/rpc/Cargo.toml +++ b/node/rpc/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" [dependencies] client = { package = "substrate-client", path = "../../core/client" } -jsonrpc-core = "14.0" +jsonrpc-core = "13.2.0" node-primitives = { path = "../primitives" } sr-primitives = { path = "../../core/sr-primitives" } srml-contracts-rpc = { path = "../../srml/contracts/rpc/" } diff --git a/srml/contracts/rpc/Cargo.toml b/srml/contracts/rpc/Cargo.toml index e516d93d63..90bf34bec1 100644 --- a/srml/contracts/rpc/Cargo.toml +++ b/srml/contracts/rpc/Cargo.toml @@ -7,9 +7,9 @@ edition = "2018" [dependencies] client = { package = "substrate-client", path = "../../../core/client" } codec = { package = "parity-scale-codec", version = "1.0.0" } -jsonrpc-core = "14.0" -jsonrpc-core-client = "14.0" -jsonrpc-derive = "14.0" +jsonrpc-core = "13.2.0" +jsonrpc-core-client = "13.2.0" +jsonrpc-derive = "13.2.0" primitives = { package = "substrate-primitives", path = "../../../core/primitives" } rpc-primitives = { package = "substrate-rpc-primitives", path = "../../../core/rpc/primitives" } serde = { version = "1.0.101", features = ["derive"] } diff --git a/srml/system/rpc/Cargo.toml b/srml/system/rpc/Cargo.toml index e3193c2018..04856a817f 100644 --- a/srml/system/rpc/Cargo.toml +++ b/srml/system/rpc/Cargo.toml @@ -7,9 +7,9 @@ edition = "2018" [dependencies] client = { package = "substrate-client", path = "../../../core/client" } codec = { package = "parity-scale-codec", version = "1.0.0" } -jsonrpc-core = "14.0" -jsonrpc-core-client = "14.0" -jsonrpc-derive = "14.0" +jsonrpc-core = "13.2.0" +jsonrpc-core-client = "13.2.0" +jsonrpc-derive = "13.2.0" log = "0.4.8" serde = { version = "1.0.101", features = ["derive"] } sr-primitives = { path = "../../../core/sr-primitives" } -- GitLab From 76a138f88cad878478f1c5ab565ec277b870362e Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Sun, 27 Oct 2019 14:36:35 +0100 Subject: [PATCH 115/167] runtime: Expose const params for nicks module (#3932) * Expose const params for nicks module * Bump runtime --- node/runtime/src/lib.rs | 4 ++-- srml/nicks/src/lib.rs | 9 +++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index fe97f806fc..2c9663cc96 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -83,8 +83,8 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // and set impl_version to equal spec_version. If only runtime // implementation changes and behavior does not, then leave spec_version as // is and increment impl_version. - spec_version: 186, - impl_version: 186, + spec_version: 187, + impl_version: 187, apis: RUNTIME_API_VERSIONS, }; diff --git a/srml/nicks/src/lib.rs b/srml/nicks/src/lib.rs index 894f7100f8..b5c433a70e 100644 --- a/srml/nicks/src/lib.rs +++ b/srml/nicks/src/lib.rs @@ -100,6 +100,15 @@ decl_module! { pub struct Module for enum Call where origin: T::Origin { fn deposit_event() = default; + /// Reservation fee. + const ReservationFee: BalanceOf = T::ReservationFee::get(); + + /// The minimum length a name may be. + const MinLength: u32 = T::MinLength::get() as u32; + + /// The maximum length a name may be. + const MaxLength: u32 = T::MaxLength::get() as u32; + /// Set an account's name. The name should be a UTF-8-encoded string by convention, though /// we don't check it. /// -- GitLab From 23da63a883ae84df2d836c3fd0fcc5c6fe8211b1 Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Sun, 27 Oct 2019 16:20:35 +0100 Subject: [PATCH 116/167] runtime: Add ability to force a name change (#3934) * Add ability to force a name change * Fix tests * Bump runtime. --- node/runtime/src/lib.rs | 6 ++--- srml/nicks/src/lib.rs | 59 ++++++++++++++++++++++++++++++++++++----- 2 files changed, 55 insertions(+), 10 deletions(-) diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index 2c9663cc96..d81ed2ebbd 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -83,8 +83,8 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // and set impl_version to equal spec_version. If only runtime // implementation changes and behavior does not, then leave spec_version as // is and increment impl_version. - spec_version: 187, - impl_version: 187, + spec_version: 188, + impl_version: 188, apis: RUNTIME_API_VERSIONS, }; @@ -469,7 +469,7 @@ impl nicks::Trait for Runtime { type Currency = Balances; type ReservationFee = ReservationFee; type Slashed = Treasury; - type KillOrigin = collective::EnsureMember; + type ForceOrigin = collective::EnsureMember; type MinLength = MinLength; type MaxLength = MaxLength; } diff --git a/srml/nicks/src/lib.rs b/srml/nicks/src/lib.rs index b5c433a70e..6b914ca5dc 100644 --- a/srml/nicks/src/lib.rs +++ b/srml/nicks/src/lib.rs @@ -40,7 +40,7 @@ use rstd::prelude::*; use sr_primitives::{ - traits::{StaticLookup, EnsureOrigin}, weights::SimpleDispatchInfo, + traits::{StaticLookup, EnsureOrigin, Zero}, weights::SimpleDispatchInfo }; use support::{ decl_module, decl_event, decl_storage, ensure, traits::{ @@ -65,8 +65,8 @@ pub trait Trait: system::Trait { /// What to do with slashed funds. type Slashed: OnUnbalanced>; - /// The origin which may forcibly remove a name. Root can always do this. - type KillOrigin: EnsureOrigin; + /// The origin which may forcibly set or remove a name. Root can always do this. + type ForceOrigin: EnsureOrigin; /// The minimum length a name may be. type MinLength: Get; @@ -86,6 +86,8 @@ decl_event!( pub enum Event where AccountId = ::AccountId, Balance = BalanceOf { /// A name was set. NameSet(AccountId), + /// A name was forcibly set. + NameForced(AccountId), /// A name was changed. NameChanged(AccountId), /// A name was cleared, and the given balance returned. @@ -170,7 +172,7 @@ decl_module! { /// Fails if `who` has not been named. The deposit is dealt with through `T::Slashed` /// imbalance handler. /// - /// The dispatch origin for this call must be _Root_ or match `T::KillOrigin`. + /// The dispatch origin for this call must be _Root_ or match `T::ForceOrigin`. /// /// # /// - O(1). @@ -180,7 +182,7 @@ decl_module! { /// # #[weight = SimpleDispatchInfo::FreeOperational] fn kill_name(origin, target: ::Source) { - T::KillOrigin::try_origin(origin) + T::ForceOrigin::try_origin(origin) .map(|_| ()) .or_else(ensure_root) .map_err(|_| "bad origin")?; @@ -194,6 +196,32 @@ decl_module! { Self::deposit_event(RawEvent::NameKilled(target, deposit)); } + + /// Set a third-party account's name with no deposit. + /// + /// No length checking is done on the name. + /// + /// The dispatch origin for this call must be _Root_ or match `T::ForceOrigin`. + /// + /// # + /// - O(1). + /// - At most one balance operation. + /// - One storage read/write. + /// - One event. + /// # + #[weight = SimpleDispatchInfo::FreeOperational] + fn force_name(origin, target: ::Source, name: Vec) { + T::ForceOrigin::try_origin(origin) + .map(|_| ()) + .or_else(ensure_root) + .map_err(|_| "bad origin")?; + + let target = T::Lookup::lookup(target)?; + let deposit = >::get(&target).map(|x| x.1).unwrap_or_else(Zero::zero); + >::insert(&target, (name, deposit)); + + Self::deposit_event(RawEvent::NameForced(target)); + } } } @@ -269,7 +297,7 @@ mod tests { type Currency = Balances; type ReservationFee = ReservationFee; type Slashed = (); - type KillOrigin = EnsureSignedBy; + type ForceOrigin = EnsureSignedBy; type MinLength = MinLength; type MaxLength = MaxLength; } @@ -292,7 +320,7 @@ mod tests { } #[test] - fn kill_names_should_work() { + fn kill_name_should_work() { new_test_ext().execute_with(|| { assert_ok!(Nicks::set_name(Origin::signed(2), b"Dave".to_vec())); assert_eq!(Balances::total_balance(&2), 10); @@ -302,6 +330,22 @@ mod tests { }); } + #[test] + fn force_name_should_work() { + new_test_ext().execute_with(|| { + assert_noop!( + Nicks::set_name(Origin::signed(2), b"Dr. David Brubeck, III".to_vec()), + "Name too long" + ); + + assert_ok!(Nicks::set_name(Origin::signed(2), b"Dave".to_vec())); + assert_eq!(Balances::reserved_balance(&2), 2); + assert_ok!(Nicks::force_name(Origin::signed(1), 2, b"Dr. David Brubeck, III".to_vec())); + assert_eq!(Balances::reserved_balance(&2), 2); + assert_eq!(>::get(2).unwrap(), (b"Dr. David Brubeck, III".to_vec(), 2)); + }); + } + #[test] fn normal_operation_should_work() { new_test_ext().execute_with(|| { @@ -335,6 +379,7 @@ mod tests { ); assert_ok!(Nicks::set_name(Origin::signed(1), b"Dave".to_vec())); assert_noop!(Nicks::kill_name(Origin::signed(2), 1), "bad origin"); + assert_noop!(Nicks::force_name(Origin::signed(2), 1, b"Whatever".to_vec()), "bad origin"); }); } } -- GitLab From 07f6bdc852c8fd6c364993716630bcb27e92fb95 Mon Sep 17 00:00:00 2001 From: kaichao Date: Mon, 28 Oct 2019 01:44:20 +0800 Subject: [PATCH 117/167] Fix test description. (#3935) --- srml/assets/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/srml/assets/src/lib.rs b/srml/assets/src/lib.rs index 528428000e..5c8b1bbd61 100644 --- a/srml/assets/src/lib.rs +++ b/srml/assets/src/lib.rs @@ -328,7 +328,7 @@ mod tests { } #[test] - fn transferring_amount_less_than_available_balance_should_not_work() { + fn transferring_amount_more_than_available_balance_should_not_work() { new_test_ext().execute_with(|| { assert_ok!(Assets::issue(Origin::signed(1), 100)); assert_eq!(Assets::balance(0, 1), 100); -- GitLab From 6e83db09cd8808173ca1573fe5cc040d29df5607 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Mon, 28 Oct 2019 09:35:09 +0100 Subject: [PATCH 118/167] `decl_storage!` check for duplicate `config()`/`get()` (#3936) * `decl_storage!` check for duplicate `config()`/`get()` * Fix tests --- Cargo.lock | 76 +++++++++---------- srml/support/procedural/src/storage/parse.rs | 62 ++++++++++----- srml/support/test/Cargo.toml | 2 +- srml/support/test/src/lib.rs | 6 -- srml/support/test/tests/decl_storage_ui.rs | 24 ++++++ .../tests/decl_storage_ui/config_duplicate.rs | 33 ++++++++ .../decl_storage_ui/config_duplicate.stderr | 5 ++ .../decl_storage_ui/config_get_duplicate.rs | 33 ++++++++ .../config_get_duplicate.stderr | 5 ++ .../tests/decl_storage_ui/get_duplicate.rs | 33 ++++++++ .../decl_storage_ui/get_duplicate.stderr | 5 ++ srml/support/test/tests/instance.rs | 1 + srml/support/test/tests/reserved_keyword.rs | 24 ++++++ 13 files changed, 244 insertions(+), 65 deletions(-) create mode 100644 srml/support/test/tests/decl_storage_ui.rs create mode 100644 srml/support/test/tests/decl_storage_ui/config_duplicate.rs create mode 100644 srml/support/test/tests/decl_storage_ui/config_duplicate.stderr create mode 100644 srml/support/test/tests/decl_storage_ui/config_get_duplicate.rs create mode 100644 srml/support/test/tests/decl_storage_ui/config_get_duplicate.stderr create mode 100644 srml/support/test/tests/decl_storage_ui/get_duplicate.rs create mode 100644 srml/support/test/tests/decl_storage_ui/get_duplicate.stderr create mode 100644 srml/support/test/tests/reserved_keyword.rs diff --git a/Cargo.lock b/Cargo.lock index 909fbb769e..af472eee31 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -124,7 +124,7 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -678,7 +678,7 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -879,9 +879,9 @@ name = "failure_derive" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "synstructure 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1441,9 +1441,9 @@ name = "impl-trait-for-tuples" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2971,9 +2971,9 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro-hack 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3073,9 +3073,9 @@ name = "proc-macro-error" version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3083,9 +3083,9 @@ name = "proc-macro-hack" version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3098,7 +3098,7 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3201,7 +3201,7 @@ name = "quote" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3546,9 +3546,9 @@ name = "rustversion" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3690,9 +3690,9 @@ name = "serde_derive" version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -4461,10 +4461,10 @@ name = "srml-staking-reward-curve" version = "2.0.0" dependencies = [ "proc-macro-crate 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -4706,9 +4706,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro-error 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -4853,9 +4853,9 @@ name = "substrate-chain-spec-derive" version = "2.0.0" dependencies = [ "proc-macro-crate 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -5164,9 +5164,9 @@ dependencies = [ name = "substrate-debug-derive" version = "2.0.0" dependencies = [ - "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -5861,10 +5861,10 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.5" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -5885,9 +5885,9 @@ name = "synstructure" version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -6527,9 +6527,9 @@ dependencies = [ "bumpalo 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "wasm-bindgen-shared 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -6559,9 +6559,9 @@ name = "wasm-bindgen-macro-support" version = "0.2.51" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "wasm-bindgen-backend 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "wasm-bindgen-shared 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -6579,9 +6579,9 @@ dependencies = [ "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "wasm-bindgen-backend 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "weedle 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -7126,7 +7126,7 @@ dependencies = [ "checksum proc-macro-error 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "aeccfe4d5d8ea175d5f0e4a2ad0637e0f4121d63bd99d356fb1f39ab2e7c6097" "checksum proc-macro-hack 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "114cdf1f426eb7f550f01af5f53a33c0946156f6814aec939b3bd77e844f9a9d" "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" -"checksum proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "90cf5f418035b98e655e9cdb225047638296b862b42411c4e45bb88d700f7fc0" +"checksum proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9c9e470a8dc4aeae2dee2f335e8f533e2d4b347e1434e5671afc49b054592f27" "checksum prost 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96d14b1c185652833d24aaad41c5832b0be5616a590227c1fbff57c616754b23" "checksum prost-build 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "eb788126ea840817128183f8f603dce02cb7aea25c2a0b764359d8e20010702e" "checksum prost-derive 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5e7dc378b94ac374644181a2247cebf59a6ec1c88b49ac77f3a94b86b79d0e11" @@ -7227,7 +7227,7 @@ dependencies = [ "checksum subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" "checksum subtle 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab3af2eb31c42e8f0ccf43548232556c42737e01a96db6e1777b0be108e79799" "checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" -"checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf" +"checksum syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "0e7bedb3320d0f3035594b0b723c8a28d7d336a3eda3881db79e61d676fb644c" "checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f" "checksum synstructure 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f085a5855930c0441ca1288cf044ea4aecf4f43a91668abdb870b4ba546a203" "checksum sysinfo 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d5bd3b813d94552a8033c650691645f8dd5a63d614dddd62428a95d3931ef7b6" diff --git a/srml/support/procedural/src/storage/parse.rs b/srml/support/procedural/src/storage/parse.rs index 53da5ae33e..e428fbe24f 100644 --- a/srml/support/procedural/src/storage/parse.rs +++ b/srml/support/procedural/src/storage/parse.rs @@ -17,7 +17,7 @@ //! Parsing of decl_storage input. use srml_support_procedural_tools::{ToTokens, Parse, syn_ext as ext}; -use syn::{Ident, Token}; +use syn::{Ident, Token, spanned::Spanned}; mod keyword { syn::custom_keyword!(hiddencrate); @@ -265,7 +265,6 @@ fn get_module_instance( pub fn parse(input: syn::parse::ParseStream) -> syn::Result { use syn::parse::Parse; - use syn::spanned::Spanned; let def = StorageDefinition::parse(input)?; @@ -303,9 +302,31 @@ pub fn parse(input: syn::parse::ParseStream) -> syn::Result, +) -> syn::Result> { + let mut storage_lines = Vec::::new(); + + for line in defs { let getter = line.getter.inner.map(|o| o.getfn.content.ident); let config = if let Some(config) = line.config.inner { if let Some(ident) = config.expr.content { @@ -315,14 +336,28 @@ pub fn parse(input: syn::parse::ParseStream) -> syn::Result super::StorageLineTypeDef::Map( super::MapDef { @@ -365,18 +400,5 @@ pub fn parse(input: syn::parse::ParseStream) -> syn::Result. + +#[test] +fn decl_storage_ui() { + // As trybuild is using `cargo check`, we don't need the real WASM binaries. + std::env::set_var("BUILD_DUMMY_WASM_BINARY", "1"); + + let t = trybuild::TestCases::new(); + t.compile_fail("tests/decl_storage_ui/*.rs"); +} diff --git a/srml/support/test/tests/decl_storage_ui/config_duplicate.rs b/srml/support/test/tests/decl_storage_ui/config_duplicate.rs new file mode 100644 index 0000000000..bdd7da7449 --- /dev/null +++ b/srml/support/test/tests/decl_storage_ui/config_duplicate.rs @@ -0,0 +1,33 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +pub trait Trait { + type Origin; + type BlockNumber: codec::Codec + codec::EncodeLike + Default + Clone; +} + +support::decl_module! { + pub struct Module for enum Call where origin: T::Origin {} +} + +support::decl_storage!{ + trait Store for Module as FinalKeysNone { + pub Value config(value): u32; + pub Value2 config(value): u32; + } +} + +fn main() {} diff --git a/srml/support/test/tests/decl_storage_ui/config_duplicate.stderr b/srml/support/test/tests/decl_storage_ui/config_duplicate.stderr new file mode 100644 index 0000000000..761e3f3b79 --- /dev/null +++ b/srml/support/test/tests/decl_storage_ui/config_duplicate.stderr @@ -0,0 +1,5 @@ +error: `config()`/`get()` with the same name already defined. + --> $DIR/config_duplicate.rs:29:21 + | +29 | pub Value2 config(value): u32; + | ^^^^^ diff --git a/srml/support/test/tests/decl_storage_ui/config_get_duplicate.rs b/srml/support/test/tests/decl_storage_ui/config_get_duplicate.rs new file mode 100644 index 0000000000..2bf8df4532 --- /dev/null +++ b/srml/support/test/tests/decl_storage_ui/config_get_duplicate.rs @@ -0,0 +1,33 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +pub trait Trait { + type Origin; + type BlockNumber: codec::Codec + codec::EncodeLike + Default + Clone; +} + +support::decl_module! { + pub struct Module for enum Call where origin: T::Origin {} +} + +support::decl_storage!{ + trait Store for Module as FinalKeysNone { + pub Value get(fn value) config(): u32; + pub Value2 config(value): u32; + } +} + +fn main() {} diff --git a/srml/support/test/tests/decl_storage_ui/config_get_duplicate.stderr b/srml/support/test/tests/decl_storage_ui/config_get_duplicate.stderr new file mode 100644 index 0000000000..34d040f4e1 --- /dev/null +++ b/srml/support/test/tests/decl_storage_ui/config_get_duplicate.stderr @@ -0,0 +1,5 @@ +error: `config()`/`get()` with the same name already defined. + --> $DIR/config_get_duplicate.rs:29:21 + | +29 | pub Value2 config(value): u32; + | ^^^^^ diff --git a/srml/support/test/tests/decl_storage_ui/get_duplicate.rs b/srml/support/test/tests/decl_storage_ui/get_duplicate.rs new file mode 100644 index 0000000000..41ca708352 --- /dev/null +++ b/srml/support/test/tests/decl_storage_ui/get_duplicate.rs @@ -0,0 +1,33 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +pub trait Trait { + type Origin; + type BlockNumber: codec::Codec + codec::EncodeLike + Default + Clone; +} + +support::decl_module! { + pub struct Module for enum Call where origin: T::Origin {} +} + +support::decl_storage!{ + trait Store for Module as FinalKeysNone { + pub Value get(fn value) config(): u32; + pub Value2 get(fn value) config(): u32; + } +} + +fn main() {} diff --git a/srml/support/test/tests/decl_storage_ui/get_duplicate.stderr b/srml/support/test/tests/decl_storage_ui/get_duplicate.stderr new file mode 100644 index 0000000000..130244196f --- /dev/null +++ b/srml/support/test/tests/decl_storage_ui/get_duplicate.stderr @@ -0,0 +1,5 @@ +error: `config()`/`get()` with the same name already defined. + --> $DIR/get_duplicate.rs:29:21 + | +29 | pub Value2 get(fn value) config(): u32; + | ^^^^^ diff --git a/srml/support/test/tests/instance.rs b/srml/support/test/tests/instance.rs index dd05cb1d8c..282fb9a6e2 100644 --- a/srml/support/test/tests/instance.rs +++ b/srml/support/test/tests/instance.rs @@ -13,6 +13,7 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . + #![recursion_limit="128"] use sr_primitives::{generic, BuildStorage, traits::{BlakeTwo256, Block as _, Verify}}; diff --git a/srml/support/test/tests/reserved_keyword.rs b/srml/support/test/tests/reserved_keyword.rs new file mode 100644 index 0000000000..898d61b827 --- /dev/null +++ b/srml/support/test/tests/reserved_keyword.rs @@ -0,0 +1,24 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +#[test] +fn reserved_keyword() { + // As trybuild is using `cargo check`, we don't need the real WASM binaries. + std::env::set_var("BUILD_DUMMY_WASM_BINARY", "1"); + + let t = trybuild::TestCases::new(); + t.compile_fail("tests/reserved_keyword/*.rs"); +} -- GitLab From 5c505d19787309a8f715fcaf1a178579ce23ef5b Mon Sep 17 00:00:00 2001 From: Max Inden Date: Mon, 28 Oct 2019 11:06:16 +0100 Subject: [PATCH 119/167] *: Disable authority discovery module (#3914) The authority discovery module enables authorities to be discoverable and discover other authorities to improve interconnection among them. In order to achieve this the module needs to know when the authority set changes, thus when a session changes. One has to register a module as a *session handler* in order for it to be notified of changing sessions. The order and number of these *session handlers* **MUST** correspond to the order and number of the *session keys*. Commit 7fc21ce added the authority discovery to the `SessionHandlers`. Given that the authority discovery module piggybacks on the Babe session keys the commit violated the above constraint. This commit reverts most of 7fc21ce, leaving `core/authority-discovery` and `srml/authority-discovery` untouched. --- Cargo.lock | 6 ----- core/service/Cargo.toml | 2 -- node/cli/Cargo.toml | 2 -- node/cli/src/chain_spec.rs | 9 +++---- node/cli/src/service.rs | 12 ++-------- node/runtime/Cargo.toml | 4 ---- node/runtime/src/lib.rs | 47 ++++++------------------------------- node/testing/src/genesis.rs | 1 - 8 files changed, 12 insertions(+), 71 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index af472eee31..3343942cc1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2392,7 +2392,6 @@ dependencies = [ "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 2.0.0", "sr-primitives 2.0.0", - "srml-authority-discovery 0.1.0", "srml-balances 2.0.0", "srml-contracts 2.0.0", "srml-finality-tracker 2.0.0", @@ -2403,7 +2402,6 @@ dependencies = [ "srml-timestamp 2.0.0", "srml-transaction-payment 2.0.0", "structopt 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "substrate-authority-discovery 2.0.0", "substrate-basic-authorship 2.0.0", "substrate-chain-spec 2.0.0", "substrate-cli 2.0.0", @@ -2510,7 +2508,6 @@ dependencies = [ "sr-staking-primitives 2.0.0", "sr-std 2.0.0", "sr-version 2.0.0", - "srml-authority-discovery 0.1.0", "srml-authorship 0.1.0", "srml-babe 2.0.0", "srml-balances 2.0.0", @@ -2539,7 +2536,6 @@ dependencies = [ "srml-transaction-payment 2.0.0", "srml-treasury 2.0.0", "srml-utility 2.0.0", - "substrate-authority-discovery-primitives 2.0.0", "substrate-client 2.0.0", "substrate-consensus-babe-primitives 2.0.0", "substrate-keyring 2.0.0", @@ -5587,8 +5583,6 @@ dependencies = [ "sr-io 2.0.0", "sr-primitives 2.0.0", "substrate-application-crypto 2.0.0", - "substrate-authority-discovery 2.0.0", - "substrate-authority-discovery-primitives 2.0.0", "substrate-chain-spec 2.0.0", "substrate-client 2.0.0", "substrate-client-db 2.0.0", diff --git a/core/service/Cargo.toml b/core/service/Cargo.toml index 04371087ef..0d6f279362 100644 --- a/core/service/Cargo.toml +++ b/core/service/Cargo.toml @@ -32,14 +32,12 @@ client = { package = "substrate-client", path = "../../core/client" } client_db = { package = "substrate-client-db", path = "../../core/client/db", features = ["kvdb-rocksdb"] } codec = { package = "parity-scale-codec", version = "1.0.0" } substrate-executor = { path = "../../core/executor" } -substrate-authority-discovery = { path = "../../core/authority-discovery"} transaction_pool = { package = "substrate-transaction-pool", path = "../../core/transaction-pool" } rpc-servers = { package = "substrate-rpc-servers", path = "../../core/rpc-servers" } rpc = { package = "substrate-rpc", path = "../../core/rpc" } tel = { package = "substrate-telemetry", path = "../../core/telemetry" } offchain = { package = "substrate-offchain", path = "../../core/offchain" } parity-multiaddr = { package = "parity-multiaddr", version = "0.5.0" } -authority-discovery-primitives = { package = "substrate-authority-discovery-primitives", path = "../authority-discovery/primitives", default-features = false } [dev-dependencies] substrate-test-runtime-client = { path = "../test-runtime/client" } diff --git a/node/cli/Cargo.toml b/node/cli/Cargo.toml index 5fa92360d6..7e011d9de8 100644 --- a/node/cli/Cargo.toml +++ b/node/cli/Cargo.toml @@ -48,8 +48,6 @@ balances = { package = "srml-balances", path = "../../srml/balances" } transaction-payment = { package = "srml-transaction-payment", path = "../../srml/transaction-payment" } support = { package = "srml-support", path = "../../srml/support", default-features = false } im_online = { package = "srml-im-online", path = "../../srml/im-online", default-features = false } -sr-authority-discovery = { package = "srml-authority-discovery", path = "../../srml/authority-discovery", default-features = false } -authority-discovery = { package = "substrate-authority-discovery", path = "../../core/authority-discovery"} serde = { version = "1.0.101", features = [ "derive" ] } client_db = { package = "substrate-client-db", path = "../../core/client/db", features = ["kvdb-rocksdb"] } offchain = { package = "substrate-offchain", path = "../../core/offchain" } diff --git a/node/cli/src/chain_spec.rs b/node/cli/src/chain_spec.rs index 360421bda1..80c74455e3 100644 --- a/node/cli/src/chain_spec.rs +++ b/node/cli/src/chain_spec.rs @@ -20,9 +20,9 @@ use chain_spec::ChainSpecExtension; use primitives::{Pair, Public, crypto::UncheckedInto, sr25519}; use serde::{Serialize, Deserialize}; use node_runtime::{ - AuthorityDiscoveryConfig, BabeConfig, BalancesConfig, ContractsConfig, CouncilConfig, DemocracyConfig, - ElectionsConfig, GrandpaConfig, ImOnlineConfig, IndicesConfig, SessionConfig, SessionKeys, StakerStatus, - StakingConfig, SudoConfig, SystemConfig, TechnicalCommitteeConfig, WASM_BINARY, + BabeConfig, BalancesConfig, ContractsConfig, CouncilConfig, DemocracyConfig, ElectionsConfig, GrandpaConfig, + ImOnlineConfig, IndicesConfig, SessionConfig, SessionKeys, StakerStatus, StakingConfig, SudoConfig, SystemConfig, + TechnicalCommitteeConfig, WASM_BINARY, }; use node_runtime::Block; use node_runtime::constants::{time::*, currency::*}; @@ -265,9 +265,6 @@ pub fn testnet_genesis( im_online: Some(ImOnlineConfig { keys: vec![], }), - authority_discovery: Some(AuthorityDiscoveryConfig{ - keys: vec![], - }), grandpa: Some(GrandpaConfig { authorities: vec![], }), diff --git a/node/cli/src/service.rs b/node/cli/src/service.rs index 78b978b72b..ef1fd8ad9f 100644 --- a/node/cli/src/service.rs +++ b/node/cli/src/service.rs @@ -130,8 +130,8 @@ macro_rules! new_full { // back-pressure. Authority discovery is triggering one event per authority within the current authority set. // This estimates the authority set size to be somewhere below 10 000 thereby setting the channel buffer size to // 10 000. - let (dht_event_tx, dht_event_rx) = - mpsc::channel::(10000); + let (dht_event_tx, _dht_event_rx) = + mpsc::channel::(10_000); let service = builder.with_network_protocol(|_| Ok(crate::service::NodeProtocol::new()))? .with_finality_proof_provider(|client, backend| @@ -169,14 +169,6 @@ macro_rules! new_full { let babe = babe::start_babe(babe_config)?; service.spawn_essential_task(babe); - - let authority_discovery = authority_discovery::AuthorityDiscovery::new( - service.client(), - service.network(), - dht_event_rx, - ); - - service.spawn_task(authority_discovery); } let config = grandpa::Config { diff --git a/node/runtime/Cargo.toml b/node/runtime/Cargo.toml index 9169f26dc3..94a7683dc5 100644 --- a/node/runtime/Cargo.toml +++ b/node/runtime/Cargo.toml @@ -12,7 +12,6 @@ rustc-hex = { version = "2.0", optional = true } safe-mix = { version = "1.0", default-features = false } serde = { version = "1.0.101", optional = true } -authority-discovery-primitives = { package = "substrate-authority-discovery-primitives", path = "../../core/authority-discovery/primitives", default-features = false } babe-primitives = { package = "substrate-consensus-babe-primitives", path = "../../core/consensus/babe/primitives", default-features = false } client = { package = "substrate-client", path = "../../core/client", default-features = false } node-primitives = { path = "../primitives", default-features = false } @@ -25,7 +24,6 @@ substrate-keyring = { path = "../../core/keyring", optional = true } substrate-session = { path = "../../core/session", default-features = false } version = { package = "sr-version", path = "../../core/sr-version", default-features = false } -authority-discovery = { package = "srml-authority-discovery", path = "../../srml/authority-discovery", default-features = false } authorship = { package = "srml-authorship", path = "../../srml/authorship", default-features = false } babe = { package = "srml-babe", path = "../../srml/babe", default-features = false } balances = { package = "srml-balances", path = "../../srml/balances", default-features = false } @@ -64,8 +62,6 @@ runtime_io = { package = "sr-io", path = "../../core/sr-io" } [features] default = ["std"] std = [ - "authority-discovery-primitives/std", - "authority-discovery/std", "authorship/std", "babe-primitives/std", "babe/std", diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index d81ed2ebbd..b56e015d77 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -29,7 +29,7 @@ use node_primitives::{ AccountId, AccountIndex, Balance, BlockNumber, Hash, Index, Moment, Signature, }; -use babe_primitives::{AuthorityId as BabeId, AuthoritySignature as BabeSignature}; +use babe_primitives::AuthorityId as BabeId; use grandpa::fg_primitives; use client::{ block_builder::api::{self as block_builder_api, InherentData, CheckInherentsResult}, @@ -50,8 +50,6 @@ use version::NativeVersion; use primitives::OpaqueMetadata; use grandpa::{AuthorityId as GrandpaId, AuthorityWeight as GrandpaWeight}; use im_online::sr25519::{AuthorityId as ImOnlineId}; -use authority_discovery_primitives::{AuthorityId as EncodedAuthorityId, Signature as EncodedSignature}; -use codec::{Encode, Decode}; use system::offchain::TransactionSubmitter; #[cfg(any(feature = "std", test))] @@ -83,8 +81,8 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // and set impl_version to equal spec_version. If only runtime // implementation changes and behavior does not, then leave spec_version as // is and increment impl_version. - spec_version: 188, - impl_version: 188, + spec_version: 189, + impl_version: 189, apis: RUNTIME_API_VERSIONS, }; @@ -211,7 +209,10 @@ impl authorship::Trait for Runtime { type EventHandler = Staking; } -type SessionHandlers = (Grandpa, Babe, ImOnline, AuthorityDiscovery); +// !!!!!!!!!!!!! +// WARNING!!!!!! SEE NOTE BELOW BEFORE TOUCHING THIS CODE +// !!!!!!!!!!!!! +type SessionHandlers = (Grandpa, Babe, ImOnline); impl_opaque_keys! { pub struct SessionKeys { @@ -439,10 +440,6 @@ impl offences::Trait for Runtime { type OnOffenceHandler = Staking; } -impl authority_discovery::Trait for Runtime { - type AuthorityId = BabeId; -} - impl grandpa::Trait for Runtime { type Event = Event; } @@ -531,7 +528,6 @@ construct_runtime!( Contracts: contracts, Sudo: sudo, ImOnline: im_online::{Module, Call, Storage, Event, ValidateUnsigned, Config}, - AuthorityDiscovery: authority_discovery::{Module, Call, Config}, Offences: offences::{Module, Call, Storage, Event}, RandomnessCollectiveFlip: randomness_collective_flip::{Module, Call, Storage}, Nicks: nicks::{Module, Call, Storage, Event}, @@ -646,35 +642,6 @@ impl_runtime_apis! { } } - impl authority_discovery_primitives::AuthorityDiscoveryApi for Runtime { - fn authorities() -> Vec { - AuthorityDiscovery::authorities().into_iter() - .map(|id| id.encode()) - .map(EncodedAuthorityId) - .collect() - } - - fn sign(payload: &Vec) -> Option<(EncodedSignature, EncodedAuthorityId)> { - AuthorityDiscovery::sign(payload).map(|(sig, id)| { - (EncodedSignature(sig.encode()), EncodedAuthorityId(id.encode())) - }) - } - - fn verify(payload: &Vec, signature: &EncodedSignature, authority_id: &EncodedAuthorityId) -> bool { - let signature = match BabeSignature::decode(&mut &signature.0[..]) { - Ok(s) => s, - _ => return false, - }; - - let authority_id = match BabeId::decode(&mut &authority_id.0[..]) { - Ok(id) => id, - _ => return false, - }; - - AuthorityDiscovery::verify(payload, signature, authority_id) - } - } - impl system_rpc_runtime_api::AccountNonceApi for Runtime { fn account_nonce(account: AccountId) -> Index { System::account_nonce(account) diff --git a/node/testing/src/genesis.rs b/node/testing/src/genesis.rs index 5220d1774b..b6ee28cf0f 100644 --- a/node/testing/src/genesis.rs +++ b/node/testing/src/genesis.rs @@ -89,7 +89,6 @@ pub fn config(support_changes_trie: bool, code: Option<&[u8]>) -> GenesisConfig authorities: vec![], }), im_online: Some(Default::default()), - authority_discovery: Some(Default::default()), democracy: Some(Default::default()), collective_Instance1: Some(Default::default()), collective_Instance2: Some(Default::default()), -- GitLab From 0e3001a1ad6fa3d1ba7da7342a8d0d3b3facb2f3 Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Mon, 28 Oct 2019 13:04:20 +0100 Subject: [PATCH 120/167] Tip payment is a different withdraw reason. (#3937) * Tip payment is a different withdraw reason. * Bump runtime version. * Test fix. * Fix lock type --- core/primitives/src/sr25519.rs | 3 --- srml/balances/src/lib.rs | 22 +++++++++++----------- srml/contracts/src/exec.rs | 2 +- srml/contracts/src/gas.rs | 2 +- srml/contracts/src/rent.rs | 4 ++-- srml/elections-phragmen/src/lib.rs | 4 ++-- srml/elections/src/lib.rs | 2 +- srml/generic-asset/src/lib.rs | 25 +++++++++++++++---------- srml/support/src/traits.rs | 12 +++++++----- srml/transaction-payment/src/lib.rs | 9 +++++++-- srml/treasury/src/lib.rs | 4 ++-- 11 files changed, 49 insertions(+), 40 deletions(-) diff --git a/core/primitives/src/sr25519.rs b/core/primitives/src/sr25519.rs index bb319b8221..ba7f480128 100644 --- a/core/primitives/src/sr25519.rs +++ b/core/primitives/src/sr25519.rs @@ -129,9 +129,6 @@ impl std::fmt::Display for Public { } } -#[cfg(not(feature = "std"))] -use core as std; - impl rstd::fmt::Debug for Public { #[cfg(feature = "std")] fn fmt(&self, f: &mut rstd::fmt::Formatter) -> rstd::fmt::Result { diff --git a/srml/balances/src/lib.rs b/srml/balances/src/lib.rs index 3c354da508..71f37cb8f8 100644 --- a/srml/balances/src/lib.rs +++ b/srml/balances/src/lib.rs @@ -824,13 +824,13 @@ where fn ensure_can_withdraw( who: &T::AccountId, _amount: T::Balance, - reason: WithdrawReason, + reasons: WithdrawReasons, new_balance: T::Balance, ) -> Result { - match reason { - WithdrawReason::Reserve | WithdrawReason::Transfer if Self::vesting_balance(who) > new_balance => - return Err("vesting balance too high to send value"), - _ => {} + if reasons.intersects(WithdrawReason::Reserve | WithdrawReason::Transfer) + && Self::vesting_balance(who) > new_balance + { + return Err("vesting balance too high to send value"); } let locks = Self::locks(who); if locks.is_empty() { @@ -842,7 +842,7 @@ where .all(|l| now >= l.until || new_balance >= l.amount - || !l.reasons.contains(reason) + || !l.reasons.intersects(reasons) ) { Ok(()) @@ -868,7 +868,7 @@ where if would_create && value < T::ExistentialDeposit::get() { return Err("value too low to create account"); } - Self::ensure_can_withdraw(transactor, value, WithdrawReason::Transfer, new_from_balance)?; + Self::ensure_can_withdraw(transactor, value, WithdrawReason::Transfer.into(), new_from_balance)?; // NOTE: total stake being stored in the same type means that this could never overflow // but better to be safe than sorry. @@ -893,7 +893,7 @@ where fn withdraw( who: &T::AccountId, value: Self::Balance, - reason: WithdrawReason, + reasons: WithdrawReasons, liveness: ExistenceRequirement, ) -> result::Result { let old_balance = Self::free_balance(who); @@ -907,7 +907,7 @@ where { return Err("payment would kill account") } - Self::ensure_can_withdraw(who, value, reason, new_balance)?; + Self::ensure_can_withdraw(who, value, reasons, new_balance)?; Self::set_free_balance(who, new_balance); Ok(NegativeImbalance::new(value)) } else { @@ -1014,7 +1014,7 @@ where Self::free_balance(who) .checked_sub(&value) .map_or(false, |new_balance| - Self::ensure_can_withdraw(who, value, WithdrawReason::Reserve, new_balance).is_ok() + Self::ensure_can_withdraw(who, value, WithdrawReason::Reserve.into(), new_balance).is_ok() ) } @@ -1028,7 +1028,7 @@ where return Err("not enough free funds") } let new_balance = b - value; - Self::ensure_can_withdraw(who, value, WithdrawReason::Reserve, new_balance)?; + Self::ensure_can_withdraw(who, value, WithdrawReason::Reserve.into(), new_balance)?; Self::set_reserved_balance(who, Self::reserved_balance(who) + value); Self::set_free_balance(who, new_balance); Ok(()) diff --git a/srml/contracts/src/exec.rs b/srml/contracts/src/exec.rs index af79c6c818..686b173ec7 100644 --- a/srml/contracts/src/exec.rs +++ b/srml/contracts/src/exec.rs @@ -642,7 +642,7 @@ fn transfer<'a, T: Trait, V: Vm, L: Loader>( if would_create && value < ctx.config.existential_deposit { return Err("value too low to create account"); } - T::Currency::ensure_can_withdraw(transactor, value, WithdrawReason::Transfer, new_from_balance)?; + T::Currency::ensure_can_withdraw(transactor, value, WithdrawReason::Transfer.into(), new_from_balance)?; let new_to_balance = match to_balance.checked_add(&value) { Some(b) => b, diff --git a/srml/contracts/src/gas.rs b/srml/contracts/src/gas.rs index 08070916fb..64997fbe81 100644 --- a/srml/contracts/src/gas.rs +++ b/srml/contracts/src/gas.rs @@ -215,7 +215,7 @@ pub fn buy_gas( let imbalance = T::Currency::withdraw( transactor, cost, - WithdrawReason::Fee, + WithdrawReason::Fee.into(), ExistenceRequirement::KeepAlive )?; diff --git a/srml/contracts/src/rent.rs b/srml/contracts/src/rent.rs index ecc5f61031..6647f89631 100644 --- a/srml/contracts/src/rent.rs +++ b/srml/contracts/src/rent.rs @@ -119,7 +119,7 @@ fn try_evict_or_and_pay_rent( let can_withdraw_rent = T::Currency::ensure_can_withdraw( account, dues_limited, - WithdrawReason::Fee, + WithdrawReason::Fee.into(), balance.saturating_sub(dues_limited), ) .is_ok(); @@ -129,7 +129,7 @@ fn try_evict_or_and_pay_rent( let imbalance = T::Currency::withdraw( account, dues_limited, - WithdrawReason::Fee, + WithdrawReason::Fee.into(), ExistenceRequirement::KeepAlive, ) .expect( diff --git a/srml/elections-phragmen/src/lib.rs b/srml/elections-phragmen/src/lib.rs index f56c5a4ec3..e74ecd8521 100644 --- a/srml/elections-phragmen/src/lib.rs +++ b/srml/elections-phragmen/src/lib.rs @@ -83,7 +83,7 @@ use srml_support::{ decl_storage, decl_event, ensure, decl_module, dispatch, traits::{ Currency, Get, LockableCurrency, LockIdentifier, ReservableCurrency, WithdrawReasons, - ChangeMembers, OnUnbalanced, + ChangeMembers, OnUnbalanced, WithdrawReason } }; use system::{self, ensure_signed, ensure_root}; @@ -215,7 +215,7 @@ decl_module! { &who, locked_balance, T::BlockNumber::max_value(), - WithdrawReasons::all(), + WithdrawReasons::except(WithdrawReason::TransactionPayment), ); >::insert(&who, locked_balance); >::insert(&who, votes); diff --git a/srml/elections/src/lib.rs b/srml/elections/src/lib.rs index 87e29f3b14..1e2349440f 100644 --- a/srml/elections/src/lib.rs +++ b/srml/elections/src/lib.rs @@ -807,7 +807,7 @@ impl Module { let imbalance = T::Currency::withdraw( &who, T::VotingFee::get(), - WithdrawReason::Fee, + WithdrawReason::Fee.into(), ExistenceRequirement::KeepAlive, )?; T::BadVoterIndex::on_unbalanced(imbalance); diff --git a/srml/generic-asset/src/lib.rs b/srml/generic-asset/src/lib.rs index fdbb57f56f..38bff08e12 100644 --- a/srml/generic-asset/src/lib.rs +++ b/srml/generic-asset/src/lib.rs @@ -128,7 +128,7 @@ //! T::Currency::withdraw( //! transactor, //! amount, -//! WithdrawReason::TransactionPayment, +//! WithdrawReason::TransactionPayment.into(), //! ExistenceRequirement::KeepAlive, //! )?; //! // ... @@ -563,11 +563,16 @@ impl Module { /// Transfer some liquid free balance from one account to another. /// This will not emit the `Transferred` event. - pub fn make_transfer(asset_id: &T::AssetId, from: &T::AccountId, to: &T::AccountId, amount: T::Balance) -> Result { + pub fn make_transfer( + asset_id: &T::AssetId, + from: &T::AccountId, + to: &T::AccountId, + amount: T::Balance + ) -> Result { let new_balance = Self::free_balance(asset_id, from) .checked_sub(&amount) .ok_or_else(|| "balance too low to send amount")?; - Self::ensure_can_withdraw(asset_id, from, amount, WithdrawReason::Transfer, new_balance)?; + Self::ensure_can_withdraw(asset_id, from, amount, WithdrawReason::Transfer.into(), new_balance)?; if from != to { >::mutate(asset_id, from, |balance| *balance -= amount); @@ -734,7 +739,7 @@ impl Module { asset_id: &T::AssetId, who: &T::AccountId, _amount: T::Balance, - reason: WithdrawReason, + reasons: WithdrawReasons, new_balance: T::Balance, ) -> Result { if asset_id != &Self::staking_asset_id() { @@ -748,7 +753,7 @@ impl Module { let now = >::block_number(); if Self::locks(who) .into_iter() - .all(|l| now >= l.until || new_balance >= l.amount || !l.reasons.contains(reason)) + .all(|l| now >= l.until || new_balance >= l.amount || !l.reasons.intersects(reasons)) { Ok(()) } else { @@ -1098,22 +1103,22 @@ where fn ensure_can_withdraw( who: &T::AccountId, amount: Self::Balance, - reason: WithdrawReason, + reasons: WithdrawReasons, new_balance: Self::Balance, ) -> Result { - >::ensure_can_withdraw(&U::asset_id(), who, amount, reason, new_balance) + >::ensure_can_withdraw(&U::asset_id(), who, amount, reasons, new_balance) } fn withdraw( who: &T::AccountId, value: Self::Balance, - reason: WithdrawReason, + reasons: WithdrawReasons, _: ExistenceRequirement, // no existential deposit policy for generic asset ) -> result::Result { let new_balance = Self::free_balance(who) .checked_sub(&value) .ok_or_else(|| "account has too few funds")?; - Self::ensure_can_withdraw(who, value, reason, new_balance)?; + Self::ensure_can_withdraw(who, value, reasons, new_balance)?; >::set_free_balance(&U::asset_id(), who, new_balance); Ok(NegativeImbalance::new(value)) } @@ -1197,7 +1202,7 @@ where .checked_sub(&value) .map_or(false, |new_balance| >::ensure_can_withdraw( - &U::asset_id(), who, value, WithdrawReason::Reserve, new_balance + &U::asset_id(), who, value, WithdrawReason::Reserve.into(), new_balance ).is_ok() ) } diff --git a/srml/support/src/traits.rs b/srml/support/src/traits.rs index c58d60ffc9..b321aeaeb9 100644 --- a/srml/support/src/traits.rs +++ b/srml/support/src/traits.rs @@ -381,7 +381,7 @@ pub trait Currency { fn ensure_can_withdraw( who: &AccountId, _amount: Self::Balance, - reason: WithdrawReason, + reasons: WithdrawReasons, new_balance: Self::Balance, ) -> result::Result<(), &'static str>; @@ -459,7 +459,7 @@ pub trait Currency { fn withdraw( who: &AccountId, value: Self::Balance, - reason: WithdrawReason, + reasons: WithdrawReasons, liveness: ExistenceRequirement, ) -> result::Result; @@ -467,11 +467,11 @@ pub trait Currency { fn settle( who: &AccountId, value: Self::PositiveImbalance, - reason: WithdrawReason, + reasons: WithdrawReasons, liveness: ExistenceRequirement, ) -> result::Result<(), Self::PositiveImbalance> { let v = value.peek(); - match Self::withdraw(who, v, reason, liveness) { + match Self::withdraw(who, v, reasons, liveness) { Ok(opposite) => Ok(drop(value.offset(opposite))), _ => Err(value), } @@ -614,6 +614,8 @@ bitmask! { Reserve = 0b00000100, /// In order to pay some other (higher-level) fees. Fee = 0b00001000, + /// In order to tip a validator for transaction inclusion. + Tip = 0b00010000, } } @@ -630,7 +632,7 @@ impl WithdrawReasons { /// # use srml_support::traits::{WithdrawReason, WithdrawReasons}; /// # fn main() { /// assert_eq!( - /// WithdrawReason::Fee | WithdrawReason::Transfer | WithdrawReason::Reserve, + /// WithdrawReason::Fee | WithdrawReason::Transfer | WithdrawReason::Reserve | WithdrawReason::Tip, /// WithdrawReasons::except(WithdrawReason::TransactionPayment), /// ); /// # } diff --git a/srml/transaction-payment/src/lib.rs b/srml/transaction-payment/src/lib.rs index 5ad5c650af..6ebda53b72 100644 --- a/srml/transaction-payment/src/lib.rs +++ b/srml/transaction-payment/src/lib.rs @@ -171,11 +171,16 @@ impl SignedExtension for ChargeTransactionPayment len: usize, ) -> TransactionValidity { // pay any fees. - let fee = Self::compute_fee(len, info, self.0); + let tip = self.0; + let fee = Self::compute_fee(len, info, tip); let imbalance = match T::Currency::withdraw( who, fee, - WithdrawReason::TransactionPayment, + if tip.is_zero() { + WithdrawReason::TransactionPayment.into() + } else { + WithdrawReason::TransactionPayment | WithdrawReason::Tip + }, ExistenceRequirement::KeepAlive, ) { Ok(imbalance) => imbalance, diff --git a/srml/treasury/src/lib.rs b/srml/treasury/src/lib.rs index 668dcaca32..7c38115bfb 100644 --- a/srml/treasury/src/lib.rs +++ b/srml/treasury/src/lib.rs @@ -324,7 +324,7 @@ impl Module { if let Err(problem) = T::Currency::settle( &Self::account_id(), imbalance, - WithdrawReason::Transfer, + WithdrawReason::Transfer.into(), ExistenceRequirement::KeepAlive ) { print("Inconsistent state - couldn't settle imbalance for funds spent by treasury"); @@ -657,7 +657,7 @@ mod tests { >::on_finalize(4); assert_eq!(Treasury::pot(), 0); // Pot is emptied - assert_eq!(Balances::free_balance(&Treasury::account_id()), 1); // but the account is still there + assert_eq!(Balances::free_balance(&Treasury::account_id()), 1); // but the account is still there }); } -- GitLab From 2ceb89e88fa98161e058f55fb1b72427edbdc298 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Mon, 28 Oct 2019 13:12:31 +0100 Subject: [PATCH 121/167] Too many addresses for a node is now a debug! rather than warn! (#3938) * Too many addresses for a node is now a debug! rather than warn! * I managed to fail this change --- core/network/src/behaviour.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/network/src/behaviour.rs b/core/network/src/behaviour.rs index 2471cbcaaf..28830b326e 100644 --- a/core/network/src/behaviour.rs +++ b/core/network/src/behaviour.rs @@ -26,7 +26,7 @@ use libp2p::core::{Multiaddr, PeerId, PublicKey}; use libp2p::kad::record; use libp2p::swarm::{NetworkBehaviourAction, NetworkBehaviourEventProcess}; use libp2p::core::{nodes::Substream, muxing::StreamMuxerBox}; -use log::warn; +use log::{debug, warn}; use sr_primitives::traits::Block as BlockT; use std::iter; use void; @@ -133,7 +133,7 @@ impl, H: ExHashT> NetworkBehaviourEventPr warn!(target: "sub-libp2p", "Connected to a non-Substrate node: {:?}", info); } if info.listen_addrs.len() > 30 { - warn!(target: "sub-libp2p", "Node {:?} has reported more than 30 addresses; \ + debug!(target: "sub-libp2p", "Node {:?} has reported more than 30 addresses; \ it is identified by {:?} and {:?}", peer_id, info.protocol_version, info.agent_version ); -- GitLab From 33e56523b9a2881484f833d63df2417306e7e315 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Mon, 28 Oct 2019 15:29:53 +0100 Subject: [PATCH 122/167] Updates to elections-phragmen and some runtime docs. (#3940) * minor changes * Refactors for phragmen-election * Bump. * Fix genesis stuff * Fix rest of the errors --- core/phragmen/src/lib.rs | 45 ++++- core/sr-primitives/src/weights.rs | 62 +++--- node/cli/src/chain_spec.rs | 14 +- node/runtime/src/lib.rs | 10 +- node/testing/src/genesis.rs | 1 - srml/elections-phragmen/src/lib.rs | 313 ++++++++++++++++++----------- srml/example/src/lib.rs | 17 +- srml/staking/src/lib.rs | 33 +-- srml/system/src/lib.rs | 1 - 9 files changed, 300 insertions(+), 196 deletions(-) diff --git a/core/phragmen/src/lib.rs b/core/phragmen/src/lib.rs index 7377bac2f8..8c8401bed6 100644 --- a/core/phragmen/src/lib.rs +++ b/core/phragmen/src/lib.rs @@ -290,7 +290,9 @@ pub fn elect( let mut assignment = (n.who.clone(), vec![]); for e in &mut n.edges { if let Some(c) = elected_candidates.iter().cloned().find(|(c, _)| *c == e.who) { - if c.0 != n.who { + // if self_vote == false, this branch should always be executed as we want to + // collect all nominations + if c.0 != n.who || !self_vote { let per_bill_parts = { if n.load == e.load { @@ -360,6 +362,47 @@ pub fn elect( }) } +/// Build the support map from the given phragmen result. +pub fn build_support_map( + elected_stashes: &Vec, + assignments: &Vec<(AccountId, Vec>)>, + stake_of: FS, + assume_self_vote: bool, +) -> SupportMap where + AccountId: Default + Ord + Member, + Balance: Default + Copy + SimpleArithmetic, + C: Convert + Convert, + for<'r> FS: Fn(&'r AccountId) -> Balance, +{ + let to_votes = |b: Balance| >::convert(b) as ExtendedBalance; + // Initialize the support of each candidate. + let mut supports = >::new(); + elected_stashes + .iter() + .map(|e| (e, if assume_self_vote { to_votes(stake_of(e)) } else { Zero::zero() } )) + .for_each(|(e, s)| { + let item = Support { own: s, total: s, ..Default::default() }; + supports.insert(e.clone(), item); + }); + + // build support struct. + for (n, assignment) in assignments.iter() { + for (c, per_thing) in assignment.iter() { + let nominator_stake = to_votes(stake_of(n)); + // AUDIT: it is crucially important for the `Mul` implementation of all + // per-things to be sound. + let other_stake = *per_thing * nominator_stake; + if let Some(support) = supports.get_mut(c) { + // For an astronomically rich validator with more astronomically rich + // set of nominators, this might saturate. + support.total = support.total.saturating_add(other_stake); + support.others.push((n.clone(), other_stake)); + } + } + } + supports +} + /// Performs equalize post-processing to the output of the election algorithm. This happens in /// rounds. The number of rounds and the maximum diff-per-round tolerance can be tuned through input /// parameters. diff --git a/core/sr-primitives/src/weights.rs b/core/sr-primitives/src/weights.rs index b245f90247..89852eb595 100644 --- a/core/sr-primitives/src/weights.rs +++ b/core/sr-primitives/src/weights.rs @@ -14,11 +14,23 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -//! Primitives for transaction weighting. +//! # Primitives for transaction weighting. //! -//! Each dispatch function within `decl_module!` can have an optional `#[weight = $x]` attribute. -//! `$x` can be any type that implements the `ClassifyDispatch` and `WeighData` traits. By -//! default, All transactions are annotated with `#[weight = SimpleDispatchInfo::default()]`. +//! All dispatchable functions defined in `decl_module!` must provide two trait implementations: +//! - [`WeightData`]: To determine the weight of the dispatch. +//! - [`ClassifyDispatch`]: To determine the class of the dispatch. See the enum definition for +//! more information on dispatch classes. +//! +//! Every dispatchable function is responsible for providing this data via an optional `#[weight = +//! $x]` attribute. In this snipped, `$x` can be any user provided struct that implements the +//! two aforementioned traits. +//! +//! Substrate then bundles then output information of the two traits into [`DispatchInfo`] struct +//! and provides it by implementing the [`GetDispatchInfo`] for all `Call` variants, and opaque +//! extrinsic types. +//! +//! If no `#[weight]` is defined, the macro automatically injects the `Default` implementation of +//! the [`SimpleDispatchInfo`]. //! //! Note that the decl_module macro _cannot_ enforce this and will simply fail if an invalid struct //! (something that does not implement `Weighable`) is passed in. @@ -31,8 +43,24 @@ pub use crate::transaction_validity::TransactionPriority; /// Numeric range of a transaction weight. pub type Weight = u32; -/// A generalized group of dispatch types. This is only distinguishing normal, user-triggered transactions -/// (`Normal`) and anything beyond which serves a higher purpose to the system (`Operational`). +/// Means of weighing some particular kind of data (`T`). +pub trait WeighData { + /// Weigh the data `T` given by `target`. When implementing this for a dispatchable, `T` will be + /// a tuple of all arguments given to the function (except origin). + fn weigh_data(&self, target: T) -> Weight; +} + +/// Means of classifying a dispatchable function. +pub trait ClassifyDispatch { + /// Classify the dispatch function based on input data `target` of type `T`. When implementing + /// this for a dispatchable, `T` will be a tuple of all arguments given to the function (except + /// origin). + fn classify_dispatch(&self, target: T) -> DispatchClass; +} + +/// A generalized group of dispatch types. This is only distinguishing normal, user-triggered +/// transactions (`Normal`) and anything beyond which serves a higher purpose to the system +/// (`Operational`). #[derive(PartialEq, Eq, Clone, Copy, RuntimeDebug)] pub enum DispatchClass { /// A normal dispatch. @@ -82,8 +110,8 @@ impl DispatchInfo { } } -/// A `Dispatchable` function (aka transaction) that can carry some static information along with it, using the -/// `#[weight]` attribute. +/// A `Dispatchable` function (aka transaction) that can carry some static information along with +/// it, using the `#[weight]` attribute. pub trait GetDispatchInfo { /// Return a `DispatchInfo`, containing relevant information of this dispatch. /// @@ -91,18 +119,6 @@ pub trait GetDispatchInfo { fn get_dispatch_info(&self) -> DispatchInfo; } -/// Means of weighing some particular kind of data (`T`). -pub trait WeighData { - /// Weigh the data `T` given by `target`. - fn weigh_data(&self, target: T) -> Weight; -} - -/// Means of classifying a dispatchable function. -pub trait ClassifyDispatch { - /// Classify the dispatch function based on input data `target` of type `T`. - fn classify_dispatch(&self, target: T) -> DispatchClass; -} - /// Default type used with the `#[weight = x]` attribute in a substrate chain. /// /// A user may pass in any other type that implements the correct traits. If not, the `Default` @@ -114,13 +130,9 @@ pub trait ClassifyDispatch { /// - A `Free` variant is equal to `::Fixed(0)`. Note that this does not guarantee inclusion. /// - A `Max` variant is equal to `::Fixed(Weight::max_value())`. /// -/// Based on the final weight value, based on the above variants: -/// - A _weight-fee_ is deducted. -/// - The block weight is consumed proportionally. -/// /// As for the generalized groups themselves: /// - `Normal` variants will be assigned a priority proportional to their weight. They can only -/// consume a portion (1/4) of the maximum block resource limits. +/// consume a portion (defined in the system module) of the maximum block resource limits. /// - `Operational` variants will be assigned the maximum priority. They can potentially consume /// the entire block resource limit. #[derive(Clone, Copy)] diff --git a/node/cli/src/chain_spec.rs b/node/cli/src/chain_spec.rs index 80c74455e3..04fb41c211 100644 --- a/node/cli/src/chain_spec.rs +++ b/node/cli/src/chain_spec.rs @@ -20,12 +20,12 @@ use chain_spec::ChainSpecExtension; use primitives::{Pair, Public, crypto::UncheckedInto, sr25519}; use serde::{Serialize, Deserialize}; use node_runtime::{ - BabeConfig, BalancesConfig, ContractsConfig, CouncilConfig, DemocracyConfig, ElectionsConfig, GrandpaConfig, - ImOnlineConfig, IndicesConfig, SessionConfig, SessionKeys, StakerStatus, StakingConfig, SudoConfig, SystemConfig, - TechnicalCommitteeConfig, WASM_BINARY, + BabeConfig, BalancesConfig, ContractsConfig, CouncilConfig, DemocracyConfig, GrandpaConfig, + ImOnlineConfig, IndicesConfig, SessionConfig, SessionKeys, StakerStatus, StakingConfig, + SudoConfig, SystemConfig, TechnicalCommitteeConfig, WASM_BINARY, }; use node_runtime::Block; -use node_runtime::constants::{time::*, currency::*}; +use node_runtime::constants::currency::*; use substrate_service; use hex_literal::hex; use substrate_telemetry::TelemetryEndpoints; @@ -243,12 +243,6 @@ pub fn testnet_genesis( members: vec![], phantom: Default::default(), }), - elections_phragmen: Some(ElectionsConfig { - members: endowed_accounts.iter().take(2).cloned().collect(), - term_duration: 28 * DAYS, - desired_members: 4, - desired_runners_up: 1, - }), contracts: Some(ContractsConfig { current_schedule: contracts::Schedule { enable_println, // this should only be enabled on development chains diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index b56e015d77..a6bd25a73e 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -82,7 +82,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // implementation changes and behavior does not, then leave spec_version as // is and increment impl_version. spec_version: 189, - impl_version: 189, + impl_version: 190, apis: RUNTIME_API_VERSIONS, }; @@ -328,6 +328,9 @@ impl collective::Trait for Runtime { parameter_types! { pub const CandidacyBond: Balance = 10 * DOLLARS; pub const VotingBond: Balance = 1 * DOLLARS; + pub const TermDuration: BlockNumber = 7 * DAYS; + pub const DesiredMembers: u32 = 13; + pub const DesiredRunnersUp: u32 = 7; } impl elections_phragmen::Trait for Runtime { @@ -336,6 +339,9 @@ impl elections_phragmen::Trait for Runtime { type CurrencyToVote = CurrencyToVoteHandler; type CandidacyBond = CandidacyBond; type VotingBond = VotingBond; + type TermDuration = TermDuration; + type DesiredMembers = DesiredMembers; + type DesiredRunnersUp = DesiredRunnersUp; type LoserCandidate = (); type BadReport = (); type KickedMember = (); @@ -520,7 +526,7 @@ construct_runtime!( Democracy: democracy::{Module, Call, Storage, Config, Event}, Council: collective::::{Module, Call, Storage, Origin, Event, Config}, TechnicalCommittee: collective::::{Module, Call, Storage, Origin, Event, Config}, - Elections: elections_phragmen::{Module, Call, Storage, Event, Config}, + Elections: elections_phragmen::{Module, Call, Storage, Event}, TechnicalMembership: membership::::{Module, Call, Storage, Event, Config}, FinalityTracker: finality_tracker::{Module, Call, Inherent}, Grandpa: grandpa::{Module, Call, Storage, Config, Event}, diff --git a/node/testing/src/genesis.rs b/node/testing/src/genesis.rs index b6ee28cf0f..0b99052f25 100644 --- a/node/testing/src/genesis.rs +++ b/node/testing/src/genesis.rs @@ -93,7 +93,6 @@ pub fn config(support_changes_trie: bool, code: Option<&[u8]>) -> GenesisConfig collective_Instance1: Some(Default::default()), collective_Instance2: Some(Default::default()), membership_Instance1: Some(Default::default()), - elections_phragmen: Some(Default::default()), sudo: Some(Default::default()), treasury: Some(Default::default()), } diff --git a/srml/elections-phragmen/src/lib.rs b/srml/elections-phragmen/src/lib.rs index e74ecd8521..f22c05ca45 100644 --- a/srml/elections-phragmen/src/lib.rs +++ b/srml/elections-phragmen/src/lib.rs @@ -86,6 +86,7 @@ use srml_support::{ ChangeMembers, OnUnbalanced, WithdrawReason } }; +use phragmen::ExtendedBalance; use system::{self, ensure_signed, ensure_root}; const MODULE_ID: LockIdentifier = *b"phrelect"; @@ -127,25 +128,26 @@ pub trait Trait: system::Trait { /// Handler for the unbalanced reduction when a member has been kicked. type KickedMember: OnUnbalanced>; + + /// Number of members to elect. + type DesiredMembers: Get; + + /// Number of runners_up to keep. + type DesiredRunnersUp: Get; + + /// How long each seat is kept. This defines the next block number at which an election + /// round will happen. If set to zero, no elections are ever triggered and the module will + /// be in passive mode. + type TermDuration: Get; } decl_storage! { trait Store for Module as PhragmenElection { - // ---- parameters - /// Number of members to elect. - pub DesiredMembers get(fn desired_members) config(): u32; - /// Number of runners_up to keep. - pub DesiredRunnersUp get(fn desired_runners_up) config(): u32; - /// How long each seat is kept. This defines the next block number at which an election - /// round will happen. If set to zero, no elections are ever triggered and the module will - /// be in passive mode. In that case only a member set defined in at genesis can exist. - pub TermDuration get(fn term_duration) config(): T::BlockNumber; - // ---- State /// The current elected membership. Sorted based on account id. - pub Members get(fn members) config(): Vec; + pub Members get(fn members): Vec<(T::AccountId, BalanceOf)>; /// The current runners_up. Sorted based on low to high merit (worse to best runner). - pub RunnersUp get(fn runners_up): Vec; + pub RunnersUp get(fn runners_up): Vec<(T::AccountId, BalanceOf)>; /// The total number of vote rounds that have happened, excluding the upcoming one. pub ElectionRounds get(fn election_rounds): u32 = Zero::zero(); @@ -166,6 +168,9 @@ decl_module! { const CandidacyBond: BalanceOf = T::CandidacyBond::get(); const VotingBond: BalanceOf = T::VotingBond::get(); + const DesiredMembers: u32 = T::DesiredMembers::get(); + const DesiredRunnersUp: u32 = T::DesiredRunnersUp::get(); + const TermDuration: T::BlockNumber = T::TermDuration::get(); /// Vote for a set of candidates for the upcoming round of election. /// @@ -194,8 +199,8 @@ decl_module! { ensure!(!allowed_votes.is_zero(), "cannot vote when no candidates or members exist"); ensure!(votes.len() <= allowed_votes, "cannot vote more than candidates"); ensure!(votes.len() <= MAXIMUM_VOTE, "cannot vote more than maximum allowed"); - ensure!(!votes.is_empty(), "must vote for at least one candidate."); + ensure!( value > T::Currency::minimum_balance(), "cannot vote with stake less than minimum balance" @@ -310,19 +315,6 @@ decl_module! { >::mutate(|c| c.insert(index, who)); } - /// Set the desired member count. Changes will be effective at the beginning of next round. - /// - /// # - /// #### State - /// Reads: O(1) - /// Writes: O(1) - /// # - #[weight = SimpleDispatchInfo::FixedOperational(10_000)] - fn set_desired_member_count(origin, #[compact] count: u32) { - ensure_root(origin)?; - DesiredMembers::put(count); - } - /// Remove a particular member from the set. This is effective immediately. /// /// If a runner-up is available, then the best runner-up will be removed and replaces the @@ -340,49 +332,45 @@ decl_module! { ensure_root(origin)?; let who = T::Lookup::lookup(who)?; - let mut members = Self::members(); - if let Ok(index) = members.binary_search(&who) { + let mut members_with_stake = Self::members(); + if let Ok(index) = members_with_stake.binary_search_by(|(ref m, ref _s)| m.cmp(&who)) { // remove, slash, emit event. - members.remove(index); + members_with_stake.remove(index); let (imbalance, _) = T::Currency::slash_reserved(&who, T::CandidacyBond::get()); T::KickedMember::on_unbalanced(imbalance); Self::deposit_event(RawEvent::MemberKicked(who.clone())); let mut runners_up = Self::runners_up(); - if let Some(replacement) = runners_up.pop() { + if let Some((replacement, stake)) = runners_up.pop() { // replace the outgoing with the best runner up. - if let Err(index) = members.binary_search(&replacement) { - members.insert(index, replacement.clone()); + if let Err(index) = members_with_stake + .binary_search_by(|(ref m, ref _s)| m.cmp(&replacement)) + { + members_with_stake.insert(index, (replacement.clone(), stake)); ElectionRounds::mutate(|v| *v += 1); - T::ChangeMembers::change_members_sorted(&[replacement], &[who], &members); + T::ChangeMembers::change_members_sorted( + &[replacement], + &[who], + &members_with_stake + .iter() + .map(|(m, _)| m.clone()) + .collect::>(), + ); } // else it would mean that the runner up was already a member. This cannot // happen. If it does, not much that we can do about it. - >::put(members); + >::put(members_with_stake); >::put(runners_up); } else { // update `Members` storage -- `do_phragmen` adds this to the candidate list. - >::put(members); + >::put(members_with_stake); // trigger a new phragmen. grab a cup of coffee. This might take a while. Self::do_phragmen(); } } } - /// Set the duration of each term. This will affect the next election's block number. - /// - /// # - /// #### State - /// Reads: O(1) - /// Writes: O(1) - /// # - #[weight = SimpleDispatchInfo::FixedOperational(10_000)] - fn set_term_duration(origin, #[compact] count: T::BlockNumber) { - ensure_root(origin)?; - >::put(count); - } - /// What to do at the end of each block. Checks if an election needs to happen or not. fn on_initialize(n: T::BlockNumber) { if let Err(e) = Self::end_block(n) { @@ -394,10 +382,13 @@ decl_module! { } decl_event!( - pub enum Event where ::AccountId { + pub enum Event where + Balance = BalanceOf, + ::AccountId, + { /// A new term with new members. This indicates that enough candidates existed, not that /// enough have has been elected. The inner value must be examined for this purpose. - NewTerm(Vec), + NewTerm(Vec<(AccountId, Balance)>), /// No (or not enough) candidates existed for this round. EmptyTerm, /// A member has been removed. This should always be followed by either `NewTerm` ot @@ -429,7 +420,32 @@ impl Module { /// /// Limited number of members. Binary search. Constant time factor. O(1) fn is_member(who: &T::AccountId) -> bool { - Self::members().binary_search(who).is_ok() + Self::members_ids().binary_search(who).is_ok() + } + + /// Returns number of desired members. + fn desired_members() -> u32 { + T::DesiredMembers::get() + } + + /// Returns number of desired runners up. + fn desired_runners_up() -> u32 { + T::DesiredRunnersUp::get() + } + + /// Returns the term duration + fn term_duration() -> T::BlockNumber { + T::TermDuration::get() + } + + /// Get the members' account ids. + fn members_ids() -> Vec { + Self::members().into_iter().map(|(m, _)| m).collect::>() + } + + /// The the runners' up account ids. + fn runners_up_ids() -> Vec { + Self::runners_up().into_iter().map(|(r, _)| r).collect::>() } /// Check if `who` is a defunct voter. @@ -500,11 +516,11 @@ impl Module { let mut exposed_candidates = candidates.clone(); // current members are always a candidate for the next round as well. // this is guaranteed to not create any duplicates. - candidates.append(&mut Self::members()); + candidates.append(&mut Self::members_ids()); // previous runners_up are also always candidates for the next round. - candidates.append(&mut Self::runners_up()); + candidates.append(&mut Self::runners_up_ids()); // and exposed to being an outgoing in case they are no longer elected. - exposed_candidates.append(&mut Self::runners_up()); + exposed_candidates.append(&mut Self::runners_up_ids()); let voters_and_votes = >::enumerate() .map(|(v, i)| (v, i)) @@ -532,14 +548,35 @@ impl Module { .filter_map(|(m, a)| if a.is_zero() { None } else { Some(m) } ) .collect::>(); + let support_map = phragmen::build_support_map::<_, _, _, T::CurrencyToVote>( + &new_set, + &phragmen_result.assignments, + Self::locked_stake_of, + false, + ); + + let to_balance = |e: ExtendedBalance| + >>::convert(e); + let new_set_with_stake = new_set + .into_iter() + .map(|ref m| { + let support = support_map.get(m) + .expect( + "entire new_set was given to build_support_map; en entry must be \ + created for each item; qed" + ); + (m.clone(), to_balance(support.total)) + }) + .collect::)>>(); + // split new set into winners and runner ups. - let split_point = desired_seats.min(new_set.len()); - let mut new_members = (&new_set[..split_point]).to_vec(); - let runners_up = &new_set[split_point..] + let split_point = desired_seats.min(new_set_with_stake.len()); + let mut new_members = (&new_set_with_stake[..split_point]).to_vec(); + let runners_up = &new_set_with_stake[split_point..] .into_iter() .cloned() .rev() - .collect::>(); + .collect::)>>(); // sort and save the members. new_members.sort(); @@ -550,13 +587,13 @@ impl Module { // report member changes. We compute diff because we need the outgoing list. let (incoming, outgoing) = T::ChangeMembers::compute_members_diff( - &new_members, - &old_members + &Self::members_ids(), + &old_members.into_iter().map(|(m, _)| m).collect::>(), ); T::ChangeMembers::change_members_sorted( &incoming, &outgoing.clone(), - &new_members + &Self::members_ids(), ); // unlike exposed_candidates, these are members who were in the list and no longer @@ -567,7 +604,8 @@ impl Module { // runner up list is not sorted. O(K*N) given K runner ups. Overall: O(NLogM + N*K) exposed_candidates.into_iter().for_each(|c| { // any candidate who is not a member and not a runner up. - if new_members.binary_search(&c).is_err() && !runners_up.contains(&c) + if new_members.binary_search_by_key(&c, |(m, _)| m.clone()).is_err() + && !Self::runners_up_ids().contains(&c) { let (imbalance, _) = T::Currency::slash_reserved(&c, T::CandidacyBond::get()); T::LoserCandidate::on_unbalanced(imbalance); @@ -651,7 +689,9 @@ mod tests { thread_local! { static VOTING_BOND: RefCell = RefCell::new(2); - static MEMBERS: RefCell> = RefCell::new(vec![]); + static DESIRED_MEMBERS: RefCell = RefCell::new(2); + static DESIRED_RUNNERS_UP: RefCell = RefCell::new(2); + static TERM_DURATION: RefCell = RefCell::new(5); } pub struct VotingBond; @@ -659,6 +699,21 @@ mod tests { fn get() -> u64 { VOTING_BOND.with(|v| *v.borrow()) } } + pub struct DesiredMembers; + impl Get for DesiredMembers { + fn get() -> u32 { DESIRED_MEMBERS.with(|v| *v.borrow()) } + } + + pub struct DesiredRunnersUp; + impl Get for DesiredRunnersUp { + fn get() -> u32 { DESIRED_RUNNERS_UP.with(|v| *v.borrow()) } + } + + pub struct TermDuration; + impl Get for TermDuration { + fn get() -> u64 { TERM_DURATION.with(|v| *v.borrow()) } + } + pub struct TestChangeMembers; impl ChangeMembers for TestChangeMembers { fn change_members_sorted(_: &[u64], _: &[u64], _: &[u64]) {} @@ -682,6 +737,9 @@ mod tests { type ChangeMembers = TestChangeMembers; type CandidacyBond = CandidacyBond; type VotingBond = VotingBond; + type TermDuration = TermDuration; + type DesiredMembers = DesiredMembers; + type DesiredRunnersUp = DesiredRunnersUp; type LoserCandidate = (); type KickedMember = (); type BadReport = (); @@ -698,7 +756,7 @@ mod tests { { System: system::{Module, Call, Event}, Balances: balances::{Module, Call, Event, Config}, - Elections: elections::{Module, Call, Event, Config}, + Elections: elections::{Module, Call, Event}, } ); @@ -707,7 +765,6 @@ mod tests { voter_bond: u64, term_duration: u64, desired_runners_up: u32, - members: Vec, } impl Default for ExtBuilder { @@ -717,7 +774,6 @@ mod tests { voter_bond: 2, desired_runners_up: 0, term_duration: 5, - members: vec![], } } } @@ -735,12 +791,10 @@ mod tests { self.term_duration = duration; self } - pub fn members(mut self, members: Vec) -> Self { - self.members = members; - self - } pub fn build(self) -> runtime_io::TestExternalities { VOTING_BOND.with(|v| *v.borrow_mut() = self.voter_bond); + TERM_DURATION.with(|v| *v.borrow_mut() = self.term_duration); + DESIRED_RUNNERS_UP.with(|v| *v.borrow_mut() = self.desired_runners_up); GenesisConfig { balances: Some(balances::GenesisConfig::{ balances: vec![ @@ -753,12 +807,6 @@ mod tests { ], vesting: vec![], }), - elections: Some(elections::GenesisConfig::{ - members: self.members, - desired_members: 2, - desired_runners_up: self.desired_runners_up, - term_duration: self.term_duration, - }), }.build_storage().unwrap().into() } } @@ -798,10 +846,9 @@ mod tests { } #[test] - fn passive_module_should_work() { + fn term_duration_zero_is_passive() { ExtBuilder::default() .term_duration(0) - .members(vec![1, 2, 3]) .build() .execute_with(|| { @@ -810,17 +857,16 @@ mod tests { assert_eq!(Elections::desired_members(), 2); assert_eq!(Elections::election_rounds(), 0); - assert_eq!(Elections::members(), vec![1, 2, 3]); + assert_eq!(Elections::members_ids(), vec![]); assert_eq!(Elections::runners_up(), vec![]); - assert_eq!(Elections::candidates(), vec![]); - assert_eq!(all_voters(), vec![]); System::set_block_number(5); assert_ok!(Elections::end_block(System::block_number())); - assert_eq!(Elections::members(), vec![1, 2, 3]); + assert_eq!(Elections::members_ids(), vec![]); assert_eq!(Elections::runners_up(), vec![]); + assert_eq!(Elections::candidates(), vec![]); }); } @@ -863,7 +909,7 @@ mod tests { assert!(Elections::is_candidate(&2).is_ok()); assert_eq!(Elections::candidates(), vec![1, 2]); - assert_eq!(Elections::members(), vec![]); + assert_eq!(Elections::members_ids(), vec![]); assert_eq!(Elections::runners_up(), vec![]); System::set_block_number(5); @@ -873,7 +919,7 @@ mod tests { assert!(Elections::is_candidate(&2).is_err()); assert_eq!(Elections::candidates(), vec![]); - assert_eq!(Elections::members(), vec![]); + assert_eq!(Elections::members_ids(), vec![]); assert_eq!(Elections::runners_up(), vec![]); }); } @@ -901,7 +947,7 @@ mod tests { System::set_block_number(5); assert_ok!(Elections::end_block(System::block_number())); - assert_eq!(Elections::members(), vec![5]); + assert_eq!(Elections::members_ids(), vec![5]); assert_eq!(Elections::runners_up(), vec![]); assert_eq!(Elections::candidates(), vec![]); @@ -994,7 +1040,7 @@ mod tests { System::set_block_number(5); assert_ok!(Elections::end_block(System::block_number())); - assert_eq!(Elections::members(), vec![4, 5]); + assert_eq!(Elections::members_ids(), vec![4, 5]); assert_eq!(Elections::candidates(), vec![]); assert_ok!(Elections::vote(Origin::signed(3), vec![4, 5], 10)); @@ -1016,7 +1062,7 @@ mod tests { #[test] fn cannot_vote_for_less_than_ed() { - ExtBuilder::default().voter_bond(8).build().execute_with(|| { + ExtBuilder::default().build().execute_with(|| { assert_ok!(Elections::submit_candidacy(Origin::signed(5))); assert_ok!(Elections::submit_candidacy(Origin::signed(4))); @@ -1101,7 +1147,7 @@ mod tests { System::set_block_number(5); assert_ok!(Elections::end_block(System::block_number())); - assert_eq!(Elections::members(), vec![3, 5]); + assert_eq!(Elections::members_ids(), vec![3, 5]); }); } @@ -1130,7 +1176,7 @@ mod tests { System::set_block_number(5); assert_ok!(Elections::end_block(System::block_number())); - assert_eq!(Elections::members(), vec![4, 5]); + assert_eq!(Elections::members_ids(), vec![4, 5]); assert_eq!(Elections::candidates(), vec![]); // all of them have a member that they voted for. @@ -1165,7 +1211,7 @@ mod tests { System::set_block_number(5); assert_ok!(Elections::end_block(System::block_number())); - assert_eq!(Elections::members(), vec![4, 5]); + assert_eq!(Elections::members_ids(), vec![4, 5]); assert_eq!(Elections::candidates(), vec![]); assert_eq!(balances(&3), (28, 2)); @@ -1194,7 +1240,7 @@ mod tests { System::set_block_number(5); assert_ok!(Elections::end_block(System::block_number())); - assert_eq!(Elections::members(), vec![4, 5]); + assert_eq!(Elections::members_ids(), vec![4, 5]); assert_eq!(Elections::candidates(), vec![]); assert_eq!(balances(&4), (35, 5)); @@ -1237,7 +1283,7 @@ mod tests { System::set_block_number(5); assert_ok!(Elections::end_block(System::block_number())); - assert_eq!(Elections::members(), vec![3, 5]); + assert_eq!(Elections::members(), vec![(3, 30), (5, 20)]); assert_eq!(Elections::runners_up(), vec![]); assert_eq_uvec!(all_voters(), vec![2, 3, 4]); assert_eq!(Elections::candidates(), vec![]); @@ -1259,7 +1305,7 @@ mod tests { System::set_block_number(5); assert_ok!(Elections::end_block(System::block_number())); - assert_eq!(Elections::members(), vec![5]); + assert_eq!(Elections::members(), vec![(5, 50)]); assert_eq!(Elections::election_rounds(), 1); // but now it has a valid target. @@ -1269,7 +1315,7 @@ mod tests { assert_ok!(Elections::end_block(System::block_number())); // candidate 4 is affected by an old vote. - assert_eq!(Elections::members(), vec![4, 5]); + assert_eq!(Elections::members(), vec![(4, 30), (5, 50)]); assert_eq!(Elections::election_rounds(), 2); assert_eq_uvec!(all_voters(), vec![3, 5]); }); @@ -1292,7 +1338,7 @@ mod tests { assert_ok!(Elections::end_block(System::block_number())); assert_eq!(Elections::election_rounds(), 1); - assert_eq!(Elections::members(), vec![4, 5]); + assert_eq!(Elections::members_ids(), vec![4, 5]); }); } @@ -1307,7 +1353,7 @@ mod tests { assert_eq!(Elections::candidates(), vec![]); assert_eq!(Elections::election_rounds(), 1); - assert_eq!(Elections::members(), vec![]); + assert_eq!(Elections::members_ids(), vec![]); }); } @@ -1327,9 +1373,9 @@ mod tests { System::set_block_number(5); assert_ok!(Elections::end_block(System::block_number())); // sorted based on account id. - assert_eq!(Elections::members(), vec![4, 5]); + assert_eq!(Elections::members_ids(), vec![4, 5]); // sorted based on merit (least -> most) - assert_eq!(Elections::runners_up(), vec![3, 2]); + assert_eq!(Elections::runners_up_ids(), vec![3, 2]); // runner ups are still locked. assert_eq!(balances(&4), (35, 5)); @@ -1353,15 +1399,15 @@ mod tests { System::set_block_number(5); assert_ok!(Elections::end_block(System::block_number())); - assert_eq!(Elections::members(), vec![4, 5]); - assert_eq!(Elections::runners_up(), vec![2, 3]); + assert_eq!(Elections::members(), vec![(4, 40), (5, 50)]); + assert_eq!(Elections::runners_up(), vec![(2, 20), (3, 30)]); assert_ok!(Elections::vote(Origin::signed(5), vec![5], 15)); System::set_block_number(10); assert_ok!(Elections::end_block(System::block_number())); - assert_eq!(Elections::members(), vec![3, 4]); - assert_eq!(Elections::runners_up(), vec![5, 2]); + assert_eq!(Elections::members(), vec![(3, 30), (4, 40)]); + assert_eq!(Elections::runners_up(), vec![(5, 15), (2, 20)]); }); } @@ -1378,9 +1424,9 @@ mod tests { System::set_block_number(5); assert_ok!(Elections::end_block(System::block_number())); - assert_eq!(Elections::members(), vec![4, 5]); + assert_eq!(Elections::members_ids(), vec![4, 5]); - assert_eq!(Elections::runners_up(), vec![2]); + assert_eq!(Elections::runners_up_ids(), vec![2]); assert_eq!(balances(&2), (15, 5)); assert_ok!(Elections::submit_candidacy(Origin::signed(3))); @@ -1388,9 +1434,9 @@ mod tests { System::set_block_number(10); assert_ok!(Elections::end_block(System::block_number())); - assert_eq!(Elections::members(), vec![4, 5]); + assert_eq!(Elections::members_ids(), vec![4, 5]); - assert_eq!(Elections::runners_up(), vec![3]); + assert_eq!(Elections::runners_up_ids(), vec![3]); assert_eq!(balances(&3), (25, 5)); assert_eq!(balances(&2), (15, 2)); }); @@ -1408,7 +1454,7 @@ mod tests { System::set_block_number(5); assert_ok!(Elections::end_block(System::block_number())); - assert_eq!(Elections::members(), vec![4, 5]); + assert_eq!(Elections::members_ids(), vec![4, 5]); assert_eq!(Elections::election_rounds(), 1); assert_ok!(Elections::submit_candidacy(Origin::signed(2))); @@ -1426,7 +1472,7 @@ mod tests { assert_ok!(Elections::end_block(System::block_number())); // 4 removed; 5 and 3 are the new best. - assert_eq!(Elections::members(), vec![3, 5]); + assert_eq!(Elections::members_ids(), vec![3, 5]); }); } @@ -1449,8 +1495,8 @@ mod tests { System::set_block_number(b.into()); assert_ok!(Elections::end_block(System::block_number())); // we keep re-electing the same folks. - assert_eq!(Elections::members(), vec![4, 5]); - assert_eq!(Elections::runners_up(), vec![2, 3]); + assert_eq!(Elections::members(), vec![(4, 40), (5, 50)]); + assert_eq!(Elections::runners_up(), vec![(2, 20), (3, 30)]); // no new candidates but old members and runners-up are always added. assert_eq!(Elections::candidates(), vec![]); assert_eq!(Elections::election_rounds(), b / 5); @@ -1476,7 +1522,7 @@ mod tests { System::set_block_number(5); assert_ok!(Elections::end_block(System::block_number())); - assert_eq!(Elections::members(), vec![4, 5]); + assert_eq!(Elections::members_ids(), vec![4, 5]); assert_eq!(Elections::election_rounds(), 1); // a new candidate @@ -1487,7 +1533,7 @@ mod tests { assert_eq!(balances(&4), (35, 2)); // slashed assert_eq!(Elections::election_rounds(), 2); // new election round - assert_eq!(Elections::members(), vec![3, 5]); // new members + assert_eq!(Elections::members_ids(), vec![3, 5]); // new members }); } @@ -1509,7 +1555,7 @@ mod tests { System::set_block_number(5); assert_ok!(Elections::end_block(System::block_number())); - assert_eq!(Elections::members(), vec![3, 5]); + assert_eq!(Elections::members_ids(), vec![3, 5]); assert_eq!(Elections::election_rounds(), 1); assert_ok!(Elections::remove_voter(Origin::signed(2))); @@ -1520,7 +1566,7 @@ mod tests { // meanwhile, no one cares to become a candidate again. System::set_block_number(10); assert_ok!(Elections::end_block(System::block_number())); - assert_eq!(Elections::members(), vec![]); + assert_eq!(Elections::members_ids(), vec![]); assert_eq!(Elections::election_rounds(), 2); }); } @@ -1538,14 +1584,14 @@ mod tests { System::set_block_number(5); assert_ok!(Elections::end_block(System::block_number())); - assert_eq!(Elections::members(), vec![5]); + assert_eq!(Elections::members_ids(), vec![5]); assert_ok!(Elections::remove_voter(Origin::signed(5))); assert_eq!(balances(&5), (47, 3)); System::set_block_number(10); assert_ok!(Elections::end_block(System::block_number())); - assert_eq!(Elections::members(), vec![]); + assert_eq!(Elections::members_ids(), vec![]); assert_eq!(balances(&5), (50, 0)); }); @@ -1565,7 +1611,7 @@ mod tests { System::set_block_number(5); assert_ok!(Elections::end_block(System::block_number())); - assert_eq!(Elections::members(), vec![5]); + assert_eq!(Elections::members_ids(), vec![5]); // winner assert_eq!(balances(&5), (47, 3)); @@ -1585,7 +1631,7 @@ mod tests { System::set_block_number(5); assert_ok!(Elections::end_block(System::block_number())); - assert_eq!(Elections::members(), vec![4, 5]); + assert_eq!(Elections::members_ids(), vec![4, 5]); assert_ok!(Elections::submit_candidacy(Origin::signed(1))); assert_ok!(Elections::submit_candidacy(Origin::signed(2))); @@ -1605,7 +1651,7 @@ mod tests { assert_ok!(Elections::end_block(System::block_number())); // 3, 4 are new members, must still be bonded, nothing slashed. - assert_eq!(Elections::members(), vec![3, 4]); + assert_eq!(Elections::members(), vec![(3, 30), (4, 48)]); assert_eq!(balances(&3), (25, 5)); assert_eq!(balances(&4), (35, 5)); @@ -1615,7 +1661,10 @@ mod tests { // 5 is an outgoing loser, it will get their bond back. assert_eq!(balances(&5), (48, 2)); - assert_eq!(System::events()[0].event, Event::elections(RawEvent::NewTerm(vec![4, 5]))); + assert_eq!( + System::events()[0].event, + Event::elections(RawEvent::NewTerm(vec![(4, 40), (5, 50)])), + ); }) } @@ -1632,8 +1681,30 @@ mod tests { System::set_block_number(5); assert_ok!(Elections::end_block(System::block_number())); - assert_eq_uvec!(Elections::members(), vec![3, 4]); + assert_eq_uvec!(Elections::members_ids(), vec![3, 4]); assert_eq!(Elections::election_rounds(), 1); }); } + + #[test] + fn members_are_sorted_based_on_id_runners_on_merit() { + ExtBuilder::default().desired_runners_up(2).build().execute_with(|| { + assert_ok!(Elections::submit_candidacy(Origin::signed(5))); + assert_ok!(Elections::submit_candidacy(Origin::signed(4))); + assert_ok!(Elections::submit_candidacy(Origin::signed(3))); + assert_ok!(Elections::submit_candidacy(Origin::signed(2))); + + assert_ok!(Elections::vote(Origin::signed(2), vec![3], 20)); + assert_ok!(Elections::vote(Origin::signed(3), vec![2], 30)); + assert_ok!(Elections::vote(Origin::signed(4), vec![5], 40)); + assert_ok!(Elections::vote(Origin::signed(5), vec![4], 50)); + + System::set_block_number(5); + assert_ok!(Elections::end_block(System::block_number())); + // id: low -> high. + assert_eq!(Elections::members(), vec![(4, 50), (5, 40)]); + // merit: low -> high. + assert_eq!(Elections::runners_up(), vec![(3, 20), (2, 30)]); + }); + } } diff --git a/srml/example/src/lib.rs b/srml/example/src/lib.rs index c9d9d93cc7..fb05e731bd 100644 --- a/srml/example/src/lib.rs +++ b/srml/example/src/lib.rs @@ -269,13 +269,13 @@ use sr_primitives::{ // the arguments and makes a decision based upon them. // // The `WeightData` trait has access to the arguments of the dispatch that it wants to assign a -// weight to. Nonetheless, the trait itself can not make any assumptions about what that type -// generic type of the arguments, `T`, is. Based on our needs, we could replace `T` with a more -// concrete type while implementing the trait. The `decl_module!` expects whatever implements -// `WeighData` to replace `T` with a tuple of the dispatch arguments. This is exactly how we will -// craft the implementation below. +// weight to. Nonetheless, the trait itself can not make any assumptions about what the generic type +// of the arguments (`T`) is. Based on our needs, we could replace `T` with a more concrete type +// while implementing the trait. The `decl_module!` expects whatever implements `WeighData` to +// replace `T` with a tuple of the dispatch arguments. This is exactly how we will craft the +// implementation below. // -// The rules of `WeightForSetDummy` is as follows: +// The rules of `WeightForSetDummy` are as follows: // - The final weight of each dispatch is calculated as the argument of the call multiplied by the // parameter given to the `WeightForSetDummy`'s constructor. // - assigns a dispatch class `operational` if the argument of the call is more than 1000. @@ -449,9 +449,8 @@ decl_module! { // The _right-hand-side_ value of the `#[weight]` attribute can be any type that implements // a set of traits, namely [`WeighData`] and [`ClassifyDispatch`]. The former conveys the // weight (a numeric representation of pure execution time and difficulty) of the - // transaction and the latter demonstrates the `DispatchClass` of the call. A higher weight - // means a larger transaction (less of which can be placed in a single block). See the - // `CheckWeight` signed extension struct in the `system` module for more information. + // transaction and the latter demonstrates the [`DispatchClass`] of the call. A higher + // weight means a larger transaction (less of which can be placed in a single block). #[weight = SimpleDispatchInfo::FixedNormal(10_000)] fn accumulate_dummy(origin, increase_by: T::Balance) -> Result { // This is a public call, so we ensure that the origin is some signed account. diff --git a/srml/staking/src/lib.rs b/srml/staking/src/lib.rs index f6d123bd13..edbf7c245f 100644 --- a/srml/staking/src/lib.rs +++ b/srml/staking/src/lib.rs @@ -278,7 +278,7 @@ use sr_staking_primitives::{ use sr_primitives::{Serialize, Deserialize}; use system::{ensure_signed, ensure_root}; -use phragmen::{elect, equalize, ExtendedBalance, Support, SupportMap, PhragmenStakedAssignment}; +use phragmen::{elect, equalize, build_support_map, ExtendedBalance, PhragmenStakedAssignment}; const DEFAULT_MINIMUM_VALIDATOR_COUNT: u32 = 4; const MAX_NOMINATIONS: usize = 16; @@ -1268,31 +1268,12 @@ impl Module { let to_balance = |e: ExtendedBalance| >>::convert(e); - // Initialize the support of each candidate. - let mut supports = >::new(); - elected_stashes - .iter() - .map(|e| (e, to_votes(Self::slashable_balance_of(e)))) - .for_each(|(e, s)| { - let item = Support { own: s, total: s, ..Default::default() }; - supports.insert(e.clone(), item); - }); - - // build support struct. - for (n, assignment) in assignments.iter() { - for (c, per_thing) in assignment.iter() { - let nominator_stake = to_votes(Self::slashable_balance_of(n)); - // AUDIT: it is crucially important for the `Mul` implementation of all - // per-things to be sound. - let other_stake = *per_thing * nominator_stake; - if let Some(support) = supports.get_mut(c) { - // For an astronomically rich validator with more astronomically rich - // set of nominators, this might saturate. - support.total = support.total.saturating_add(other_stake); - support.others.push((n.clone(), other_stake)); - } - } - } + let mut supports = build_support_map::<_, _, _, T::CurrencyToVote>( + &elected_stashes, + &assignments, + Self::slashable_balance_of, + true, + ); if cfg!(feature = "equalize") { let mut staked_assignments diff --git a/srml/system/src/lib.rs b/srml/system/src/lib.rs index 87c38096ab..e07b937751 100644 --- a/srml/system/src/lib.rs +++ b/srml/system/src/lib.rs @@ -772,7 +772,6 @@ impl CheckWeight { fn get_dispatch_limit_ratio(class: DispatchClass) -> Perbill { match class { DispatchClass::Operational => Perbill::one(), - // TODO: this must be some sort of a constant. DispatchClass::Normal => T::AvailableBlockRatio::get(), } } -- GitLab From 4f6f830a3818bbb4691ac4cb5774696dcafc107f Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Mon, 28 Oct 2019 16:04:45 +0100 Subject: [PATCH 123/167] RPC to query transaction fee + weight + info (#3876) * initial version for testing * New version that compiles * optional at block parameter * Fix some more view grumbles. * Update srml/transaction-payment/src/lib.rs --- Cargo.lock | 31 +++++ Cargo.toml | 2 + .../src/generic/unchecked_extrinsic.rs | 12 ++ core/sr-primitives/src/weights.rs | 12 +- node/rpc/Cargo.toml | 2 + node/rpc/src/lib.rs | 8 +- node/runtime/Cargo.toml | 2 + node/runtime/src/lib.rs | 19 ++- srml/executive/src/lib.rs | 2 +- srml/transaction-payment/Cargo.toml | 2 + srml/transaction-payment/rpc/Cargo.toml | 17 +++ .../rpc/runtime-api/Cargo.toml | 22 ++++ .../rpc/runtime-api/src/lib.rs | 47 ++++++++ srml/transaction-payment/rpc/src/lib.rs | 108 ++++++++++++++++++ srml/transaction-payment/src/lib.rs | 94 +++++++++++++-- 15 files changed, 359 insertions(+), 21 deletions(-) create mode 100644 srml/transaction-payment/rpc/Cargo.toml create mode 100644 srml/transaction-payment/rpc/runtime-api/Cargo.toml create mode 100644 srml/transaction-payment/rpc/runtime-api/src/lib.rs create mode 100644 srml/transaction-payment/rpc/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 3343942cc1..d369bbb5f6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2473,9 +2473,11 @@ version = "2.0.0" dependencies = [ "jsonrpc-core 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "node-primitives 2.0.0", + "node-runtime 2.0.0", "sr-primitives 2.0.0", "srml-contracts-rpc 2.0.0", "srml-system-rpc 2.0.0", + "srml-transaction-payment-rpc 2.0.0", "substrate-client 2.0.0", "substrate-transaction-pool 2.0.0", ] @@ -2534,6 +2536,7 @@ dependencies = [ "srml-system-rpc-runtime-api 2.0.0", "srml-timestamp 2.0.0", "srml-transaction-payment 2.0.0", + "srml-transaction-payment-rpc-runtime-api 2.0.0", "srml-treasury 2.0.0", "srml-utility 2.0.0", "substrate-client 2.0.0", @@ -4617,9 +4620,37 @@ dependencies = [ "srml-balances 2.0.0", "srml-support 2.0.0", "srml-system 2.0.0", + "srml-transaction-payment-rpc-runtime-api 2.0.0", "substrate-primitives 2.0.0", ] +[[package]] +name = "srml-transaction-payment-rpc" +version = "2.0.0" +dependencies = [ + "jsonrpc-core 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core-client 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-derive 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-primitives 2.0.0", + "srml-transaction-payment-rpc-runtime-api 2.0.0", + "substrate-client 2.0.0", + "substrate-primitives 2.0.0", + "substrate-rpc-primitives 2.0.0", +] + +[[package]] +name = "srml-transaction-payment-rpc-runtime-api" +version = "2.0.0" +dependencies = [ + "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-primitives 2.0.0", + "sr-std 2.0.0", + "substrate-client 2.0.0", +] + [[package]] name = "srml-treasury" version = "2.0.0" diff --git a/Cargo.toml b/Cargo.toml index 2c1e361fc9..2d68511b2e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -82,6 +82,7 @@ members = [ "srml/aura", "srml/balances", "srml/contracts", + "srml/contracts/rpc", "srml/collective", "srml/democracy", "srml/elections", @@ -109,6 +110,7 @@ members = [ "srml/timestamp", "srml/treasury", "srml/transaction-payment", + "srml/transaction-payment/rpc", "srml/utility", "node/cli", "node/executor", diff --git a/core/sr-primitives/src/generic/unchecked_extrinsic.rs b/core/sr-primitives/src/generic/unchecked_extrinsic.rs index c7bff1f4c8..befa857dff 100644 --- a/core/sr-primitives/src/generic/unchecked_extrinsic.rs +++ b/core/sr-primitives/src/generic/unchecked_extrinsic.rs @@ -23,6 +23,7 @@ use codec::{Decode, Encode, EncodeLike, Input, Error}; use crate::{ traits::{self, Member, MaybeDisplay, SignedExtension, Checkable, Extrinsic, IdentifyAccount}, generic::CheckedExtrinsic, transaction_validity::{TransactionValidityError, InvalidTransaction}, + weights::{GetDispatchInfo, DispatchInfo}, }; const TRANSACTION_VERSION: u8 = 4; @@ -280,6 +281,17 @@ where } } +impl GetDispatchInfo + for UncheckedExtrinsic +where + Call: GetDispatchInfo, + Extra: SignedExtension, +{ + fn get_dispatch_info(&self) -> DispatchInfo { + self.function.get_dispatch_info() + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/core/sr-primitives/src/weights.rs b/core/sr-primitives/src/weights.rs index 89852eb595..088f13244e 100644 --- a/core/sr-primitives/src/weights.rs +++ b/core/sr-primitives/src/weights.rs @@ -35,9 +35,13 @@ //! Note that the decl_module macro _cannot_ enforce this and will simply fail if an invalid struct //! (something that does not implement `Weighable`) is passed in. +#[cfg(feature = "std")] +use serde::{Serialize, Deserialize}; +use codec::{Encode, Decode}; use arithmetic::traits::Bounded; use crate::RuntimeDebug; +/// Re-export priority as type pub use crate::transaction_validity::TransactionPriority; /// Numeric range of a transaction weight. @@ -58,10 +62,10 @@ pub trait ClassifyDispatch { fn classify_dispatch(&self, target: T) -> DispatchClass; } -/// A generalized group of dispatch types. This is only distinguishing normal, user-triggered -/// transactions (`Normal`) and anything beyond which serves a higher purpose to the system -/// (`Operational`). -#[derive(PartialEq, Eq, Clone, Copy, RuntimeDebug)] +/// A generalized group of dispatch types. This is only distinguishing normal, user-triggered transactions +/// (`Normal`) and anything beyond which serves a higher purpose to the system (`Operational`). +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +#[derive(PartialEq, Eq, Clone, Copy, Encode, Decode, RuntimeDebug)] pub enum DispatchClass { /// A normal dispatch. Normal, diff --git a/node/rpc/Cargo.toml b/node/rpc/Cargo.toml index 5d2ca81e0f..5e8b761489 100644 --- a/node/rpc/Cargo.toml +++ b/node/rpc/Cargo.toml @@ -8,7 +8,9 @@ edition = "2018" client = { package = "substrate-client", path = "../../core/client" } jsonrpc-core = "13.2.0" node-primitives = { path = "../primitives" } +node-runtime = { path = "../runtime" } sr-primitives = { path = "../../core/sr-primitives" } srml-contracts-rpc = { path = "../../srml/contracts/rpc/" } +srml-transaction-payment-rpc = { path = "../../srml/transaction-payment/rpc/" } srml-system-rpc = { path = "../../srml/system/rpc/" } transaction_pool = { package = "substrate-transaction-pool", path = "../../core/transaction-pool" } diff --git a/node/rpc/src/lib.rs b/node/rpc/src/lib.rs index 398d458e63..99321373f8 100644 --- a/node/rpc/src/lib.rs +++ b/node/rpc/src/lib.rs @@ -32,6 +32,7 @@ use std::sync::Arc; use node_primitives::{Block, AccountId, Index, Balance}; +use node_runtime::UncheckedExtrinsic; use sr_primitives::traits::ProvideRuntimeApi; use transaction_pool::txpool::{ChainApi, Pool}; @@ -42,18 +43,23 @@ pub fn create(client: Arc, pool: Arc>) -> jsonrpc_core::IoHa C: Send + Sync + 'static, C::Api: srml_system_rpc::AccountNonceApi, C::Api: srml_contracts_rpc::ContractsRuntimeApi, + C::Api: srml_transaction_payment_rpc::TransactionPaymentRuntimeApi, P: ChainApi + Sync + Send + 'static, M: jsonrpc_core::Metadata + Default, { use srml_system_rpc::{System, SystemApi}; use srml_contracts_rpc::{Contracts, ContractsApi}; + use srml_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApi}; let mut io = jsonrpc_core::IoHandler::default(); io.extend_with( SystemApi::to_delegate(System::new(client.clone(), pool)) ); io.extend_with( - ContractsApi::to_delegate(Contracts::new(client)) + ContractsApi::to_delegate(Contracts::new(client.clone())) + ); + io.extend_with( + TransactionPaymentApi::to_delegate(TransactionPayment::new(client)) ); io } diff --git a/node/runtime/Cargo.toml b/node/runtime/Cargo.toml index 94a7683dc5..0aa2dc551e 100644 --- a/node/runtime/Cargo.toml +++ b/node/runtime/Cargo.toml @@ -52,6 +52,7 @@ timestamp = { package = "srml-timestamp", path = "../../srml/timestamp", default treasury = { package = "srml-treasury", path = "../../srml/treasury", default-features = false } utility = { package = "srml-utility", path = "../../srml/utility", default-features = false } transaction-payment = { package = "srml-transaction-payment", path = "../../srml/transaction-payment", default-features = false } +transaction-payment-rpc-runtime-api = { package = "srml-transaction-payment-rpc-runtime-api", path = "../../srml/transaction-payment/rpc/runtime-api/", default-features = false } [build-dependencies] wasm-builder-runner = { package = "substrate-wasm-builder-runner", version = "1.0.4", path = "../../core/utils/wasm-builder-runner" } @@ -103,5 +104,6 @@ std = [ "treasury/std", "utility/std", "transaction-payment/std", + "transaction-payment-rpc-runtime-api/std", "version/std", ] diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index a6bd25a73e..3dba79d27b 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -50,6 +50,8 @@ use version::NativeVersion; use primitives::OpaqueMetadata; use grandpa::{AuthorityId as GrandpaId, AuthorityWeight as GrandpaWeight}; use im_online::sr25519::{AuthorityId as ImOnlineId}; +use transaction_payment_rpc_runtime_api::RuntimeDispatchInfo; +use contracts_rpc_runtime_api::ContractExecResult; use system::offchain::TransactionSubmitter; #[cfg(any(feature = "std", test))] @@ -661,9 +663,7 @@ impl_runtime_apis! { value: Balance, gas_limit: u64, input_data: Vec, - ) -> contracts_rpc_runtime_api::ContractExecResult { - use contracts_rpc_runtime_api::ContractExecResult; - + ) -> ContractExecResult { let exec_result = Contracts::bare_call( origin, dest.into(), @@ -681,9 +681,20 @@ impl_runtime_apis! { } } + impl transaction_payment_rpc_runtime_api::TransactionPaymentApi< + Block, + Balance, + UncheckedExtrinsic, + > for Runtime { + fn query_info(uxt: UncheckedExtrinsic, len: u32) -> RuntimeDispatchInfo { + TransactionPayment::query_info(uxt, len) + } + } + impl substrate_session::SessionKeys for Runtime { fn generate_session_keys(seed: Option>) -> Vec { - let seed = seed.as_ref().map(|s| rstd::str::from_utf8(&s).expect("Seed is an utf8 string")); + let seed = seed.as_ref().map(|s| rstd::str::from_utf8(&s) + .expect("Seed is an utf8 string")); SessionKeys::generate(seed) } } diff --git a/srml/executive/src/lib.rs b/srml/executive/src/lib.rs index 401f07d206..927a7fef25 100644 --- a/srml/executive/src/lib.rs +++ b/srml/executive/src/lib.rs @@ -571,7 +571,7 @@ mod tests { assert!(Executive::apply_extrinsic(x2.clone()).unwrap().is_ok()); // default weight for `TestXt` == encoded length. - assert_eq!(>::all_extrinsics_weight(), (3 * len).into()); + assert_eq!(>::all_extrinsics_weight(), (3 * len) as u32); assert_eq!(>::all_extrinsics_len(), 3 * len); let _ = >::finalize(); diff --git a/srml/transaction-payment/Cargo.toml b/srml/transaction-payment/Cargo.toml index 7f8eddab19..cbce1e945e 100644 --- a/srml/transaction-payment/Cargo.toml +++ b/srml/transaction-payment/Cargo.toml @@ -10,6 +10,7 @@ rstd = { package = "sr-std", path = "../../core/sr-std", default-features = fals sr-primitives = { path = "../../core/sr-primitives", default-features = false } support = { package = "srml-support", path = "../support", default-features = false } system = { package = "srml-system", path = "../system", default-features = false } +transaction-payment-rpc-runtime-api = { package = "srml-transaction-payment-rpc-runtime-api", path = "./rpc/runtime-api", default-features = false } [dev-dependencies] runtime-io = { package = "sr-io", path = "../../core/sr-io" } @@ -24,4 +25,5 @@ std = [ "sr-primitives/std", "support/std", "system/std", + "transaction-payment-rpc-runtime-api/std" ] diff --git a/srml/transaction-payment/rpc/Cargo.toml b/srml/transaction-payment/rpc/Cargo.toml new file mode 100644 index 0000000000..e3dc6f553f --- /dev/null +++ b/srml/transaction-payment/rpc/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "srml-transaction-payment-rpc" +version = "2.0.0" +authors = ["Parity Technologies "] +edition = "2018" + +[dependencies] +client = { package = "substrate-client", path = "../../../core/client" } +codec = { package = "parity-scale-codec", version = "1.0.0" } +jsonrpc-core = "13.2.0" +jsonrpc-core-client = "13.2.0" +jsonrpc-derive = "13.2.0" +primitives = { package = "substrate-primitives", path = "../../../core/primitives" } +rpc-primitives = { package = "substrate-rpc-primitives", path = "../../../core/rpc/primitives" } +serde = { version = "1.0.101", features = ["derive"] } +sr-primitives = { path = "../../../core/sr-primitives" } +srml-transaction-payment-rpc-runtime-api = { path = "./runtime-api" } diff --git a/srml/transaction-payment/rpc/runtime-api/Cargo.toml b/srml/transaction-payment/rpc/runtime-api/Cargo.toml new file mode 100644 index 0000000000..c26f295f4b --- /dev/null +++ b/srml/transaction-payment/rpc/runtime-api/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "srml-transaction-payment-rpc-runtime-api" +version = "2.0.0" +authors = ["Parity Technologies "] +edition = "2018" + +[dependencies] +serde = { version = "1.0.101", optional = true, features = ["derive"] } +client = { package = "substrate-client", path = "../../../../core/client", default-features = false } +codec = { package = "parity-scale-codec", version = "1.0.6", default-features = false, features = ["derive"] } +rstd = { package = "sr-std", path = "../../../../core/sr-std", default-features = false } +sr-primitives = { path = "../../../../core/sr-primitives", default-features = false } + +[features] +default = ["std"] +std = [ + "serde", + "client/std", + "codec/std", + "rstd/std", + "sr-primitives/std", +] diff --git a/srml/transaction-payment/rpc/runtime-api/src/lib.rs b/srml/transaction-payment/rpc/runtime-api/src/lib.rs new file mode 100644 index 0000000000..dc6360ca88 --- /dev/null +++ b/srml/transaction-payment/rpc/runtime-api/src/lib.rs @@ -0,0 +1,47 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +//! Runtime API definition for transaction payment module. + +#![cfg_attr(not(feature = "std"), no_std)] + +use rstd::prelude::*; +use sr_primitives::weights::{Weight, DispatchClass}; +use codec::{Encode, Codec, Decode}; +#[cfg(feature = "std")] +use serde::{Serialize, Deserialize}; + +/// Some information related to a dispatchable that can be queried from the runtime. +#[derive(Eq, PartialEq, Encode, Decode, Default)] +#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))] +pub struct RuntimeDispatchInfo { + /// Weight of this dispatch. + pub weight: Weight, + /// Class of this dispatch. + pub class: DispatchClass, + /// The partial inclusion fee of this dispatch. This does not include tip or anything else which + /// is dependent on the signature (aka. depends on a `SignedExtension`). + pub partial_fee: Balance, +} + +client::decl_runtime_apis! { + pub trait TransactionPaymentApi where + Balance: Codec, + Extrinsic: Codec, + { + fn query_info(uxt: Extrinsic, len: u32) -> RuntimeDispatchInfo; + } +} diff --git a/srml/transaction-payment/rpc/src/lib.rs b/srml/transaction-payment/rpc/src/lib.rs new file mode 100644 index 0000000000..6ee3c7eddb --- /dev/null +++ b/srml/transaction-payment/rpc/src/lib.rs @@ -0,0 +1,108 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +//! RPC interface for the transaction payment module. + +use std::sync::Arc; +use codec::{Codec, Decode}; +use client::blockchain::HeaderBackend; +use jsonrpc_core::{Error as RpcError, ErrorCode, Result}; +use jsonrpc_derive::rpc; +use sr_primitives::{ + generic::BlockId, + traits::{Block as BlockT, ProvideRuntimeApi}, +}; +use primitives::Bytes; +use srml_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo; +pub use srml_transaction_payment_rpc_runtime_api::TransactionPaymentApi as TransactionPaymentRuntimeApi; +pub use self::gen_client::Client as TransactionPaymentClient; + +#[rpc] +pub trait TransactionPaymentApi { + #[rpc(name = "payment_queryInfo")] + fn query_info( + &self, + encoded_xt: Bytes, + at: Option + ) -> Result>; +} + +/// A struct that implements the [`TransactionPaymentApi`]. +pub struct TransactionPayment { + client: Arc, + _marker: std::marker::PhantomData

, +} + +impl TransactionPayment { + /// Create new `TransactionPayment` with the given reference to the client. + pub fn new(client: Arc) -> Self { + TransactionPayment { client, _marker: Default::default() } + } +} + +/// Error type of this RPC api. +pub enum Error { + /// The transaction was not decodable. + DecodeError, + /// The call to runtime failed. + RuntimeError, +} + +impl From for i64 { + fn from(e: Error) -> i64 { + match e { + Error::RuntimeError => 1, + Error::DecodeError => 2, + } + } +} + +impl TransactionPaymentApi<::Hash, Balance> + for TransactionPayment +where + Block: BlockT, + C: Send + Sync + 'static, + C: ProvideRuntimeApi, + C: HeaderBackend, + C::Api: TransactionPaymentRuntimeApi, + Balance: Codec, + Extrinsic: Codec + Send + Sync + 'static, +{ + fn query_info( + &self, + encoded_xt: Bytes, + at: Option<::Hash> + ) -> Result> { + let api = self.client.runtime_api(); + let at = BlockId::hash(at.unwrap_or_else(|| + // If the block hash is not supplied assume the best block. + self.client.info().best_hash + )); + + let encoded_len = encoded_xt.len() as u32; + + let uxt: Extrinsic = Decode::decode(&mut &*encoded_xt).map_err(|e| RpcError { + code: ErrorCode::ServerError(Error::DecodeError.into()), + message: "Unable to query dispatch info.".into(), + data: Some(format!("{:?}", e).into()), + })?; + api.query_info(&at, uxt, encoded_len).map_err(|e| RpcError { + code: ErrorCode::ServerError(Error::RuntimeError.into()), + message: "Unable to query dispatch info.".into(), + data: Some(format!("{:?}", e).into()), + }) + } +} diff --git a/srml/transaction-payment/src/lib.rs b/srml/transaction-payment/src/lib.rs index 6ebda53b72..2314edf053 100644 --- a/srml/transaction-payment/src/lib.rs +++ b/srml/transaction-payment/src/lib.rs @@ -44,8 +44,9 @@ use sr_primitives::{ TransactionValidity, }, traits::{Zero, Saturating, SignedExtension, SaturatedConversion, Convert}, - weights::{Weight, DispatchInfo}, + weights::{Weight, DispatchInfo, GetDispatchInfo}, }; +use transaction_payment_rpc_runtime_api::RuntimeDispatchInfo; type Multiplier = Fixed64; type BalanceOf = @@ -95,7 +96,33 @@ decl_module! { } } -impl Module {} +impl Module { + /// Query the data that we know about the fee of a given `call`. + /// + /// As this module is not and cannot be aware of the internals of a signed extension, it only + /// interprets them as some encoded value and takes their length into account. + /// + /// All dispatchables must be annotated with weight and will have some fee info. This function + /// always returns. + // NOTE: we can actually make it understand `ChargeTransactionPayment`, but would be some hassle + // for sure. We have to make it aware of the index of `ChargeTransactionPayment` in `Extra`. + // Alternatively, we could actually execute the tx's per-dispatch and record the balance of the + // sender before and after the pipeline.. but this is way too much hassle for a very very little + // potential gain in the future. + pub fn query_info( + unchecked_extrinsic: Extrinsic, + len: u32, + ) -> RuntimeDispatchInfo> + where T: Send + Sync, + { + let dispatch_info = ::get_dispatch_info(&unchecked_extrinsic); + + let partial_fee = >::compute_fee(len, dispatch_info, 0u32.into()); + let DispatchInfo { weight, class } = dispatch_info; + + RuntimeDispatchInfo { weight, class, partial_fee } + } +} /// Require the transactor pay for themselves and maybe include a tip to gain additional priority /// in the queue. @@ -117,9 +144,9 @@ impl ChargeTransactionPayment { /// and the time it consumes. /// - (optional) _tip_: if included in the transaction, it will be added on top. Only signed /// transactions can have a tip. - fn compute_fee(len: usize, info: DispatchInfo, tip: BalanceOf) -> BalanceOf { + fn compute_fee(len: u32, info: DispatchInfo, tip: BalanceOf) -> BalanceOf { let len_fee = if info.pay_length_fee() { - let len = >::from(len as u32); + let len = >::from(len); let base = T::TransactionBaseFee::get(); let per_byte = T::TransactionByteFee::get(); base.saturating_add(per_byte.saturating_mul(len)) @@ -172,7 +199,7 @@ impl SignedExtension for ChargeTransactionPayment ) -> TransactionValidity { // pay any fees. let tip = self.0; - let fee = Self::compute_fee(len, info, tip); + let fee = Self::compute_fee(len as u32, info, tip); let imbalance = match T::Currency::withdraw( who, fee, @@ -199,17 +226,27 @@ impl SignedExtension for ChargeTransactionPayment #[cfg(test)] mod tests { use super::*; - use support::{parameter_types, impl_outer_origin}; + use codec::Encode; + use support::{parameter_types, impl_outer_origin, impl_outer_dispatch}; use primitives::H256; use sr_primitives::{ Perbill, - testing::Header, - traits::{BlakeTwo256, IdentityLookup}, - weights::DispatchClass, + testing::{Header, TestXt}, + traits::{BlakeTwo256, IdentityLookup, Extrinsic}, + weights::{DispatchClass, DispatchInfo, GetDispatchInfo}, }; + use balances::Call as BalancesCall; use rstd::cell::RefCell; + use transaction_payment_rpc_runtime_api::RuntimeDispatchInfo; - const CALL: &::Call = &(); + const CALL: &::Call = &Call::Balances(BalancesCall::transfer(2, 69)); + + impl_outer_dispatch! { + pub enum Call for Runtime where origin: Origin { + balances::Balances, + system::System, + } + } #[derive(Clone, PartialEq, Eq, Debug)] pub struct Runtime; @@ -229,7 +266,7 @@ mod tests { type Origin = Origin; type Index = u64; type BlockNumber = u64; - type Call = (); + type Call = Call; type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u64; @@ -294,6 +331,8 @@ mod tests { } type Balances = balances::Module; + type System = system::Module; + type TransactionPayment = Module; pub struct ExtBuilder { balance_factor: u64, @@ -457,6 +496,39 @@ mod tests { assert_eq!(Balances::free_balance(&1), 100 - 10 - (5 + 10 + 3) * 3 / 2); }) } + + #[test] + fn query_info_works() { + let call = Call::Balances(BalancesCall::transfer(2, 69)); + let origin = 111111; + let extra = (); + let xt = TestXt::new(call, Some((origin, extra))).unwrap(); + let info = xt.get_dispatch_info(); + let ext = xt.encode(); + let len = ext.len() as u32; + ExtBuilder::default() + .fees(5, 1, 2) + .build() + .execute_with(|| + { + // all fees should be x1.5 + NextFeeMultiplier::put(Fixed64::from_rational(1, 2)); + + assert_eq!( + TransactionPayment::query_info(xt, len), + RuntimeDispatchInfo { + weight: info.weight, + class: info.class, + partial_fee: ( + 5 /* base */ + + len as u64 /* len * 1 */ + + info.weight.min(MaximumBlockWeight::get()) as u64 * 2 /* weight * weight_to_fee */ + ) * 3 / 2 + }, + ); + + }); + } } -- GitLab From 30faeef4dc80b99c9e1bcf43075bb94563bd278a Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Mon, 28 Oct 2019 18:05:52 +0300 Subject: [PATCH 124/167] Basic extrinsic pool benchmarks (#3922) * Working bench for 50 sequental * configured benches * fix warnings * Optimize and fix issues * add preamble * Fix benchmarks. * fix compilation * remove unneeded features for now --- Cargo.lock | 1 + core/transaction-pool/graph/Cargo.toml | 5 + core/transaction-pool/graph/benches/basics.rs | 165 ++++++++++++++++++ core/transaction-pool/graph/src/pool.rs | 1 - 4 files changed, 171 insertions(+), 1 deletion(-) create mode 100644 core/transaction-pool/graph/benches/basics.rs diff --git a/Cargo.lock b/Cargo.lock index d369bbb5f6..4bade61225 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5788,6 +5788,7 @@ name = "substrate-transaction-graph" version = "2.0.0" dependencies = [ "assert_matches 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "criterion 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "derive_more 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "futures-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/core/transaction-pool/graph/Cargo.toml b/core/transaction-pool/graph/Cargo.toml index fa0d6f14b6..4b628079cd 100644 --- a/core/transaction-pool/graph/Cargo.toml +++ b/core/transaction-pool/graph/Cargo.toml @@ -18,3 +18,8 @@ assert_matches = "1.3.0" env_logger = "0.7.0" codec = { package = "parity-scale-codec", version = "1.0.0" } test_runtime = { package = "substrate-test-runtime", path = "../../test-runtime" } +criterion = "0.3" + +[[bench]] +name = "basics" +harness = false diff --git a/core/transaction-pool/graph/benches/basics.rs b/core/transaction-pool/graph/benches/basics.rs new file mode 100644 index 0000000000..dcd725ce46 --- /dev/null +++ b/core/transaction-pool/graph/benches/basics.rs @@ -0,0 +1,165 @@ +// Copyright 2018-2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +use criterion::{criterion_group, criterion_main, Criterion}; + +use futures::executor::block_on; +use substrate_transaction_graph::*; +use sr_primitives::transaction_validity::{ValidTransaction, InvalidTransaction}; +use codec::Encode; +use test_runtime::{Block, Extrinsic, Transfer, H256, AccountId}; +use sr_primitives::{ + generic::BlockId, + transaction_validity::{TransactionValidity, TransactionTag as Tag}, +}; +use primitives::blake2_256; + +#[derive(Clone, Debug, Default)] +struct TestApi { + nonce_dependant: bool, +} + +impl TestApi { + fn new_dependant() -> Self { + TestApi { nonce_dependant: true } + } +} + +fn to_tag(nonce: u64, from: AccountId) -> Tag { + let mut data = [0u8; 40]; + data[..8].copy_from_slice(&nonce.to_le_bytes()[..]); + data[8..].copy_from_slice(&from.0[..]); + data.to_vec() +} + +impl ChainApi for TestApi { + type Block = Block; + type Hash = H256; + type Error = error::Error; + type ValidationFuture = futures::future::Ready>; + + fn validate_transaction( + &self, + at: &BlockId, + uxt: ExtrinsicFor, + ) -> Self::ValidationFuture { + let nonce = uxt.transfer().nonce; + let from = uxt.transfer().from.clone(); + + match self.block_id_to_number(at) { + Ok(Some(num)) if num > 5 => { + return futures::future::ready( + Ok(Err(InvalidTransaction::Stale.into())) + ) + }, + _ => {}, + } + + futures::future::ready( + Ok(Ok(ValidTransaction { + priority: 4, + requires: if nonce > 1 && self.nonce_dependant { + vec![to_tag(nonce-1, from.clone())] + } else { vec![] }, + provides: vec![to_tag(nonce, from)], + longevity: 10, + propagate: true, + })) + ) + } + + fn block_id_to_number( + &self, + at: &BlockId, + ) -> Result>, Self::Error> { + Ok(match at { + BlockId::Number(num) => Some(*num), + BlockId::Hash(_) => None, + }) + } + + fn block_id_to_hash( + &self, + at: &BlockId, + ) -> Result>, Self::Error> { + Ok(match at { + BlockId::Number(num) => Some(H256::from_low_u64_be(*num)).into(), + BlockId::Hash(_) => None, + }) + } + + fn hash_and_length(&self, uxt: &ExtrinsicFor) -> (Self::Hash, usize) { + let encoded = uxt.encode(); + (blake2_256(&encoded).into(), encoded.len()) + } +} + +fn uxt(transfer: Transfer) -> Extrinsic { + Extrinsic::Transfer(transfer, Default::default()) +} + +fn bench_configured(pool: Pool, number: u64) { + let mut futures = Vec::new(); + let mut tags = Vec::new(); + + for nonce in 1..=number { + let xt = uxt(Transfer { + from: AccountId::from_h256(H256::from_low_u64_be(1)), + to: AccountId::from_h256(H256::from_low_u64_be(2)), + amount: 5, + nonce, + }); + + tags.push(to_tag(nonce, AccountId::from_h256(H256::from_low_u64_be(1)))); + futures.push(pool.submit_one(&BlockId::Number(1), xt)); + } + + let res = block_on(futures::future::join_all(futures.into_iter())); + assert!(res.iter().all(Result::is_ok)); + + assert_eq!(pool.status().future, 0); + assert_eq!(pool.status().ready, number as usize); + + // Prune all transactions. + let block_num = 6; + block_on(pool.prune_tags( + &BlockId::Number(block_num), + tags, + vec![], + )).expect("Prune failed"); + + // pool is empty + assert_eq!(pool.status().ready, 0); + assert_eq!(pool.status().future, 0); +} + +fn benchmark_main(c: &mut Criterion) { + + c.bench_function("sequential 50 tx", |b| { + b.iter(|| { + bench_configured(Pool::new(Default::default(), TestApi::new_dependant()), 50); + }); + }); + + c.bench_function("random 100 tx", |b| { + b.iter(|| { + bench_configured(Pool::new(Default::default(), TestApi::default()), 100); + }); + }); +} + +criterion_group!(benches, benchmark_main); +criterion_main!(benches); diff --git a/core/transaction-pool/graph/src/pool.rs b/core/transaction-pool/graph/src/pool.rs index 621aeabda8..97244f1cec 100644 --- a/core/transaction-pool/graph/src/pool.rs +++ b/core/transaction-pool/graph/src/pool.rs @@ -475,7 +475,6 @@ mod tests { Pool::new(Default::default(), TestApi::default()) } - #[test] fn should_validate_and_import_transaction() { // given -- GitLab From 7389b73f98f34f142ed4e720d4917033bd03012c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Mon, 28 Oct 2019 16:06:20 +0100 Subject: [PATCH 125/167] Fix a import+prune+replace case for multi-provides transactions. (#3939) * Fix a import+prune+replace case for multi-provides transactions. * Fix tests. --- core/transaction-pool/graph/src/pool.rs | 3 ++ core/transaction-pool/graph/src/ready.rs | 15 ++++++- core/transaction-pool/src/tests.rs | 57 ++++++++++++++++++++---- 3 files changed, 65 insertions(+), 10 deletions(-) diff --git a/core/transaction-pool/graph/src/pool.rs b/core/transaction-pool/graph/src/pool.rs index 97244f1cec..dcb54f710f 100644 --- a/core/transaction-pool/graph/src/pool.rs +++ b/core/transaction-pool/graph/src/pool.rs @@ -240,6 +240,7 @@ impl Pool { tags: impl IntoIterator, known_imported_hashes: impl IntoIterator> + Clone, ) -> impl Future> { + log::trace!(target: "txpool", "Pruning at {:?}", at); // Prune all transactions that provide given tags let prune_status = match self.validated_pool.prune_tags(tags) { Ok(prune_status) => prune_status, @@ -257,6 +258,7 @@ impl Pool { let pruned_transactions = prune_status.pruned.into_iter().map(|tx| tx.data.clone()); let reverify_future = self.verify(at, pruned_transactions, false); + log::trace!(target: "txpool", "Prunning at {:?}. Resubmitting transactions.", at); // And finally - submit reverified transactions back to the pool let at = at.clone(); let validated_pool = self.validated_pool.clone(); @@ -908,3 +910,4 @@ mod tests { } } } + diff --git a/core/transaction-pool/graph/src/ready.rs b/core/transaction-pool/graph/src/ready.rs index 85bb4dd783..3698bf447e 100644 --- a/core/transaction-pool/graph/src/ready.rs +++ b/core/transaction-pool/graph/src/ready.rs @@ -338,7 +338,20 @@ impl ReadyTransactions { } } - debug!(target: "txpool", "[{:?}] Pruned.", tx.hash); + // we also need to remove all other tags that this transaction provides, + // but since all the hard work is done, we only clear the provided_tag -> hash + // mapping. + let current_tag = &tag; + for tag in &tx.provides { + let removed = self.provided_tags.remove(tag); + assert_eq!( + removed.as_ref(), + if current_tag == tag { None } else { Some(&tx.hash) }, + "The pool contains exactly one transaction providing given tag; the removed transaction + claims to provide that tag, so it has to be mapped to it's hash; qed" + ); + } + removed.push(tx); } } diff --git a/core/transaction-pool/src/tests.rs b/core/transaction-pool/src/tests.rs index d1ad27dd26..60a9e0562f 100644 --- a/core/transaction-pool/src/tests.rs +++ b/core/transaction-pool/src/tests.rs @@ -27,11 +27,15 @@ use sr_primitives::{ transaction_validity::{TransactionValidity, ValidTransaction}, }; -struct TestApi; +struct TestApi { + pub modifier: Box, +} impl TestApi { fn default() -> Self { - TestApi + TestApi { + modifier: Box::new(|_| {}), + } } } @@ -54,14 +58,18 @@ impl txpool::ChainApi for TestApi { }; let provides = vec![vec![uxt.transfer().nonce as u8]]; + let mut validity = ValidTransaction { + priority: 1, + requires, + provides, + longevity: 64, + propagate: true, + }; + + (self.modifier)(&mut validity); + futures::future::ready(Ok( - Ok(ValidTransaction { - priority: 1, - requires, - provides, - longevity: 64, - propagate: true, - }) + Ok(validity) )) } @@ -181,3 +189,34 @@ fn should_ban_invalid_transactions() { // then block_on(pool.submit_one(&BlockId::number(0), uxt.clone())).unwrap_err(); } + +#[test] +fn should_correctly_prune_transactions_providing_more_than_one_tag() { + let mut api = TestApi::default(); + api.modifier = Box::new(|v: &mut ValidTransaction| { + v.provides.push(vec![155]); + }); + let pool = Pool::new(Default::default(), api); + let xt = uxt(Alice, 209); + block_on(pool.submit_one(&BlockId::number(0), xt.clone())).expect("1. Imported"); + assert_eq!(pool.status().ready, 1); + + // remove the transaction that just got imported. + block_on(pool.prune_tags(&BlockId::number(1), vec![vec![209]], vec![])).expect("1. Pruned"); + assert_eq!(pool.status().ready, 0); + // it's re-imported to future + assert_eq!(pool.status().future, 1); + + // so now let's insert another transaction that also provides the 155 + let xt = uxt(Alice, 211); + block_on(pool.submit_one(&BlockId::number(2), xt.clone())).expect("2. Imported"); + assert_eq!(pool.status().ready, 1); + assert_eq!(pool.status().future, 1); + let pending: Vec<_> = pool.ready().map(|a| a.data.transfer().nonce).collect(); + assert_eq!(pending, vec![211]); + + // prune it and make sure the pool is empty + block_on(pool.prune_tags(&BlockId::number(3), vec![vec![155]], vec![])).expect("2. Pruned"); + assert_eq!(pool.status().ready, 0); + assert_eq!(pool.status().future, 2); +} -- GitLab From 43961e8555b569ec06f75aa6cb3abcbaa55e0d1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 29 Oct 2019 00:58:58 +0100 Subject: [PATCH 126/167] Remove footgun around session keys/handlers (#3949) * Remove footgun around session keys/handlers - `OpaqueKeys` now has an associated type `KeyTypeIdProviders`. This can be used in the runtime as input for `SessionHandler` from the session trait. - `impl_opaque_keys` now works with modules and extracts the `KeyTypeId` from the module directly. - Added some checks to the `session` storage initialization that checks that the `SessionHandler` and `Keys` use the same number of keys and that the order is equal. * Update core/sr-primitives/src/traits.rs --- Cargo.lock | 20 ++++---- core/application-crypto/src/ed25519.rs | 4 ++ core/application-crypto/src/sr25519.rs | 4 ++ core/application-crypto/src/traits.rs | 5 ++ core/sr-primitives/src/lib.rs | 2 +- core/sr-primitives/src/testing.rs | 10 ++-- core/sr-primitives/src/traits.rs | 67 +++++++++++++++++--------- core/test-runtime/src/lib.rs | 12 +---- node-template/runtime/src/lib.rs | 8 ++- node/runtime/src/lib.rs | 27 +++-------- srml/aura/src/lib.rs | 4 ++ srml/authority-discovery/src/lib.rs | 8 ++- srml/babe/src/lib.rs | 4 ++ srml/babe/src/mock.rs | 5 +- srml/grandpa/src/lib.rs | 7 ++- srml/im-online/src/lib.rs | 5 +- srml/session/Cargo.toml | 2 +- srml/session/src/historical.rs | 6 +-- srml/session/src/lib.rs | 42 ++++++++++++---- srml/session/src/mock.rs | 2 +- srml/staking/src/mock.rs | 6 ++- 21 files changed, 150 insertions(+), 100 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4bade61225..2dadb19b69 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1438,7 +1438,7 @@ dependencies = [ [[package]] name = "impl-trait-for-tuples" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3928,7 +3928,7 @@ dependencies = [ name = "sr-primitives" version = "2.0.0" dependencies = [ - "impl-trait-for-tuples 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "impl-trait-for-tuples 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "paste 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4040,7 +4040,7 @@ dependencies = [ name = "srml-authorship" version = "0.1.0" dependencies = [ - "impl-trait-for-tuples 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "impl-trait-for-tuples 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 2.0.0", "sr-primitives 2.0.0", @@ -4248,7 +4248,7 @@ dependencies = [ name = "srml-finality-tracker" version = "2.0.0" dependencies = [ - "impl-trait-for-tuples 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "impl-trait-for-tuples 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 2.0.0", @@ -4415,7 +4415,7 @@ dependencies = [ name = "srml-session" version = "2.0.0" dependencies = [ - "impl-trait-for-tuples 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "impl-trait-for-tuples 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4485,7 +4485,7 @@ name = "srml-support" version = "2.0.0" dependencies = [ "bitmask 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "impl-trait-for-tuples 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "impl-trait-for-tuples 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "once_cell 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4553,7 +4553,7 @@ name = "srml-system" version = "2.0.0" dependencies = [ "criterion 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "impl-trait-for-tuples 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "impl-trait-for-tuples 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4597,7 +4597,7 @@ dependencies = [ name = "srml-timestamp" version = "2.0.0" dependencies = [ - "impl-trait-for-tuples 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "impl-trait-for-tuples 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 2.0.0", @@ -4865,7 +4865,7 @@ dependencies = [ name = "substrate-chain-spec" version = "2.0.0" dependencies = [ - "impl-trait-for-tuples 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "impl-trait-for-tuples 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", @@ -7019,7 +7019,7 @@ dependencies = [ "checksum idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9" "checksum impl-codec 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3fa0086251524c50fd53b32e7b05eb6d79e2f97221eaf0c53c0ca9c3096f21d3" "checksum impl-serde 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a263dc95daa6c3788c8f7133d86dc2ad89ec5a0c56167f9e3441c5f7f33358c4" -"checksum impl-trait-for-tuples 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6947b372790f8948f439bb6aaa6baabdf80be1a207a477ff072f83fb793e428f" +"checksum impl-trait-for-tuples 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7ef5550a42e3740a0e71f909d4c861056a284060af885ae7aa6242820f920d9d" "checksum indexmap 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a61202fbe46c4a951e9404a720a0180bcf3212c750d735cb5c4ba4dc551299f3" "checksum integer-sqrt 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ea155abb3ba6f382a75f1418988c05fe82959ed9ce727de427f9cfd425b0c903" "checksum interleaved-ordered 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "141340095b15ed7491bd3d4ced9d20cebfb826174b6bb03386381f62b01e3d77" diff --git a/core/application-crypto/src/ed25519.rs b/core/application-crypto/src/ed25519.rs index b0113718b5..ac01cef61b 100644 --- a/core/application-crypto/src/ed25519.rs +++ b/core/application-crypto/src/ed25519.rs @@ -23,6 +23,10 @@ pub use primitives::ed25519::*; mod app { use primitives::testing::ED25519; crate::app_crypto!(super, ED25519); + + impl crate::traits::BoundToRuntimeAppPublic for Public { + type Public = Self; + } } pub use app::Public as AppPublic; diff --git a/core/application-crypto/src/sr25519.rs b/core/application-crypto/src/sr25519.rs index 40f6c6b22e..c343a2e167 100644 --- a/core/application-crypto/src/sr25519.rs +++ b/core/application-crypto/src/sr25519.rs @@ -23,6 +23,10 @@ pub use primitives::sr25519::*; mod app { use primitives::testing::SR25519; crate::app_crypto!(super, SR25519); + + impl crate::traits::BoundToRuntimeAppPublic for Public { + type Public = Self; + } } pub use app::Public as AppPublic; diff --git a/core/application-crypto/src/traits.rs b/core/application-crypto/src/traits.rs index 66e6cd6579..db71f3072a 100644 --- a/core/application-crypto/src/traits.rs +++ b/core/application-crypto/src/traits.rs @@ -127,3 +127,8 @@ pub trait RuntimeAppPublic: Sized { fn verify>(&self, msg: &M, signature: &Self::Signature) -> bool; } +/// Something that bound to a fixed `RuntimeAppPublic`. +pub trait BoundToRuntimeAppPublic { + /// The `RuntimeAppPublic` this type is bound to. + type Public: RuntimeAppPublic; +} diff --git a/core/sr-primitives/src/lib.rs b/core/sr-primitives/src/lib.rs index 4341e3543a..fce9f7def0 100644 --- a/core/sr-primitives/src/lib.rs +++ b/core/sr-primitives/src/lib.rs @@ -60,7 +60,7 @@ pub use generic::{DigestItem, Digest}; /// Re-export this since it's part of the API of this crate. pub use primitives::{TypeId, crypto::{key_types, KeyTypeId, CryptoType, AccountId32}}; -pub use app_crypto::RuntimeAppPublic; +pub use app_crypto::{RuntimeAppPublic, BoundToRuntimeAppPublic}; /// Re-export `RuntimeDebug`, to avoid dependency clutter. pub use primitives::RuntimeDebug; diff --git a/core/sr-primitives/src/testing.rs b/core/sr-primitives/src/testing.rs index b790347118..d60e58bab1 100644 --- a/core/sr-primitives/src/testing.rs +++ b/core/sr-primitives/src/testing.rs @@ -117,10 +117,10 @@ impl app_crypto::RuntimeAppPublic for UintAuthorityId { } impl OpaqueKeys for UintAuthorityId { - type KeyTypeIds = std::iter::Cloned>; + type KeyTypeIdProviders = (); - fn key_ids() -> Self::KeyTypeIds { - [key_types::DUMMY].iter().cloned() + fn key_ids() -> &'static [KeyTypeId] { + &[key_types::DUMMY] } fn get_raw(&self, _: KeyTypeId) -> &[u8] { @@ -132,6 +132,10 @@ impl OpaqueKeys for UintAuthorityId { } } +impl crate::BoundToRuntimeAppPublic for UintAuthorityId { + type Public = Self; +} + /// Digest item pub type DigestItem = generic::DigestItem; diff --git a/core/sr-primitives/src/traits.rs b/core/sr-primitives/src/traits.rs index 4586a84511..ecaf6a78fc 100644 --- a/core/sr-primitives/src/traits.rs +++ b/core/sr-primitives/src/traits.rs @@ -982,11 +982,11 @@ pub trait ValidateUnsigned { /// Opaque datatype that may be destructured into a series of raw byte slices (which represent /// individual keys). pub trait OpaqueKeys: Clone { - /// An iterator over the type IDs of keys that this holds. - type KeyTypeIds: IntoIterator; + /// Types bound to this opaque keys that provide the key type ids returned. + type KeyTypeIdProviders; - /// Return an iterator over the key-type IDs supported by this set. - fn key_ids() -> Self::KeyTypeIds; + /// Return the key-type IDs supported by this set. + fn key_ids() -> &'static [crate::KeyTypeId]; /// Get the raw bytes of key with key-type ID `i`. fn get_raw(&self, i: super::KeyTypeId) -> &[u8]; /// Get the decoded key with index `i`. @@ -1086,22 +1086,25 @@ macro_rules! count { } /// Implement `OpaqueKeys` for a described struct. -/// Would be much nicer for this to be converted to `derive` code. /// -/// Every field type must be equivalent implement `as_ref()`, which is expected -/// to hold the standard SCALE-encoded form of that key. This is typically -/// just the bytes of the key. +/// Every field type must implement [`BoundToRuntimeAppPublic`](crate::BoundToRuntimeAppPublic). +/// `KeyTypeIdProviders` is set to the types given as fields. /// /// ```rust -/// use sr_primitives::{impl_opaque_keys, KeyTypeId, app_crypto::{sr25519, ed25519}}; -/// use primitives::testing::{SR25519, ED25519}; +/// use sr_primitives::{ +/// impl_opaque_keys, KeyTypeId, BoundToRuntimeAppPublic, app_crypto::{sr25519, ed25519} +/// }; +/// +/// pub struct KeyModule; +/// impl BoundToRuntimeAppPublic for KeyModule { type Public = ed25519::AppPublic; } +/// +/// pub struct KeyModule2; +/// impl BoundToRuntimeAppPublic for KeyModule2 { type Public = sr25519::AppPublic; } /// /// impl_opaque_keys! { /// pub struct Keys { -/// #[id(ED25519)] -/// pub ed25519: ed25519::AppPublic, -/// #[id(SR25519)] -/// pub sr25519: sr25519::AppPublic, +/// pub key_module: KeyModule, +/// pub key_module2: KeyModule2, /// } /// } /// ``` @@ -1110,7 +1113,6 @@ macro_rules! impl_opaque_keys { ( pub struct $name:ident { $( - #[id($key_id:expr)] pub $field:ident: $type:ty, )* } @@ -1119,12 +1121,12 @@ macro_rules! impl_opaque_keys { Default, Clone, PartialEq, Eq, $crate::codec::Encode, $crate::codec::Decode, - $crate::RuntimeDebug + $crate::RuntimeDebug, )] #[cfg_attr(feature = "std", derive($crate::serde::Serialize, $crate::serde::Deserialize))] pub struct $name { $( - pub $field: $type, + pub $field: <$type as $crate::BoundToRuntimeAppPublic>::Public, )* } @@ -1137,7 +1139,11 @@ macro_rules! impl_opaque_keys { pub fn generate(seed: Option<&str>) -> $crate::rstd::vec::Vec { let keys = Self{ $( - $field: <$type as $crate::app_crypto::RuntimeAppPublic>::generate_pair(seed), + $field: < + < + $type as $crate::BoundToRuntimeAppPublic + >::Public as $crate::RuntimeAppPublic + >::generate_pair(seed), )* }; $crate::codec::Encode::encode(&keys) @@ -1145,17 +1151,30 @@ macro_rules! impl_opaque_keys { } impl $crate::traits::OpaqueKeys for $name { - type KeyTypeIds = $crate::rstd::iter::Cloned< - $crate::rstd::slice::Iter<'static, $crate::KeyTypeId> - >; + type KeyTypeIdProviders = ( $( $type, )* ); - fn key_ids() -> Self::KeyTypeIds { - [ $($key_id),* ].iter().cloned() + fn key_ids() -> &'static [$crate::KeyTypeId] { + &[ + $( + < + < + $type as $crate::BoundToRuntimeAppPublic + >::Public as $crate::RuntimeAppPublic + >::ID + ),* + ] } fn get_raw(&self, i: $crate::KeyTypeId) -> &[u8] { match i { - $( i if i == $key_id => self.$field.as_ref(), )* + $( + i if i == < + < + $type as $crate::BoundToRuntimeAppPublic + >::Public as $crate::RuntimeAppPublic + >::ID => + self.$field.as_ref(), + )* _ => &[], } } diff --git a/core/test-runtime/src/lib.rs b/core/test-runtime/src/lib.rs index 45d86f891c..7fac0e702e 100644 --- a/core/test-runtime/src/lib.rs +++ b/core/test-runtime/src/lib.rs @@ -25,15 +25,7 @@ pub mod system; use rstd::{prelude::*, marker::PhantomData}; use codec::{Encode, Decode, Input, Error}; -use primitives::{ - Blake2Hasher, - OpaqueMetadata, - RuntimeDebug, - testing::{ - ED25519, - SR25519, - } -}; +use primitives::{Blake2Hasher, OpaqueMetadata, RuntimeDebug}; use app_crypto::{ed25519, sr25519, RuntimeAppPublic}; pub use app_crypto; use trie_db::{TrieMut, Trie}; @@ -454,9 +446,7 @@ fn code_using_trie() -> u64 { impl_opaque_keys! { pub struct SessionKeys { - #[id(ED25519)] pub ed25519: ed25519::AppPublic, - #[id(SR25519)] pub sr25519: sr25519::AppPublic, } } diff --git a/node-template/runtime/src/lib.rs b/node-template/runtime/src/lib.rs index b803e18417..c0cd2cf337 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::{OpaqueMetadata, crypto::key_types}; +use primitives::OpaqueMetadata; use sr_primitives::{ ApplyResult, transaction_validity::TransactionValidity, generic, create_runtime_str, impl_opaque_keys, MultiSignature @@ -84,10 +84,8 @@ pub mod opaque { impl_opaque_keys! { pub struct SessionKeys { - #[id(key_types::AURA)] - pub aura: AuraId, - #[id(key_types::GRANDPA)] - pub grandpa: GrandpaId, + pub aura: Aura, + pub grandpa: Grandpa, } } } diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index 3dba79d27b..b5d0405ed0 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -29,20 +29,18 @@ use node_primitives::{ AccountId, AccountIndex, Balance, BlockNumber, Hash, Index, Moment, Signature, }; -use babe_primitives::AuthorityId as BabeId; use grandpa::fg_primitives; use client::{ block_builder::api::{self as block_builder_api, InherentData, CheckInherentsResult}, runtime_api as client_api, impl_runtime_apis }; -use sr_primitives::{ - Permill, Perbill, ApplyResult, impl_opaque_keys, generic, create_runtime_str, key_types -}; +use sr_primitives::{Permill, Perbill, ApplyResult, impl_opaque_keys, generic, create_runtime_str}; use sr_primitives::curve::PiecewiseLinear; use sr_primitives::transaction_validity::TransactionValidity; use sr_primitives::weights::Weight; use sr_primitives::traits::{ self, BlakeTwo256, Block as BlockT, NumberFor, StaticLookup, SaturatedConversion, + OpaqueKeys, }; use version::RuntimeVersion; #[cfg(any(feature = "std", test))] @@ -211,34 +209,21 @@ impl authorship::Trait for Runtime { type EventHandler = Staking; } -// !!!!!!!!!!!!! -// WARNING!!!!!! SEE NOTE BELOW BEFORE TOUCHING THIS CODE -// !!!!!!!!!!!!! -type SessionHandlers = (Grandpa, Babe, ImOnline); - impl_opaque_keys! { pub struct SessionKeys { - #[id(key_types::GRANDPA)] - pub grandpa: GrandpaId, - #[id(key_types::BABE)] - pub babe: BabeId, - #[id(key_types::IM_ONLINE)] - pub im_online: ImOnlineId, + pub grandpa: Grandpa, + pub babe: Babe, + pub im_online: ImOnline, } } -// NOTE: `SessionHandler` and `SessionKeys` are co-dependent: One key will be used for each handler. -// The number and order of items in `SessionHandler` *MUST* be the same number and order of keys in -// `SessionKeys`. -// TODO: Introduce some structure to tie these together to make it a bit less of a footgun. This -// should be easy, since OneSessionHandler trait provides the `Key` as an associated type. #2858 parameter_types! { pub const DisabledValidatorsThreshold: Perbill = Perbill::from_percent(17); } impl session::Trait for Runtime { type OnSessionEnding = Staking; - type SessionHandler = SessionHandlers; + type SessionHandler = ::KeyTypeIdProviders; type ShouldEndSession = Babe; type Event = Event; type Keys = SessionKeys; diff --git a/srml/aura/src/lib.rs b/srml/aura/src/lib.rs index f9034c7ca0..f27cb98c01 100644 --- a/srml/aura/src/lib.rs +++ b/srml/aura/src/lib.rs @@ -182,6 +182,10 @@ impl Module { } } +impl sr_primitives::BoundToRuntimeAppPublic for Module { + type Public = T::AuthorityId; +} + impl session::OneSessionHandler for Module { type Key = T::AuthorityId; diff --git a/srml/authority-discovery/src/lib.rs b/srml/authority-discovery/src/lib.rs index c82d580fd9..8c2951f3ac 100644 --- a/srml/authority-discovery/src/lib.rs +++ b/srml/authority-discovery/src/lib.rs @@ -107,6 +107,10 @@ impl Module { } } +impl sr_primitives::BoundToRuntimeAppPublic for Module { + type Public = T::AuthorityId; +} + impl session::OneSessionHandler for Module { type Key = T::AuthorityId; @@ -139,7 +143,7 @@ mod tests { use runtime_io::TestExternalities; use sr_primitives::{ testing::{Header, UintAuthorityId}, traits::{ConvertInto, IdentityLookup, OpaqueKeys}, - Perbill, + Perbill, KeyTypeId, }; use support::{impl_outer_origin, parameter_types}; @@ -218,6 +222,8 @@ mod tests { pub struct TestSessionHandler; impl session::SessionHandler for TestSessionHandler { + const KEY_TYPE_IDS: &'static [KeyTypeId] = &[key_types::DUMMY]; + fn on_new_session( _changed: bool, _validators: &[(AuthorityId, Ks)], diff --git a/srml/babe/src/lib.rs b/srml/babe/src/lib.rs index ee2d66fbe6..e12e123daf 100644 --- a/srml/babe/src/lib.rs +++ b/srml/babe/src/lib.rs @@ -546,6 +546,10 @@ impl OnTimestampSet for Module { fn on_timestamp_set(_moment: T::Moment) { } } +impl sr_primitives::BoundToRuntimeAppPublic for Module { + type Public = AuthorityId; +} + impl session::OneSessionHandler for Module { type Key = AuthorityId; diff --git a/srml/babe/src/mock.rs b/srml/babe/src/mock.rs index 5a6b80a2a6..d7aed7b42a 100644 --- a/srml/babe/src/mock.rs +++ b/srml/babe/src/mock.rs @@ -20,9 +20,7 @@ use super::{Trait, Module, GenesisConfig}; use babe_primitives::AuthorityId; use sr_primitives::{ - traits::IdentityLookup, Perbill, - testing::{Header, UintAuthorityId}, - impl_opaque_keys, key_types::DUMMY, + traits::IdentityLookup, Perbill, testing::{Header, UintAuthorityId}, impl_opaque_keys, }; use sr_version::RuntimeVersion; use support::{impl_outer_origin, parameter_types}; @@ -71,7 +69,6 @@ impl system::Trait for Test { impl_opaque_keys! { pub struct MockSessionKeys { - #[id(DUMMY)] pub dummy: UintAuthorityId, } } diff --git a/srml/grandpa/src/lib.rs b/srml/grandpa/src/lib.rs index 0fc0df382a..f3e876f2c4 100644 --- a/srml/grandpa/src/lib.rs +++ b/srml/grandpa/src/lib.rs @@ -36,8 +36,7 @@ use support::{ decl_event, decl_storage, decl_module, dispatch::Result, }; use sr_primitives::{ - generic::{DigestItem, OpaqueDigestItemId}, traits::Zero, - Perbill, + generic::{DigestItem, OpaqueDigestItemId}, traits::Zero, Perbill, }; use sr_staking_primitives::{ SessionIndex, @@ -374,6 +373,10 @@ impl Module { } } +impl sr_primitives::BoundToRuntimeAppPublic for Module { + type Public = AuthorityId; +} + impl session::OneSessionHandler for Module where T: session::Trait { diff --git a/srml/im-online/src/lib.rs b/srml/im-online/src/lib.rs index 82b866d32b..aeeaf74dc6 100644 --- a/srml/im-online/src/lib.rs +++ b/srml/im-online/src/lib.rs @@ -427,8 +427,11 @@ impl Module { } } -impl session::OneSessionHandler for Module { +impl sr_primitives::BoundToRuntimeAppPublic for Module { + type Public = T::AuthorityId; +} +impl session::OneSessionHandler for Module { type Key = T::AuthorityId; fn on_genesis_session<'a, I: 'a>(validators: I) diff --git a/srml/session/Cargo.toml b/srml/session/Cargo.toml index b114755ad9..1346867910 100644 --- a/srml/session/Cargo.toml +++ b/srml/session/Cargo.toml @@ -16,7 +16,7 @@ system = { package = "srml-system", path = "../system", default-features = false timestamp = { package = "srml-timestamp", path = "../timestamp", default-features = false } substrate-trie = { path = "../../core/trie", default-features = false, optional = true } runtime-io ={ package = "sr-io", path = "../../core/sr-io", default-features = false } -impl-trait-for-tuples = "0.1.2" +impl-trait-for-tuples = "0.1.3" [dev-dependencies] primitives = { package = "substrate-primitives", path = "../../core/primitives" } diff --git a/srml/session/src/historical.rs b/srml/session/src/historical.rs index d3fbc67b95..7975da4998 100644 --- a/srml/session/src/historical.rs +++ b/srml/session/src/historical.rs @@ -182,11 +182,9 @@ impl ProvingTrie { // map each key to the owner index. for key_id in T::Keys::key_ids() { - let key = keys.get_raw(key_id); + let key = keys.get_raw(*key_id); let res = (key_id, key).using_encoded(|k| - i.using_encoded(|v| - trie.insert(k, v) - ) + i.using_encoded(|v| trie.insert(k, v)) ); let _ = res.map_err(|_| "failed to insert into trie")?; diff --git a/srml/session/src/lib.rs b/srml/session/src/lib.rs index 76cc6d0663..7f66673483 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 codec::Decode; -use sr_primitives::{KeyTypeId, Perbill, RuntimeAppPublic}; +use sr_primitives::{KeyTypeId, Perbill, RuntimeAppPublic, BoundToRuntimeAppPublic}; use sr_primitives::weights::SimpleDispatchInfo; use sr_primitives::traits::{Convert, Zero, Member, OpaqueKeys}; use sr_staking_primitives::SessionIndex; @@ -192,6 +192,12 @@ impl OnSessionEnding for () { /// Handler for session lifecycle events. pub trait SessionHandler { + /// All the key type ids this session handler can process. + /// + /// The order must be the same as it expects them in + /// [`on_new_session`](Self::on_new_session) and [`on_genesis_session`](Self::on_genesis_session). + const KEY_TYPE_IDS: &'static [KeyTypeId]; + /// The given validator set will be used for the genesis session. /// It is guaranteed that the given validator set will also be used /// for the second session, therefore the first call to `on_new_session` @@ -220,7 +226,7 @@ pub trait SessionHandler { } /// A session handler for specific key type. -pub trait OneSessionHandler { +pub trait OneSessionHandler: BoundToRuntimeAppPublic { /// The key type expected. type Key: Decode + Default + RuntimeAppPublic; @@ -258,6 +264,10 @@ pub trait OneSessionHandler { impl SessionHandler for Tuple { for_tuples!( where #( Tuple: OneSessionHandler )* ); + for_tuples!( + const KEY_TYPE_IDS: &'static [KeyTypeId] = &[ #( ::ID ),* ]; + ); + fn on_genesis_session(validators: &[(AId, Ks)]) { for_tuples!( #( @@ -382,6 +392,20 @@ decl_storage! { add_extra_genesis { config(keys): Vec<(T::ValidatorId, T::Keys)>; build(|config: &GenesisConfig| { + if T::SessionHandler::KEY_TYPE_IDS.len() != T::Keys::key_ids().len() { + panic!("Number of keys in session handler and session keys does not match"); + } + + T::SessionHandler::KEY_TYPE_IDS.iter().zip(T::Keys::key_ids()).enumerate() + .for_each(|(i, (sk, kk))| { + if sk != kk { + panic!( + "Session handler and session key expect different key type at index: {}", + i, + ); + } + }); + for (who, keys) in config.keys.iter().cloned() { assert!( >::load_keys(&who).is_none(), @@ -594,23 +618,23 @@ impl Module { let old_keys = Self::load_keys(&who); for id in T::Keys::key_ids() { - let key = keys.get_raw(id); + let key = keys.get_raw(*id); // ensure keys are without duplication. ensure!( - Self::key_owner(id, key).map_or(true, |owner| &owner == who), + Self::key_owner(*id, key).map_or(true, |owner| &owner == who), "registered duplicate key" ); - if let Some(old) = old_keys.as_ref().map(|k| k.get_raw(id)) { + if let Some(old) = old_keys.as_ref().map(|k| k.get_raw(*id)) { if key == old { continue; } - Self::clear_key_owner(id, old); + Self::clear_key_owner(*id, old); } - Self::put_key_owner(id, key, &who); + Self::put_key_owner(*id, key, &who); } Self::put_keys(&who, &keys); @@ -621,8 +645,8 @@ impl Module { fn prune_dead_keys(who: &T::ValidatorId) { if let Some(old_keys) = Self::take_keys(who) { for id in T::Keys::key_ids() { - let key_data = old_keys.get_raw(id); - Self::clear_key_owner(id, key_data); + let key_data = old_keys.get_raw(*id); + Self::clear_key_owner(*id, key_data); } } } diff --git a/srml/session/src/mock.rs b/srml/session/src/mock.rs index d680fdc96b..cb95a35570 100644 --- a/srml/session/src/mock.rs +++ b/srml/session/src/mock.rs @@ -28,7 +28,6 @@ use sr_staking_primitives::SessionIndex; impl_opaque_keys! { pub struct MockSessionKeys { - #[id(DUMMY)] pub dummy: UintAuthorityId, } } @@ -67,6 +66,7 @@ impl ShouldEndSession for TestShouldEndSession { pub struct TestSessionHandler; impl SessionHandler for TestSessionHandler { + const KEY_TYPE_IDS: &'static [sr_primitives::KeyTypeId] = &[UintAuthorityId::ID]; fn on_genesis_session(_validators: &[(u64, T)]) {} fn on_new_session( changed: bool, diff --git a/srml/staking/src/mock.rs b/srml/staking/src/mock.rs index 41a2ad4802..b0ad771435 100644 --- a/srml/staking/src/mock.rs +++ b/srml/staking/src/mock.rs @@ -17,12 +17,12 @@ //! Test utilities use std::{collections::HashSet, cell::RefCell}; -use sr_primitives::Perbill; +use sr_primitives::{Perbill, KeyTypeId}; use sr_primitives::curve::PiecewiseLinear; use sr_primitives::traits::{IdentityLookup, Convert, OpaqueKeys, OnInitialize, SaturatedConversion}; use sr_primitives::testing::{Header, UintAuthorityId}; use sr_staking_primitives::SessionIndex; -use primitives::H256; +use primitives::{H256, crypto::key_types}; use runtime_io; use support::{assert_ok, impl_outer_origin, parameter_types, StorageLinkedMap}; use support::traits::{Currency, Get, FindAuthor}; @@ -52,6 +52,8 @@ thread_local! { pub struct TestSessionHandler; impl session::SessionHandler for TestSessionHandler { + const KEY_TYPE_IDS: &'static [KeyTypeId] = &[key_types::DUMMY]; + fn on_genesis_session(_validators: &[(AccountId, Ks)]) {} fn on_new_session( -- GitLab From 23c1956157545a60ec1444613ffd6ecef5f423ec Mon Sep 17 00:00:00 2001 From: Ashley Date: Tue, 29 Oct 2019 12:47:27 +0000 Subject: [PATCH 127/167] Switch sr-arithmetic benchmarking to criterion (#3902) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Change DefaultMaxDepth from 1024 to 32 * Switch sr-arithmetic benchmarking to criterion * Update core/sr-arithmetic/Cargo.toml Co-Authored-By: Bastian Köcher * Update core/sr-arithmetic/benches/bench.rs Co-Authored-By: Bastian Köcher * Test on variable limb lengths * Change license * Rework division --- Cargo.lock | 1 + core/primitives/Cargo.toml | 2 +- .../benches/{benches.rs => bench.rs} | 0 core/sr-arithmetic/Cargo.toml | 6 +- core/sr-arithmetic/benches/bench.rs | 80 +++++++++++++++++++ core/sr-arithmetic/src/biguint.rs | 80 ------------------- core/sr-arithmetic/src/lib.rs | 4 - 7 files changed, 87 insertions(+), 86 deletions(-) rename core/primitives/benches/{benches.rs => bench.rs} (100%) create mode 100644 core/sr-arithmetic/benches/bench.rs diff --git a/Cargo.lock b/Cargo.lock index 2dadb19b69..6ee62fe8b0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3897,6 +3897,7 @@ dependencies = [ name = "sr-arithmetic" version = "2.0.0" dependencies = [ + "criterion 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "integer-sqrt 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/core/primitives/Cargo.toml b/core/primitives/Cargo.toml index bc8106de3a..9d76b4f7af 100644 --- a/core/primitives/Cargo.toml +++ b/core/primitives/Cargo.toml @@ -45,7 +45,7 @@ rand = "0.7.2" criterion = "0.2.11" [[bench]] -name = "benches" +name = "bench" harness = false [lib] diff --git a/core/primitives/benches/benches.rs b/core/primitives/benches/bench.rs similarity index 100% rename from core/primitives/benches/benches.rs rename to core/primitives/benches/bench.rs diff --git a/core/sr-arithmetic/Cargo.toml b/core/sr-arithmetic/Cargo.toml index 3962daf493..fd484671dd 100644 --- a/core/sr-arithmetic/Cargo.toml +++ b/core/sr-arithmetic/Cargo.toml @@ -15,9 +15,9 @@ substrate-debug-derive = { path = "../primitives/debug-derive", default-features [dev-dependencies] primitive-types = "0.6.0" rand = "0.7.2" +criterion = "0.3" [features] -bench = [] default = ["std"] std = [ "codec/std", @@ -26,3 +26,7 @@ std = [ "serde", "substrate-debug-derive/std", ] + +[[bench]] +name = "bench" +harness = false diff --git a/core/sr-arithmetic/benches/bench.rs b/core/sr-arithmetic/benches/bench.rs new file mode 100644 index 0000000000..22c0ce6f56 --- /dev/null +++ b/core/sr-arithmetic/benches/bench.rs @@ -0,0 +1,80 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +use criterion::{Criterion, Throughput, BenchmarkId, criterion_group, criterion_main}; +use sr_arithmetic::biguint::{BigUint, Single}; +use rand::Rng; + +fn random_big_uint(size: usize) -> BigUint { + let mut rng = rand::thread_rng(); + let digits: Vec<_> = (0..size).map(|_| rng.gen_range(0, Single::max_value())).collect(); + BigUint::from_limbs(&digits) +} + +fn bench_op(c: &mut Criterion, name: &str, op: F) { + let mut group = c.benchmark_group(name); + + for size in [2, 4, 6, 8, 10].iter() { + group.throughput(Throughput::Elements(*size)); + group.bench_with_input(BenchmarkId::from_parameter(size), size, |bencher, &size| { + let a = random_big_uint(size as usize); + let b = random_big_uint(size as usize); + + bencher.iter(|| op(&a, &b)); + }); + } +} + +fn bench_addition(c: &mut Criterion) { + bench_op(c, "addition", |a, b| { + let _ = a.clone().add(&b); + }); +} + +fn bench_subtraction(c: &mut Criterion) { + bench_op(c, "subtraction", |a, b| { + let _ = a.clone().sub(&b); + }); +} + +fn bench_multiplication(c: &mut Criterion) { + bench_op(c, "multiplication", |a, b| { + let _ = a.clone().mul(&b); + }); +} + +fn bench_division(c: &mut Criterion) { + let mut group = c.benchmark_group("division"); + + for size in [4, 6, 8, 10].iter() { + group.throughput(Throughput::Elements(*size)); + group.bench_with_input(BenchmarkId::from_parameter(size), size, |bencher, &size| { + let a = random_big_uint(size as usize); + let b = random_big_uint(rand::thread_rng().gen_range(2, size as usize)); + + bencher.iter(|| { + let _ = a.clone().div(&b, true); + }); + }); + } +} + +criterion_group!{ + name = benches; + config = Criterion::default(); + targets = bench_addition, bench_subtraction, bench_multiplication, bench_division +} +criterion_main!(benches); diff --git a/core/sr-arithmetic/src/biguint.rs b/core/sr-arithmetic/src/biguint.rs index c0836e09b3..1a701a5ebd 100644 --- a/core/sr-arithmetic/src/biguint.rs +++ b/core/sr-arithmetic/src/biguint.rs @@ -561,8 +561,6 @@ impl From for BigUint { #[cfg(test)] pub mod tests { use super::*; - #[cfg(feature = "bench")] - use test::Bencher; fn with_limbs(n: usize) -> BigUint { BigUint { digits: vec![1; n] } @@ -734,82 +732,4 @@ pub mod tests { assert_eq!(b.clone().div_unit(7), BigUint::from(((B + 100) / 7) as Single)); } - - #[cfg(feature = "bench")] - fn random_big_uint(size: usize) -> BigUint { - use rand::Rng; - let mut rng = rand::thread_rng(); - let digits = (0..size).map(|_| rng.gen_range(0, Single::max_value())).collect(); - BigUint { digits } - } - - #[cfg(feature = "bench")] - #[bench] - fn bench_addition_2_digit(bencher: &mut Bencher) { - let a = random_big_uint(2); - let b = random_big_uint(2); - bencher.iter(|| { - let _ = a.clone().add(&b); - }); - } - - #[cfg(feature = "bench")] - #[bench] - fn bench_addition_4_digit(bencher: &mut Bencher) { - let a = random_big_uint(4); - let b = random_big_uint(4); - bencher.iter(|| { - let _ = a.clone().add(&b); - }); - } - - #[cfg(feature = "bench")] - #[bench] - fn bench_subtraction_2_digit(bencher: &mut Bencher) { - let a = random_big_uint(2); - let b = random_big_uint(2); - bencher.iter(|| { - let _ = a.clone().sub(&b); - }); - } - - #[cfg(feature = "bench")] - #[bench] - fn bench_subtraction_4_digit(bencher: &mut Bencher) { - let a = random_big_uint(4); - let b = random_big_uint(4); - bencher.iter(|| { - let _ = a.clone().sub(&b); - }); - } - - #[cfg(feature = "bench")] - #[bench] - fn bench_multiplication_2_digit(bencher: &mut Bencher) { - let a = random_big_uint(2); - let b = random_big_uint(2); - bencher.iter(|| { - let _ = a.clone().mul(&b); - }); - } - - #[cfg(feature = "bench")] - #[bench] - fn bench_multiplication_4_digit(bencher: &mut Bencher) { - let a = random_big_uint(4); - let b = random_big_uint(4); - bencher.iter(|| { - let _ = a.clone().mul(&b); - }); - } - - #[cfg(feature = "bench")] - #[bench] - fn bench_division_4_digit(bencher: &mut Bencher) { - let a = random_big_uint(4); - let b = random_big_uint(2); - bencher.iter(|| { - let _ = a.clone().div(&b, true); - }); - } } diff --git a/core/sr-arithmetic/src/lib.rs b/core/sr-arithmetic/src/lib.rs index 847ca9e797..7b285002e5 100644 --- a/core/sr-arithmetic/src/lib.rs +++ b/core/sr-arithmetic/src/lib.rs @@ -18,10 +18,6 @@ #![cfg_attr(not(feature = "std"), no_std)] -// to allow benchmarking -#![cfg_attr(feature = "bench", feature(test))] -#[cfg(feature = "bench")] extern crate test; - /// Copied from `sr-primitives` and documented there. #[cfg(test)] macro_rules! assert_eq_error_rate { -- GitLab From bf0c5aef0c1c6a37620b20a59632ef3e23996298 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Tue, 29 Oct 2019 15:46:34 +0100 Subject: [PATCH 128/167] Storage migration of elections-phragmen (#3948) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Initial sotrage migration * Fix some deps * test added * another dep removed * Update srml/elections-phragmen/src/lib.rs Co-Authored-By: Bastian Köcher * Apply suggestions from code review Co-Authored-By: Bastian Köcher * a bit nicer --- srml/elections-phragmen/Cargo.toml | 9 ++--- srml/elections-phragmen/src/lib.rs | 63 +++++++++++++++++++++++++++++- 2 files changed, 65 insertions(+), 7 deletions(-) diff --git a/srml/elections-phragmen/Cargo.toml b/srml/elections-phragmen/Cargo.toml index 02898fc754..85532849ec 100644 --- a/srml/elections-phragmen/Cargo.toml +++ b/srml/elections-phragmen/Cargo.toml @@ -5,10 +5,7 @@ authors = ["Parity Technologies "] edition = "2018" [dependencies] -serde = { version = "1.0.101", optional = true } codec = { package = "parity-scale-codec", version = "1.0.0", default-features = false, features = ["derive"] } -primitives = { package = "substrate-primitives", path = "../../core/primitives", default-features = false } -runtime_io = { package = "sr-io", path = "../../core/sr-io", default-features = false } sr-primitives = { path = "../../core/sr-primitives", default-features = false } phragmen = { package = "substrate-phragmen", path = "../../core/phragmen", default-features = false } srml-support = { path = "../support", default-features = false } @@ -16,16 +13,16 @@ system = { package = "srml-system", path = "../system", default-features = false rstd = { package = "sr-std", path = "../../core/sr-std", default-features = false } [dev-dependencies] +runtime_io = { package = "sr-io", path = "../../core/sr-io" } hex-literal = "0.2.1" balances = { package = "srml-balances", path = "../balances" } +primitives = { package = "substrate-primitives", path = "../../core/primitives" } +serde = { version = "1.0.101" } [features] default = ["std"] std = [ "codec/std", - "primitives/std", - "serde", - "runtime_io/std", "srml-support/std", "sr-primitives/std", "phragmen/std", diff --git a/srml/elections-phragmen/src/lib.rs b/srml/elections-phragmen/src/lib.rs index f22c05ca45..9b277815f3 100644 --- a/srml/elections-phragmen/src/lib.rs +++ b/srml/elections-phragmen/src/lib.rs @@ -77,10 +77,12 @@ #![cfg_attr(not(feature = "std"), no_std)] use rstd::prelude::*; +use codec::Decode; use sr_primitives::{print, traits::{Zero, StaticLookup, Bounded, Convert}}; use sr_primitives::weights::SimpleDispatchInfo; use srml_support::{ decl_storage, decl_event, ensure, decl_module, dispatch, + storage::unhashed, traits::{ Currency, Get, LockableCurrency, LockIdentifier, ReservableCurrency, WithdrawReasons, ChangeMembers, OnUnbalanced, WithdrawReason @@ -159,6 +161,11 @@ decl_storage! { /// The present candidate list. Sorted based on account id. A current member can never enter /// this vector and is always implicitly assumed to be a candidate. pub Candidates get(fn candidates): Vec; + + /// Has the storage format been updated? + /// NOTE: Only use and set to false if you have used an early version of this module. Should + /// be set to true otherwise. + DidMigrate: bool; } } @@ -373,6 +380,10 @@ decl_module! { /// What to do at the end of each block. Checks if an election needs to happen or not. fn on_initialize(n: T::BlockNumber) { + if !DidMigrate::exists() { + DidMigrate::put(true); + Self::do_migrate(); + } if let Err(e) = Self::end_block(n) { print("Guru meditation"); print(e); @@ -626,6 +637,32 @@ impl Module { ElectionRounds::mutate(|v| *v += 1); } + + /// Perform the storage update needed to migrate the module from the initial version of the + /// storage. + /// + /// If decoding the old storage fails in any way, the consequence is that we start with an empty + /// set. + fn do_migrate() { + // old storage format. + let old_members: Vec = unhashed::get_raw(&>::hashed_key()) + .and_then(|bytes| Decode::decode(&mut &*bytes).ok()).unwrap_or_default(); + let old_runners: Vec = unhashed::get_raw(&>::hashed_key()) + .and_then(|bytes| Decode::decode(&mut &*bytes).ok()).unwrap_or_default(); + + // new storage format. + let new_runners: Vec<(T::AccountId, BalanceOf)> = old_runners + .into_iter() + .map(|r| (r, Zero::zero())) + .collect(); + let new_members: Vec<(T::AccountId, BalanceOf)> = old_members + .into_iter() + .map(|r| (r, Zero::zero())) + .collect(); + + >::put(new_members); + >::put(new_runners); + } } #[cfg(test)] @@ -636,7 +673,7 @@ mod tests { use primitives::H256; use sr_primitives::{ Perbill, testing::Header, BuildStorage, - traits::{BlakeTwo256, IdentityLookup, Block as BlockT}, + traits::{OnInitialize, BlakeTwo256, IdentityLookup, Block as BlockT}, }; use crate as elections; @@ -825,6 +862,30 @@ mod tests { lock.amount } + #[test] + fn temp_migration_works() { + ExtBuilder::default().build().execute_with(|| { + use srml_support::storage::unhashed; + use codec::Encode; + + let old_members = vec![1u64, 2]; + let old_runners = vec![3u64]; + + let members_key = >::hashed_key(); + let runners_key = >::hashed_key(); + + unhashed::put_raw(&members_key, &old_members.encode()[..]); + unhashed::put_raw(&runners_key, &old_runners.encode()[..]); + + assert_eq!(DidMigrate::get(), false); + >::on_initialize(1); + assert_eq!(DidMigrate::get(), true); + + assert_eq!(Elections::members(), vec![(1, 0), (2, 0)]); + assert_eq!(Elections::runners_up(), vec![(3, 0)]); + }); + } + #[test] fn params_should_work() { ExtBuilder::default().build().execute_with(|| { -- GitLab From 2b74b2d44a467ca4306c96b7eee7da7ad23580df Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Tue, 29 Oct 2019 17:03:17 +0100 Subject: [PATCH 129/167] More robust punishment (#3952) * Introduce new option "always force new era". * Take appropriate action, even for small offences. - Deselect the offender in all circumstances - Ensure that deselection forces a new era - Ensure that forcing a new era works with the always-forcing. * Bump runtime --- node/runtime/src/lib.rs | 2 +- srml/staking/src/lib.rs | 39 ++++++++++++++++++++++---- srml/staking/src/tests.rs | 58 +++++++++++++++++++++++++++++++++++++-- 3 files changed, 90 insertions(+), 9 deletions(-) diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index b5d0405ed0..558c6e3be7 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -81,7 +81,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // and set impl_version to equal spec_version. If only runtime // implementation changes and behavior does not, then leave spec_version as // is and increment impl_version. - spec_version: 189, + spec_version: 190, impl_version: 190, apis: RUNTIME_API_VERSIONS, }; diff --git a/srml/staking/src/lib.rs b/srml/staking/src/lib.rs index edbf7c245f..23f0d7715c 100644 --- a/srml/staking/src/lib.rs +++ b/srml/staking/src/lib.rs @@ -536,6 +536,8 @@ pub enum Forcing { ForceNew, /// Avoid a new era indefinitely. ForceNone, + /// Force a new era at the end of all sessions indefinitely. + ForceAlways, } impl Default for Forcing { @@ -956,7 +958,7 @@ decl_module! { } /// The ideal number of validators. - #[weight = SimpleDispatchInfo::FixedOperational(150_000)] + #[weight = SimpleDispatchInfo::FreeOperational] fn set_validator_count(origin, #[compact] new: u32) { ensure_root(origin)?; ValidatorCount::put(new); @@ -969,7 +971,7 @@ decl_module! { /// # /// - No arguments. /// # - #[weight = SimpleDispatchInfo::FixedOperational(10_000)] + #[weight = SimpleDispatchInfo::FreeOperational] fn force_no_eras(origin) { ensure_root(origin)?; ForceEra::put(Forcing::ForceNone); @@ -981,14 +983,14 @@ decl_module! { /// # /// - No arguments. /// # - #[weight = SimpleDispatchInfo::FixedOperational(10_000)] + #[weight = SimpleDispatchInfo::FreeOperational] fn force_new_era(origin) { ensure_root(origin)?; ForceEra::put(Forcing::ForceNew); } /// Set the validators who cannot be slashed (if any). - #[weight = SimpleDispatchInfo::FixedOperational(10_000)] + #[weight = SimpleDispatchInfo::FreeOperational] fn set_invulnerables(origin, validators: Vec) { ensure_root(origin)?; >::put(validators); @@ -1004,6 +1006,17 @@ decl_module! { // remove all staking-related information. Self::kill_stash(&stash); } + + /// Force there to be a new era at the end of sessions indefinitely. + /// + /// # + /// - One storage write + /// # + #[weight = SimpleDispatchInfo::FreeOperational] + fn force_new_era_always(origin) { + ensure_root(origin)?; + ForceEra::put(Forcing::ForceAlways); + } } } @@ -1155,6 +1168,7 @@ impl Module { let era_length = session_index.checked_sub(Self::current_era_start_session_index()).unwrap_or(0); match ForceEra::get() { Forcing::ForceNew => ForceEra::kill(), + Forcing::ForceAlways => (), Forcing::NotForcing if era_length >= T::SessionsPerEra::get() => (), _ => return None, } @@ -1406,6 +1420,14 @@ impl Module { } }); } + + /// Ensures that at the end of the current session there will be a new era. + fn ensure_new_era() { + match ForceEra::get() { + Forcing::ForceAlways | Forcing::ForceNew => (), + _ => ForceEra::put(Forcing::ForceNew), + } + } } impl session::OnSessionEnding for Module { @@ -1502,6 +1524,13 @@ impl OnOffenceHandler>::exists(stash) { + >::remove(stash); + Self::ensure_new_era(); + } + // calculate the amount to slash let slash_exposure = exposure.total; let amount = *slash_fraction * slash_exposure; @@ -1514,7 +1543,7 @@ impl OnOffenceHandler>::exists(11)); + Staking::on_offence( + &[OffenceDetails { + offender: ( + 11, + Staking::stakers(&11), + ), + reporters: vec![], + }], + &[Perbill::from_percent(0)], + ); + assert_eq!(Staking::force_era(), Forcing::ForceNew); + assert!(!>::exists(11)); + }); +} + #[test] fn slashing_performed_according_exposure() { // This test checks that slashing is performed according the exposure (or more precisely, @@ -1873,6 +1926,5 @@ fn dont_slash_if_fraction_is_zero() { // The validator hasn't been slashed. The new era is not forced. assert_eq!(Balances::free_balance(&11), 1000); - assert_eq!(Staking::force_era(), Forcing::NotForcing); }); } -- GitLab From 0ac702e6aa0211903eeac5a7807d1c593d99e5b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= Date: Tue, 29 Oct 2019 18:15:49 +0000 Subject: [PATCH 130/167] grandpa: fix handling of catch-up requests (#3956) * grandpa: fix handling of catch-up requests * grandpa: fix tests * grandpa: add test for catch-up handling when observer disabled * grandpa: extend doc comment * grandpa: rename existing catch up test --- .../src/communication/gossip.rs | 139 +++++++++++++++--- .../finality-grandpa/src/communication/mod.rs | 2 - .../src/communication/tests.rs | 3 +- core/finality-grandpa/src/lib.rs | 8 +- core/finality-grandpa/src/observer.rs | 1 - core/finality-grandpa/src/tests.rs | 18 ++- node-template/src/service.rs | 2 + node/cli/src/service.rs | 2 + 8 files changed, 147 insertions(+), 28 deletions(-) diff --git a/core/finality-grandpa/src/communication/gossip.rs b/core/finality-grandpa/src/communication/gossip.rs index 24402c8a02..efcd1d48c6 100644 --- a/core/finality-grandpa/src/communication/gossip.rs +++ b/core/finality-grandpa/src/communication/gossip.rs @@ -512,6 +512,40 @@ enum PendingCatchUp { }, } +/// Configuration for the round catch-up mechanism. +enum CatchUpConfig { + /// Catch requests are enabled, our node will issue them whenever it sees a + /// neighbor packet for a round further than `CATCH_UP_THRESHOLD`. If + /// `only_from_authorities` is set, the node will only send catch-up + /// requests to other authorities it is connected to. This is useful if the + /// GRANDPA observer protocol is live on the network, in which case full + /// nodes (non-authorities) don't have the necessary round data to answer + /// catch-up requests. + Enabled { only_from_authorities: bool }, + /// Catch-up requests are disabled, our node will never issue them. This is + /// useful for the GRANDPA observer mode, where we are only interested in + /// commit messages and don't need to follow the full round protocol. + Disabled, +} + +impl CatchUpConfig { + fn enabled(only_from_authorities: bool) -> CatchUpConfig { + CatchUpConfig::Enabled { only_from_authorities } + } + + fn disabled() -> CatchUpConfig { + CatchUpConfig::Disabled + } + + fn request_allowed(&self, peer: &PeerInfo) -> bool { + match self { + CatchUpConfig::Disabled => false, + CatchUpConfig::Enabled { only_from_authorities, .. } => + !only_from_authorities || peer.roles.is_authority(), + } + } +} + struct Inner { local_view: Option>>, peers: Peers>, @@ -520,13 +554,30 @@ struct Inner { config: crate::Config, next_rebroadcast: Instant, pending_catch_up: PendingCatchUp, - catch_up_enabled: bool, + catch_up_config: CatchUpConfig, } type MaybeMessage = Option<(Vec, NeighborPacket>)>; impl Inner { - fn new(config: crate::Config, catch_up_enabled: bool) -> Self { + fn new(config: crate::Config) -> Self { + let catch_up_config = if config.observer_enabled { + if config.is_authority { + // since the observer protocol is enabled, we will only issue + // catch-up requests if we are an authority (and only to other + // authorities). + CatchUpConfig::enabled(true) + } else { + // otherwise, we are running the observer protocol and don't + // care about catch-up requests. + CatchUpConfig::disabled() + } + } else { + // if the observer protocol isn't enabled, then any full node should + // be able to answer catch-up requests. + CatchUpConfig::enabled(false) + }; + Inner { local_view: None, peers: Peers::default(), @@ -534,7 +585,7 @@ impl Inner { next_rebroadcast: Instant::now() + REBROADCAST_AFTER, authorities: Vec::new(), pending_catch_up: PendingCatchUp::None, - catch_up_enabled, + catch_up_config, config, } } @@ -823,10 +874,6 @@ impl Inner { } fn try_catch_up(&mut self, who: &PeerId) -> (Option>, Option) { - if !self.catch_up_enabled { - return (None, None); - } - let mut catch_up = None; let mut report = None; @@ -836,7 +883,7 @@ impl Inner { // won't be able to reply since they don't follow the full GRANDPA // protocol and therefore might not have the vote data available. if let (Some(peer), Some(local_view)) = (self.peers.peer(who), &self.local_view) { - if peer.roles.is_authority() && + if self.catch_up_config.request_allowed(&peer) && peer.view.set_id == local_view.set_id && peer.view.round.0.saturating_sub(CATCH_UP_THRESHOLD) > local_view.round.0 { @@ -949,11 +996,10 @@ impl GossipValidator { pub(super) fn new( config: crate::Config, set_state: environment::SharedVoterSetState, - catch_up_enabled: bool, ) -> (GossipValidator, ReportStream) { let (tx, rx) = mpsc::unbounded(); let val = GossipValidator { - inner: parking_lot::RwLock::new(Inner::new(config, catch_up_enabled)), + inner: parking_lot::RwLock::new(Inner::new(config)), set_state, report_sender: tx, }; @@ -1274,6 +1320,8 @@ mod tests { justification_period: 256, keystore: None, name: None, + is_authority: true, + observer_enabled: true, } } @@ -1438,7 +1486,6 @@ mod tests { let (val, _) = GossipValidator::::new( config(), voter_set_state(), - true, ); let set_id = 1; @@ -1474,7 +1521,6 @@ mod tests { let (val, _) = GossipValidator::::new( config(), voter_set_state(), - true, ); let set_id = 1; let auth = AuthorityId::from_slice(&[1u8; 32]); @@ -1519,7 +1565,6 @@ mod tests { let (val, _) = GossipValidator::::new( config(), voter_set_state(), - true, ); let set_id = 1; @@ -1588,7 +1633,6 @@ mod tests { let (val, _) = GossipValidator::::new( config(), set_state.clone(), - true, ); let set_id = 1; @@ -1643,7 +1687,6 @@ mod tests { let (val, _) = GossipValidator::::new( config(), set_state.clone(), - true, ); // the validator starts at set id 2 @@ -1723,7 +1766,6 @@ mod tests { let (val, _) = GossipValidator::::new( config(), voter_set_state(), - true, ); // the validator starts at set id 1. @@ -1783,10 +1825,20 @@ mod tests { #[test] fn doesnt_send_catch_up_requests_when_disabled() { // we create a gossip validator with catch up requests disabled. + let config = { + let mut c = config(); + + // if the observer protocol is enabled and we are not an authority, + // then we don't issue any catch-up requests. + c.is_authority = false; + c.observer_enabled = true; + + c + }; + let (val, _) = GossipValidator::::new( - config(), + config, voter_set_state(), - false, ); // the validator starts at set id 1. @@ -1816,11 +1868,10 @@ mod tests { } #[test] - fn doesnt_send_catch_up_requests_to_non_authorities() { + fn doesnt_send_catch_up_requests_to_non_authorities_when_observer_enabled() { let (val, _) = GossipValidator::::new( config(), voter_set_state(), - true, ); // the validator starts at set id 1. @@ -1865,13 +1916,59 @@ mod tests { } } + #[test] + fn sends_catch_up_requests_to_non_authorities_when_observer_disabled() { + let config = { + let mut c = config(); + + // if the observer protocol is disable any full-node should be able + // to answer catch-up requests. + c.observer_enabled = false; + + c + }; + + let (val, _) = GossipValidator::::new( + config, + voter_set_state(), + ); + + // the validator starts at set id 1. + val.note_set(SetId(1), Vec::new(), |_, _| {}); + + // add the peer making the requests to the validator, otherwise it is + // discarded. + let peer_full = PeerId::random(); + val.inner.write().peers.new_peer(peer_full.clone(), Roles::FULL); + + let (_, _, catch_up_request, _) = val.inner.write().import_neighbor_message( + &peer_full, + NeighborPacket { + round: Round(42), + set_id: SetId(1), + commit_finalized_height: 50, + }, + ); + + // importing a neighbor message from a peer in the same set in a later + // round should lead to a catch up request, the node is not an + // authority, but since the observer protocol is disabled we should + // issue a catch-up request to it anyway. + match catch_up_request { + Some(GossipMessage::CatchUpRequest(request)) => { + assert_eq!(request.set_id, SetId(1)); + assert_eq!(request.round, Round(41)); + }, + _ => panic!("expected catch up message"), + } + } + #[test] fn doesnt_expire_next_round_messages() { // NOTE: this is a regression test let (val, _) = GossipValidator::::new( config(), voter_set_state(), - true, ); // the validator starts at set id 1. diff --git a/core/finality-grandpa/src/communication/mod.rs b/core/finality-grandpa/src/communication/mod.rs index 9a6a40fb8d..4cc772fe9d 100644 --- a/core/finality-grandpa/src/communication/mod.rs +++ b/core/finality-grandpa/src/communication/mod.rs @@ -289,7 +289,6 @@ impl> NetworkBridge { config: crate::Config, set_state: crate::environment::SharedVoterSetState, on_exit: impl Future + Clone + Send + 'static, - catch_up_enabled: bool, ) -> ( Self, impl Future + Send + 'static, @@ -298,7 +297,6 @@ impl> NetworkBridge { let (validator, report_stream) = GossipValidator::new( config, set_state.clone(), - catch_up_enabled, ); let validator = Arc::new(validator); diff --git a/core/finality-grandpa/src/communication/tests.rs b/core/finality-grandpa/src/communication/tests.rs index 7b91b2ef0a..f918f47258 100644 --- a/core/finality-grandpa/src/communication/tests.rs +++ b/core/finality-grandpa/src/communication/tests.rs @@ -139,6 +139,8 @@ fn config() -> crate::Config { justification_period: 256, keystore: None, name: None, + is_authority: true, + observer_enabled: true, } } @@ -186,7 +188,6 @@ fn make_test_network() -> ( config(), voter_set_state(), Exit, - true, ); ( diff --git a/core/finality-grandpa/src/lib.rs b/core/finality-grandpa/src/lib.rs index 68019dc8eb..0decea5811 100644 --- a/core/finality-grandpa/src/lib.rs +++ b/core/finality-grandpa/src/lib.rs @@ -201,6 +201,13 @@ pub struct Config { /// at least every justification_period blocks. There are some other events which might cause /// justification generation. pub justification_period: u32, + /// Whether the GRANDPA observer protocol is live on the network and thereby + /// a full-node not running as a validator is running the GRANDPA observer + /// protocol (we will only issue catch-up requests to authorities when the + /// observer protocol is enabled). + pub observer_enabled: bool, + /// Whether the node is running as an authority (i.e. running the full GRANDPA protocol). + pub is_authority: bool, /// Some local identifier of the voter. pub name: Option, /// The keystore that manages the keys of this node. @@ -548,7 +555,6 @@ pub fn run_grandpa_voter, N, RA, SC, VR, X>( config.clone(), persistent_data.set_state.clone(), on_exit.clone(), - true, ); register_finality_tracker_inherent_data_provider(client.clone(), &inherent_data_providers)?; diff --git a/core/finality-grandpa/src/observer.rs b/core/finality-grandpa/src/observer.rs index 39eeafcb1b..e4d90ddc22 100644 --- a/core/finality-grandpa/src/observer.rs +++ b/core/finality-grandpa/src/observer.rs @@ -176,7 +176,6 @@ pub fn run_grandpa_observer, N, RA, SC>( config.clone(), persistent_data.set_state.clone(), on_exit.clone(), - false, ); let observer_work = ObserverWork::new( diff --git a/core/finality-grandpa/src/tests.rs b/core/finality-grandpa/src/tests.rs index 2767c14b27..3917374171 100644 --- a/core/finality-grandpa/src/tests.rs +++ b/core/finality-grandpa/src/tests.rs @@ -379,6 +379,8 @@ fn run_to_completion_with( justification_period: 32, keystore: Some(keystore), name: Some(format!("peer#{}", peer_id)), + is_authority: true, + observer_enabled: true, }, link: link, network: net_service, @@ -511,6 +513,8 @@ fn finalize_3_voters_1_full_observer() { justification_period: 32, keystore, name: Some(format!("peer#{}", peer_id)), + is_authority: true, + observer_enabled: true, }, link: link, network: net_service, @@ -672,6 +676,8 @@ fn transition_3_voters_twice_1_full_observer() { justification_period: 32, keystore: Some(keystore), name: Some(format!("peer#{}", peer_id)), + is_authority: true, + observer_enabled: true, }, link: link, network: net_service, @@ -1095,6 +1101,8 @@ fn voter_persists_its_votes() { justification_period: 32, keystore: Some(self.keystore.clone()), name: Some(format!("peer#{}", 0)), + is_authority: true, + observer_enabled: true, }, link, network: self.net.lock().peers[0].network_service().clone(), @@ -1150,6 +1158,8 @@ fn voter_persists_its_votes() { justification_period: 32, keystore: Some(keystore), name: Some(format!("peer#{}", 1)), + is_authority: true, + observer_enabled: true, }; let set_state = { @@ -1164,7 +1174,6 @@ fn voter_persists_its_votes() { config.clone(), set_state, Exit, - true, ); runtime.block_on(routing_work).unwrap(); @@ -1299,6 +1308,8 @@ fn finalize_3_voters_1_light_observer() { justification_period: 32, keystore: None, name: Some("observer".to_string()), + is_authority: false, + observer_enabled: true, }, link, net.lock().peers[3].network_service().clone(), @@ -1426,6 +1437,8 @@ fn voter_catches_up_to_latest_round_when_behind() { justification_period: 32, keystore, name: Some(format!("peer#{}", peer_id)), + is_authority: true, + observer_enabled: true, }, link, network: net.lock().peer(peer_id).network_service().clone(), @@ -1542,6 +1555,8 @@ fn grandpa_environment_respects_voting_rules() { justification_period: 32, keystore: None, name: None, + is_authority: true, + observer_enabled: true, }; let (network, _) = NetworkBridge::new( @@ -1549,7 +1564,6 @@ fn grandpa_environment_respects_voting_rules() { config.clone(), set_state.clone(), Exit, - true, ); Environment { diff --git a/node-template/src/service.rs b/node-template/src/service.rs index 8972cffa96..c03c254da4 100644 --- a/node-template/src/service.rs +++ b/node-template/src/service.rs @@ -125,6 +125,8 @@ pub fn new_full(config: Configuration Date: Tue, 29 Oct 2019 18:58:34 +0000 Subject: [PATCH 131/167] node: add sentry mode flag (#3959) * node: add sentry mode flag * cli: extend docs on validator and sentry modes * service: add missing field in test Configuration * node: Display instead of Debug when printing node role --- core/cli/src/lib.rs | 17 ++++++++++++++++- core/cli/src/params.rs | 24 +++++++++++++++++++++++- core/service/src/config.rs | 5 +++++ core/service/test/src/lib.rs | 1 + node-template/src/cli.rs | 4 ++-- node-template/src/service.rs | 17 +++++++++++++++-- node/cli/src/lib.rs | 4 ++-- node/cli/src/service.rs | 17 +++++++++++++++-- 8 files changed, 79 insertions(+), 10 deletions(-) diff --git a/core/cli/src/lib.rs b/core/cli/src/lib.rs index b49f686ae6..a22797861b 100644 --- a/core/cli/src/lib.rs +++ b/core/cli/src/lib.rs @@ -236,6 +236,17 @@ where } } +/// Returns a string displaying the node role, special casing the sentry mode +/// (returning `SENTRY`), since the node technically has an `AUTHORITY` role but +/// doesn't participate. +pub fn display_role(config: &Configuration<(), A, B>) -> String { + if config.sentry_mode { + "SENTRY".to_string() + } else { + format!("{:?}", config.roles) + } +} + /// Output of calling `parse_and_prepare`. #[must_use] pub enum ParseAndPrepare<'a, CC, RP> { @@ -658,16 +669,20 @@ where config.state_cache_size = cli.state_cache_size; let is_dev = cli.shared_params.dev; + let is_authority = cli.validator || cli.sentry || is_dev || cli.keyring.account.is_some(); let role = if cli.light { service::Roles::LIGHT - } else if cli.validator || is_dev || cli.keyring.account.is_some() { + } else if is_authority { service::Roles::AUTHORITY } else { service::Roles::FULL }; + // set sentry mode (i.e. act as an authority but **never** actively participate) + config.sentry_mode = cli.sentry; + // by default we disable pruning if the node is an authority (i.e. // `ArchiveAll`), otherwise we keep state for the last 256 blocks. if the // node is an authority and pruning is enabled explicitly, then we error diff --git a/core/cli/src/params.rs b/core/cli/src/params.rs index 4480736066..007bdabf0b 100644 --- a/core/cli/src/params.rs +++ b/core/cli/src/params.rs @@ -301,9 +301,31 @@ pub struct ExecutionStrategies { #[derive(Debug, StructOpt, Clone)] pub struct RunCmd { /// Enable validator mode. - #[structopt(long = "validator")] + /// + /// The node will be started with the authority role and actively + /// participate in any consensus task that it can (e.g. depending on + /// availability of local keys). + #[structopt( + long = "validator", + conflicts_with_all = &[ "sentry" ] + )] pub validator: bool, + /// Enable sentry mode. + /// + /// The node will be started with the authority role and participate in + /// consensus tasks as an "observer", it will never actively participate + /// regardless of whether it could (e.g. keys are available locally). This + /// mode is useful as a secure proxy for validators (which would run + /// detached from the network), since we want this node to participate in + /// the full consensus protocols in order to have all needed consensus data + /// available to relay to private nodes. + #[structopt( + long = "sentry", + conflicts_with_all = &[ "validator" ] + )] + pub sentry: bool, + /// Disable GRANDPA voter when running in validator mode, otherwise disables the GRANDPA observer. #[structopt(long = "no-grandpa")] pub no_grandpa: bool, diff --git a/core/service/src/config.rs b/core/service/src/config.rs index a1ba83753f..8abef5c572 100644 --- a/core/service/src/config.rs +++ b/core/service/src/config.rs @@ -82,6 +82,10 @@ pub struct Configuration { pub default_heap_pages: Option, /// Should offchain workers be executed. pub offchain_worker: bool, + /// Sentry mode is enabled, the node's role is AUTHORITY but it should not + /// actively participate in consensus (i.e. no keystores should be passed to + /// consensus modules). + pub sentry_mode: bool, /// Enable authoring even when offline. pub force_authoring: bool, /// Disable GRANDPA when running in validator mode @@ -129,6 +133,7 @@ impl Configuration where telemetry_external_transport: None, default_heap_pages: None, offchain_worker: Default::default(), + sentry_mode: false, force_authoring: false, disable_grandpa: false, keystore_password: None, diff --git a/core/service/test/src/lib.rs b/core/service/test/src/lib.rs index 806996576f..28ed5bfdbc 100644 --- a/core/service/test/src/lib.rs +++ b/core/service/test/src/lib.rs @@ -188,6 +188,7 @@ fn node_config ( telemetry_external_transport: None, default_heap_pages: None, offchain_worker: false, + sentry_mode: false, force_authoring: false, disable_grandpa: false, dev_key_seed: key_seed, diff --git a/node-template/src/cli.rs b/node-template/src/cli.rs index 15c1a0486f..ceb51504e2 100644 --- a/node-template/src/cli.rs +++ b/node-template/src/cli.rs @@ -3,7 +3,7 @@ use futures::{future, Future, sync::oneshot}; use std::cell::RefCell; use tokio::runtime::Runtime; pub use substrate_cli::{VersionInfo, IntoExit, error}; -use substrate_cli::{informant, parse_and_prepare, ParseAndPrepare, NoCustom}; +use substrate_cli::{display_role, informant, parse_and_prepare, ParseAndPrepare, NoCustom}; use substrate_service::{AbstractService, Roles as ServiceRoles, Configuration}; use aura_primitives::sr25519::{AuthorityPair as AuraPair}; use crate::chain_spec; @@ -24,7 +24,7 @@ pub fn run(args: I, exit: E, version: VersionInfo) -> error::Result<()> info!(" by {}, 2017, 2018", version.author); info!("Chain specification: {}", config.chain_spec.name()); info!("Node name: {}", config.name); - info!("Roles: {:?}", config.roles); + info!("Roles: {}", display_role(&config)); let runtime = Runtime::new().map_err(|e| format!("{:?}", e))?; match config.roles { ServiceRoles::LIGHT => run_until_exit( diff --git a/node-template/src/service.rs b/node-template/src/service.rs index c03c254da4..398795325f 100644 --- a/node-template/src/service.rs +++ b/node-template/src/service.rs @@ -80,6 +80,11 @@ pub fn new_full(config: Configuration(config: Configuration(config: Configuration(args: I, exit: E, version: cli::VersionInfo) -> error::Resul info!(" by Parity Technologies, 2017-2019"); info!("Chain specification: {}", config.chain_spec.name()); info!("Node name: {}", config.name); - info!("Roles: {:?}", config.roles); + info!("Roles: {}", display_role(&config)); let runtime = RuntimeBuilder::new().name_prefix("main-tokio-").build() .map_err(|e| format!("{:?}", e))?; match config.roles { diff --git a/node/cli/src/service.rs b/node/cli/src/service.rs index 842acd41ed..47e36bd926 100644 --- a/node/cli/src/service.rs +++ b/node/cli/src/service.rs @@ -124,6 +124,11 @@ macro_rules! new_full { $config.disable_grandpa ); + // sentry nodes announce themselves as authorities to the network + // and should run the same protocols authorities do, but it should + // never actively participate in any consensus process. + let participates_in_consensus = is_authority && !$config.sentry_mode; + let (builder, mut import_setup, inherent_data_providers) = new_full_start!($config); // Dht event channel from the network to the authority discovery module. Use bounded channel to ensure @@ -145,7 +150,7 @@ macro_rules! new_full { ($with_startup_data)(&block_import, &babe_link); - if is_authority { + if participates_in_consensus { let proposer = substrate_basic_authorship::ProposerFactory { client: service.client(), transaction_pool: service.transaction_pool(), @@ -171,13 +176,21 @@ macro_rules! new_full { service.spawn_essential_task(babe); } + // if the node isn't actively participating in consensus then it doesn't + // need a keystore, regardless of which protocol we use below. + let keystore = if participates_in_consensus { + Some(service.keystore()) + } else { + None + }; + let config = grandpa::Config { // FIXME #1578 make this available through chainspec gossip_duration: std::time::Duration::from_millis(333), justification_period: 512, name: Some(name), - keystore: Some(service.keystore()), observer_enabled: true, + keystore, is_authority, }; -- GitLab From 9d41555a12251b4fde23293cf076fedf2470db48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 29 Oct 2019 20:22:20 +0100 Subject: [PATCH 132/167] Upgrade `impl-serde` to `0.2.3` (#3960) --- Cargo.lock | 12 ++++++------ core/primitives/Cargo.toml | 2 +- core/primitives/storage/Cargo.toml | 2 +- core/sr-version/Cargo.toml | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6ee62fe8b0..861222cc98 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1430,7 +1430,7 @@ dependencies = [ [[package]] name = "impl-serde" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3045,7 +3045,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "fixed-hash 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "impl-codec 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "impl-serde 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "impl-serde 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "uint 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3977,7 +3977,7 @@ dependencies = [ name = "sr-version" version = "2.0.0" dependencies = [ - "impl-serde 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "impl-serde 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", @@ -5460,7 +5460,7 @@ dependencies = [ "hash256-std-hasher 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "hex-literal 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "impl-serde 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "impl-serde 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libsecp256k1 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -5492,7 +5492,7 @@ dependencies = [ name = "substrate-primitives-storage" version = "2.0.0" dependencies = [ - "impl-serde 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "impl-serde 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "sr-std 2.0.0", "substrate-debug-derive 2.0.0", @@ -7019,7 +7019,7 @@ dependencies = [ "checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" "checksum idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9" "checksum impl-codec 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3fa0086251524c50fd53b32e7b05eb6d79e2f97221eaf0c53c0ca9c3096f21d3" -"checksum impl-serde 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a263dc95daa6c3788c8f7133d86dc2ad89ec5a0c56167f9e3441c5f7f33358c4" +"checksum impl-serde 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "58e3cae7e99c7ff5a995da2cf78dd0a5383740eda71d98cf7b1910c301ac69b8" "checksum impl-trait-for-tuples 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7ef5550a42e3740a0e71f909d4c861056a284060af885ae7aa6242820f920d9d" "checksum indexmap 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a61202fbe46c4a951e9404a720a0180bcf3212c750d735cb5c4ba4dc551299f3" "checksum integer-sqrt 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ea155abb3ba6f382a75f1418988c05fe82959ed9ce727de427f9cfd425b0c903" diff --git a/core/primitives/Cargo.toml b/core/primitives/Cargo.toml index 9d76b4f7af..30c1aab29f 100644 --- a/core/primitives/Cargo.toml +++ b/core/primitives/Cargo.toml @@ -13,7 +13,7 @@ serde = { version = "1.0.101", optional = true, features = ["derive"] } twox-hash = { version = "1.5.0", optional = true } byteorder = { version = "1.3.2", default-features = false } primitive-types = { version = "0.5.1", default-features = false, features = ["codec"] } -impl-serde = { version = "0.2.1", optional = true } +impl-serde = { version = "0.2.3", optional = true } wasmi = { version = "0.5.1", optional = true } hash-db = { version = "0.15.2", default-features = false } hash256-std-hasher = { version = "0.15.2", default-features = false } diff --git a/core/primitives/storage/Cargo.toml b/core/primitives/storage/Cargo.toml index 7bb2b95623..1e5d7ee8b4 100644 --- a/core/primitives/storage/Cargo.toml +++ b/core/primitives/storage/Cargo.toml @@ -8,7 +8,7 @@ description = "Storage related primitives" [dependencies] rstd = { package = "sr-std", path = "../../sr-std", default-features = false } serde = { version = "1.0.101", optional = true, features = ["derive"] } -impl-serde = { version = "0.2.1", optional = true } +impl-serde = { version = "0.2.3", optional = true } substrate-debug-derive = { version = "2.0.0", path = "../debug-derive" } [features] diff --git a/core/sr-version/Cargo.toml b/core/sr-version/Cargo.toml index fcae97b4d2..5be3048f82 100644 --- a/core/sr-version/Cargo.toml +++ b/core/sr-version/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] edition = "2018" [dependencies] -impl-serde = { version = "0.2.1", optional = true } +impl-serde = { version = "0.2.3", optional = true } serde = { version = "1.0.101", optional = true, features = ["derive"] } codec = { package = "parity-scale-codec", version = "1.0.5", default-features = false, features = ["derive"] } rstd = { package = "sr-std", path = "../sr-std", default-features = false } -- GitLab From e98b829287313502fce0cde6c1d09439b0f2a9f7 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Tue, 29 Oct 2019 20:41:43 +0100 Subject: [PATCH 133/167] test-utils/chain-spec-builder: Add note to run builder in release mode (#3958) --- test-utils/chain-spec-builder/Cargo.toml | 1 + test-utils/chain-spec-builder/build.rs | 23 +++++++++++++++++++++++ test-utils/chain-spec-builder/src/main.rs | 7 +++++++ 3 files changed, 31 insertions(+) create mode 100644 test-utils/chain-spec-builder/build.rs diff --git a/test-utils/chain-spec-builder/Cargo.toml b/test-utils/chain-spec-builder/Cargo.toml index 324d33cbf0..e8ca8d3540 100644 --- a/test-utils/chain-spec-builder/Cargo.toml +++ b/test-utils/chain-spec-builder/Cargo.toml @@ -3,6 +3,7 @@ name = "chain-spec-builder" version = "2.0.0" authors = ["Parity Technologies "] edition = "2018" +build = "build.rs" [dependencies] ansi_term = "0.12.1" diff --git a/test-utils/chain-spec-builder/build.rs b/test-utils/chain-spec-builder/build.rs new file mode 100644 index 0000000000..36730271c7 --- /dev/null +++ b/test-utils/chain-spec-builder/build.rs @@ -0,0 +1,23 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +use std::env; + +fn main() { + if let Ok(profile) = env::var("PROFILE") { + println!("cargo:rustc-cfg=build_type=\"{}\"", profile); + } +} diff --git a/test-utils/chain-spec-builder/src/main.rs b/test-utils/chain-spec-builder/src/main.rs index 8fdd282345..d46f4b7f0b 100644 --- a/test-utils/chain-spec-builder/src/main.rs +++ b/test-utils/chain-spec-builder/src/main.rs @@ -207,6 +207,13 @@ fn print_seeds( } fn main() -> Result<(), String> { + #[cfg(build_type="debug")] + println!( + "The chain spec builder builds a chain specification that includes a Substrate runtime compiled as WASM. To \ + ensure proper functioning of the included runtime compile (or run) the chain spec builder binary in \ + `--release` mode.\n", + ); + let builder = ChainSpecBuilder::from_args(); let chain_spec_path = builder.chain_spec_path().to_path_buf(); -- GitLab From c744aa5ae3c1962d8b9c5484b420b8ea83a02988 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= Date: Tue, 29 Oct 2019 20:07:11 +0000 Subject: [PATCH 134/167] cli: fix display_role helper (#3961) --- core/cli/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/cli/src/lib.rs b/core/cli/src/lib.rs index a22797861b..adf0a57aaf 100644 --- a/core/cli/src/lib.rs +++ b/core/cli/src/lib.rs @@ -239,7 +239,7 @@ where /// Returns a string displaying the node role, special casing the sentry mode /// (returning `SENTRY`), since the node technically has an `AUTHORITY` role but /// doesn't participate. -pub fn display_role(config: &Configuration<(), A, B>) -> String { +pub fn display_role(config: &Configuration) -> String { if config.sentry_mode { "SENTRY".to_string() } else { -- GitLab From 93123cc63eac37fed7a6cc6cc58e7e43d666ee03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 29 Oct 2019 21:20:09 +0100 Subject: [PATCH 135/167] Provide simple `TestSessionHandler` that works with `UintAuthorityId` (#3962) --- core/primitives/src/crypto.rs | 1 - srml/session/src/lib.rs | 16 +++++++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/core/primitives/src/crypto.rs b/core/primitives/src/crypto.rs index 6e46793432..93f499b230 100644 --- a/core/primitives/src/crypto.rs +++ b/core/primitives/src/crypto.rs @@ -898,7 +898,6 @@ pub mod key_types { /// Key type for ImOnline module, built-in. pub const IM_ONLINE: KeyTypeId = KeyTypeId(*b"imon"); /// A key type ID useful for tests. - #[cfg(feature = "std")] pub const DUMMY: KeyTypeId = KeyTypeId(*b"dumy"); } diff --git a/srml/session/src/lib.rs b/srml/session/src/lib.rs index 7f66673483..42324d387f 100644 --- a/srml/session/src/lib.rs +++ b/srml/session/src/lib.rs @@ -259,7 +259,7 @@ pub trait OneSessionHandler: BoundToRuntimeAppPublic { fn on_disabled(_validator_index: usize); } -#[impl_trait_for_tuples::impl_for_tuples(30)] +#[impl_trait_for_tuples::impl_for_tuples(1, 30)] #[tuple_types_no_default_trait_bound] impl SessionHandler for Tuple { for_tuples!( where #( Tuple: OneSessionHandler )* ); @@ -307,6 +307,20 @@ impl SessionHandler for Tuple { } } +/// `SessionHandler` for tests that use `UintAuthorityId` as `Keys`. +pub struct TestSessionHandler; +impl SessionHandler for TestSessionHandler { + const KEY_TYPE_IDS: &'static [KeyTypeId] = &[sr_primitives::key_types::DUMMY]; + + fn on_genesis_session(_: &[(AId, Ks)]) {} + + fn on_new_session(_: bool, _: &[(AId, Ks)], _: &[(AId, Ks)]) {} + + fn on_before_session_ending() {} + + fn on_disabled(_: usize) {} +} + /// Handler for selecting the genesis validator set. pub trait SelectInitialValidators { /// Returns the initial validator set. If `None` is returned -- GitLab From 4d466a089e2e323f1bc1f46bd031be50a43e8f47 Mon Sep 17 00:00:00 2001 From: Ashley Date: Tue, 29 Oct 2019 23:26:44 +0000 Subject: [PATCH 136/167] Remove deprecated Client::backend (#3951) --- core/client/src/client.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/core/client/src/client.rs b/core/client/src/client.rs index d853d851c5..25c2fab48d 100644 --- a/core/client/src/client.rs +++ b/core/client/src/client.rs @@ -342,15 +342,6 @@ impl Client where self.backend.state_at(*block) } - /// Expose backend reference. To be used in tests only - #[doc(hidden)] - #[deprecated(note="Rather than relying on `client` to provide this, access \ - to the backend should be handled at setup only - see #1134. This function \ - will be removed once that is in place.")] - pub fn backend(&self) -> &Arc { - &self.backend - } - /// Given a `BlockId` and a key prefix, return the matching child storage keys in that block. pub fn storage_keys(&self, id: &BlockId, key_prefix: &StorageKey) -> error::Result> { let keys = self.state_at(id)?.keys(&key_prefix.0).into_iter().map(StorageKey).collect(); -- GitLab From 958c2882464482a018d802fe282681cffd5d456a Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Wed, 30 Oct 2019 12:08:46 +0100 Subject: [PATCH 137/167] Make substrate-offchain compile for WASM again (#3965) * Make substrate-offchain compile for WASM again * Minor adjustments --- .gitlab-ci.yml | 1 + core/offchain/Cargo.toml | 6 +- core/offchain/src/api.rs | 7 ++ core/offchain/src/api/http_dummy.rs | 109 ++++++++++++++++++++++++++++ 4 files changed, 121 insertions(+), 2 deletions(-) create mode 100644 core/offchain/src/api/http_dummy.rs diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 769ee60d1e..7f941c6172 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -204,6 +204,7 @@ check-web-wasm: - time cargo web build -p substrate-keystore - time cargo web build -p substrate-executor - time cargo web build -p substrate-network + - time cargo web build -p substrate-offchain - time cargo web build -p substrate-panic-handler - time cargo web build -p substrate-peerset - time cargo web build -p substrate-primitives diff --git a/core/offchain/Cargo.toml b/core/offchain/Cargo.toml index 678d943c59..b52118aae7 100644 --- a/core/offchain/Cargo.toml +++ b/core/offchain/Cargo.toml @@ -13,8 +13,6 @@ fnv = "1.0.6" futures01 = { package = "futures", version = "0.1" } futures-preview = "0.3.0-alpha.19" futures-timer = "0.4.0" -hyper = "0.12.35" -hyper-tls = "0.3.2" log = "0.4.8" threadpool = "1.7" num_cpus = "1.10" @@ -28,6 +26,10 @@ transaction_pool = { package = "substrate-transaction-pool", path = "../../core/ network = { package = "substrate-network", path = "../../core/network" } keystore = { package = "substrate-keystore", path = "../keystore" } +[target.'cfg(not(target_os = "unknown"))'.dependencies] +hyper = "0.12.35" +hyper-tls = "0.3.2" + [dev-dependencies] env_logger = "0.7.0" client-db = { package = "substrate-client-db", path = "../../core/client/db/", default-features = true } diff --git a/core/offchain/src/api.rs b/core/offchain/src/api.rs index d4301d22ed..35b6e20df2 100644 --- a/core/offchain/src/api.rs +++ b/core/offchain/src/api.rs @@ -33,7 +33,14 @@ use primitives::offchain::{ use sr_primitives::{generic::BlockId, traits::{self, Extrinsic}}; use transaction_pool::txpool::{Pool, ChainApi}; +#[cfg(not(target_os = "unknown"))] mod http; + +#[cfg(target_os = "unknown")] +use http_dummy as http; +#[cfg(target_os = "unknown")] +mod http_dummy; + mod timestamp; /// A message between the offchain extension and the processing thread. diff --git a/core/offchain/src/api/http_dummy.rs b/core/offchain/src/api/http_dummy.rs new file mode 100644 index 0000000000..e3cb272a0d --- /dev/null +++ b/core/offchain/src/api/http_dummy.rs @@ -0,0 +1,109 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +//! Contains the same API as the `http` module, except that everything returns an error. + +use primitives::offchain::{HttpRequestId, Timestamp, HttpRequestStatus, HttpError}; +use std::{future::Future, pin::Pin, task::Context, task::Poll}; + +/// Creates a pair of [`HttpApi`] and [`HttpWorker`]. +pub fn http() -> (HttpApi, HttpWorker) { + (HttpApi, HttpWorker) +} + +/// Dummy implementation of HTTP capabilities. +#[derive(Debug)] +pub struct HttpApi; + +/// Dummy implementation of HTTP capabilities. +#[derive(Debug)] +pub struct HttpWorker; + +impl HttpApi { + /// Mimicks the corresponding method in the offchain API. + pub fn request_start( + &mut self, + _: &str, + _: &str + ) -> Result { + /// Because this always returns an error, none of the other methods should ever be called. + Err(()) + } + + /// Mimicks the corresponding method in the offchain API. + pub fn request_add_header( + &mut self, + _: HttpRequestId, + _: &str, + _: &str + ) -> Result<(), ()> { + unreachable!("Creating a request always fails, thus this function will \ + never be called; qed") + } + + /// Mimicks the corresponding method in the offchain API. + pub fn request_write_body( + &mut self, + _: HttpRequestId, + _: &[u8], + _: Option + ) -> Result<(), HttpError> { + unreachable!("Creating a request always fails, thus this function will \ + never be called; qed") + } + + /// Mimicks the corresponding method in the offchain API. + pub fn response_wait( + &mut self, + requests: &[HttpRequestId], + _: Option + ) -> Vec { + if requests.is_empty() { + Vec::new() + } else { + unreachable!("Creating a request always fails, thus the list of requests should \ + always be empty; qed") + } + } + + /// Mimicks the corresponding method in the offchain API. + pub fn response_headers( + &mut self, + _: HttpRequestId + ) -> Vec<(Vec, Vec)> { + unreachable!("Creating a request always fails, thus this function will \ + never be called; qed") + } + + /// Mimicks the corresponding method in the offchain API. + pub fn response_read_body( + &mut self, + _: HttpRequestId, + _: &mut [u8], + _: Option + ) -> Result { + unreachable!("Creating a request always fails, thus this function will \ + never be called; qed") + } +} + +impl Future for HttpWorker { + type Output = (); + + fn poll(self: Pin<&mut Self>, _: &mut Context) -> Poll { + Poll::Ready(()) + } +} -- GitLab From caa7af88404dd8e9a2355bd6158ccdba5da336d5 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Wed, 30 Oct 2019 12:22:04 +0100 Subject: [PATCH 138/167] Fix TODO for the WASM CI build of rpc-servers (#3966) --- .gitlab-ci.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 7f941c6172..5cb8db916e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -208,8 +208,7 @@ check-web-wasm: - time cargo web build -p substrate-panic-handler - time cargo web build -p substrate-peerset - time cargo web build -p substrate-primitives - # TODO: we can't use cargo web until https://github.com/paritytech/jsonrpc/pull/436 is deployed - - time cargo build -p substrate-rpc-servers --target wasm32-unknown-unknown + - time cargo web build -p substrate-rpc-servers - time cargo web build -p substrate-serializer - time cargo web build -p substrate-state-db - time cargo web build -p substrate-state-machine -- GitLab From b88bdef40ee870e17f408f4a3aaf8b999249fad3 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Wed, 30 Oct 2019 13:19:55 +0100 Subject: [PATCH 139/167] Remove the RPC helpers module (#3967) --- core/rpc/src/helpers.rs | 25 ------------------------- core/rpc/src/lib.rs | 1 - core/rpc/src/state/state_full.rs | 2 +- 3 files changed, 1 insertion(+), 27 deletions(-) delete mode 100644 core/rpc/src/helpers.rs diff --git a/core/rpc/src/helpers.rs b/core/rpc/src/helpers.rs deleted file mode 100644 index e579c743ac..0000000000 --- a/core/rpc/src/helpers.rs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2018-2019 Parity Technologies (UK) Ltd. -// This file is part of Substrate. - -// Substrate is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Substrate is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Substrate. If not, see . - -/// Unwraps the trailing parameter or falls back with the closure result. -pub fn unwrap_or_else(or_else: F, optional: Option) -> Result where - F: FnOnce() -> Result, -{ - match optional.into() { - None => or_else(), - Some(x) => Ok(x), - } -} diff --git a/core/rpc/src/lib.rs b/core/rpc/src/lib.rs index 9ce9f82fda..1341acb63d 100644 --- a/core/rpc/src/lib.rs +++ b/core/rpc/src/lib.rs @@ -20,7 +20,6 @@ #![warn(missing_docs)] -mod helpers; mod metadata; pub use api::Subscriptions; diff --git a/core/rpc/src/state/state_full.rs b/core/rpc/src/state/state_full.rs index cd05093c3a..ff4c5e5599 100644 --- a/core/rpc/src/state/state_full.rs +++ b/core/rpc/src/state/state_full.rs @@ -77,7 +77,7 @@ impl FullState /// Returns given block hash or best block hash if None is passed. fn block_or_best(&self, hash: Option) -> ClientResult { - crate::helpers::unwrap_or_else(|| Ok(self.client.info().chain.best_hash), hash) + Ok(hash.unwrap_or_else(|| self.client.info().chain.best_hash)) } /// Splits the `query_storage` block range into 'filtered' and 'unfiltered' subranges. -- GitLab From 155c217178cc8e3cf4da668dd54e28a8b113eb6b Mon Sep 17 00:00:00 2001 From: Sergei Pepyakin Date: Wed, 30 Oct 2019 13:54:57 +0100 Subject: [PATCH 140/167] Implement contract_getStorage RPC API (#3944) --- node/runtime/src/lib.rs | 15 ++++ srml/contracts/rpc/runtime-api/src/lib.rs | 25 +++++++ srml/contracts/rpc/src/lib.rs | 87 +++++++++++++++++++---- srml/contracts/src/exec.rs | 3 +- srml/contracts/src/lib.rs | 32 ++++++++- 5 files changed, 147 insertions(+), 15 deletions(-) diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index 558c6e3be7..4f26143146 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -664,6 +664,21 @@ impl_runtime_apis! { Err(_) => ContractExecResult::Error, } } + + fn get_storage( + address: AccountId, + key: [u8; 32], + ) -> contracts_rpc_runtime_api::GetStorageResult { + Contracts::get_storage(address, key).map_err(|rpc_err| { + use contracts::GetStorageError; + use contracts_rpc_runtime_api::{GetStorageError as RpcGetStorageError}; + /// Map the contract error into the RPC layer error. + match rpc_err { + GetStorageError::ContractDoesntExist => RpcGetStorageError::ContractDoesntExist, + GetStorageError::IsTombstone => RpcGetStorageError::IsTombstone, + } + }) + } } impl transaction_payment_rpc_runtime_api::TransactionPaymentApi< diff --git a/srml/contracts/rpc/runtime-api/src/lib.rs b/srml/contracts/rpc/runtime-api/src/lib.rs index 7f01b8bdfa..054f110beb 100644 --- a/srml/contracts/rpc/runtime-api/src/lib.rs +++ b/srml/contracts/rpc/runtime-api/src/lib.rs @@ -45,6 +45,20 @@ pub enum ContractExecResult { Error, } +/// A result type of the get storage call. +/// +/// See [`ContractsApi::get_storage`] for more info. +pub type GetStorageResult = Result>, GetStorageError>; + +/// The possible errors that can happen querying the storage of a contract. +#[derive(Eq, PartialEq, Encode, Decode, RuntimeDebug)] +pub enum GetStorageError { + /// The given address doesn't point on a contract. + ContractDoesntExist, + /// The specified contract is a tombstone and thus cannot have any storage. + IsTombstone, +} + client::decl_runtime_apis! { /// The API to interact with contracts without using executive. pub trait ContractsApi where @@ -61,5 +75,16 @@ client::decl_runtime_apis! { gas_limit: u64, input_data: Vec, ) -> ContractExecResult; + + /// Query a given storage key in a given contract. + /// + /// Returns `Ok(Some(Vec))` if the storage value exists under the given key in the + /// specified account and `Ok(None)` if it doesn't. If the account specified by the address + /// doesn't exist, or doesn't have a contract or if the contract is a tombstone, then `Err` + /// is returned. + fn get_storage( + address: AccountId, + key: [u8; 32], + ) -> GetStorageResult; } } diff --git a/srml/contracts/rpc/src/lib.rs b/srml/contracts/rpc/src/lib.rs index ba50bd12f0..91783df996 100644 --- a/srml/contracts/rpc/src/lib.rs +++ b/srml/contracts/rpc/src/lib.rs @@ -18,24 +18,50 @@ use std::sync::Arc; -use serde::{Serialize, Deserialize}; use client::blockchain::HeaderBackend; use codec::Codec; use jsonrpc_core::{Error, ErrorCode, Result}; use jsonrpc_derive::rpc; -use primitives::Bytes; +use primitives::{H256, Bytes}; +use rpc_primitives::number; +use serde::{Deserialize, Serialize}; use sr_primitives::{ generic::BlockId, traits::{Block as BlockT, ProvideRuntimeApi}, }; -use rpc_primitives::number; -pub use srml_contracts_rpc_runtime_api::{ContractExecResult, ContractsApi as ContractsRuntimeApi}; pub use self::gen_client::Client as ContractsClient; +pub use srml_contracts_rpc_runtime_api::{ + self as runtime_api, ContractExecResult, ContractsApi as ContractsRuntimeApi, GetStorageResult, +}; + +const RUNTIME_ERROR: i64 = 1; +const CONTRACT_DOESNT_EXIST: i64 = 2; +const CONTRACT_IS_A_TOMBSTONE: i64 = 3; + +// A private newtype for converting `GetStorageError` into an RPC error. +struct GetStorageError(runtime_api::GetStorageError); +impl From for Error { + fn from(e: GetStorageError) -> Error { + use runtime_api::GetStorageError::*; + match e.0 { + ContractDoesntExist => Error { + code: ErrorCode::ServerError(CONTRACT_DOESNT_EXIST), + message: "The specified contract doesn't exist.".into(), + data: None, + }, + IsTombstone => Error { + code: ErrorCode::ServerError(CONTRACT_IS_A_TOMBSTONE), + message: "The contract is a tombstone and doesn't have any storage.".into(), + data: None, + } + } + } +} /// A struct that encodes RPC parameters required for a call to a smart-contract. #[derive(Serialize, Deserialize)] -#[serde(rename_all="camelCase")] +#[serde(rename_all = "camelCase")] #[serde(deny_unknown_fields)] pub struct CallRequest { origin: AccountId, @@ -60,6 +86,16 @@ pub trait ContractsApi { call_request: CallRequest, at: Option, ) -> Result; + + /// Returns the value under a specified storage `key` in a contract given by `address` param, + /// or `None` if it is not set. + #[rpc(name = "contracts_getStorage")] + fn get_storage( + &self, + address: AccountId, + key: H256, + at: Option, + ) -> Result>; } /// An implementation of contract specific RPC methods. @@ -71,13 +107,15 @@ pub struct Contracts { impl Contracts { /// Create new `Contracts` with the given reference to the client. pub fn new(client: Arc) -> Self { - Contracts { client, _marker: Default::default() } + Contracts { + client, + _marker: Default::default(), + } } } -const RUNTIME_ERROR: i64 = 1; - -impl ContractsApi<::Hash, AccountId, Balance> for Contracts +impl ContractsApi<::Hash, AccountId, Balance> + for Contracts where Block: BlockT, C: Send + Sync + 'static, @@ -95,15 +133,14 @@ where let api = self.client.runtime_api(); let at = BlockId::hash(at.unwrap_or_else(|| // If the block hash is not supplied assume the best block. - self.client.info().best_hash - )); + self.client.info().best_hash)); let CallRequest { origin, dest, value, gas_limit, - input_data + input_data, } = call_request; let gas_limit = gas_limit.to_number().map_err(|e| Error { code: ErrorCode::InvalidParams, @@ -121,4 +158,30 @@ where Ok(exec_result) } + + fn get_storage( + &self, + address: AccountId, + key: H256, + at: Option<::Hash>, + ) -> Result> { + let api = self.client.runtime_api(); + let at = BlockId::hash(at.unwrap_or_else(|| + // If the block hash is not supplied assume the best block. + self.client.info().best_hash)); + + let get_storage_result = api + .get_storage(&at, address, key.into()) + .map_err(|e| + // Handle general API calling errors. + Error { + code: ErrorCode::ServerError(RUNTIME_ERROR), + message: "Runtime trapped while querying storage.".into(), + data: Some(format!("{:?}", e).into()), + })? + .map_err(GetStorageError)? + .map(Bytes); + + Ok(get_storage_result) + } } diff --git a/srml/contracts/src/exec.rs b/srml/contracts/src/exec.rs index 686b173ec7..08fd8999a4 100644 --- a/srml/contracts/src/exec.rs +++ b/srml/contracts/src/exec.rs @@ -29,6 +29,7 @@ pub type CallOf = ::Call; pub type MomentOf = <::Time as Time>::Moment; pub type SeedOf = ::Hash; pub type BlockNumberOf = ::BlockNumber; +pub type StorageKey = [u8; 32]; /// A type that represents a topic of an event. At the moment a hash is used. pub type TopicOf = ::Hash; @@ -84,8 +85,6 @@ macro_rules! try_or_exec_error { } } -pub type StorageKey = [u8; 32]; - /// An interface that provides access to the external environment in which the /// smart-contract is executed. /// diff --git a/srml/contracts/src/lib.rs b/srml/contracts/src/lib.rs index 8eaef951ba..df38747cc5 100644 --- a/srml/contracts/src/lib.rs +++ b/srml/contracts/src/lib.rs @@ -650,10 +650,19 @@ decl_module! { } } +/// The possible errors that can happen querying the storage of a contract. +pub enum GetStorageError { + /// The given address doesn't point on a contract. + ContractDoesntExist, + /// The specified contract is a tombstone and thus cannot have any storage. + IsTombstone, +} + +/// Public APIs provided by the contracts module. impl Module { /// Perform a call to a specified contract. /// - /// This function is similar to `Self::call`, but doesn't perform any lookups and better + /// This function is similar to `Self::call`, but doesn't perform any address lookups and better /// suitable for calling directly from Rust. pub fn bare_call( origin: T::AccountId, @@ -667,6 +676,27 @@ impl Module { }) } + /// Query storage of a specified contract under a specified key. + pub fn get_storage( + address: T::AccountId, + key: [u8; 32], + ) -> rstd::result::Result>, GetStorageError> { + let contract_info = >::get(&address) + .ok_or(GetStorageError::ContractDoesntExist)? + .get_alive() + .ok_or(GetStorageError::IsTombstone)?; + + let maybe_value = AccountDb::::get_storage( + &DirectAccountDb, + &address, + Some(&contract_info.trie_id), + &key, + ); + Ok(maybe_value) + } +} + +impl Module { fn execute_wasm( origin: T::AccountId, gas_limit: Gas, -- GitLab From 1fa9b541a409228cde567d6118afa4f517b3078f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 30 Oct 2019 16:34:00 +0100 Subject: [PATCH 141/167] Catch native panics when executing the wasm runtime (#3953) As with the native runtime, we now catch all native panics when we execute the wasm runtime. The panics inside the wasm runtime were already catched before by the wasm executor automatically, but any panic in the host functions could bring down the node. The recent switch to execute the native counterpart of the host function in `sr-io`, makes this change required. The native `sr-io` functions just `panic` when something is not provided or any other error occured. --- core/executor/src/host_interface.rs | 107 +++++---------------------- core/executor/src/native_executor.rs | 69 +++++++++++++---- core/executor/src/wasm_runtime.rs | 27 +++++-- core/executor/src/wasmi_execution.rs | 13 +++- core/wasm-interface/src/lib.rs | 2 +- 5 files changed, 102 insertions(+), 116 deletions(-) diff --git a/core/executor/src/host_interface.rs b/core/executor/src/host_interface.rs index 7d87d93333..4d1515d769 100644 --- a/core/executor/src/host_interface.rs +++ b/core/executor/src/host_interface.rs @@ -18,10 +18,8 @@ //! //! These are the host functions callable from within the Substrate runtime. -use crate::error::{Error, Result}; - use codec::Encode; -use std::{convert::TryFrom, str, panic}; +use std::{convert::TryFrom, str}; use primitives::{ blake2_128, blake2_256, twox_64, twox_128, twox_256, ed25519, sr25519, Blake2Hasher, Pair, crypto::KeyTypeId, offchain, @@ -211,10 +209,7 @@ impl_wasm_host_interface! { .map_err(|_| "Invalid attempt to determine key in ext_set_storage")?; let value = context.read_memory(value_data, value_len) .map_err(|_| "Invalid attempt to determine value in ext_set_storage")?; - with_external_storage(move || - Ok(runtime_io::set_storage(&key, &value)) - )?; - Ok(()) + Ok(runtime_io::set_storage(&key, &value)) } ext_set_child_storage( @@ -232,10 +227,7 @@ impl_wasm_host_interface! { let value = context.read_memory(value_data, value_len) .map_err(|_| "Invalid attempt to determine value in ext_set_child_storage")?; - with_external_storage(move || - Ok(runtime_io::set_child_storage(&storage_key, &key, &value)) - )?; - Ok(()) + Ok(runtime_io::set_child_storage(&storage_key, &key, &value)) } ext_clear_child_storage( @@ -249,27 +241,19 @@ impl_wasm_host_interface! { let key = context.read_memory(key_data, key_len) .map_err(|_| "Invalid attempt to determine key in ext_clear_child_storage")?; - with_external_storage(move || - Ok(runtime_io::clear_child_storage(&storage_key, &key)) - )?; - Ok(()) + Ok(runtime_io::clear_child_storage(&storage_key, &key)) } ext_clear_storage(key_data: Pointer, key_len: WordSize) { let key = context.read_memory(key_data, key_len) .map_err(|_| "Invalid attempt to determine key in ext_clear_storage")?; - with_external_storage(move || - Ok(runtime_io::clear_storage(&key)) - )?; - Ok(()) + Ok(runtime_io::clear_storage(&key)) } ext_exists_storage(key_data: Pointer, key_len: WordSize) -> u32 { let key = context.read_memory(key_data, key_len) .map_err(|_| "Invalid attempt to determine key in ext_exists_storage")?; - with_external_storage(move || - Ok(if runtime_io::exists_storage(&key) { 1 } else { 0 }) - ) + Ok(if runtime_io::exists_storage(&key) { 1 } else { 0 }) } ext_exists_child_storage( @@ -283,18 +267,13 @@ impl_wasm_host_interface! { let key = context.read_memory(key_data, key_len) .map_err(|_| "Invalid attempt to determine key in ext_exists_child_storage")?; - with_external_storage(move || - Ok(if runtime_io::exists_child_storage(&storage_key, &key) { 1 } else { 0 }) - ) + Ok(if runtime_io::exists_child_storage(&storage_key, &key) { 1 } else { 0 }) } ext_clear_prefix(prefix_data: Pointer, prefix_len: WordSize) { let prefix = context.read_memory(prefix_data, prefix_len) .map_err(|_| "Invalid attempt to determine prefix in ext_clear_prefix")?; - with_external_storage(move || - Ok(runtime_io::clear_prefix(&prefix)) - )?; - Ok(()) + Ok(runtime_io::clear_prefix(&prefix)) } ext_clear_child_prefix( @@ -307,21 +286,13 @@ impl_wasm_host_interface! { .map_err(|_| "Invalid attempt to determine storage_key in ext_clear_child_prefix")?; let prefix = context.read_memory(prefix_data, prefix_len) .map_err(|_| "Invalid attempt to determine prefix in ext_clear_child_prefix")?; - with_external_storage(move || - Ok(runtime_io::clear_child_prefix(&storage_key, &prefix)) - )?; - - Ok(()) + Ok(runtime_io::clear_child_prefix(&storage_key, &prefix)) } ext_kill_child_storage(storage_key_data: Pointer, storage_key_len: WordSize) { let storage_key = context.read_memory(storage_key_data, storage_key_len) .map_err(|_| "Invalid attempt to determine storage_key in ext_kill_child_storage")?; - with_external_storage(move || - Ok(runtime_io::kill_child_storage(&storage_key)) - )?; - - Ok(()) + Ok(runtime_io::kill_child_storage(&storage_key)) } ext_get_allocated_storage( @@ -331,11 +302,8 @@ impl_wasm_host_interface! { ) -> Pointer { let key = context.read_memory(key_data, key_len) .map_err(|_| "Invalid attempt to determine key in ext_get_allocated_storage")?; - let maybe_value = with_external_storage(move || - Ok(runtime_io::storage(&key)) - )?; - if let Some(value) = maybe_value { + if let Some(value) = runtime_io::storage(&key) { let offset = context.allocate_memory(value.len() as u32)?; context.write_memory(offset, &value) .map_err(|_| "Invalid attempt to set memory in ext_get_allocated_storage")?; @@ -361,11 +329,7 @@ impl_wasm_host_interface! { let key = context.read_memory(key_data, key_len) .map_err(|_| "Invalid attempt to determine key in ext_get_allocated_child_storage")?; - let maybe_value = with_external_storage(move || - Ok(runtime_io::child_storage(&storage_key, &key)) - )?; - - if let Some(value) = maybe_value { + if let Some(value) = runtime_io::child_storage(&storage_key, &key) { let offset = context.allocate_memory(value.len() as u32)?; context.write_memory(offset, &value) .map_err(|_| "Invalid attempt to set memory in ext_get_allocated_child_storage")?; @@ -388,11 +352,8 @@ impl_wasm_host_interface! { ) -> WordSize { let key = context.read_memory(key_data, key_len) .map_err(|_| "Invalid attempt to get key in ext_get_storage_into")?; - let maybe_value = with_external_storage(move || - Ok(runtime_io::storage(&key)) - )?; - if let Some(value) = maybe_value { + if let Some(value) = runtime_io::storage(&key) { let data = &value[value.len().min(value_offset as usize)..]; let written = std::cmp::min(value_len as usize, data.len()); context.write_memory(value_data, &data[..written]) @@ -417,11 +378,7 @@ impl_wasm_host_interface! { let key = context.read_memory(key_data, key_len) .map_err(|_| "Invalid attempt to get key in ext_get_child_storage_into")?; - let maybe_value = with_external_storage(move || - Ok(runtime_io::child_storage(&storage_key, &key)) - )?; - - if let Some(value) = maybe_value { + if let Some(value) = runtime_io::child_storage(&storage_key, &key) { let data = &value[value.len().min(value_offset as usize)..]; let written = std::cmp::min(value_len as usize, data.len()); context.write_memory(value_data, &data[..written]) @@ -433,12 +390,8 @@ impl_wasm_host_interface! { } ext_storage_root(result: Pointer) { - let r = with_external_storage(move || - Ok(runtime_io::storage_root()) - )?; - context.write_memory(result, r.as_ref()) - .map_err(|_| "Invalid attempt to set memory in ext_storage_root")?; - Ok(()) + context.write_memory(result, runtime_io::storage_root().as_ref()) + .map_err(|_| "Invalid attempt to set memory in ext_storage_root".into()) } ext_child_storage_root( @@ -448,9 +401,7 @@ impl_wasm_host_interface! { ) -> Pointer { let storage_key = context.read_memory(storage_key_data, storage_key_len) .map_err(|_| "Invalid attempt to determine storage_key in ext_child_storage_root")?; - let value = with_external_storage(move || - Ok(runtime_io::child_storage_root(&storage_key)) - )?; + let value = runtime_io::child_storage_root(&storage_key); let offset = context.allocate_memory(value.len() as u32)?; context.write_memory(offset, &value) @@ -468,11 +419,8 @@ impl_wasm_host_interface! { let mut parent_hash = [0u8; 32]; context.read_memory_into(parent_hash_data, &mut parent_hash[..]) .map_err(|_| "Invalid attempt to get parent_hash in ext_storage_changes_root")?; - let r = with_external_storage(move || - Ok(runtime_io::storage_changes_root(parent_hash)) - )?; - if let Some(r) = r { + if let Some(r) = runtime_io::storage_changes_root(parent_hash) { context.write_memory(result, &r[..]) .map_err(|_| "Invalid attempt to set memory in ext_storage_changes_root")?; Ok(1) @@ -1146,25 +1094,6 @@ impl ReadPrimitive for &mut dyn FunctionContext { } } -/// Execute closure that access external storage. -/// -/// All panics that happen within closure are captured and transformed into -/// runtime error. This requires special panic handler mode to be enabled -/// during the call (see `panic_handler::AbortGuard::never_abort`). -/// If this mode isn't enabled, then all panics within externalities are -/// leading to process abort. -fn with_external_storage(f: F) -> std::result::Result - where - F: panic::UnwindSafe + FnOnce() -> Result -{ - // it is safe beause basic methods of StorageExternalities are guaranteed to touch only - // its internal state + we should discard it on error - panic::catch_unwind(move || f()) - .map_err(|_| Error::Runtime) - .and_then(|result| result) - .map_err(|err| format!("{}", err)) -} - fn deadline_to_timestamp(deadline: u64) -> Option { if deadline == 0 { None diff --git a/core/executor/src/native_executor.rs b/core/executor/src/native_executor.rs index 7323703ed9..082f0ba2ad 100644 --- a/core/executor/src/native_executor.rs +++ b/core/executor/src/native_executor.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -use std::{result, cell::RefCell, panic::UnwindSafe}; +use std::{result, cell::RefCell, panic::{UnwindSafe, AssertUnwindSafe}}; use crate::error::{Error, Result}; use crate::wasm_runtime::{RuntimesCache, WasmExecutionMethod, WasmRuntime}; use crate::RuntimeInfo; @@ -30,7 +30,7 @@ thread_local! { /// Default num of pages for the heap const DEFAULT_HEAP_PAGES: u64 = 1024; -fn safe_call(f: F) -> Result +pub(crate) fn safe_call(f: F) -> Result where F: UnwindSafe + FnOnce() -> U { // Substrate uses custom panic hook that terminates process on panic. Disable termination for the native call. @@ -65,7 +65,7 @@ pub trait NativeExecutionDispatch: Send + Sync { #[derive(Debug)] pub struct NativeExecutor { /// Dummy field to avoid the compiler complaining about us not using `D`. - _dummy: ::std::marker::PhantomData, + _dummy: std::marker::PhantomData, /// Method used to execute fallback Wasm code. fallback_method: WasmExecutionMethod, /// Native runtime version info. @@ -92,15 +92,45 @@ impl NativeExecutor { } } + /// Execute the given closure `f` with the latest runtime (based on the `CODE` key in `ext`). + /// + /// The closure `f` is expected to return `Err(_)` when there happened a `panic!` in native code + /// while executing the runtime in Wasm. If a `panic!` occurred, the runtime is invalidated to + /// prevent any poisoned state. Native runtime execution does not need to report back + /// any `panic!`. + /// + /// # Safety + /// + /// `runtime` and `ext` are given as `AssertUnwindSafe` to the closure. As described above, the + /// runtime is invalidated on any `panic!` to prevent a poisoned state. `ext` is already + /// implicitly handled as unwind safe, as we store it in a global variable while executing the + /// native runtime. fn with_runtime( &self, ext: &mut E, - f: impl for <'a> FnOnce(&'a mut dyn WasmRuntime, &'a mut E) -> Result, + f: impl for<'a> FnOnce( + AssertUnwindSafe<&'a mut (dyn WasmRuntime + 'static)>, + AssertUnwindSafe<&'a mut E>, + ) -> Result>, ) -> Result where E: Externalities { RUNTIMES_CACHE.with(|cache| { let mut cache = cache.borrow_mut(); - let runtime = cache.fetch_runtime(ext, self.fallback_method, self.default_heap_pages)?; - f(runtime, ext) + let (runtime, code_hash) = cache.fetch_runtime( + ext, + self.fallback_method, + self.default_heap_pages, + )?; + + let runtime = AssertUnwindSafe(runtime); + let ext = AssertUnwindSafe(ext); + + match f(runtime, ext) { + Ok(res) => res, + Err(e) => { + cache.invalidate_runtime(self.fallback_method, code_hash); + Err(e) + } + } }) } } @@ -125,7 +155,7 @@ impl RuntimeInfo for NativeExecutor { &self, ext: &mut E, ) -> Option { - match self.with_runtime(ext, |runtime, _ext| Ok(runtime.version())) { + match self.with_runtime(ext, |runtime, _ext| Ok(Ok(runtime.version()))) { Ok(version) => version, Err(e) => { warn!(target: "executor", "Failed to fetch runtime: {:?}", e); @@ -141,8 +171,8 @@ impl CodeExecutor for NativeExecutor { fn call < E: Externalities, - R:Decode + Encode + PartialEq, - NC: FnOnce() -> result::Result + UnwindSafe + R: Decode + Encode + PartialEq, + NC: FnOnce() -> result::Result + UnwindSafe, >( &self, ext: &mut E, @@ -152,7 +182,7 @@ impl CodeExecutor for NativeExecutor { native_call: Option, ) -> (Result>, bool){ let mut used_native = false; - let result = self.with_runtime(ext, |runtime, ext| { + let result = self.with_runtime(ext, |mut runtime, mut ext| { let onchain_version = runtime.version(); match ( use_native, @@ -170,9 +200,16 @@ impl CodeExecutor for NativeExecutor { .as_ref() .map_or_else(||"".into(), |v| format!("{}", v)) ); - runtime.call(ext, method, data).map(NativeOrEncoded::Encoded) + + safe_call( + move || runtime.call(&mut **ext, method, data).map(NativeOrEncoded::Encoded) + ) } - (false, _, _) => runtime.call(ext, method, data).map(NativeOrEncoded::Encoded), + (false, _, _) => { + safe_call( + move || runtime.call(&mut **ext, method, data).map(NativeOrEncoded::Encoded) + ) + }, (true, true, Some(call)) => { trace!( target: "executor", @@ -184,11 +221,13 @@ impl CodeExecutor for NativeExecutor { ); used_native = true; - with_native_environment(ext, move || (call)()) + let res = with_native_environment(&mut **ext, move || (call)()) .and_then(|r| r .map(NativeOrEncoded::Native) .map_err(|s| Error::ApiError(s.to_string())) - ) + ); + + Ok(res) } _ => { trace!( @@ -199,7 +238,7 @@ impl CodeExecutor for NativeExecutor { ); used_native = true; - D::dispatch(ext, method, data).map(NativeOrEncoded::Encoded) + Ok(D::dispatch(&mut **ext, method, data).map(NativeOrEncoded::Encoded)) } } }); diff --git a/core/executor/src/wasm_runtime.rs b/core/executor/src/wasm_runtime.rs index 8d2291fe04..29a6c51e39 100644 --- a/core/executor/src/wasm_runtime.rs +++ b/core/executor/src/wasm_runtime.rs @@ -23,7 +23,7 @@ use crate::error::{Error, WasmError}; use crate::wasmi_execution; use log::{trace, warn}; use codec::Decode; -use primitives::{storage::well_known_keys, traits::Externalities}; +use primitives::{storage::well_known_keys, traits::Externalities, H256}; use runtime_version::RuntimeVersion; use std::{collections::hash_map::{Entry, HashMap}}; @@ -99,9 +99,8 @@ impl RuntimesCache { /// /// # Return value /// - /// If no error occurred a tuple `(wasmi::ModuleRef, Option)` is - /// returned. `RuntimeVersion` is contained if the call to `Core_version` returned - /// a version. + /// If no error occurred a tuple `(&mut WasmRuntime, H256)` is + /// returned. `H256` is the hash of the runtime code. /// /// In case of failure one of two errors can be returned: /// @@ -114,7 +113,7 @@ impl RuntimesCache { ext: &mut E, wasm_method: WasmExecutionMethod, default_heap_pages: u64, - ) -> Result<&mut (dyn WasmRuntime + 'static), Error> { + ) -> Result<(&mut (dyn WasmRuntime + 'static), H256), Error> { let code_hash = ext .original_storage_hash(well_known_keys::CODE) .ok_or(Error::InvalidCode("`CODE` not found in storage.".into()))?; @@ -131,7 +130,7 @@ impl RuntimesCache { if !cached_runtime.update_heap_pages(heap_pages) { trace!( target: "runtimes_cache", - "heap_pages were changed. Reinstantiating the instance" + "heap_pages were changed. Reinstantiating the instance", ); *result = create_wasm_runtime(ext, wasm_method, heap_pages); if let Err(ref err) = result { @@ -152,9 +151,23 @@ impl RuntimesCache { }; result.as_mut() - .map(|runtime| runtime.as_mut()) + .map(|runtime| (runtime.as_mut(), code_hash)) .map_err(|ref e| Error::InvalidCode(format!("{:?}", e))) } + + /// Invalidate the runtime for the given `wasm_method` and `code_hash`. + /// + /// Invalidation of a runtime is useful when there was a `panic!` in native while executing it. + /// The `panic!` maybe have brought the runtime into a poisoned state and so, it is better to + /// invalidate this runtime instance. + pub fn invalidate_runtime( + &mut self, + wasm_method: WasmExecutionMethod, + code_hash: H256, + ) { + // Just remove the instance, it will be re-created the next time it is requested. + self.instances.remove(&(wasm_method, code_hash.into())); + } } /// Create a wasm runtime with the given `code`. diff --git a/core/executor/src/wasmi_execution.rs b/core/executor/src/wasmi_execution.rs index 2b832b4906..a83729b4b6 100644 --- a/core/executor/src/wasmi_execution.rs +++ b/core/executor/src/wasmi_execution.rs @@ -16,7 +16,7 @@ //! Implementation of a Wasm runtime using the Wasmi interpreter. -use std::{str, mem}; +use std::{str, mem, panic::AssertUnwindSafe}; use wasmi::{ Module, ModuleInstance, MemoryInstance, MemoryRef, TableRef, ImportsBuilder, ModuleRef, memory_units::Pages, RuntimeValue::{I32, I64, self}, @@ -625,9 +625,14 @@ pub fn create_instance(ext: &mut E, code: &[u8], heap_pages: u ", ); - let version = call_in_wasm_module(ext, &instance, "Core_version", &[]) - .ok() - .and_then(|v| RuntimeVersion::decode(&mut v.as_slice()).ok()); + let mut ext = AssertUnwindSafe(ext); + let call_instance = AssertUnwindSafe(&instance); + let version = crate::native_executor::safe_call( + move || call_in_wasm_module(&mut **ext, *call_instance, "Core_version", &[]) + .ok() + .and_then(|v| RuntimeVersion::decode(&mut v.as_slice()).ok()) + ).map_err(WasmError::Instantiation)?; + Ok(WasmiRuntime { instance, version, diff --git a/core/wasm-interface/src/lib.rs b/core/wasm-interface/src/lib.rs index b3cbde556e..1e67260638 100644 --- a/core/wasm-interface/src/lib.rs +++ b/core/wasm-interface/src/lib.rs @@ -180,7 +180,7 @@ pub trait Function { fn execute( &self, context: &mut dyn FunctionContext, - args: &mut dyn Iterator, + args: &mut dyn Iterator, ) -> Result>; } -- GitLab From fc563644f2d36af9cdd26b0f8125cb5da2a6180e Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Wed, 30 Oct 2019 16:49:17 +0100 Subject: [PATCH 142/167] Remove node/src/main.rs (#3969) --- Cargo.lock | 12 ++---------- Cargo.toml | 25 ------------------------- build.rs | 24 ------------------------ node/cli/Cargo.toml | 13 +++++++++++++ node/{src => cli/bin}/main.rs | 2 +- node/cli/build.rs | 6 ++++-- 6 files changed, 20 insertions(+), 62 deletions(-) delete mode 100644 build.rs rename node/{src => cli/bin}/main.rs (97%) diff --git a/Cargo.lock b/Cargo.lock index 861222cc98..233151e336 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2377,6 +2377,7 @@ dependencies = [ name = "node-cli" version = "2.0.0" dependencies = [ + "ctrlc 3.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "exit-future 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "futures-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2426,6 +2427,7 @@ dependencies = [ "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", "transaction-factory 0.0.1", + "vergen 3.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -4776,16 +4778,6 @@ dependencies = [ "tiny-bip39 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "substrate" -version = "2.0.0" -dependencies = [ - "ctrlc 3.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "node-cli 2.0.0", - "vergen 3.0.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "substrate-application-crypto" version = "2.0.0" diff --git a/Cargo.toml b/Cargo.toml index 2d68511b2e..31a08f4eaf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,22 +1,3 @@ -[[bin]] -name = "substrate" -path = "node/src/main.rs" - -[package] -name = "substrate" -version = "2.0.0" -authors = ["Parity Technologies "] -build = "build.rs" -edition = "2018" - -[dependencies] -cli = { package = "node-cli", path = "node/cli" } -futures = "0.1.29" -ctrlc = { version = "3.1.3", features = ["termination"] } - -[build-dependencies] -vergen = "3.0.4" - [workspace] members = [ "core/authority-discovery", @@ -124,12 +105,6 @@ members = [ "test-utils/chain-spec-builder", ] -[badges] -travis-ci = { repository = "paritytech/substrate", branch = "master" } -maintenance = { status = "actively-developed" } -is-it-maintained-issue-resolution = { repository = "paritytech/substrate" } -is-it-maintained-open-issues = { repository = "paritytech/substrate" } - [profile.release] # Substrate runtime requires unwinding. panic = "unwind" diff --git a/build.rs b/build.rs deleted file mode 100644 index 273700c525..0000000000 --- a/build.rs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2015-2019 Parity Technologies (UK) Ltd. -// This file is part of Substrate. - -// Substrate is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Substrate is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Substrate. If not, see . - -use vergen::{ConstantsFlags, generate_cargo_keys}; - -const ERROR_MSG: &str = "Failed to generate metadata files"; - -fn main() { - generate_cargo_keys(ConstantsFlags::all()).expect(ERROR_MSG); - println!("cargo:rerun-if-changed=.git/HEAD"); -} diff --git a/node/cli/Cargo.toml b/node/cli/Cargo.toml index 7e011d9de8..b85014eeef 100644 --- a/node/cli/Cargo.toml +++ b/node/cli/Cargo.toml @@ -5,6 +5,17 @@ authors = ["Parity Technologies "] description = "Substrate node implementation in Rust." build = "build.rs" edition = "2018" +default-run = "substrate" + +[badges] +travis-ci = { repository = "paritytech/substrate", branch = "master" } +maintenance = { status = "actively-developed" } +is-it-maintained-issue-resolution = { repository = "paritytech/substrate" } +is-it-maintained-open-issues = { repository = "paritytech/substrate" } + +[[bin]] +name = "substrate" +path = "bin/main.rs" [dependencies] log = "0.4.8" @@ -51,6 +62,7 @@ im_online = { package = "srml-im-online", path = "../../srml/im-online", default serde = { version = "1.0.101", features = [ "derive" ] } client_db = { package = "substrate-client-db", path = "../../core/client/db", features = ["kvdb-rocksdb"] } offchain = { package = "substrate-offchain", path = "../../core/offchain" } +ctrlc = { version = "3.1.3", features = ["termination"] } [dev-dependencies] keystore = { package = "substrate-keystore", path = "../../core/keystore" } @@ -63,3 +75,4 @@ tempfile = "3.1.0" [build-dependencies] cli = { package = "substrate-cli", path = "../../core/cli" } structopt = "0.3.3" +vergen = "3.0.4" diff --git a/node/src/main.rs b/node/cli/bin/main.rs similarity index 97% rename from node/src/main.rs rename to node/cli/bin/main.rs index 9f76cf638c..4b07d8c8a4 100644 --- a/node/src/main.rs +++ b/node/cli/bin/main.rs @@ -54,5 +54,5 @@ fn main() -> Result<(), cli::error::Error> { support_url: "https://github.com/paritytech/substrate/issues/new", }; - cli::run(std::env::args(), Exit, version) + node_cli::run(std::env::args(), Exit, version) } diff --git a/node/cli/build.rs b/node/cli/build.rs index e7a7b271f1..48b57c4600 100644 --- a/node/cli/build.rs +++ b/node/cli/build.rs @@ -15,13 +15,15 @@ // along with Substrate. If not, see . use cli::{NoCustom, CoreParams}; - use std::{fs, env, path::Path}; - use structopt::{StructOpt, clap::Shell}; +use vergen::{ConstantsFlags, generate_cargo_keys}; fn main() { build_shell_completion(); + generate_cargo_keys(ConstantsFlags::all()) + .expect("Failed to generate metadata files"); + println!("cargo:rerun-if-changed=.git/HEAD"); } /// Build shell completion scripts for all known shells -- GitLab From 2aa1d46fd7a6f2c5efe06e3e4bb459912a36edb7 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Wed, 30 Oct 2019 16:50:08 +0100 Subject: [PATCH 143/167] Allow passing a custom database when creating the Service (#3957) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Put the DB configuration in an enum * Allow passing a custom database to client-db * Clean-ups in client-db * Fix client tests * Fix service tests * Hopefully fix tests for good this time 😩 * Address review --- Cargo.lock | 1 + core/cli/src/lib.rs | 27 +++++++++---- core/client/Cargo.toml | 1 + core/client/db/src/lib.rs | 57 ++++++++++++++-------------- core/client/db/src/light.rs | 12 ------ core/client/db/src/utils.rs | 26 ++++++++----- core/client/src/client.rs | 8 ++-- core/service/src/builder.rs | 73 ++++++++++++++++++++++-------------- core/service/src/config.rs | 31 +++++++++++---- core/service/test/src/lib.rs | 7 +++- 10 files changed, 145 insertions(+), 98 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 233151e336..75a1b797b0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4934,6 +4934,7 @@ dependencies = [ "sr-primitives 2.0.0", "sr-std 2.0.0", "sr-version 2.0.0", + "substrate-client-db 2.0.0", "substrate-consensus-common 2.0.0", "substrate-executor 2.0.0", "substrate-header-metadata 2.0.0", diff --git a/core/cli/src/lib.rs b/core/cli/src/lib.rs index adf0a57aaf..7b96788433 100644 --- a/core/cli/src/lib.rs +++ b/core/cli/src/lib.rs @@ -28,7 +28,7 @@ pub mod informant; use client::ExecutionStrategies; use service::{ - config::Configuration, + config::{Configuration, DatabaseConfig}, ServiceBuilderExport, ServiceBuilderImport, ServiceBuilderRevert, RuntimeGenesis, ChainSpecExtension, PruningMode, ChainSpec, }; @@ -351,7 +351,9 @@ impl<'a> ParseAndPrepareExport<'a> { { let config = create_config_with_db_path(spec_factory, &self.params.shared_params, self.version)?; - info!("DB path: {}", config.database_path.display()); + if let DatabaseConfig::Path { ref path, .. } = &config.database { + info!("DB path: {}", path.display()); + } let from = self.params.from.unwrap_or(1); let to = self.params.to; let json = self.params.json; @@ -430,7 +432,13 @@ impl<'a> ParseAndPreparePurge<'a> { let config = create_config_with_db_path::<(), _, _, _>( spec_factory, &self.params.shared_params, self.version )?; - let db_path = config.database_path; + let db_path = match config.database { + DatabaseConfig::Path { path, .. } => path, + _ => { + eprintln!("Cannot purge custom database implementation"); + return Ok(()); + } + }; if !self.params.yes { print!("Are you sure to remove {:?}? [y/N]: ", &db_path); @@ -455,7 +463,7 @@ impl<'a> ParseAndPreparePurge<'a> { Ok(()) }, Result::Err(ref err) if err.kind() == ErrorKind::NotFound => { - println!("{:?} did not exist.", &db_path); + eprintln!("{:?} did not exist.", &db_path); Ok(()) }, Result::Err(err) => Result::Err(err.into()) @@ -664,8 +672,10 @@ where || keystore_path(&base_path, config.chain_spec.id()) ); - config.database_path = db_path(&base_path, config.chain_spec.id()); - config.database_cache_size = cli.database_cache_size; + config.database = DatabaseConfig::Path { + path: db_path(&base_path, config.chain_spec.id()), + cache_size: cli.database_cache_size, + }; config.state_cache_size = cli.state_cache_size; let is_dev = cli.shared_params.dev; @@ -829,7 +839,10 @@ where let base_path = base_path(cli, version); let mut config = service::Configuration::default_with_spec(spec.clone()); - config.database_path = db_path(&base_path, spec.id()); + config.database = DatabaseConfig::Path { + path: db_path(&base_path, spec.id()), + cache_size: None, + }; Ok(config) } diff --git a/core/client/Cargo.toml b/core/client/Cargo.toml index 5a0afd2d6f..761b2a9da2 100644 --- a/core/client/Cargo.toml +++ b/core/client/Cargo.toml @@ -32,6 +32,7 @@ header-metadata = { package = "substrate-header-metadata", path = "header-metada [dev-dependencies] env_logger = "0.7.0" tempfile = "3.1.0" +client-db = { package = "substrate-client-db", path = "./db", features = ["kvdb-rocksdb"] } test-client = { package = "substrate-test-runtime-client", path = "../test-runtime/client" } kvdb-memorydb = { git = "https://github.com/paritytech/parity-common", rev="b0317f649ab2c665b7987b8475878fc4d2e1f81d" } panic-handler = { package = "substrate-panic-handler", path = "../panic-handler" } diff --git a/core/client/db/src/lib.rs b/core/client/db/src/lib.rs index 0f765506a3..8bd0001981 100644 --- a/core/client/db/src/lib.rs +++ b/core/client/db/src/lib.rs @@ -83,6 +83,9 @@ const DEFAULT_CHILD_RATIO: (usize, usize) = (1, 10); /// DB-backed patricia trie state, transaction type is an overlay of changes to commit. pub type DbState = state_machine::TrieBackend>, Blake2Hasher>; +/// Re-export the KVDB trait so that one can pass an implementation of it. +pub use kvdb; + /// A reference tracking state. /// /// It makes sure that the hash we are using stays pinned in storage @@ -191,16 +194,28 @@ impl StateBackend for RefTrackingState { /// Database settings. pub struct DatabaseSettings { - /// Cache size in bytes. If `None` default is used. - pub cache_size: Option, /// State cache size. pub state_cache_size: usize, /// Ratio of cache size dedicated to child tries. pub state_cache_child_ratio: Option<(usize, usize)>, - /// Path to the database. - pub path: PathBuf, /// Pruning mode. pub pruning: PruningMode, + /// Where to find the database. + pub source: DatabaseSettingsSrc, +} + +/// Where to find the database.. +pub enum DatabaseSettingsSrc { + /// Load a database from a given path. Recommended for most uses. + Path { + /// Path to the database. + path: PathBuf, + /// Cache size in bytes. If `None` default is used. + cache_size: Option, + }, + + /// Use a custom already-open database. + Custom(Arc), } /// Create an instance of db-backed client. @@ -775,17 +790,7 @@ impl> Backend { /// /// The pruning window is how old a block must be before the state is pruned. pub fn new(config: DatabaseSettings, canonicalization_delay: u64) -> ClientResult { - Self::new_inner(config, canonicalization_delay) - } - - fn new_inner(config: DatabaseSettings, canonicalization_delay: u64) -> ClientResult { - #[cfg(feature = "kvdb-rocksdb")] let db = crate::utils::open_database(&config, columns::META, "full")?; - #[cfg(not(feature = "kvdb-rocksdb"))] - let db = { - log::warn!("Running without the RocksDB feature. The database will NOT be saved."); - Arc::new(kvdb_memorydb::create(crate::utils::NUM_COLUMNS)) - }; Self::from_kvdb(db as Arc<_>, canonicalization_delay, &config) } @@ -793,25 +798,14 @@ impl> Backend { #[cfg(any(test, feature = "test-helpers"))] pub fn new_test(keep_blocks: u32, canonicalization_delay: u64) -> Self { let db = Arc::new(kvdb_memorydb::create(crate::utils::NUM_COLUMNS)); - Self::new_test_db(keep_blocks, canonicalization_delay, db as Arc<_>) - } - - /// Creates a client backend with test settings. - #[cfg(any(test, feature = "test-helpers"))] - pub fn new_test_db(keep_blocks: u32, canonicalization_delay: u64, db: Arc) -> Self { - let db_setting = DatabaseSettings { - cache_size: None, state_cache_size: 16777216, state_cache_child_ratio: Some((50, 100)), - path: Default::default(), pruning: PruningMode::keep_blocks(keep_blocks), + source: DatabaseSettingsSrc::Custom(db), }; - Self::from_kvdb( - db, - canonicalization_delay, - &db_setting, - ).expect("failed to create test-db") + + Self::new(db_setting, canonicalization_delay).expect("failed to create test-db") } fn from_kvdb( @@ -1636,7 +1630,12 @@ mod tests { db.storage.db.clone() }; - let backend = Backend::::new_test_db(1, 0, backing); + let backend = Backend::::new(DatabaseSettings { + state_cache_size: 16777216, + state_cache_child_ratio: Some((50, 100)), + pruning: PruningMode::keep_blocks(1), + source: DatabaseSettingsSrc::Custom(backing), + }, 0).unwrap(); assert_eq!(backend.blockchain().info().best_number, 9); for i in 0..10 { assert!(backend.blockchain().hash(i).unwrap().is_some()) diff --git a/core/client/db/src/light.rs b/core/client/db/src/light.rs index 19fc7fde35..6e71b88ae7 100644 --- a/core/client/db/src/light.rs +++ b/core/client/db/src/light.rs @@ -70,22 +70,10 @@ impl LightStorage { /// Create new storage with given settings. pub fn new(config: DatabaseSettings) -> ClientResult { - Self::new_inner(config) - } - - #[cfg(feature = "kvdb-rocksdb")] - fn new_inner(config: DatabaseSettings) -> ClientResult { let db = crate::utils::open_database(&config, columns::META, "light")?; Self::from_kvdb(db as Arc<_>) } - #[cfg(not(feature = "kvdb-rocksdb"))] - fn new_inner(_config: DatabaseSettings) -> ClientResult { - log::warn!("Running without the RocksDB feature. The database will NOT be saved."); - let db = Arc::new(kvdb_memorydb::create(crate::utils::NUM_COLUMNS)); - Self::from_kvdb(db as Arc<_>) - } - /// Create new memory-backed `LightStorage` for tests. #[cfg(any(test, feature = "test-helpers"))] pub fn new_test() -> Self { diff --git a/core/client/db/src/utils.rs b/core/client/db/src/utils.rs index 70f0ff2058..0a6112abe7 100644 --- a/core/client/db/src/utils.rs +++ b/core/client/db/src/utils.rs @@ -17,7 +17,6 @@ //! Db-based backend utility structures and functions, used by both //! full and light storages. -#[cfg(feature = "kvdb-rocksdb")] use std::sync::Arc; use std::{io, convert::TryInto}; @@ -34,8 +33,7 @@ use sr_primitives::traits::{ Block as BlockT, Header as HeaderT, Zero, UniqueSaturatedFrom, UniqueSaturatedInto, }; -#[cfg(feature = "kvdb-rocksdb")] -use crate::DatabaseSettings; +use crate::{DatabaseSettings, DatabaseSettingsSrc}; /// Number of columns in the db. Must be the same for both full && light dbs. /// Otherwise RocksDb will fail to open database && check its type. @@ -206,16 +204,26 @@ pub fn db_err(err: io::Error) -> client::error::Error { } /// Open RocksDB database. -#[cfg(feature = "kvdb-rocksdb")] pub fn open_database( config: &DatabaseSettings, col_meta: Option, db_type: &str ) -> client::error::Result> { - let mut db_config = DatabaseConfig::with_columns(Some(NUM_COLUMNS)); - db_config.memory_budget = config.cache_size; - let path = config.path.to_str().ok_or_else(|| client::error::Error::Backend("Invalid database path".into()))?; - let db = Database::open(&db_config, &path).map_err(db_err)?; + let db: Arc = match &config.source { + #[cfg(feature = "kvdb-rocksdb")] + DatabaseSettingsSrc::Path { path, cache_size } => { + let mut db_config = DatabaseConfig::with_columns(Some(NUM_COLUMNS)); + db_config.memory_budget = *cache_size; + let path = path.to_str().ok_or_else(|| client::error::Error::Backend("Invalid database path".into()))?; + Arc::new(Database::open(&db_config, &path).map_err(db_err)?) + }, + #[cfg(not(feature = "kvdb-rocksdb"))] + DatabaseSettingsSrc::Path { .. } => { + let msg = "Try to open RocksDB database with RocksDB disabled".into(); + return Err(client::error::Error::Backend(msg)); + }, + DatabaseSettingsSrc::Custom(db) => db.clone(), + }; // check database type match db.get(col_meta, meta_keys::TYPE).map_err(db_err)? { @@ -232,7 +240,7 @@ pub fn open_database( }, } - Ok(Arc::new(db)) + Ok(db) } /// Read database column entry for the given block. diff --git a/core/client/src/client.rs b/core/client/src/client.rs index 25c2fab48d..56a495e683 100644 --- a/core/client/src/client.rs +++ b/core/client/src/client.rs @@ -1871,7 +1871,7 @@ pub(crate) mod tests { use consensus::{BlockOrigin, SelectChain}; use test_client::{ prelude::*, - client_db::{Backend, DatabaseSettings, PruningMode}, + client_db::{Backend, DatabaseSettings, DatabaseSettingsSrc, PruningMode}, runtime::{self, Block, Transfer, RuntimeApi, TestAPI}, }; @@ -2755,11 +2755,13 @@ pub(crate) mod tests { // states let backend = Arc::new(Backend::new( DatabaseSettings { - cache_size: None, state_cache_size: 1 << 20, state_cache_child_ratio: None, - path: tmp.path().into(), pruning: PruningMode::ArchiveAll, + source: DatabaseSettingsSrc::Path { + path: tmp.path().into(), + cache_size: None, + } }, u64::max_value(), ).unwrap()); diff --git a/core/service/src/builder.rs b/core/service/src/builder.rs index b2a6cc731a..e39610b702 100644 --- a/core/service/src/builder.rs +++ b/core/service/src/builder.rs @@ -17,7 +17,7 @@ use crate::{Service, NetworkStatus, NetworkState, error::{self, Error}, DEFAULT_PROTOCOL_ID}; use crate::{SpawnTaskHandle, start_rpc_servers, build_network_future, TransactionPoolAdapter}; use crate::status_sinks; -use crate::config::Configuration; +use crate::config::{Configuration, DatabaseConfig}; use client::{ BlockchainEvents, Client, runtime_api, backend::RemoteBackend, light::blockchain::RemoteBlockchain, @@ -157,15 +157,6 @@ where TGen: RuntimeGenesis, TCSExt: Extension { >, Error> { let keystore = Keystore::open(config.keystore_path.clone(), config.keystore_password.clone())?; - let db_settings = client_db::DatabaseSettings { - cache_size: None, - state_cache_size: config.state_cache_size, - state_cache_child_ratio: - config.state_cache_child_ratio.map(|v| (v, 100)), - path: config.database_path.clone(), - pruning: config.pruning.clone(), - }; - let executor = NativeExecutor::::new( config.wasm_method, config.default_heap_pages, @@ -177,14 +168,32 @@ where TGen: RuntimeGenesis, TCSExt: Extension { .cloned() .unwrap_or_default(); - let (client, backend) = client_db::new_client( - db_settings, - executor, - &config.chain_spec, - fork_blocks, - config.execution_strategies.clone(), - Some(keystore.clone()), - )?; + let (client, backend) = { + let db_config = client_db::DatabaseSettings { + state_cache_size: config.state_cache_size, + state_cache_child_ratio: + config.state_cache_child_ratio.map(|v| (v, 100)), + pruning: config.pruning.clone(), + source: match &config.database { + DatabaseConfig::Path { path, cache_size } => + client_db::DatabaseSettingsSrc::Path { + path: path.clone(), + cache_size: cache_size.clone().map(|u| u as usize), + }, + DatabaseConfig::Custom(db) => + client_db::DatabaseSettingsSrc::Custom(db.clone()), + }, + }; + + client_db::new_client( + db_config, + executor, + &config.chain_spec, + fork_blocks, + config.execution_strategies.clone(), + Some(keystore.clone()), + )? + }; let client = Arc::new(client); @@ -229,21 +238,29 @@ where TGen: RuntimeGenesis, TCSExt: Extension { >, Error> { let keystore = Keystore::open(config.keystore_path.clone(), config.keystore_password.clone())?; - let db_settings = client_db::DatabaseSettings { - cache_size: config.database_cache_size.map(|u| u as usize), - state_cache_size: config.state_cache_size, - state_cache_child_ratio: - config.state_cache_child_ratio.map(|v| (v, 100)), - path: config.database_path.clone(), - pruning: config.pruning.clone(), - }; - let executor = NativeExecutor::::new( config.wasm_method, config.default_heap_pages, ); - let db_storage = client_db::light::LightStorage::new(db_settings)?; + let db_storage = { + let db_settings = client_db::DatabaseSettings { + state_cache_size: config.state_cache_size, + state_cache_child_ratio: + config.state_cache_child_ratio.map(|v| (v, 100)), + pruning: config.pruning.clone(), + source: match &config.database { + DatabaseConfig::Path { path, cache_size } => + client_db::DatabaseSettingsSrc::Path { + path: path.clone(), + cache_size: cache_size.clone().map(|u| u as usize), + }, + DatabaseConfig::Custom(db) => + client_db::DatabaseSettingsSrc::Custom(db.clone()), + }, + }; + client_db::light::LightStorage::new(db_settings)? + }; let light_blockchain = client::light::new_light_blockchain(db_storage); let fetch_checker = Arc::new(client::light::new_fetch_checker(light_blockchain.clone(), executor.clone())); let fetcher = Arc::new(network::OnDemand::new(fetch_checker)); diff --git a/core/service/src/config.rs b/core/service/src/config.rs index 8abef5c572..21acae3cab 100644 --- a/core/service/src/config.rs +++ b/core/service/src/config.rs @@ -17,11 +17,11 @@ //! Service configuration. pub use client::ExecutionStrategies; -pub use client_db::PruningMode; +pub use client_db::{kvdb::KeyValueDB, PruningMode}; pub use network::config::{ExtTransport, NetworkConfiguration, Roles}; pub use substrate_executor::WasmExecutionMethod; -use std::{path::PathBuf, net::SocketAddr}; +use std::{path::PathBuf, net::SocketAddr, sync::Arc}; use transaction_pool; use chain_spec::{ChainSpec, RuntimeGenesis, Extension, NoExtension}; use primitives::crypto::Protected; @@ -45,10 +45,8 @@ pub struct Configuration { pub network: NetworkConfiguration, /// Path to key files. pub keystore_path: PathBuf, - /// Path to the database. - pub database_path: PathBuf, - /// Cache Size for internal database in MiB - pub database_cache_size: Option, + /// Configuration for the database. + pub database: DatabaseConfig, /// Size of internal state cache in Bytes pub state_cache_size: usize, /// Size in percent of cache size dedicated to child tries @@ -100,6 +98,21 @@ pub struct Configuration { pub dev_key_seed: Option, } +/// Configuration of the database of the client. +#[derive(Clone)] +pub enum DatabaseConfig { + /// Database file at a specific path. Recommended for most uses. + Path { + /// Path to the database. + path: PathBuf, + /// Cache Size for internal database in MiB + cache_size: Option, + }, + + /// A custom implementation of an already-open database. + Custom(Arc), +} + impl Configuration where C: Default, G: RuntimeGenesis, @@ -117,8 +130,10 @@ impl Configuration where transaction_pool: Default::default(), network: Default::default(), keystore_path: Default::default(), - database_path: Default::default(), - database_cache_size: Default::default(), + database: DatabaseConfig::Path { + path: Default::default(), + cache_size: Default::default(), + }, state_cache_size: Default::default(), state_cache_child_ratio: Default::default(), custom: Default::default(), diff --git a/core/service/test/src/lib.rs b/core/service/test/src/lib.rs index 28ed5bfdbc..27f03e0963 100644 --- a/core/service/test/src/lib.rs +++ b/core/service/test/src/lib.rs @@ -29,6 +29,7 @@ use service::{ AbstractService, ChainSpec, Configuration, + config::DatabaseConfig, Roles, Error, }; @@ -170,8 +171,10 @@ fn node_config ( network: network_config, keystore_path: root.join("key"), keystore_password: None, - database_path: root.join("db"), - database_cache_size: None, + database: DatabaseConfig::Path { + path: root.join("db"), + cache_size: None + }, state_cache_size: 16777216, state_cache_child_ratio: None, pruning: Default::default(), -- GitLab From 64e9a777882136a18a2df309075838fac067fb1f Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Wed, 30 Oct 2019 20:54:22 +0100 Subject: [PATCH 144/167] Fix compiling substrate-chain-spec for WASM (#3971) * Fix compiling substrate-chain-spec for WASM * Fix tests --- .gitlab-ci.yml | 1 + core/chain-spec/Cargo.toml | 2 +- core/chain-spec/src/extension.rs | 2 +- core/chain-spec/src/lib.rs | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 5cb8db916e..1b944157fe 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -196,6 +196,7 @@ check-web-wasm: - time cargo web build -p sr-io - time cargo web build -p sr-primitives - time cargo web build -p sr-std + - time cargo web build -p substrate-chain-spec - time cargo web build -p substrate-client - time cargo web build -p substrate-consensus-aura - time cargo web build -p substrate-consensus-babe diff --git a/core/chain-spec/Cargo.toml b/core/chain-spec/Cargo.toml index 1a3c56affb..b4d9d004e4 100644 --- a/core/chain-spec/Cargo.toml +++ b/core/chain-spec/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] edition = "2018" [dependencies] -chain-spec-derive = { package = "substrate-chain-spec-derive", path = "./derive" } +substrate-chain-spec-derive = { path = "./derive" } impl-trait-for-tuples = "0.1.2" network = { package = "substrate-network", path = "../../core/network" } primitives = { package = "substrate-primitives", path = "../primitives" } diff --git a/core/chain-spec/src/extension.rs b/core/chain-spec/src/extension.rs index bf98ced04d..e5110a77d5 100644 --- a/core/chain-spec/src/extension.rs +++ b/core/chain-spec/src/extension.rs @@ -253,7 +253,7 @@ impl Extension for Forks where #[cfg(test)] mod tests { use super::*; - use chain_spec_derive::{ChainSpecGroup, ChainSpecExtension}; + use substrate_chain_spec_derive::{ChainSpecGroup, ChainSpecExtension}; // Make the proc macro work for tests and doc tests. use crate as substrate_chain_spec; diff --git a/core/chain-spec/src/lib.rs b/core/chain-spec/src/lib.rs index 705be998b7..8c35c22d9b 100644 --- a/core/chain-spec/src/lib.rs +++ b/core/chain-spec/src/lib.rs @@ -113,7 +113,7 @@ mod extension; pub use chain_spec::{ChainSpec, Properties, NoExtension}; pub use extension::{Group, Fork, Forks, Extension}; -pub use chain_spec_derive::{ChainSpecExtension, ChainSpecGroup}; +pub use substrate_chain_spec_derive::{ChainSpecExtension, ChainSpecGroup}; use serde::{Serialize, de::DeserializeOwned}; use sr_primitives::BuildStorage; -- GitLab From 0865253dd2161fd2e8bbb21cd578dcf70939d2ba Mon Sep 17 00:00:00 2001 From: Denis Pisarev Date: Wed, 30 Oct 2019 23:19:34 +0100 Subject: [PATCH 145/167] retry on gitlab system failures (#3970) * retry on gitlab system failures * test * 5 retries for the most popular project * max is just 2 --- .gitlab-ci.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 1b944157fe..baca78fd3a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -49,6 +49,12 @@ variables: - schedules - web - /^[0-9]+$/ # PRs + retry: + max: 2 + when: + - runner_system_failure + - unknown_failure + - api_failure tags: - linux-docker -- GitLab From efe7add76acc57f9d47f526ab09034c89e0f8c73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 31 Oct 2019 00:19:31 +0100 Subject: [PATCH 146/167] Increase priority of ImOnline heartbeats (#3972) * Make sure im-online reports are high priority. * Bump runtime. --- node/runtime/src/lib.rs | 2 +- srml/im-online/src/lib.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index 4f26143146..9bda317c33 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -82,7 +82,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // implementation changes and behavior does not, then leave spec_version as // is and increment impl_version. spec_version: 190, - impl_version: 190, + impl_version: 191, apis: RUNTIME_API_VERSIONS, }; diff --git a/srml/im-online/src/lib.rs b/srml/im-online/src/lib.rs index aeeaf74dc6..6dcaf1d3ab 100644 --- a/srml/im-online/src/lib.rs +++ b/srml/im-online/src/lib.rs @@ -80,6 +80,7 @@ use sr_primitives::{ traits::{Convert, Member, Printable, Saturating}, Perbill, transaction_validity::{ TransactionValidity, TransactionLongevity, ValidTransaction, InvalidTransaction, + TransactionPriority, }, }; use sr_staking_primitives::{ @@ -532,7 +533,7 @@ impl support::unsigned::ValidateUnsigned for Module { } Ok(ValidTransaction { - priority: 0, + priority: TransactionPriority::max_value(), requires: vec![], provides: vec![(current_session, authority_id).encode()], longevity: TransactionLongevity::max_value(), -- GitLab From 71b2f209cf759ef18bd73c5eb8311e614dde71c5 Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Thu, 31 Oct 2019 09:24:23 +0100 Subject: [PATCH 147/167] Add translate API for storage values (#3947) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add translate item. * fix * doc * fix doc * A test added. * Apply suggestions from code review Co-Authored-By: Bastian Köcher * address suggestion --- srml/support/src/storage/generator/mod.rs | 49 +++++++++++++++++++++ srml/support/src/storage/generator/value.rs | 19 +++++++- srml/support/src/storage/mod.rs | 24 +++++++++- 3 files changed, 90 insertions(+), 2 deletions(-) diff --git a/srml/support/src/storage/generator/mod.rs b/srml/support/src/storage/generator/mod.rs index ab7616158a..1bda791023 100644 --- a/srml/support/src/storage/generator/mod.rs +++ b/srml/support/src/storage/generator/mod.rs @@ -30,3 +30,52 @@ pub use linked_map::{StorageLinkedMap, Enumerator, Linkage}; pub use map::StorageMap; pub use double_map::StorageDoubleMap; pub use value::StorageValue; + + +#[cfg(test)] +#[allow(dead_code)] +mod tests { + use runtime_io::TestExternalities; + use codec::Encode; + use crate::storage::{unhashed, generator::StorageValue}; + + struct Runtime {} + pub trait Trait { + type Origin; + type BlockNumber; + } + + impl Trait for Runtime { + type Origin = u32; + type BlockNumber = u32; + } + + decl_module! { + pub struct Module for enum Call where origin: T::Origin {} + } + + crate::decl_storage! { + trait Store for Module as Runtime { + Value get(fn value) config(): (u64, u64); + } + } + + #[test] + fn value_translate_works() { + let t = GenesisConfig::default().build_storage().unwrap(); + TestExternalities::new(t).execute_with(|| { + // put the old value `1111u32` in the storage. + let key = Value::storage_value_final_key(); + unhashed::put_raw(&key, &1111u32.encode()); + + // translate + let translate_fn = |old: Option| -> Option<(u64, u64)> { + old.map(|o| (o.into(), (o*2).into())) + }; + let _ = Value::translate(translate_fn); + + // new storage should be `(1111, 1111 * 2)` + assert_eq!(Value::get(), (1111, 2222)); + }) + } +} diff --git a/srml/support/src/storage/generator/value.rs b/srml/support/src/storage/generator/value.rs index 8423503dde..5ebc25a70a 100644 --- a/srml/support/src/storage/generator/value.rs +++ b/srml/support/src/storage/generator/value.rs @@ -16,7 +16,7 @@ #[cfg(not(feature = "std"))] use rstd::prelude::*; -use codec::{FullCodec, Encode, EncodeAppend, EncodeLike}; +use codec::{FullCodec, Encode, EncodeAppend, EncodeLike, Decode}; use crate::{storage::{self, unhashed}, hash::{Twox128, StorageHasher}, traits::Len}; /// Generator for `StorageValue` used by `decl_storage`. @@ -60,6 +60,23 @@ impl> storage::StorageValue for G { G::from_optional_value_to_query(value) } + fn translate) -> Option>(f: F) -> Result, ()> { + let key = Self::storage_value_final_key(); + + // attempt to get the length directly. + let maybe_old = match unhashed::get_raw(&key) { + Some(old_data) => Some(O::decode(&mut &old_data[..]).map_err(|_| ())?), + None => None, + }; + let maybe_new = f(maybe_old); + if let Some(new) = maybe_new.as_ref() { + new.using_encoded(|d| unhashed::put_raw(&key, d)); + } else { + unhashed::kill(&key); + } + Ok(maybe_new) + } + fn put>(val: Arg) { unhashed::put(&Self::storage_value_final_key(), &val) } diff --git a/srml/support/src/storage/mod.rs b/srml/support/src/storage/mod.rs index 648009b470..5636d21199 100644 --- a/srml/support/src/storage/mod.rs +++ b/srml/support/src/storage/mod.rs @@ -17,7 +17,7 @@ //! Stuff to do with the runtime's storage. use rstd::prelude::*; -use codec::{FullCodec, FullEncode, Encode, EncodeAppend, EncodeLike}; +use codec::{FullCodec, FullEncode, Encode, EncodeAppend, EncodeLike, Decode}; use crate::traits::Len; #[macro_use] @@ -41,6 +41,28 @@ pub trait StorageValue { /// Load the value from the provided storage instance. fn get() -> Self::Query; + /// Translate a value from some previous type (`O`) to the current type. + /// + /// `f: F` is the translation function. + /// + /// Returns `Err` if the storage item could not be interpreted as the old type, and Ok, along + /// with the new value if it could. + /// + /// NOTE: This operates from and to `Option<_>` types; no effort is made to respect the default + /// value of the original type. + /// + /// # Warning + /// + /// This function must be used with care, before being updated the storage still contains the + /// old type, thus other calls (such as `get`) will fail at decoding it. + /// + /// # Usage + /// + /// This would typically be called inside the module implementation of on_initialize, while + /// ensuring **no usage of this storage are made before the call to `on_initialize`**. (More + /// precisely prior initialized modules doesn't make use of this storage). + fn translate) -> Option>(f: F) -> Result, ()>; + /// Store a value under this key into the provided storage instance. fn put>(val: Arg); -- GitLab From 8a22faac927a48ff8273e8b54e3a984e17c39658 Mon Sep 17 00:00:00 2001 From: Jim Posen Date: Thu, 31 Oct 2019 11:02:29 +0100 Subject: [PATCH 148/167] Create opaque struct for StorageProof. (#3834) Passing around Vec> everywhere is gross and confusing and breaks encapsulation. --- Cargo.lock | 1 + core/authority-discovery/src/lib.rs | 4 +- .../client/src/block_builder/block_builder.rs | 3 +- core/client/src/call_executor.rs | 8 +- core/client/src/cht.rs | 6 +- core/client/src/client.rs | 22 ++-- core/client/src/lib.rs | 2 +- core/client/src/light/call_executor.rs | 24 ++--- core/client/src/light/fetcher.rs | 36 ++++--- core/client/src/runtime_api.rs | 4 +- core/finality-grandpa/Cargo.toml | 1 + core/finality-grandpa/src/finality_proof.rs | 32 +++--- core/finality-grandpa/src/tests.rs | 32 ++++-- core/network/src/chain.rs | 21 ++-- core/network/src/protocol.rs | 12 +-- core/network/src/protocol/light_dispatch.rs | 34 +++--- core/network/src/protocol/message.rs | 11 +- core/sr-api-macros/src/impl_runtime_apis.rs | 12 ++- core/state-machine/src/lib.rs | 22 ++-- core/state-machine/src/proving_backend.rs | 100 ++++++++++++++++-- 20 files changed, 246 insertions(+), 141 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 75a1b797b0..a7d9628b6b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5256,6 +5256,7 @@ dependencies = [ "substrate-keystore 2.0.0", "substrate-network 2.0.0", "substrate-primitives 2.0.0", + "substrate-state-machine 2.0.0", "substrate-telemetry 2.0.0", "substrate-test-runtime-client 2.0.0", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/core/authority-discovery/src/lib.rs b/core/authority-discovery/src/lib.rs index 987169ead9..8e2663d210 100644 --- a/core/authority-discovery/src/lib.rs +++ b/core/authority-discovery/src/lib.rs @@ -44,7 +44,7 @@ //! 4. Adds the retrieved external addresses as priority nodes to the peerset. use authority_discovery_primitives::{AuthorityDiscoveryApi, AuthorityId, Signature}; -use client::blockchain::HeaderBackend; +use client::{blockchain::HeaderBackend, runtime_api::StorageProof}; use error::{Error, Result}; use futures::{prelude::*, sync::mpsc::Receiver}; use log::{debug, error, log_enabled, warn}; @@ -528,7 +528,7 @@ mod tests { unimplemented!("Not required for testing!") } - fn extract_proof(&mut self) -> Option>> { + fn extract_proof(&mut self) -> Option { unimplemented!("Not required for testing!") } } diff --git a/core/client/src/block_builder/block_builder.rs b/core/client/src/block_builder/block_builder.rs index 08711469e9..f5cd6a9f66 100644 --- a/core/client/src/block_builder/block_builder.rs +++ b/core/client/src/block_builder/block_builder.rs @@ -22,6 +22,7 @@ use sr_primitives::traits::{ Header as HeaderT, Hash, Block as BlockT, One, HashFor, ProvideRuntimeApi, ApiRef, DigestFor, }; use primitives::{H256, ExecutionContext}; +use state_machine::StorageProof; use crate::blockchain::HeaderBackend; use crate::runtime_api::{Core, ApiExt}; use crate::error; @@ -140,7 +141,7 @@ where /// /// The proof will be `Some(_)`, if proof recording was enabled while creating /// the block builder. - pub fn bake_and_extract_proof(mut self) -> error::Result<(Block, Option>>)> { + pub fn bake_and_extract_proof(mut self) -> error::Result<(Block, Option)> { self.bake_impl()?; let proof = self.api.extract_proof(); diff --git a/core/client/src/call_executor.rs b/core/client/src/call_executor.rs index 05a2a8eba1..e634fcf8fa 100644 --- a/core/client/src/call_executor.rs +++ b/core/client/src/call_executor.rs @@ -21,7 +21,7 @@ use sr_primitives::{ }; use state_machine::{ self, OverlayedChanges, Ext, ExecutionManager, StateMachine, ExecutionStrategy, - backend::Backend as _, ChangesTrieTransaction, + backend::Backend as _, ChangesTrieTransaction, StorageProof, }; use executor::{RuntimeVersion, RuntimeInfo, NativeVersion}; use hash_db::Hasher; @@ -127,7 +127,7 @@ where overlay: &mut OverlayedChanges, method: &str, call_data: &[u8] - ) -> Result<(Vec, Vec>), error::Error> { + ) -> Result<(Vec, StorageProof), error::Error> { let trie_state = state.as_trie_backend() .ok_or_else(|| Box::new(state_machine::ExecutionError::UnableToGenerateProof) @@ -145,7 +145,7 @@ where overlay: &mut OverlayedChanges, method: &str, call_data: &[u8] - ) -> Result<(Vec, Vec>), error::Error>; + ) -> Result<(Vec, StorageProof), error::Error>; /// Get runtime version if supported. fn native_runtime_version(&self) -> Option<&NativeVersion>; @@ -377,7 +377,7 @@ where overlay: &mut OverlayedChanges, method: &str, call_data: &[u8] - ) -> Result<(Vec, Vec>), error::Error> { + ) -> Result<(Vec, StorageProof), error::Error> { state_machine::prove_execution_on_trie_backend( trie_state, overlay, diff --git a/core/client/src/cht.rs b/core/client/src/cht.rs index 63a5b39c26..aff875032d 100644 --- a/core/client/src/cht.rs +++ b/core/client/src/cht.rs @@ -30,7 +30,7 @@ use trie; use primitives::{H256, convert_hash}; use sr_primitives::traits::{Header as HeaderT, SimpleArithmetic, Zero, One}; use state_machine::backend::InMemory as InMemoryState; -use state_machine::{MemoryDB, TrieBackend, Backend as StateBackend, +use state_machine::{MemoryDB, TrieBackend, Backend as StateBackend, StorageProof, prove_read_on_trie_backend, read_proof_check, read_proof_check_on_proving_backend}; use crate::error::{Error as ClientError, Result as ClientResult}; @@ -88,7 +88,7 @@ pub fn build_proof( cht_num: Header::Number, blocks: BlocksI, hashes: HashesI -) -> ClientResult>> +) -> ClientResult where Header: HeaderT, Hasher: hash_db::Hasher, @@ -114,7 +114,7 @@ pub fn check_proof( local_root: Header::Hash, local_number: Header::Number, remote_hash: Header::Hash, - remote_proof: Vec> + remote_proof: StorageProof, ) -> ClientResult<()> where Header: HeaderT, diff --git a/core/client/src/client.rs b/core/client/src/client.rs index 56a495e683..71d6e4f01d 100644 --- a/core/client/src/client.rs +++ b/core/client/src/client.rs @@ -43,7 +43,7 @@ use state_machine::{ DBValue, Backend as StateBackend, ChangesTrieAnchorBlockId, ExecutionStrategy, ExecutionManager, prove_read, prove_child_read, ChangesTrieRootsStorage, ChangesTrieStorage, ChangesTrieTransaction, ChangesTrieConfigurationRange, key_changes, key_changes_proof, - OverlayedChanges, BackendTrustLevel, + OverlayedChanges, BackendTrustLevel, StorageProof, merge_storage_proofs, }; use executor::{RuntimeVersion, RuntimeInfo}; use consensus::{ @@ -421,7 +421,7 @@ impl Client where } /// Reads storage value at a given block + key, returning read proof. - pub fn read_proof(&self, id: &BlockId, keys: I) -> error::Result>> where + pub fn read_proof(&self, id: &BlockId, keys: I) -> error::Result where I: IntoIterator, I::Item: AsRef<[u8]>, { @@ -437,7 +437,7 @@ impl Client where id: &BlockId, storage_key: &[u8], keys: I, - ) -> error::Result>> where + ) -> error::Result where I: IntoIterator, I::Item: AsRef<[u8]>, { @@ -454,14 +454,14 @@ impl Client where id: &BlockId, method: &str, call_data: &[u8] - ) -> error::Result<(Vec, Vec>)> { + ) -> error::Result<(Vec, StorageProof)> { let state = self.state_at(id)?; let header = self.prepare_environment_block(id)?; prove_execution(state, header, &self.executor, method, call_data) } /// Reads given header and generates CHT-based header proof. - pub fn header_proof(&self, id: &BlockId) -> error::Result<(Block::Header, Vec>)> { + pub fn header_proof(&self, id: &BlockId) -> error::Result<(Block::Header, StorageProof)> { self.header_proof_with_cht_size(id, cht::size()) } @@ -477,7 +477,7 @@ impl Client where &self, id: &BlockId, cht_size: NumberFor, - ) -> error::Result<(Block::Header, Vec>)> { + ) -> error::Result<(Block::Header, StorageProof)> { let proof_error = || error::Error::Backend(format!("Failed to generate header proof for {:?}", id)); let header = self.backend.blockchain().expect_header(*id)?; let block_num = *header.number(); @@ -696,18 +696,18 @@ impl Client where &self, cht_size: NumberFor, blocks: I - ) -> error::Result>> { + ) -> error::Result { // most probably we have touched several changes tries that are parts of the single CHT // => GroupBy changes tries by CHT number and then gather proof for the whole group at once - let mut proof = HashSet::new(); + let mut proofs = Vec::new(); cht::for_each_cht_group::(cht_size, blocks, |_, cht_num, cht_blocks| { let cht_proof = self.changes_trie_roots_proof_at_cht(cht_size, cht_num, cht_blocks)?; - proof.extend(cht_proof); + proofs.push(cht_proof); Ok(()) }, ())?; - Ok(proof.into_iter().collect()) + Ok(merge_storage_proofs(proofs)) } /// Generates CHT-based proof for roots of changes tries at given blocks (that are part of single CHT). @@ -716,7 +716,7 @@ impl Client where cht_size: NumberFor, cht_num: NumberFor, blocks: Vec> - ) -> error::Result>> { + ) -> error::Result { let cht_start = cht::start_number(cht_size, cht_num); let mut current_num = cht_start; let cht_range = ::std::iter::from_fn(|| { diff --git a/core/client/src/lib.rs b/core/client/src/lib.rs index 5a2cb746f3..57147eb18b 100644 --- a/core/client/src/lib.rs +++ b/core/client/src/lib.rs @@ -122,7 +122,7 @@ pub use crate::client::{ #[cfg(feature = "std")] pub use crate::notifications::{StorageEventStream, StorageChangeSet}; #[cfg(feature = "std")] -pub use state_machine::ExecutionStrategy; +pub use state_machine::{ExecutionStrategy, StorageProof}; #[cfg(feature = "std")] pub use crate::leaves::LeafSet; #[cfg(feature = "std")] diff --git a/core/client/src/light/call_executor.rs b/core/client/src/light/call_executor.rs index 65776bcfe0..7f54004ae6 100644 --- a/core/client/src/light/call_executor.rs +++ b/core/client/src/light/call_executor.rs @@ -16,10 +16,7 @@ //! Methods that light client could use to execute runtime calls. -use std::{ - collections::HashSet, sync::Arc, panic::UnwindSafe, result, - cell::RefCell, rc::Rc, -}; +use std::{sync::Arc, panic::UnwindSafe, result, cell::RefCell, rc::Rc}; use codec::{Encode, Decode}; use primitives::{ @@ -31,7 +28,8 @@ use sr_primitives::{ }; use state_machine::{ self, Backend as StateBackend, OverlayedChanges, ExecutionStrategy, create_proof_check_backend, - execution_proof_check_on_trie_backend, ExecutionManager, ChangesTrieTransaction, + execution_proof_check_on_trie_backend, ExecutionManager, ChangesTrieTransaction, StorageProof, + merge_storage_proofs, }; use hash_db::Hasher; @@ -179,7 +177,7 @@ impl CallExecutor for _changes: &mut OverlayedChanges, _method: &str, _call_data: &[u8] - ) -> ClientResult<(Vec, Vec>)> { + ) -> ClientResult<(Vec, StorageProof)> { Err(ClientError::NotAvailableOnLightClient) } @@ -198,7 +196,7 @@ pub fn prove_execution( executor: &E, method: &str, call_data: &[u8], -) -> ClientResult<(Vec, Vec>)> +) -> ClientResult<(Vec, StorageProof)> where Block: BlockT, S: StateBackend, @@ -218,11 +216,7 @@ pub fn prove_execution( // execute method + record execution proof let (result, exec_proof) = executor.prove_at_trie_state(&trie_state, &mut changes, method, call_data)?; - let total_proof = init_proof.into_iter() - .chain(exec_proof.into_iter()) - .collect::>() - .into_iter() - .collect(); + let total_proof = merge_storage_proofs(vec![init_proof, exec_proof]); Ok((result, total_proof)) } @@ -234,7 +228,7 @@ pub fn prove_execution( pub fn check_execution_proof( executor: &E, request: &RemoteCallRequest

, - remote_proof: Vec>, + remote_proof: StorageProof, ) -> ClientResult> where Header: HeaderT, @@ -258,7 +252,7 @@ pub fn check_execution_proof( fn check_execution_proof_with_make_header Header>( executor: &E, request: &RemoteCallRequest
, - remote_proof: Vec>, + remote_proof: StorageProof, make_next_header: MakeNextHeader, ) -> ClientResult> where @@ -382,7 +376,7 @@ mod tests { _overlay: &mut OverlayedChanges, _method: &str, _call_data: &[u8] - ) -> Result<(Vec, Vec>), ClientError> { + ) -> Result<(Vec, StorageProof), ClientError> { unreachable!() } diff --git a/core/client/src/light/fetcher.rs b/core/client/src/light/fetcher.rs index dbf6d41c38..6ae28b748c 100644 --- a/core/client/src/light/fetcher.rs +++ b/core/client/src/light/fetcher.rs @@ -33,6 +33,7 @@ use state_machine::{ TrieBackend, read_proof_check, key_changes_proof_check, create_proof_check_backend_storage, read_child_proof_check, }; +pub use state_machine::StorageProof; use crate::cht; use crate::error::{Error as ClientError, Result as ClientResult}; @@ -129,7 +130,7 @@ pub struct ChangesProof { pub roots: BTreeMap, /// The proofs for all changes tries roots that have been touched AND are /// missing from the requester' node. It is a map of CHT number => proof. - pub roots_proof: Vec>, + pub roots_proof: StorageProof, } /// Remote block body request @@ -186,25 +187,25 @@ pub trait FetchChecker: Send + Sync { &self, request: &RemoteHeaderRequest, header: Option, - remote_proof: Vec> + remote_proof: StorageProof, ) -> ClientResult; /// Check remote storage read proof. fn check_read_proof( &self, request: &RemoteReadRequest, - remote_proof: Vec> + remote_proof: StorageProof, ) -> ClientResult, Option>>>; /// Check remote storage read proof. fn check_read_child_proof( &self, request: &RemoteReadChildRequest, - remote_proof: Vec> + remote_proof: StorageProof, ) -> ClientResult, Option>>>; /// Check remote method execution proof. fn check_execution_proof( &self, request: &RemoteCallRequest, - remote_proof: Vec> + remote_proof: StorageProof, ) -> ClientResult>; /// Check remote changes query proof. fn check_changes_proof( @@ -318,7 +319,7 @@ impl> LightDataChecker { &self, cht_size: NumberFor, remote_roots: &BTreeMap, B::Hash>, - remote_roots_proof: Vec>, + remote_roots_proof: StorageProof, ) -> ClientResult<()> where H: Hasher, @@ -378,7 +379,7 @@ impl FetchChecker for LightDataChecker &self, request: &RemoteHeaderRequest, remote_header: Option, - remote_proof: Vec> + remote_proof: StorageProof, ) -> ClientResult { let remote_header = remote_header.ok_or_else(|| ClientError::from(ClientError::InvalidCHTProof))?; @@ -394,7 +395,7 @@ impl FetchChecker for LightDataChecker fn check_read_proof( &self, request: &RemoteReadRequest, - remote_proof: Vec>, + remote_proof: StorageProof, ) -> ClientResult, Option>>> { read_proof_check::( convert_hash(request.header.state_root()), @@ -406,7 +407,7 @@ impl FetchChecker for LightDataChecker fn check_read_child_proof( &self, request: &RemoteReadChildRequest, - remote_proof: Vec> + remote_proof: StorageProof, ) -> ClientResult, Option>>> { read_child_proof_check::( convert_hash(request.header.state_root()), @@ -419,7 +420,7 @@ impl FetchChecker for LightDataChecker fn check_execution_proof( &self, request: &RemoteCallRequest, - remote_proof: Vec> + remote_proof: StorageProof, ) -> ClientResult> { check_execution_proof::<_, _, H>(&self.executor, request, remote_proof) } @@ -572,7 +573,7 @@ pub mod tests { NativeExecutor::new(WasmExecutionMethod::Interpreted, None) } - fn prepare_for_read_proof_check() -> (TestChecker, Header, Vec>, u32) { + fn prepare_for_read_proof_check() -> (TestChecker, Header, StorageProof, u32) { // prepare remote client let remote_client = test_client::new(); let remote_block_id = BlockId::Number(0); @@ -606,7 +607,7 @@ pub mod tests { (local_checker, remote_block_header, remote_read_proof, heap_pages) } - fn prepare_for_read_child_proof_check() -> (TestChecker, Header, Vec>, Vec) { + fn prepare_for_read_child_proof_check() -> (TestChecker, Header, StorageProof, Vec) { use test_client::DefaultTestClientBuilderExt; use test_client::TestClientBuilderExt; // prepare remote client @@ -648,7 +649,7 @@ pub mod tests { (local_checker, remote_block_header, remote_read_proof, child_value) } - fn prepare_for_header_proof_check(insert_cht: bool) -> (TestChecker, Hash, Header, Vec>) { + fn prepare_for_header_proof_check(insert_cht: bool) -> (TestChecker, Hash, Header, StorageProof) { // prepare remote client let remote_client = test_client::new(); let mut local_headers_hashes = Vec::new(); @@ -899,13 +900,13 @@ pub mod tests { max_block: remote_proof.max_block, proof: remote_proof.proof.clone(), roots: vec![(begin - 1, Default::default())].into_iter().collect(), - roots_proof: vec![], + roots_proof: StorageProof::empty(), }).is_err()); assert!(local_checker.check_changes_proof(&request, ChangesProof { max_block: remote_proof.max_block, proof: remote_proof.proof.clone(), roots: vec![(end + 1, Default::default())].into_iter().collect(), - roots_proof: vec![], + roots_proof: StorageProof::empty(), }).is_err()); } @@ -945,7 +946,10 @@ pub mod tests { Arc::new(DummyBlockchain::new(local_storage)), local_executor(), ); - assert!(local_checker.check_changes_tries_proof(4, &remote_proof.roots, vec![]).is_err()); + let result = local_checker.check_changes_tries_proof( + 4, &remote_proof.roots, StorageProof::empty() + ); + assert!(result.is_err()); } #[test] diff --git a/core/client/src/runtime_api.rs b/core/client/src/runtime_api.rs index 68b49e5910..0fa0545dae 100644 --- a/core/client/src/runtime_api.rs +++ b/core/client/src/runtime_api.rs @@ -18,7 +18,7 @@ #[doc(hidden)] #[cfg(feature = "std")] -pub use state_machine::OverlayedChanges; +pub use state_machine::{OverlayedChanges, StorageProof}; #[doc(hidden)] #[cfg(feature = "std")] pub use primitives::NativeOrEncoded; @@ -106,7 +106,7 @@ pub trait ApiExt { /// Extract the recorded proof. /// This stops the proof recording. - fn extract_proof(&mut self) -> Option>>; + fn extract_proof(&mut self) -> Option; } /// Before calling any runtime api function, the runtime need to be initialized diff --git a/core/finality-grandpa/Cargo.toml b/core/finality-grandpa/Cargo.toml index 84178c8a78..a4c6a0278a 100644 --- a/core/finality-grandpa/Cargo.toml +++ b/core/finality-grandpa/Cargo.toml @@ -34,6 +34,7 @@ network = { package = "substrate-network", path = "../network", features = ["tes keyring = { package = "substrate-keyring", path = "../keyring" } test-client = { package = "substrate-test-runtime-client", path = "../test-runtime/client"} babe_primitives = { package = "substrate-consensus-babe-primitives", path = "../consensus/babe/primitives" } +state_machine = { package = "substrate-state-machine", path = "../state-machine" } env_logger = "0.7.0" tokio = "0.1.22" tempfile = "3.1.0" diff --git a/core/finality-grandpa/src/finality_proof.rs b/core/finality-grandpa/src/finality_proof.rs index da5732f2f6..bd22a7bbac 100644 --- a/core/finality-grandpa/src/finality_proof.rs +++ b/core/finality-grandpa/src/finality_proof.rs @@ -40,7 +40,7 @@ use log::{trace, warn}; use client::{ backend::Backend, blockchain::Backend as BlockchainBackend, CallExecutor, Client, error::{Error as ClientError, Result as ClientResult}, - light::fetcher::{FetchChecker, RemoteCallRequest}, ExecutionStrategy, + light::fetcher::{FetchChecker, RemoteCallRequest, StorageProof}, ExecutionStrategy, }; use codec::{Encode, Decode}; use grandpa::BlockNumberOps; @@ -62,7 +62,7 @@ pub trait AuthoritySetForFinalityProver: Send + Sync { /// Call GrandpaApi::grandpa_authorities at given block. fn authorities(&self, block: &BlockId) -> ClientResult>; /// Prove call of GrandpaApi::grandpa_authorities at given block. - fn prove_authorities(&self, block: &BlockId) -> ClientResult>>; + fn prove_authorities(&self, block: &BlockId) -> ClientResult; } /// Client-based implementation of AuthoritySetForFinalityProver. @@ -85,7 +85,7 @@ impl, RA> AuthoritySetForFinalityProver fo ))) } - fn prove_authorities(&self, block: &BlockId) -> ClientResult>> { + fn prove_authorities(&self, block: &BlockId) -> ClientResult { self.execution_proof(block, "GrandpaApi_grandpa_authorities",&[]).map(|(_, proof)| proof) } } @@ -97,7 +97,7 @@ pub trait AuthoritySetForFinalityChecker: Send + Sync { &self, hash: Block::Hash, header: Block::Header, - proof: Vec>, + proof: StorageProof, ) -> ClientResult>; } @@ -107,7 +107,7 @@ impl AuthoritySetForFinalityChecker for Arc>, + proof: StorageProof, ) -> ClientResult> { let request = RemoteCallRequest { block: hash, @@ -207,7 +207,7 @@ struct FinalityProofFragment { /// The set of headers in the range (U; F] that we believe are unknown to the caller. Ordered. pub unknown_headers: Vec
, /// Optional proof of execution of GRANDPA::authorities(). - pub authorities_proof: Option>>, + pub authorities_proof: Option, } /// Proof of finality is the ordered set of finality fragments, where: @@ -582,13 +582,13 @@ pub(crate) mod tests { impl AuthoritySetForFinalityProver for (GetAuthorities, ProveAuthorities) where GetAuthorities: Send + Sync + Fn(BlockId) -> ClientResult>, - ProveAuthorities: Send + Sync + Fn(BlockId) -> ClientResult>>, + ProveAuthorities: Send + Sync + Fn(BlockId) -> ClientResult, { fn authorities(&self, block: &BlockId) -> ClientResult> { self.0(*block) } - fn prove_authorities(&self, block: &BlockId) -> ClientResult>> { + fn prove_authorities(&self, block: &BlockId) -> ClientResult { self.1(*block) } } @@ -597,13 +597,13 @@ pub(crate) mod tests { impl AuthoritySetForFinalityChecker for ClosureAuthoritySetForFinalityChecker where - Closure: Send + Sync + Fn(H256, Header, Vec>) -> ClientResult>, + Closure: Send + Sync + Fn(H256, Header, StorageProof) -> ClientResult>, { fn check_authorities_proof( &self, hash: H256, header: Header, - proof: Vec>, + proof: StorageProof, ) -> ClientResult> { self.0(hash, header, proof) } @@ -824,8 +824,8 @@ pub(crate) mod tests { _ => unreachable!("no other authorities should be fetched: {:?}", block_id), }, |block_id| match block_id { - BlockId::Number(4) => Ok(vec![vec![40]]), - BlockId::Number(6) => Ok(vec![vec![60]]), + BlockId::Number(4) => Ok(StorageProof::new(vec![vec![40]])), + BlockId::Number(6) => Ok(StorageProof::new(vec![vec![60]])), _ => unreachable!("no other authorities should be proved: {:?}", block_id), }, ), @@ -841,14 +841,14 @@ pub(crate) mod tests { block: header(5).hash(), justification: just5, unknown_headers: Vec::new(), - authorities_proof: Some(vec![vec![40]]), + authorities_proof: Some(StorageProof::new(vec![vec![40]])), }, // last fragment provides justification for #7 && unknown#7 FinalityProofFragment { block: header(7).hash(), justification: just7, unknown_headers: vec![header(7)], - authorities_proof: Some(vec![vec![60]]), + authorities_proof: Some(StorageProof::new(vec![vec![60]])), }, ]); } @@ -895,7 +895,7 @@ pub(crate) mod tests { block: header(4).hash(), justification: TestJustification(true, vec![7]).encode(), unknown_headers: vec![header(4)], - authorities_proof: Some(vec![vec![42]]), + authorities_proof: Some(StorageProof::new(vec![vec![42]])), }, FinalityProofFragment { block: header(5).hash(), justification: TestJustification(true, vec![8]).encode(), @@ -942,7 +942,7 @@ pub(crate) mod tests { block: header(2).hash(), justification: TestJustification(true, vec![7]).encode(), unknown_headers: Vec::new(), - authorities_proof: Some(vec![vec![42]]), + authorities_proof: Some(StorageProof::new(vec![vec![42]])), }, FinalityProofFragment { block: header(4).hash(), justification: TestJustification(true, vec![8]).encode(), diff --git a/core/finality-grandpa/src/tests.rs b/core/finality-grandpa/src/tests.rs index 3917374171..2339379a60 100644 --- a/core/finality-grandpa/src/tests.rs +++ b/core/finality-grandpa/src/tests.rs @@ -27,7 +27,7 @@ use tokio::runtime::current_thread; use keyring::Ed25519Keyring; use client::{ error::Result, - runtime_api::{Core, RuntimeVersion, ApiExt}, + runtime_api::{Core, RuntimeVersion, ApiExt, StorageProof}, LongestChain, }; use test_client::{self, runtime::BlockNumber}; @@ -40,6 +40,7 @@ use sr_primitives::traits::{ApiRef, ProvideRuntimeApi, Header as HeaderT}; use sr_primitives::generic::{BlockId, DigestItem}; use primitives::{NativeOrEncoded, ExecutionContext, crypto::Public}; use fg_primitives::{GRANDPA_ENGINE_ID, AuthorityId}; +use state_machine::{backend::InMemory, prove_read, read_proof_check}; use authorities::AuthoritySet; use finality_proof::{FinalityProofProvider, AuthoritySetForFinalityProver, AuthoritySetForFinalityChecker}; @@ -258,7 +259,7 @@ impl ApiExt for RuntimeApi { unimplemented!("Not required for testing!") } - fn extract_proof(&mut self) -> Option>> { + fn extract_proof(&mut self) -> Option { unimplemented!("Not required for testing!") } } @@ -285,8 +286,14 @@ impl AuthoritySetForFinalityProver for TestApi { }) } - fn prove_authorities(&self, block: &BlockId) -> Result>> { - self.authorities(block).map(|auth| vec![auth.encode()]) + fn prove_authorities(&self, block: &BlockId) -> Result { + let authorities = self.authorities(block)?; + let backend = >::from(vec![ + (None, b"authorities".to_vec(), Some(authorities.encode())) + ]); + let proof = prove_read(backend, vec![b"authorities"]) + .expect("failure proving read from in-memory storage backend"); + Ok(proof) } } @@ -294,11 +301,20 @@ impl AuthoritySetForFinalityChecker for TestApi { fn check_authorities_proof( &self, _hash: ::Hash, - _header: ::Header, - proof: Vec>, + header: ::Header, + proof: StorageProof, ) -> Result> { - Decode::decode(&mut &proof[0][..]) - .map_err(|_| unreachable!("incorrect value is passed as GRANDPA authorities proof")) + let results = read_proof_check::( + *header.state_root(), proof, vec![b"authorities"] + ) + .expect("failure checking read proof for authorities"); + let encoded = results.get(&b"authorities"[..]) + .expect("returned map must contain all proof keys") + .as_ref() + .expect("authorities in proof is None"); + let authorities = Decode::decode(&mut &encoded[..]) + .expect("failure decoding authorities read from proof"); + Ok(authorities) } } diff --git a/core/network/src/chain.rs b/core/network/src/chain.rs index f68942fd96..2b32c07009 100644 --- a/core/network/src/chain.rs +++ b/core/network/src/chain.rs @@ -18,7 +18,7 @@ use client::{self, Client as SubstrateClient, ClientInfo, CallExecutor}; use client::error::Error; -use client::light::fetcher::ChangesProof; +use client::light::fetcher::{ChangesProof, StorageProof}; use consensus::{BlockImport, BlockStatus, Error as ConsensusError}; use sr_primitives::traits::{Block as BlockT, Header as HeaderT}; use sr_primitives::generic::{BlockId}; @@ -46,10 +46,11 @@ pub trait Client: Send + Sync { fn justification(&self, id: &BlockId) -> Result, Error>; /// Get block header proof. - fn header_proof(&self, block_number: ::Number) -> Result<(Block::Header, Vec>), Error>; + fn header_proof(&self, block_number: ::Number) + -> Result<(Block::Header, StorageProof), Error>; /// Get storage read execution proof. - fn read_proof(&self, block: &Block::Hash, keys: &[Vec]) -> Result>, Error>; + fn read_proof(&self, block: &Block::Hash, keys: &[Vec]) -> Result; /// Get child storage read execution proof. fn read_child_proof( @@ -57,10 +58,10 @@ pub trait Client: Send + Sync { block: &Block::Hash, storage_key: &[u8], keys: &[Vec], - ) -> Result>, Error>; + ) -> Result; /// Get method execution proof. - fn execution_proof(&self, block: &Block::Hash, method: &str, data: &[u8]) -> Result<(Vec, Vec>), Error>; + fn execution_proof(&self, block: &Block::Hash, method: &str, data: &[u8]) -> Result<(Vec, StorageProof), Error>; /// Get key changes proof. fn key_changes_proof( @@ -120,11 +121,13 @@ impl Client for SubstrateClient where (self as &SubstrateClient).justification(id) } - fn header_proof(&self, block_number: ::Number) -> Result<(Block::Header, Vec>), Error> { + fn header_proof(&self, block_number: ::Number) + -> Result<(Block::Header, StorageProof), Error> + { (self as &SubstrateClient).header_proof(&BlockId::Number(block_number)) } - fn read_proof(&self, block: &Block::Hash, keys: &[Vec]) -> Result>, Error> { + fn read_proof(&self, block: &Block::Hash, keys: &[Vec]) -> Result { (self as &SubstrateClient).read_proof(&BlockId::Hash(block.clone()), keys) } @@ -133,12 +136,12 @@ impl Client for SubstrateClient where block: &Block::Hash, storage_key: &[u8], keys: &[Vec], - ) -> Result>, Error> { + ) -> Result { (self as &SubstrateClient) .read_child_proof(&BlockId::Hash(block.clone()), storage_key, keys) } - fn execution_proof(&self, block: &Block::Hash, method: &str, data: &[u8]) -> Result<(Vec, Vec>), Error> { + fn execution_proof(&self, block: &Block::Hash, method: &str, data: &[u8]) -> Result<(Vec, StorageProof), Error> { (self as &SubstrateClient).execution_proof(&BlockId::Hash(block.clone()), method, data) } diff --git a/core/network/src/protocol.rs b/core/network/src/protocol.rs index 2e036cf118..476113953b 100644 --- a/core/network/src/protocol.rs +++ b/core/network/src/protocol.rs @@ -48,7 +48,7 @@ use std::sync::Arc; use std::{cmp, num::NonZeroUsize, time}; use log::{trace, debug, warn, error}; use crate::chain::{Client, FinalityProofProvider}; -use client::light::fetcher::{FetchChecker, ChangesProof}; +use client::light::fetcher::{FetchChecker, ChangesProof, StorageProof}; use crate::error; use util::LruHashSet; @@ -1226,7 +1226,7 @@ impl, H: ExHashT> Protocol { error ); self.peerset_handle.report_peer(who.clone(), RPC_FAILED_REPUTATION_CHANGE); - Default::default() + StorageProof::empty() } }; @@ -1343,7 +1343,7 @@ impl, H: ExHashT> Protocol { request.block, error ); - Default::default() + StorageProof::empty() } }; self.send_message( @@ -1386,7 +1386,7 @@ impl, H: ExHashT> Protocol { request.block, error ); - Default::default() + StorageProof::empty() } }; self.send_message( @@ -1426,7 +1426,7 @@ impl, H: ExHashT> Protocol { request.block, error ); - (Default::default(), Default::default()) + (Default::default(), StorageProof::empty()) } }; self.send_message( @@ -1495,7 +1495,7 @@ impl, H: ExHashT> Protocol { max_block: Zero::zero(), proof: vec![], roots: BTreeMap::new(), - roots_proof: vec![], + roots_proof: StorageProof::empty(), } } }; diff --git a/core/network/src/protocol/light_dispatch.rs b/core/network/src/protocol/light_dispatch.rs index 33ff23c909..3c0185da87 100644 --- a/core/network/src/protocol/light_dispatch.rs +++ b/core/network/src/protocol/light_dispatch.rs @@ -28,7 +28,7 @@ use linked_hash_map::{Entry, LinkedHashMap}; use client::error::Error as ClientError; use client::light::fetcher::{FetchChecker, RemoteHeaderRequest, RemoteCallRequest, RemoteReadRequest, RemoteChangesRequest, ChangesProof, - RemoteReadChildRequest, RemoteBodyRequest}; + RemoteReadChildRequest, RemoteBodyRequest, StorageProof}; use crate::message::{self, BlockAttributes, Direction, FromBlock, RequestId}; use libp2p::PeerId; use crate::config::Roles; @@ -174,7 +174,7 @@ impl FetchChecker for AlwaysBadChecker { &self, _request: &RemoteHeaderRequest, _remote_header: Option, - _remote_proof: Vec> + _remote_proof: StorageProof, ) -> Result { Err(ClientError::Msg("AlwaysBadChecker".into())) } @@ -182,7 +182,7 @@ impl FetchChecker for AlwaysBadChecker { fn check_read_proof( &self, _request: &RemoteReadRequest, - _remote_proof: Vec> + _remote_proof: StorageProof, ) -> Result,Option>>, ClientError> { Err(ClientError::Msg("AlwaysBadChecker".into())) } @@ -190,7 +190,7 @@ impl FetchChecker for AlwaysBadChecker { fn check_read_child_proof( &self, _request: &RemoteReadChildRequest, - _remote_proof: Vec> + _remote_proof: StorageProof, ) -> Result, Option>>, ClientError> { Err(ClientError::Msg("AlwaysBadChecker".into())) } @@ -198,7 +198,7 @@ impl FetchChecker for AlwaysBadChecker { fn check_execution_proof( &self, _request: &RemoteCallRequest, - _remote_proof: Vec> + _remote_proof: StorageProof, ) -> Result, ClientError> { Err(ClientError::Msg("AlwaysBadChecker".into())) } @@ -684,7 +684,7 @@ pub mod tests { use crate::config::Roles; use crate::message::{self, BlockAttributes, Direction, FromBlock, RequestId}; use libp2p::PeerId; - use super::{REQUEST_TIMEOUT, LightDispatch, LightDispatchNetwork, RequestData}; + use super::{REQUEST_TIMEOUT, LightDispatch, LightDispatchNetwork, RequestData, StorageProof}; use test_client::runtime::{changes_trie_config, Block, Extrinsic, Header}; struct DummyFetchChecker { ok: bool } @@ -694,7 +694,7 @@ pub mod tests { &self, _request: &RemoteHeaderRequest
, header: Option
, - _remote_proof: Vec> + _remote_proof: StorageProof, ) -> ClientResult
{ match self.ok { true if header.is_some() => Ok(header.unwrap()), @@ -705,7 +705,7 @@ pub mod tests { fn check_read_proof( &self, request: &RemoteReadRequest
, - _: Vec>, + _: StorageProof, ) -> ClientResult, Option>>> { match self.ok { true => Ok(request.keys @@ -721,7 +721,7 @@ pub mod tests { fn check_read_child_proof( &self, request: &RemoteReadChildRequest
, - _: Vec> + _: StorageProof, ) -> ClientResult, Option>>> { match self.ok { true => Ok(request.keys @@ -734,7 +734,7 @@ pub mod tests { } } - fn check_execution_proof(&self, _: &RemoteCallRequest
, _: Vec>) -> ClientResult> { + fn check_execution_proof(&self, _: &RemoteCallRequest
, _: StorageProof) -> ClientResult> { match self.ok { true => Ok(vec![42]), false => Err(ClientError::Backend("Test error".into())), @@ -780,7 +780,7 @@ pub mod tests { ) { light_dispatch.on_remote_call_response(network_interface, peer, message::RemoteCallResponse { id: id, - proof: vec![vec![2]], + proof: StorageProof::empty(), }); } @@ -943,7 +943,7 @@ pub mod tests { light_dispatch.on_remote_read_response(&mut network_interface, peer0.clone(), message::RemoteReadResponse { id: 0, - proof: vec![vec![2]], + proof: StorageProof::empty(), }); assert_disconnected_peer(&network_interface); assert_eq!(light_dispatch.pending_requests.len(), 1); @@ -1013,7 +1013,7 @@ pub mod tests { light_dispatch.on_remote_read_response(&mut network_interface, peer0.clone(), message::RemoteReadResponse { id: 0, - proof: vec![vec![2]], + proof: StorageProof::empty(), }); assert_eq!(response.wait().unwrap().unwrap().remove(b":key".as_ref()).unwrap(), Some(vec![42])); } @@ -1037,7 +1037,7 @@ pub mod tests { light_dispatch.on_remote_read_response(&mut network_interface, peer0.clone(), message::RemoteReadResponse { id: 0, - proof: vec![vec![2]], + proof: StorageProof::empty(), }); assert_eq!(response.wait().unwrap().unwrap().remove(b":key".as_ref()).unwrap(), Some(vec![42])); } @@ -1065,7 +1065,7 @@ pub mod tests { extrinsics_root: Default::default(), digest: Default::default(), }), - proof: vec![vec![2]], + proof: StorageProof::empty(), }); assert_eq!( response.wait().unwrap().unwrap().hash(), @@ -1097,7 +1097,7 @@ pub mod tests { max: 1000, proof: vec![vec![2]], roots: vec![], - roots_proof: vec![], + roots_proof: StorageProof::empty(), }); assert_eq!(response.wait().unwrap().unwrap(), vec![(100, 2)]); } @@ -1145,7 +1145,7 @@ pub mod tests { light_dispatch.on_remote_header_response(&mut network_interface, peer1.clone(), message::RemoteHeaderResponse { id: 0, header: Some(dummy_header()), - proof: vec![], + proof: StorageProof::empty(), }); assert!(!light_dispatch.idle_peers.iter().any(|_| true)); diff --git a/core/network/src/protocol/message.rs b/core/network/src/protocol/message.rs index 6560ed0f13..ef5e4dbb1d 100644 --- a/core/network/src/protocol/message.rs +++ b/core/network/src/protocol/message.rs @@ -26,6 +26,7 @@ pub use self::generic::{ FinalityProofRequest, FinalityProofResponse, FromBlock, RemoteReadChildRequest, }; +use client::light::fetcher::StorageProof; /// A unique ID of a request. pub type RequestId = u64; @@ -122,7 +123,7 @@ pub struct RemoteCallResponse { /// Id of a request this response was made for. pub id: RequestId, /// Execution proof. - pub proof: Vec>, + pub proof: StorageProof, } #[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] @@ -131,7 +132,7 @@ pub struct RemoteReadResponse { /// Id of a request this response was made for. pub id: RequestId, /// Read proof. - pub proof: Vec>, + pub proof: StorageProof, } /// Generic types. @@ -142,7 +143,7 @@ pub mod generic { use super::{ RemoteReadResponse, Transactions, Direction, RequestId, BlockAttributes, RemoteCallResponse, ConsensusEngineId, - BlockState, + BlockState, StorageProof, }; /// Consensus is mostly opaque to us #[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] @@ -359,7 +360,7 @@ pub mod generic { /// Header. None if proof generation has failed (e.g. header is unknown). pub header: Option
, /// Header proof. - pub proof: Vec>, + pub proof: StorageProof, } #[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] @@ -395,7 +396,7 @@ pub mod generic { /// Changes tries roots missing on the requester' node. pub roots: Vec<(N, H)>, /// Missing changes tries roots proof. - pub roots_proof: Vec>, + pub roots_proof: StorageProof, } #[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] diff --git a/core/sr-api-macros/src/impl_runtime_apis.rs b/core/sr-api-macros/src/impl_runtime_apis.rs index 28eb5c6072..42d653b1ab 100644 --- a/core/sr-api-macros/src/impl_runtime_apis.rs +++ b/core/sr-api-macros/src/impl_runtime_apis.rs @@ -300,15 +300,17 @@ fn generate_runtime_api_base_structures(impls: &[ItemImpl]) -> Result Option>> { + fn extract_proof(&mut self) -> Option<#crate_::runtime_api::StorageProof> { self.recorder .take() - .map(|r| { - r.borrow_mut() + .map(|recorder| { + let trie_nodes = recorder + .borrow_mut() .drain() .into_iter() - .map(|n| n.data.to_vec()) - .collect() + .map(|record| record.data) + .collect(); + #crate_::runtime_api::StorageProof::new(trie_nodes) }) } } diff --git a/core/state-machine/src/lib.rs b/core/state-machine/src/lib.rs index c3092367f0..1da9cfb4e7 100644 --- a/core/state-machine/src/lib.rs +++ b/core/state-machine/src/lib.rs @@ -59,8 +59,8 @@ pub use changes_trie::{ }; pub use overlayed_changes::OverlayedChanges; pub use proving_backend::{ - create_proof_check_backend, create_proof_check_backend_storage, - Recorder as ProofRecorder, ProvingBackend, + create_proof_check_backend, create_proof_check_backend_storage, merge_storage_proofs, + Recorder as ProofRecorder, ProvingBackend, StorageProof, }; pub use trie_backend_essence::{TrieBackendStorage, Storage}; pub use trie_backend::TrieBackend; @@ -463,7 +463,7 @@ pub fn prove_execution( method: &str, call_data: &[u8], keystore: Option, -) -> Result<(Vec, Vec>), Box> +) -> Result<(Vec, StorageProof), Box> where B: Backend, H: Hasher, @@ -490,7 +490,7 @@ pub fn prove_execution_on_trie_backend( method: &str, call_data: &[u8], keystore: Option, -) -> Result<(Vec, Vec>), Box> +) -> Result<(Vec, StorageProof), Box> where S: trie_backend_essence::TrieBackendStorage, H: Hasher, @@ -513,7 +513,7 @@ where /// Check execution proof, generated by `prove_execution` call. pub fn execution_proof_check( root: H::Out, - proof: Vec>, + proof: StorageProof, overlay: &mut OverlayedChanges, exec: &Exec, method: &str, @@ -557,7 +557,7 @@ where pub fn prove_read( mut backend: B, keys: I, -) -> Result>, Box> +) -> Result> where B: Backend, H: Hasher, @@ -577,7 +577,7 @@ pub fn prove_child_read( mut backend: B, storage_key: &[u8], keys: I, -) -> Result>, Box> +) -> Result> where B: Backend, H: Hasher, @@ -594,7 +594,7 @@ where pub fn prove_read_on_trie_backend( trie_backend: &TrieBackend, keys: I, -) -> Result>, Box> +) -> Result> where S: trie_backend_essence::TrieBackendStorage, H: Hasher, @@ -616,7 +616,7 @@ pub fn prove_child_read_on_trie_backend( trie_backend: &TrieBackend, storage_key: &[u8], keys: I, -) -> Result>, Box> +) -> Result> where S: trie_backend_essence::TrieBackendStorage, H: Hasher, @@ -636,7 +636,7 @@ where /// Check storage read proof, generated by `prove_read` call. pub fn read_proof_check( root: H::Out, - proof: Vec>, + proof: StorageProof, keys: I, ) -> Result, Option>>, Box> where @@ -657,7 +657,7 @@ where /// Check child storage read proof, generated by `prove_child_read` call. pub fn read_child_proof_check( root: H::Out, - proof: Vec>, + proof: StorageProof, storage_key: &[u8], keys: I, ) -> Result, Option>>, Box> diff --git a/core/state-machine/src/proving_backend.rs b/core/state-machine/src/proving_backend.rs index c6c4ef1ec8..14f17a3a48 100644 --- a/core/state-machine/src/proving_backend.rs +++ b/core/state-machine/src/proving_backend.rs @@ -16,7 +16,8 @@ //! Proving state machine backend. -use std::{cell::RefCell, rc::Rc}; +use std::{cell::RefCell, collections::HashSet, rc::Rc}; +use codec::{Decode, Encode}; use log::debug; use hash_db::{Hasher, HashDB, EMPTY_PREFIX}; use trie::{ @@ -29,6 +30,82 @@ use crate::trie_backend::TrieBackend; use crate::trie_backend_essence::{Ephemeral, TrieBackendEssence, TrieBackendStorage}; use crate::{Error, ExecutionError, Backend}; +/// A proof that some set of key-value pairs are included in the storage trie. The proof contains +/// the storage values so that the partial storage backend can be reconstructed by a verifier that +/// does not already have access to the key-value pairs. +/// +/// The proof consists of the set of serialized nodes in the storage trie accessed when looking up +/// the keys covered by the proof. Verifying the proof requires constructing the partial trie from +/// the serialized nodes and performing the key lookups. +#[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] +pub struct StorageProof { + trie_nodes: Vec>, +} + +impl StorageProof { + /// Constructs a storage proof from a subset of encoded trie nodes in a storage backend. + pub fn new(trie_nodes: Vec>) -> Self { + StorageProof { trie_nodes } + } + + /// Returns a new empty proof. + /// + /// An empty proof is capable of only proving trivial statements (ie. that an empty set of + /// key-value pairs exist in storage). + pub fn empty() -> Self { + StorageProof { + trie_nodes: Vec::new(), + } + } + + /// Returns whether this is an empty proof. + pub fn is_empty(&self) -> bool { + self.trie_nodes.is_empty() + } + + /// Create an iterator over trie nodes constructed from the proof. The nodes are not guaranteed + /// to be traversed in any particular order. + pub fn iter_nodes(self) -> StorageProofNodeIterator { + StorageProofNodeIterator::new(self) + } +} + +/// An iterator over trie nodes constructed from a storage proof. The nodes are not guaranteed to +/// be traversed in any particular order. +pub struct StorageProofNodeIterator { + inner: > as IntoIterator>::IntoIter, +} + +impl StorageProofNodeIterator { + fn new(proof: StorageProof) -> Self { + StorageProofNodeIterator { + inner: proof.trie_nodes.into_iter(), + } + } +} + +impl Iterator for StorageProofNodeIterator { + type Item = Vec; + + fn next(&mut self) -> Option { + self.inner.next() + } +} + +/// Merges multiple storage proofs covering potentially different sets of keys into one proof +/// covering all keys. The merged proof output may be smaller than the aggregate size of the input +/// proofs due to deduplication of trie nodes. +pub fn merge_storage_proofs(proofs: I) -> StorageProof + where I: IntoIterator +{ + let trie_nodes = proofs.into_iter() + .flat_map(|proof| proof.iter_nodes()) + .collect::>() + .into_iter() + .collect(); + StorageProof { trie_nodes } +} + /// Patricia trie-based backend essence which also tracks all touched storage trie values. /// These can be sent to remote node and used as a proof of execution. pub struct ProvingBackendEssence<'a, S: 'a + TrieBackendStorage, H: 'a + Hasher> { @@ -129,13 +206,14 @@ impl<'a, S: 'a + TrieBackendStorage, H: 'a + Hasher> ProvingBackend<'a, S, H> } /// Consume the backend, extracting the gathered proof in lexicographical order by value. - pub fn extract_proof(&self) -> Vec> { - self.proof_recorder + pub fn extract_proof(&self) -> StorageProof { + let trie_nodes = self.proof_recorder .borrow_mut() .drain() .into_iter() - .map(|n| n.data.to_vec()) - .collect() + .map(|record| record.data) + .collect(); + StorageProof::new(trie_nodes) } } @@ -217,7 +295,7 @@ impl<'a, S, H> Backend for ProvingBackend<'a, S, H> /// Create proof check backend. pub fn create_proof_check_backend( root: H::Out, - proof: Vec> + proof: StorageProof, ) -> Result, H>, Box> where H: Hasher, @@ -233,13 +311,13 @@ where /// Create in-memory storage of proof check backend. pub fn create_proof_check_backend_storage( - proof: Vec> + proof: StorageProof, ) -> MemoryDB where H: Hasher, { let mut db = MemoryDB::default(); - for item in proof { + for item in proof.iter_nodes() { db.insert(EMPTY_PREFIX, &item); } db @@ -275,7 +353,11 @@ mod tests { #[test] fn proof_is_invalid_when_does_not_contains_root() { use primitives::H256; - assert!(create_proof_check_backend::(H256::from_low_u64_be(1), vec![]).is_err()); + let result = create_proof_check_backend::( + H256::from_low_u64_be(1), + StorageProof::empty() + ); + assert!(result.is_err()); } #[test] -- GitLab From a746d38d2b76da28e0e5fe77bad6c43ecc4d88c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= Date: Thu, 31 Oct 2019 10:11:11 +0000 Subject: [PATCH 149/167] im-online: account for block authorship (#3973) * im-online: account for block authorship * im-online: add test for block authorship onlineness * im-online: cleanup * im-online: fix test --- Cargo.lock | 1 + node/runtime/src/lib.rs | 2 +- srml/im-online/Cargo.toml | 2 ++ srml/im-online/src/lib.rs | 72 ++++++++++++++++++++++++++++++++----- srml/im-online/src/mock.rs | 11 ++++++ srml/im-online/src/tests.rs | 30 ++++++++++++++++ 6 files changed, 108 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a7d9628b6b..13fc0dcd51 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4305,6 +4305,7 @@ dependencies = [ "sr-primitives 2.0.0", "sr-staking-primitives 2.0.0", "sr-std 2.0.0", + "srml-authorship 0.1.0", "srml-session 2.0.0", "srml-support 2.0.0", "srml-system 2.0.0", diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index 9bda317c33..a0ee20988e 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -206,7 +206,7 @@ impl authorship::Trait for Runtime { type FindAuthor = session::FindAccountFromAuthorIndex; type UncleGenerations = UncleGenerations; type FilterUncle = (); - type EventHandler = Staking; + type EventHandler = (Staking, ImOnline); } impl_opaque_keys! { diff --git a/srml/im-online/Cargo.toml b/srml/im-online/Cargo.toml index b62cc2a8f9..4c7ccf1487 100644 --- a/srml/im-online/Cargo.toml +++ b/srml/im-online/Cargo.toml @@ -6,6 +6,7 @@ edition = "2018" [dependencies] app-crypto = { package = "substrate-application-crypto", path = "../../core/application-crypto", default-features = false } +authorship = { package = "srml-authorship", path = "../authorship", default-features = false } codec = { package = "parity-scale-codec", version = "1.0.0", default-features = false, features = ["derive"] } primitives = { package="substrate-primitives", path = "../../core/primitives", default-features = false } rstd = { package = "sr-std", path = "../../core/sr-std", default-features = false } @@ -24,6 +25,7 @@ offchain = { package = "substrate-offchain", path = "../../core/offchain" } default = ["std", "session/historical"] std = [ "app-crypto/std", + "authorship/std", "codec/std", "primitives/std", "rstd/std", diff --git a/srml/im-online/src/lib.rs b/srml/im-online/src/lib.rs index 6dcaf1d3ab..46e26ff32f 100644 --- a/srml/im-online/src/lib.rs +++ b/srml/im-online/src/lib.rs @@ -214,10 +214,15 @@ decl_storage! { /// The current set of keys that may issue a heartbeat. Keys get(fn keys): Vec; - /// For each session index we keep a mapping of `AuthorityId` + /// For each session index, we keep a mapping of `AuthIndex` /// to `offchain::OpaqueNetworkState`. ReceivedHeartbeats get(fn received_heartbeats): double_map SessionIndex, blake2_256(AuthIndex) => Vec; + + /// For each session index, we keep a mapping of `T::ValidatorId` to the + /// number of blocks authored by the given authority. + AuthoredBlocks get(fn authored_blocks): double_map SessionIndex, + blake2_256(T::ValidatorId) => u32; } add_extra_genesis { config(keys): Vec; @@ -278,14 +283,63 @@ decl_module! { } } +/// Keep track of number of authored blocks per authority, uncles are counted as +/// well since they're a valid proof of onlineness. +impl authorship::EventHandler for Module { + fn note_author(author: T::ValidatorId) { + Self::note_authorship(author); + } + + fn note_uncle(author: T::ValidatorId, _age: T::BlockNumber) { + Self::note_authorship(author); + } +} + impl Module { + /// Returns `true` if a heartbeat has been received for the authority at + /// `authority_index` in the authorities series or if the authority has + /// authored at least one block, during the current session. Otherwise + /// `false`. + pub fn is_online_in_current_session(authority_index: AuthIndex) -> bool { + let current_validators = >::validators(); + + if authority_index >= current_validators.len() as u32 { + return false; + } + + let authority = ¤t_validators[authority_index as usize]; + + Self::is_online_in_current_session_aux(authority_index, authority) + } + + fn is_online_in_current_session_aux(authority_index: AuthIndex, authority: &T::ValidatorId) -> bool { + let current_session = >::current_index(); + + ::exists(¤t_session, &authority_index) || + >::get( + ¤t_session, + authority, + ) != 0 + } + /// Returns `true` if a heartbeat has been received for the authority at `authority_index` in /// the authorities series, during the current session. Otherwise `false`. - pub fn is_online_in_current_session(authority_index: AuthIndex) -> bool { + pub fn received_heartbeat_in_current_session(authority_index: AuthIndex) -> bool { let current_session = >::current_index(); ::exists(¤t_session, &authority_index) } + /// Note that the given authority has authored a block in the current session. + fn note_authorship(author: T::ValidatorId) { + let current_session = >::current_index(); + + >::mutate( + ¤t_session, + author, + |authored| *authored += 1, + ); + } + pub(crate) fn offchain(now: T::BlockNumber) { let next_gossip = >::get(); let check = Self::check_not_yet_gossipped(now, next_gossip); @@ -461,9 +515,7 @@ impl session::OneSessionHandler for Module { let current_validators = >::validators(); for (auth_idx, validator_id) in current_validators.into_iter().enumerate() { - let auth_idx = auth_idx as u32; - let exists = ::exists(¤t_session, &auth_idx); - if !exists { + if !Self::is_online_in_current_session_aux(auth_idx as u32, &validator_id) { let full_identification = T::FullIdentificationOf::convert(validator_id.clone()) .expect( "we got the validator_id from current_validators; @@ -477,6 +529,12 @@ impl session::OneSessionHandler for Module { } } + // Remove all received heartbeats and number of authored blocks from the + // current session, they have already been processed and won't be needed + // anymore. + ::remove_prefix(&>::current_index()); + >::remove_prefix(&>::current_index()); + if unresponsive.is_empty() { return; } @@ -489,10 +547,6 @@ impl session::OneSessionHandler for Module { }; T::ReportUnresponsiveness::report_offence(vec![], offence); - - // Remove all received heartbeats from the current session, they have - // already been processed and won't be needed anymore. - ::remove_prefix(&>::current_index()); } fn on_disabled(_i: usize) { diff --git a/srml/im-online/src/mock.rs b/srml/im-online/src/mock.rs index e50e7779e9..233e055f88 100644 --- a/srml/im-online/src/mock.rs +++ b/srml/im-online/src/mock.rs @@ -145,6 +145,17 @@ impl session::historical::Trait for Runtime { type FullIdentificationOf = ConvertInto; } +parameter_types! { + pub const UncleGenerations: u32 = 5; +} + +impl authorship::Trait for Runtime { + type FindAuthor = (); + type UncleGenerations = UncleGenerations; + type FilterUncle = (); + type EventHandler = ImOnline; +} + impl Trait for Runtime { type AuthorityId = UintAuthorityId; type Event = (); diff --git a/srml/im-online/src/tests.rs b/srml/im-online/src/tests.rs index 652d751281..42c1aa0227 100644 --- a/srml/im-online/src/tests.rs +++ b/srml/im-online/src/tests.rs @@ -243,3 +243,33 @@ fn should_cleanup_received_heartbeats_on_session_end() { assert!(ImOnline::received_heartbeats(&2, &0).is_empty()); }); } + +#[test] +fn should_mark_online_validator_when_block_is_authored() { + use authorship::EventHandler; + + new_test_ext().execute_with(|| { + advance_session(); + // given + VALIDATORS.with(|l| *l.borrow_mut() = Some(vec![1, 2, 3, 4, 5, 6])); + assert_eq!(Session::validators(), Vec::::new()); + // enact the change and buffer another one + advance_session(); + + assert_eq!(Session::current_index(), 2); + assert_eq!(Session::validators(), vec![1, 2, 3]); + + for i in 0..3 { + assert!(!ImOnline::is_online_in_current_session(i)); + } + + // when + ImOnline::note_author(1); + ImOnline::note_uncle(2, 0); + + // then + assert!(ImOnline::is_online_in_current_session(0)); + assert!(ImOnline::is_online_in_current_session(1)); + assert!(!ImOnline::is_online_in_current_session(2)); + }); +} -- GitLab From c3b1a9836c3cde2e1028162091a96efefb9a1d0e Mon Sep 17 00:00:00 2001 From: Jim Posen Date: Thu, 31 Oct 2019 14:33:34 +0100 Subject: [PATCH 150/167] grandpa: Use storage proofs for Grandpa authorities (#3734) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * grandpa: Write Grandpa authorities to well known key. Instead of requiring execution proofs for Grandpa authorities, this enables much simpler storage proofs. * grandpa: Introduce named AuthorityList type. * grandpa: Storage migration for srml-grandpa module. * Remove no-longer-used GrandpaApi runtime API. * grandpa: Write AuthorityList to storage with encoding version. We expect the AuthorityList type may change (eg. key changes). To make upgrades smoother, include a version in the stored value. * Bump node runtime spec version. * Update srml/grandpa/src/lib.rs Co-Authored-By: André Silva --- Cargo.lock | 1 - core/finality-grandpa/primitives/Cargo.toml | 2 - core/finality-grandpa/primitives/src/lib.rs | 78 ++++++++++++----- core/finality-grandpa/src/authorities.rs | 8 +- core/finality-grandpa/src/aux_schema.rs | 9 +- .../src/communication/tests.rs | 3 +- core/finality-grandpa/src/finality_proof.rs | 86 ++++++++++--------- core/finality-grandpa/src/lib.rs | 43 ++++++---- core/finality-grandpa/src/light_import.rs | 58 ++++++------- core/finality-grandpa/src/tests.rs | 39 +++------ node-template/runtime/src/lib.rs | 9 +- node-template/src/service.rs | 6 +- node/cli/src/service.rs | 16 ++-- node/runtime/src/lib.rs | 11 +-- srml/grandpa/Cargo.toml | 1 + srml/grandpa/src/lib.rs | 66 +++++++++----- srml/grandpa/src/mock.rs | 4 +- srml/grandpa/src/tests.rs | 18 ++++ 18 files changed, 263 insertions(+), 195 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 13fc0dcd51..5bee6302ec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5275,7 +5275,6 @@ dependencies = [ "sr-primitives 2.0.0", "sr-std 2.0.0", "substrate-application-crypto 2.0.0", - "substrate-client 2.0.0", ] [[package]] diff --git a/core/finality-grandpa/primitives/Cargo.toml b/core/finality-grandpa/primitives/Cargo.toml index 02439d4150..90d7af5777 100644 --- a/core/finality-grandpa/primitives/Cargo.toml +++ b/core/finality-grandpa/primitives/Cargo.toml @@ -5,7 +5,6 @@ authors = ["Parity Technologies "] edition = "2018" [dependencies] -client = { package = "substrate-client", path = "../../client", default-features = false } app-crypto = { package = "substrate-application-crypto", path = "../../application-crypto", default-features = false } codec = { package = "parity-scale-codec", version = "1.0.0", default-features = false, features = ["derive"] } sr-primitives = { path = "../../sr-primitives", default-features = false } @@ -15,7 +14,6 @@ serde = { version = "1.0.101", optional = true, features = ["derive"] } [features] default = ["std"] std = [ - "client/std", "codec/std", "sr-primitives/std", "rstd/std", diff --git a/core/finality-grandpa/primitives/src/lib.rs b/core/finality-grandpa/primitives/src/lib.rs index 27139bbeef..3f5b4cb7f6 100644 --- a/core/finality-grandpa/primitives/src/lib.rs +++ b/core/finality-grandpa/primitives/src/lib.rs @@ -23,9 +23,9 @@ extern crate alloc; #[cfg(feature = "std")] use serde::Serialize; -use codec::{Encode, Decode, Codec}; +use codec::{Encode, Decode, Input, Codec}; use sr_primitives::{ConsensusEngineId, RuntimeDebug}; -use client::decl_runtime_apis; +use rstd::borrow::Cow; use rstd::vec::Vec; mod app { @@ -46,6 +46,10 @@ pub type AuthoritySignature = app::Signature; /// The `ConsensusEngineId` of GRANDPA. pub const GRANDPA_ENGINE_ID: ConsensusEngineId = *b"FRNK"; +/// The storage key for the current set of weighted Grandpa authorities. +/// The value stored is an encoded VersionedAuthorityList. +pub const GRANDPA_AUTHORITIES_KEY: &'static [u8] = b":grandpa_authorities"; + /// The weight of an authority. pub type AuthorityWeight = u64; @@ -58,12 +62,15 @@ pub type SetId = u64; /// The round indicator. pub type RoundNumber = u64; +/// A list of Grandpa authorities with associated weights. +pub type AuthorityList = Vec<(AuthorityId, AuthorityWeight)>; + /// A scheduled change of authority set. #[cfg_attr(feature = "std", derive(Serialize))] #[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug)] pub struct ScheduledChange { /// The new authorities after the change, along with their respective weights. - pub next_authorities: Vec<(AuthorityId, AuthorityWeight)>, + pub next_authorities: AuthorityList, /// The number of blocks to delay. pub delay: N, } @@ -154,24 +161,51 @@ pub const PENDING_CHANGE_CALL: &str = "grandpa_pending_change"; /// WASM function call to get current GRANDPA authorities. pub const AUTHORITIES_CALL: &str = "grandpa_authorities"; -decl_runtime_apis! { - /// APIs for integrating the GRANDPA finality gadget into runtimes. - /// This should be implemented on the runtime side. - /// - /// This is primarily used for negotiating authority-set changes for the - /// gadget. GRANDPA uses a signaling model of changing authority sets: - /// changes should be signaled with a delay of N blocks, and then automatically - /// applied in the runtime after those N blocks have passed. - /// - /// The consensus protocol will coordinate the handoff externally. - #[api_version(2)] - pub trait GrandpaApi { - /// Get the current GRANDPA authorities and weights. This should not change except - /// for when changes are scheduled and the corresponding delay has passed. - /// - /// When called at block B, it will return the set of authorities that should be - /// used to finalize descendants of this block (B+1, B+2, ...). The block B itself - /// is finalized by the authorities from block B-1. - fn grandpa_authorities() -> Vec<(AuthorityId, AuthorityWeight)>; +/// The current version of the stored AuthorityList type. The encoding version MUST be updated any +/// time the AuthorityList type changes. +const AUTHORITIES_VERISON: u8 = 1; + +/// An AuthorityList that is encoded with a version specifier. The encoding version is updated any +/// time the AuthorityList type changes. This ensures that encodings of different versions of an +/// AuthorityList are differentiable. Attempting to decode an authority list with an unknown +/// version will fail. +#[derive(Default)] +pub struct VersionedAuthorityList<'a>(Cow<'a, AuthorityList>); + +impl<'a> From for VersionedAuthorityList<'a> { + fn from(authorities: AuthorityList) -> Self { + VersionedAuthorityList(Cow::Owned(authorities)) + } +} + +impl<'a> From<&'a AuthorityList> for VersionedAuthorityList<'a> { + fn from(authorities: &'a AuthorityList) -> Self { + VersionedAuthorityList(Cow::Borrowed(authorities)) + } +} + +impl<'a> Into for VersionedAuthorityList<'a> { + fn into(self) -> AuthorityList { + self.0.into_owned() + } +} + +impl<'a> Encode for VersionedAuthorityList<'a> { + fn size_hint(&self) -> usize { + (AUTHORITIES_VERISON, self.0.as_ref()).size_hint() + } + + fn using_encoded R>(&self, f: F) -> R { + (AUTHORITIES_VERISON, self.0.as_ref()).using_encoded(f) + } +} + +impl<'a> Decode for VersionedAuthorityList<'a> { + fn decode(value: &mut I) -> Result { + let (version, authorities): (u8, AuthorityList) = Decode::decode(value)?; + if version != AUTHORITIES_VERISON { + return Err("unknown Grandpa authorities version".into()); + } + Ok(authorities.into()) } } diff --git a/core/finality-grandpa/src/authorities.rs b/core/finality-grandpa/src/authorities.rs index 9b83c9feb6..263f2dc076 100644 --- a/core/finality-grandpa/src/authorities.rs +++ b/core/finality-grandpa/src/authorities.rs @@ -22,7 +22,7 @@ use grandpa::voter_set::VoterSet; use codec::{Encode, Decode}; use log::{debug, info}; use substrate_telemetry::{telemetry, CONSENSUS_INFO}; -use fg_primitives::AuthorityId; +use fg_primitives::{AuthorityId, AuthorityList}; use std::cmp::Ord; use std::fmt::Debug; @@ -86,7 +86,7 @@ pub(crate) struct Status { /// A set of authorities. #[derive(Debug, Clone, Encode, Decode, PartialEq)] pub(crate) struct AuthoritySet { - pub(crate) current_authorities: Vec<(AuthorityId, u64)>, + pub(crate) current_authorities: AuthorityList, pub(crate) set_id: u64, // Tree of pending standard changes across forks. Standard changes are // enacted on finality and must be enacted (i.e. finalized) in-order across @@ -103,7 +103,7 @@ where H: PartialEq, N: Ord, { /// Get a genesis set with given authorities. - pub(crate) fn genesis(initial: Vec<(AuthorityId, u64)>) -> Self { + pub(crate) fn genesis(initial: AuthorityList) -> Self { AuthoritySet { current_authorities: initial, set_id: 0, @@ -390,7 +390,7 @@ pub(crate) enum DelayKind { #[derive(Debug, Clone, Encode, PartialEq)] pub(crate) struct PendingChange { /// The new authorities and weights to apply. - pub(crate) next_authorities: Vec<(AuthorityId, u64)>, + pub(crate) next_authorities: AuthorityList, /// How deep in the chain the announcing block must be /// before the change is applied. pub(crate) delay: N, diff --git a/core/finality-grandpa/src/aux_schema.rs b/core/finality-grandpa/src/aux_schema.rs index a2b05a0cd6..1aed0b95ab 100644 --- a/core/finality-grandpa/src/aux_schema.rs +++ b/core/finality-grandpa/src/aux_schema.rs @@ -25,7 +25,7 @@ use fork_tree::ForkTree; use grandpa::round::State as RoundState; use sr_primitives::traits::{Block as BlockT, NumberFor}; use log::{info, warn}; -use fg_primitives::{AuthorityId, AuthorityWeight, SetId, RoundNumber}; +use fg_primitives::{AuthorityList, SetId, RoundNumber}; use crate::authorities::{AuthoritySet, SharedAuthoritySet, PendingChange, DelayKind}; use crate::consensus_changes::{SharedConsensusChanges, ConsensusChanges}; @@ -55,7 +55,7 @@ type V0VoterSetState = (RoundNumber, RoundState); #[derive(Debug, Clone, Encode, Decode, PartialEq)] struct V0PendingChange { - next_authorities: Vec<(AuthorityId, AuthorityWeight)>, + next_authorities: AuthorityList, delay: N, canon_height: N, canon_hash: H, @@ -63,7 +63,7 @@ struct V0PendingChange { #[derive(Debug, Clone, Encode, Decode, PartialEq)] struct V0AuthoritySet { - current_authorities: Vec<(AuthorityId, AuthorityWeight)>, + current_authorities: AuthorityList, set_id: SetId, pending_changes: Vec>, } @@ -266,7 +266,7 @@ pub(crate) fn load_persistent( -> ClientResult> where B: AuxStore, - G: FnOnce() -> ClientResult>, + G: FnOnce() -> ClientResult, { let version: Option = load_decode(backend, VERSION_KEY)?; let consensus_changes = load_decode(backend, CONSENSUS_CHANGES_KEY)? @@ -426,6 +426,7 @@ pub(crate) fn load_authorities(backend: &B) #[cfg(test)] mod test { + use fg_primitives::AuthorityId; use primitives::H256; use test_client; use super::*; diff --git a/core/finality-grandpa/src/communication/tests.rs b/core/finality-grandpa/src/communication/tests.rs index f918f47258..af6d842be3 100644 --- a/core/finality-grandpa/src/communication/tests.rs +++ b/core/finality-grandpa/src/communication/tests.rs @@ -28,6 +28,7 @@ use codec::Encode; use sr_primitives::traits::NumberFor; use crate::environment::SharedVoterSetState; +use fg_primitives::AuthorityList; use super::gossip::{self, GossipValidator}; use super::{AuthorityId, VoterSet, Round, SetId}; @@ -200,7 +201,7 @@ fn make_test_network() -> ( ) } -fn make_ids(keys: &[Ed25519Keyring]) -> Vec<(AuthorityId, u64)> { +fn make_ids(keys: &[Ed25519Keyring]) -> AuthorityList { keys.iter() .map(|key| key.clone().public().into()) .map(|id| (id, 1)) diff --git a/core/finality-grandpa/src/finality_proof.rs b/core/finality-grandpa/src/finality_proof.rs index bd22a7bbac..aa7207b422 100644 --- a/core/finality-grandpa/src/finality_proof.rs +++ b/core/finality-grandpa/src/finality_proof.rs @@ -34,13 +34,14 @@ //! finality proof (that finalizes some block C that is ancestor of the B and descendant //! of the U) could be returned. +use std::iter; use std::sync::Arc; use log::{trace, warn}; use client::{ backend::Backend, blockchain::Backend as BlockchainBackend, CallExecutor, Client, error::{Error as ClientError, Result as ClientResult}, - light::fetcher::{FetchChecker, RemoteCallRequest, StorageProof}, ExecutionStrategy, + light::fetcher::{FetchChecker, RemoteReadRequest, StorageProof}, }; use codec::{Encode, Decode}; use grandpa::BlockNumberOps; @@ -48,9 +49,9 @@ use sr_primitives::{ Justification, generic::BlockId, traits::{NumberFor, Block as BlockT, Header as HeaderT, One}, }; -use primitives::{H256, Blake2Hasher}; +use primitives::{H256, Blake2Hasher, storage::StorageKey}; use substrate_telemetry::{telemetry, CONSENSUS_INFO}; -use fg_primitives::AuthorityId; +use fg_primitives::{AuthorityId, AuthorityList, VersionedAuthorityList, GRANDPA_AUTHORITIES_KEY}; use crate::justification::GrandpaJustification; @@ -59,9 +60,9 @@ const MAX_FRAGMENTS_IN_PROOF: usize = 8; /// GRANDPA authority set related methods for the finality proof provider. pub trait AuthoritySetForFinalityProver: Send + Sync { - /// Call GrandpaApi::grandpa_authorities at given block. - fn authorities(&self, block: &BlockId) -> ClientResult>; - /// Prove call of GrandpaApi::grandpa_authorities at given block. + /// Read GRANDPA_AUTHORITIES_KEY from storage at given block. + fn authorities(&self, block: &BlockId) -> ClientResult; + /// Prove storage read of GRANDPA_AUTHORITIES_KEY at given block. fn prove_authorities(&self, block: &BlockId) -> ClientResult; } @@ -72,33 +73,28 @@ impl, RA> AuthoritySetForFinalityProver fo E: CallExecutor + 'static + Clone + Send + Sync, RA: Send + Sync, { - fn authorities(&self, block: &BlockId) -> ClientResult> { - self.executor().call( - block, - "GrandpaApi_grandpa_authorities", - &[], - ExecutionStrategy::NativeElseWasm, - None, - ).and_then(|call_result| Decode::decode(&mut &call_result[..]) - .map_err(|err| ClientError::CallResultDecode( - "failed to decode GRANDPA authorities set proof".into(), err - ))) + fn authorities(&self, block: &BlockId) -> ClientResult { + let storage_key = StorageKey(GRANDPA_AUTHORITIES_KEY.to_vec()); + self.storage(block, &storage_key)? + .and_then(|encoded| VersionedAuthorityList::decode(&mut encoded.0.as_slice()).ok()) + .map(|versioned| versioned.into()) + .ok_or(ClientError::InvalidAuthoritiesSet) } fn prove_authorities(&self, block: &BlockId) -> ClientResult { - self.execution_proof(block, "GrandpaApi_grandpa_authorities",&[]).map(|(_, proof)| proof) + self.read_proof(block, iter::once(GRANDPA_AUTHORITIES_KEY)) } } /// GRANDPA authority set related methods for the finality proof checker. pub trait AuthoritySetForFinalityChecker: Send + Sync { - /// Check execution proof of Grandpa::grandpa_authorities at given block. + /// Check storage read proof of GRANDPA_AUTHORITIES_KEY at given block. fn check_authorities_proof( &self, hash: Block::Hash, header: Block::Header, proof: StorageProof, - ) -> ClientResult>; + ) -> ClientResult; } /// FetchChecker-based implementation of AuthoritySetForFinalityChecker. @@ -108,22 +104,30 @@ impl AuthoritySetForFinalityChecker for Arc ClientResult> { - let request = RemoteCallRequest { + ) -> ClientResult { + let storage_key = GRANDPA_AUTHORITIES_KEY.to_vec(); + let request = RemoteReadRequest { block: hash, header, - method: "GrandpaApi_grandpa_authorities".into(), - call_data: vec![], + keys: vec![storage_key.clone()], retry_count: None, }; - self.check_execution_proof(&request, proof) - .and_then(|authorities| { - let authorities: Vec<(AuthorityId, u64)> = Decode::decode(&mut &authorities[..]) - .map_err(|err| ClientError::CallResultDecode( - "failed to decode GRANDPA authorities set proof".into(), err - ))?; - Ok(authorities.into_iter().collect()) + self.check_read_proof(&request, proof) + .and_then(|results| { + let maybe_encoded = results.get(&storage_key) + .expect( + "storage_key is listed in the request keys; \ + check_read_proof must return a value for each requested key; + qed" + ); + maybe_encoded + .as_ref() + .and_then(|encoded| { + VersionedAuthorityList::decode(&mut encoded.as_slice()).ok() + }) + .map(|versioned| versioned.into()) + .ok_or(ClientError::InvalidAuthoritiesSet) }) } } @@ -189,7 +193,7 @@ pub struct FinalityEffects { /// New authorities set id that should be applied starting from block. pub new_set_id: u64, /// New authorities set that should be applied starting from block. - pub new_authorities: Vec<(AuthorityId, u64)>, + pub new_authorities: AuthorityList, } /// Single fragment of proof-of-finality. @@ -408,7 +412,7 @@ pub(crate) fn prove_finality, B: BlockchainBackend, B>( blockchain: &B, current_set_id: u64, - current_authorities: Vec<(AuthorityId, u64)>, + current_authorities: AuthorityList, authorities_provider: &dyn AuthoritySetForFinalityChecker, remote_proof: Vec, ) -> ClientResult> @@ -427,7 +431,7 @@ pub(crate) fn check_finality_proof, B>( fn do_check_finality_proof, B, J>( blockchain: &B, current_set_id: u64, - current_authorities: Vec<(AuthorityId, u64)>, + current_authorities: AuthorityList, authorities_provider: &dyn AuthoritySetForFinalityChecker, remote_proof: Vec, ) -> ClientResult> @@ -522,12 +526,12 @@ fn check_finality_proof_fragment, B, J>( /// Authorities set from initial authorities set or finality effects. enum AuthoritiesOrEffects { - Authorities(u64, Vec<(AuthorityId, u64)>), + Authorities(u64, AuthorityList), Effects(FinalityEffects
), } impl AuthoritiesOrEffects
{ - pub fn extract_authorities(self) -> (u64, Vec<(AuthorityId, u64)>) { + pub fn extract_authorities(self) -> (u64, AuthorityList) { match self { AuthoritiesOrEffects::Authorities(set_id, authorities) => (set_id, authorities), AuthoritiesOrEffects::Effects(effects) => (effects.new_set_id, effects.new_authorities), @@ -581,10 +585,10 @@ pub(crate) mod tests { impl AuthoritySetForFinalityProver for (GetAuthorities, ProveAuthorities) where - GetAuthorities: Send + Sync + Fn(BlockId) -> ClientResult>, + GetAuthorities: Send + Sync + Fn(BlockId) -> ClientResult, ProveAuthorities: Send + Sync + Fn(BlockId) -> ClientResult, { - fn authorities(&self, block: &BlockId) -> ClientResult> { + fn authorities(&self, block: &BlockId) -> ClientResult { self.0(*block) } @@ -597,14 +601,14 @@ pub(crate) mod tests { impl AuthoritySetForFinalityChecker for ClosureAuthoritySetForFinalityChecker where - Closure: Send + Sync + Fn(H256, Header, StorageProof) -> ClientResult>, + Closure: Send + Sync + Fn(H256, Header, StorageProof) -> ClientResult, { fn check_authorities_proof( &self, hash: H256, header: Header, - proof: StorageProof, - ) -> ClientResult> { + proof: StorageProof + ) -> ClientResult { self.0(hash, header, proof) } } diff --git a/core/finality-grandpa/src/lib.rs b/core/finality-grandpa/src/lib.rs index 0decea5811..67acaa21d7 100644 --- a/core/finality-grandpa/src/lib.rs +++ b/core/finality-grandpa/src/lib.rs @@ -61,10 +61,7 @@ use client::{ use client::blockchain::HeaderBackend; use codec::Encode; use sr_primitives::generic::BlockId; -use sr_primitives::traits::{ - NumberFor, Block as BlockT, DigestFor, ProvideRuntimeApi -}; -use fg_primitives::{GrandpaApi, AuthorityPair}; +use sr_primitives::traits::{NumberFor, Block as BlockT, DigestFor, Zero}; use keystore::KeyStorePtr; use inherents::InherentDataProviders; use consensus_common::SelectChain; @@ -108,7 +105,7 @@ use environment::{Environment, VoterSetState}; use import::GrandpaBlockImport; use until_imported::UntilGlobalMessageBlocksImported; use communication::NetworkBridge; -use fg_primitives::{AuthoritySignature, SetId, AuthorityWeight}; +use fg_primitives::{AuthorityList, AuthorityPair, AuthoritySignature, SetId}; // Re-export these two because it's just so damn convenient. pub use fg_primitives::{AuthorityId, ScheduledChange}; @@ -295,7 +292,7 @@ pub(crate) struct NewAuthoritySet { pub(crate) canon_number: N, pub(crate) canon_hash: H, pub(crate) set_id: SetId, - pub(crate) authorities: Vec<(AuthorityId, AuthorityWeight)>, + pub(crate) authorities: AuthorityList, } /// Commands issued to the voter. @@ -367,11 +364,30 @@ pub struct LinkHalf, RA, SC> { voter_commands_rx: mpsc::UnboundedReceiver>>, } +/// Provider for the Grandpa authority set configured on the genesis block. +pub trait GenesisAuthoritySetProvider { + /// Get the authority set at the genesis block. + fn get(&self) -> Result; +} + +impl, RA> GenesisAuthoritySetProvider for Client + where + B: Backend + Send + Sync + 'static, + E: CallExecutor + 'static + Clone + Send + Sync, + RA: Send + Sync, +{ + fn get(&self) -> Result { + use finality_proof::AuthoritySetForFinalityProver; + + self.authorities(&BlockId::Number(Zero::zero())) + } +} + /// Make block importer and link half necessary to tie the background voter /// to it. -pub fn block_import, RA, PRA, SC>( +pub fn block_import, RA, SC>( client: Arc>, - api: &PRA, + genesis_authorities_provider: &dyn GenesisAuthoritySetProvider, select_chain: SC, ) -> Result<( GrandpaBlockImport, @@ -381,12 +397,8 @@ where B: Backend + 'static, E: CallExecutor + 'static + Clone + Send + Sync, RA: Send + Sync, - PRA: ProvideRuntimeApi, - PRA::Api: GrandpaApi, SC: SelectChain, { - use sr_primitives::traits::Zero; - let chain_info = client.info(); let genesis_hash = chain_info.chain.genesis_hash; @@ -395,12 +407,11 @@ where genesis_hash, >::zero(), || { - let genesis_authorities = api.runtime_api() - .grandpa_authorities(&BlockId::number(Zero::zero()))?; + let authorities = genesis_authorities_provider.get()?; telemetry!(CONSENSUS_DEBUG; "afg.loading_authorities"; - "authorities_len" => ?genesis_authorities.len() + "authorities_len" => ?authorities.len() ); - Ok(genesis_authorities) + Ok(authorities) } )?; diff --git a/core/finality-grandpa/src/light_import.rs b/core/finality-grandpa/src/light_import.rs index 30af3a06d3..30008b51ec 100644 --- a/core/finality-grandpa/src/light_import.rs +++ b/core/finality-grandpa/src/light_import.rs @@ -34,17 +34,18 @@ use consensus_common::{ }; use network::config::{BoxFinalityProofRequestBuilder, FinalityProofRequestBuilder}; use sr_primitives::Justification; -use sr_primitives::traits::{ - NumberFor, Block as BlockT, Header as HeaderT, ProvideRuntimeApi, DigestFor, -}; -use fg_primitives::{self, GrandpaApi, AuthorityId}; +use sr_primitives::traits::{NumberFor, Block as BlockT, Header as HeaderT, DigestFor}; +use fg_primitives::{self, AuthorityList}; use sr_primitives::generic::BlockId; use primitives::{H256, Blake2Hasher}; +use crate::GenesisAuthoritySetProvider; use crate::aux_schema::load_decode; use crate::consensus_changes::ConsensusChanges; use crate::environment::canonical_at_height; -use crate::finality_proof::{AuthoritySetForFinalityChecker, ProvableJustification, make_finality_proof_request}; +use crate::finality_proof::{ + AuthoritySetForFinalityChecker, ProvableJustification, make_finality_proof_request, +}; use crate::justification::GrandpaJustification; /// LightAuthoritySet is saved under this key in aux storage. @@ -53,21 +54,23 @@ const LIGHT_AUTHORITY_SET_KEY: &[u8] = b"grandpa_voters"; const LIGHT_CONSENSUS_CHANGES_KEY: &[u8] = b"grandpa_consensus_changes"; /// Create light block importer. -pub fn light_block_import, RA, PRA>( +pub fn light_block_import, RA>( client: Arc>, backend: Arc, + genesis_authorities_provider: &dyn GenesisAuthoritySetProvider, authority_set_provider: Arc>, - api: Arc, ) -> Result, ClientError> where B: Backend + 'static, E: CallExecutor + 'static + Clone + Send + Sync, RA: Send + Sync, - PRA: ProvideRuntimeApi, - PRA::Api: GrandpaApi, { let info = client.info(); - let import_data = load_aux_import_data(info.chain.finalized_hash, &*client, api)?; + let import_data = load_aux_import_data( + info.chain.finalized_hash, + &*client, + genesis_authorities_provider, + )?; Ok(GrandpaLightBlockImport { client, backend, @@ -110,7 +113,7 @@ struct LightImportData> { #[derive(Debug, Encode, Decode)] struct LightAuthoritySet { set_id: u64, - authorities: Vec<(AuthorityId, u64)>, + authorities: AuthorityList, } impl, RA> GrandpaLightBlockImport { @@ -194,7 +197,7 @@ impl, RA> FinalityProofImport impl LightAuthoritySet { /// Get a genesis set with given authorities. - pub fn genesis(initial: Vec<(AuthorityId, u64)>) -> Self { + pub fn genesis(initial: AuthorityList) -> Self { LightAuthoritySet { set_id: fg_primitives::SetId::default(), authorities: initial, @@ -207,12 +210,12 @@ impl LightAuthoritySet { } /// Get latest authorities set. - pub fn authorities(&self) -> Vec<(AuthorityId, u64)> { + pub fn authorities(&self) -> AuthorityList { self.authorities.clone() } /// Set new authorities set. - pub fn update(&mut self, set_id: u64, authorities: Vec<(AuthorityId, u64)>) { + pub fn update(&mut self, set_id: u64, authorities: AuthorityList) { self.set_id = set_id; std::mem::replace(&mut self.authorities, authorities); } @@ -472,17 +475,14 @@ fn do_finalize_block>( } /// Load light import aux data from the store. -fn load_aux_import_data, PRA>( +fn load_aux_import_data>( last_finalized: Block::Hash, aux_store: &B, - api: Arc, + genesis_authorities_provider: &dyn GenesisAuthoritySetProvider, ) -> Result, ClientError> where B: AuxStore, - PRA: ProvideRuntimeApi, - PRA::Api: GrandpaApi, { - use sr_primitives::traits::Zero; let authority_set = match load_decode(aux_store, LIGHT_AUTHORITY_SET_KEY)? { Some(authority_set) => authority_set, None => { @@ -490,7 +490,7 @@ fn load_aux_import_data, PRA>( from genesis on what appears to be first startup."); // no authority set on disk: fetch authorities from genesis state - let genesis_authorities = api.runtime_api().grandpa_authorities(&BlockId::number(Zero::zero()))?; + let genesis_authorities = genesis_authorities_provider.get()?; let authority_set = LightAuthoritySet::genesis(genesis_authorities); let encoded = authority_set.encode(); @@ -546,6 +546,7 @@ fn on_post_finalization_error(error: ClientError, value_type: &str) -> Consensus pub mod tests { use super::*; use consensus_common::ForkChoiceStrategy; + use fg_primitives::AuthorityId; use primitives::{H256, crypto::Public}; use test_client::client::in_mem::Blockchain as InMemoryAuxStore; use test_client::runtime::{Block, Header}; @@ -622,20 +623,19 @@ pub mod tests { } /// Creates light block import that ignores justifications that came outside of finality proofs. - pub fn light_block_import_without_justifications, RA, PRA>( + pub fn light_block_import_without_justifications, RA>( client: Arc>, backend: Arc, + genesis_authorities_provider: &dyn GenesisAuthoritySetProvider, authority_set_provider: Arc>, - api: Arc, ) -> Result, ClientError> where B: Backend + 'static, E: CallExecutor + 'static + Clone + Send + Sync, RA: Send + Sync, - PRA: ProvideRuntimeApi, - PRA::Api: GrandpaApi, { - light_block_import(client, backend, authority_set_provider, api).map(NoJustificationsImport) + light_block_import(client, backend, genesis_authorities_provider, authority_set_provider) + .map(NoJustificationsImport) } fn import_block( @@ -729,14 +729,14 @@ pub mod tests { #[test] fn aux_data_updated_on_start() { let aux_store = InMemoryAuxStore::::new(); - let api = Arc::new(TestApi::new(vec![(AuthorityId::from_slice(&[1; 32]), 1)])); + let api = TestApi::new(vec![(AuthorityId::from_slice(&[1; 32]), 1)]); // when aux store is empty initially assert!(aux_store.get_aux(LIGHT_AUTHORITY_SET_KEY).unwrap().is_none()); assert!(aux_store.get_aux(LIGHT_CONSENSUS_CHANGES_KEY).unwrap().is_none()); // it is updated on importer start - load_aux_import_data(Default::default(), &aux_store, api).unwrap(); + load_aux_import_data(Default::default(), &aux_store, &api).unwrap(); assert!(aux_store.get_aux(LIGHT_AUTHORITY_SET_KEY).unwrap().is_some()); assert!(aux_store.get_aux(LIGHT_CONSENSUS_CHANGES_KEY).unwrap().is_some()); } @@ -744,7 +744,7 @@ pub mod tests { #[test] fn aux_data_loaded_on_restart() { let aux_store = InMemoryAuxStore::::new(); - let api = Arc::new(TestApi::new(vec![(AuthorityId::from_slice(&[1; 32]), 1)])); + let api = TestApi::new(vec![(AuthorityId::from_slice(&[1; 32]), 1)]); // when aux store is non-empty initially let mut consensus_changes = ConsensusChanges::::empty(); @@ -766,7 +766,7 @@ pub mod tests { ).unwrap(); // importer uses it on start - let data = load_aux_import_data(Default::default(), &aux_store, api).unwrap(); + let data = load_aux_import_data(Default::default(), &aux_store, &api).unwrap(); assert_eq!(data.authority_set.authorities(), vec![(AuthorityId::from_slice(&[42; 32]), 2)]); assert_eq!(data.consensus_changes.pending_changes(), &[(42, Default::default())]); } diff --git a/core/finality-grandpa/src/tests.rs b/core/finality-grandpa/src/tests.rs index 2339379a60..93c08a9661 100644 --- a/core/finality-grandpa/src/tests.rs +++ b/core/finality-grandpa/src/tests.rs @@ -39,7 +39,7 @@ use codec::Decode; use sr_primitives::traits::{ApiRef, ProvideRuntimeApi, Header as HeaderT}; use sr_primitives::generic::{BlockId, DigestItem}; use primitives::{NativeOrEncoded, ExecutionContext, crypto::Public}; -use fg_primitives::{GRANDPA_ENGINE_ID, AuthorityId}; +use fg_primitives::{GRANDPA_ENGINE_ID, AuthorityList}; use state_machine::{backend::InMemory, prove_read, read_proof_check}; use authorities::AuthoritySet; @@ -137,8 +137,8 @@ impl TestNetFactory for GrandpaTestNet { let import = light_block_import_without_justifications( client.clone(), backend.clone(), + &self.test_config, authorities_provider, - Arc::new(self.test_config.clone()) ).expect("Could not create block import for fresh peer."); let finality_proof_req_builder = import.0.create_finality_proof_request_builder(); let proof_import = Box::new(import.clone()); @@ -188,26 +188,24 @@ impl Future for Exit { #[derive(Default, Clone)] pub(crate) struct TestApi { - genesis_authorities: Vec<(AuthorityId, u64)>, + genesis_authorities: AuthorityList, } impl TestApi { - pub fn new(genesis_authorities: Vec<(AuthorityId, u64)>) -> Self { + pub fn new(genesis_authorities: AuthorityList) -> Self { TestApi { genesis_authorities, } } } -pub(crate) struct RuntimeApi { - inner: TestApi, -} +pub(crate) struct RuntimeApi; impl ProvideRuntimeApi for TestApi { type Api = RuntimeApi; fn runtime_api<'a>(&'a self) -> ApiRef<'a, Self::Api> { - RuntimeApi { inner: self.clone() }.into() + RuntimeApi.into() } } @@ -264,26 +262,15 @@ impl ApiExt for RuntimeApi { } } -impl GrandpaApi for RuntimeApi { - fn GrandpaApi_grandpa_authorities_runtime_api_impl( - &self, - _: &BlockId, - _: ExecutionContext, - _: Option<()>, - _: Vec, - ) -> Result>> { - Ok(self.inner.genesis_authorities.clone()).map(NativeOrEncoded::Native) +impl GenesisAuthoritySetProvider for TestApi { + fn get(&self) -> Result { + Ok(self.genesis_authorities.clone()) } } impl AuthoritySetForFinalityProver for TestApi { - fn authorities(&self, block: &BlockId) -> Result> { - let runtime_api = RuntimeApi { inner: self.clone() }; - runtime_api.GrandpaApi_grandpa_authorities_runtime_api_impl(block, ExecutionContext::Syncing, None, Vec::new()) - .map(|v| match v { - NativeOrEncoded::Native(value) => value, - _ => unreachable!("only providing native values"), - }) + fn authorities(&self, _block: &BlockId) -> Result { + Ok(self.genesis_authorities.clone()) } fn prove_authorities(&self, block: &BlockId) -> Result { @@ -303,7 +290,7 @@ impl AuthoritySetForFinalityChecker for TestApi { _hash: ::Hash, header: ::Header, proof: StorageProof, - ) -> Result> { + ) -> Result { let results = read_proof_check::( *header.state_root(), proof, vec![b"authorities"] ) @@ -320,7 +307,7 @@ impl AuthoritySetForFinalityChecker for TestApi { const TEST_GOSSIP_DURATION: Duration = Duration::from_millis(500); -fn make_ids(keys: &[Ed25519Keyring]) -> Vec<(AuthorityId, u64)> { +fn make_ids(keys: &[Ed25519Keyring]) -> AuthorityList { keys.iter().map(|key| key.clone().public().into()).map(|id| (id, 1)).collect() } diff --git a/node-template/runtime/src/lib.rs b/node-template/runtime/src/lib.rs index c0cd2cf337..5b440cdd9b 100644 --- a/node-template/runtime/src/lib.rs +++ b/node-template/runtime/src/lib.rs @@ -23,8 +23,7 @@ use client::{ runtime_api as client_api, impl_runtime_apis }; use aura_primitives::sr25519::AuthorityId as AuraId; -use grandpa::{AuthorityId as GrandpaId, AuthorityWeight as GrandpaWeight}; -use grandpa::fg_primitives; +use grandpa::AuthorityId as GrandpaId; use version::RuntimeVersion; #[cfg(feature = "std")] use version::NativeVersion; @@ -353,10 +352,4 @@ impl_runtime_apis! { opaque::SessionKeys::generate(seed) } } - - impl fg_primitives::GrandpaApi for Runtime { - fn grandpa_authorities() -> Vec<(GrandpaId, GrandpaWeight)> { - Grandpa::grandpa_authorities() - } - } } diff --git a/node-template/src/service.rs b/node-template/src/service.rs index 398795325f..7967a1d2d4 100644 --- a/node-template/src/service.rs +++ b/node-template/src/service.rs @@ -48,7 +48,7 @@ macro_rules! new_full_start { .ok_or_else(|| substrate_service::Error::SelectChainRequired)?; let (grandpa_block_import, grandpa_link) = - grandpa::block_import::<_, _, _, runtime::RuntimeApi, _, _>( + grandpa::block_import::<_, _, _, runtime::RuntimeApi, _>( client.clone(), &*client, select_chain )?; @@ -197,8 +197,8 @@ pub fn new_light(config: Configuration( - client.clone(), backend, Arc::new(fetch_checker), client.clone() + let grandpa_block_import = grandpa::light_block_import::<_, _, _, RuntimeApi>( + client.clone(), backend, &*client.clone(), Arc::new(fetch_checker), )?; let finality_proof_import = grandpa_block_import.clone(); let finality_proof_request_builder = diff --git a/node/cli/src/service.rs b/node/cli/src/service.rs index 47e36bd926..789dfc02fb 100644 --- a/node/cli/src/service.rs +++ b/node/cli/src/service.rs @@ -69,10 +69,11 @@ macro_rules! new_full_start { .with_import_queue(|_config, client, mut select_chain, _transaction_pool| { let select_chain = select_chain.take() .ok_or_else(|| substrate_service::Error::SelectChainRequired)?; - let (grandpa_block_import, grandpa_link) = - grandpa::block_import::<_, _, _, node_runtime::RuntimeApi, _, _>( - client.clone(), &*client, select_chain - )?; + let (grandpa_block_import, grandpa_link) = grandpa::block_import( + client.clone(), + &*client, + select_chain, + )?; let justification_import = grandpa_block_import.clone(); let (block_import, babe_link) = babe::block_import( @@ -291,8 +292,11 @@ pub fn new_light(config: NodeConfiguration) let fetch_checker = fetcher .map(|fetcher| fetcher.checker().clone()) .ok_or_else(|| "Trying to start light import queue without active fetch checker")?; - let grandpa_block_import = grandpa::light_block_import::<_, _, _, RuntimeApi, _>( - client.clone(), backend, Arc::new(fetch_checker), client.clone() + let grandpa_block_import = grandpa::light_block_import::<_, _, _, RuntimeApi>( + client.clone(), + backend, + &*client, + Arc::new(fetch_checker), )?; let finality_proof_import = grandpa_block_import.clone(); diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index a0ee20988e..adee13775d 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -29,7 +29,6 @@ use node_primitives::{ AccountId, AccountIndex, Balance, BlockNumber, Hash, Index, Moment, Signature, }; -use grandpa::fg_primitives; use client::{ block_builder::api::{self as block_builder_api, InherentData, CheckInherentsResult}, runtime_api as client_api, impl_runtime_apis @@ -46,7 +45,7 @@ use version::RuntimeVersion; #[cfg(any(feature = "std", test))] use version::NativeVersion; use primitives::OpaqueMetadata; -use grandpa::{AuthorityId as GrandpaId, AuthorityWeight as GrandpaWeight}; +use grandpa::AuthorityId as GrandpaId; use im_online::sr25519::{AuthorityId as ImOnlineId}; use transaction_payment_rpc_runtime_api::RuntimeDispatchInfo; use contracts_rpc_runtime_api::ContractExecResult; @@ -81,7 +80,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // and set impl_version to equal spec_version. If only runtime // implementation changes and behavior does not, then leave spec_version as // is and increment impl_version. - spec_version: 190, + spec_version: 191, impl_version: 191, apis: RUNTIME_API_VERSIONS, }; @@ -611,12 +610,6 @@ impl_runtime_apis! { } } - impl fg_primitives::GrandpaApi for Runtime { - fn grandpa_authorities() -> Vec<(GrandpaId, GrandpaWeight)> { - Grandpa::grandpa_authorities() - } - } - impl babe_primitives::BabeApi for Runtime { fn configuration() -> babe_primitives::BabeConfiguration { // The choice of `c` parameter (where `1 - c` represents the diff --git a/srml/grandpa/Cargo.toml b/srml/grandpa/Cargo.toml index 4b494cfeff..21b48d3cdc 100644 --- a/srml/grandpa/Cargo.toml +++ b/srml/grandpa/Cargo.toml @@ -35,3 +35,4 @@ std = [ "session/std", "finality-tracker/std", ] +migrate-authorities = [] diff --git a/srml/grandpa/src/lib.rs b/srml/grandpa/src/lib.rs index f3e876f2c4..b635b88521 100644 --- a/srml/grandpa/src/lib.rs +++ b/srml/grandpa/src/lib.rs @@ -21,9 +21,6 @@ //! //! In the future, it will also handle misbehavior reports, and on-chain //! finality notifications. -//! -//! For full integration with GRANDPA, the `GrandpaApi` should be implemented. -//! The necessary items are re-exported via the `fg_primitives` crate. #![cfg_attr(not(feature = "std"), no_std)] @@ -32,9 +29,7 @@ pub use substrate_finality_grandpa_primitives as fg_primitives; use rstd::prelude::*; use codec::{self as codec, Encode, Decode, Error}; -use support::{ - decl_event, decl_storage, decl_module, dispatch::Result, -}; +use support::{decl_event, decl_storage, decl_module, dispatch::Result, storage}; use sr_primitives::{ generic::{DigestItem, OpaqueDigestItemId}, traits::Zero, Perbill, }; @@ -42,8 +37,10 @@ use sr_staking_primitives::{ SessionIndex, offence::{Offence, Kind}, }; -use fg_primitives::{GRANDPA_ENGINE_ID, ScheduledChange, ConsensusLog, SetId, RoundNumber}; -pub use fg_primitives::{AuthorityId, AuthorityWeight}; +use fg_primitives::{ + GRANDPA_AUTHORITIES_KEY, GRANDPA_ENGINE_ID, ScheduledChange, ConsensusLog, SetId, RoundNumber, +}; +pub use fg_primitives::{AuthorityId, AuthorityList, AuthorityWeight, VersionedAuthorityList}; use system::{ensure_signed, DigestOf}; mod mock; @@ -64,7 +61,7 @@ pub struct OldStoredPendingChange { /// The delay in blocks until it will be applied. pub delay: N, /// The next authority set. - pub next_authorities: Vec<(AuthorityId, AuthorityWeight)>, + pub next_authorities: AuthorityList, } /// A stored pending change. @@ -75,7 +72,7 @@ pub struct StoredPendingChange { /// The delay in blocks until it will be applied. pub delay: N, /// The next authority set. - pub next_authorities: Vec<(AuthorityId, AuthorityWeight)>, + pub next_authorities: AuthorityList, /// If defined it means the change was forced and the given block number /// indicates the median last finalized block when the change was signaled. pub forced: Option, @@ -126,7 +123,7 @@ pub enum StoredState { decl_event!( pub enum Event { /// New authority set has been applied. - NewAuthorities(Vec<(AuthorityId, AuthorityWeight)>), + NewAuthorities(AuthorityList), /// Current authority set has been paused. Paused, /// Current authority set has been resumed. @@ -136,8 +133,12 @@ decl_event!( decl_storage! { trait Store for Module as GrandpaFinality { - /// The current authority set. - Authorities get(fn authorities): Vec<(AuthorityId, AuthorityWeight)>; + /// DEPRECATED + /// + /// This used to store the current authority set, which has been migrated to the well-known + /// GRANDPA_AUTHORITES_KEY unhashed key. + #[cfg(feature = "migrate-authorities")] + pub(crate) Authorities get(fn authorities): AuthorityList; /// State of the current authority set. State get(fn state): StoredState = StoredState::Live; @@ -159,7 +160,7 @@ decl_storage! { SetIdSession get(fn session_for_set): map SetId => Option; } add_extra_genesis { - config(authorities): Vec<(AuthorityId, AuthorityWeight)>; + config(authorities): AuthorityList; build(|config| Module::::initialize_authorities(&config.authorities)) } } @@ -174,6 +175,11 @@ decl_module! { // FIXME: https://github.com/paritytech/substrate/issues/1112 } + fn on_initialize() { + #[cfg(feature = "migrate-authorities")] + Self::migrate_authorities(); + } + fn on_finalize(block_number: T::BlockNumber) { // check for scheduled pending authority set changes if let Some(pending_change) = >::get() { @@ -199,7 +205,7 @@ decl_module! { // enact the change if we've reached the enacting block if block_number == pending_change.scheduled_at + pending_change.delay { - Authorities::put(&pending_change.next_authorities); + Self::set_grandpa_authorities(&pending_change.next_authorities); Self::deposit_event( Event::NewAuthorities(pending_change.next_authorities) ); @@ -241,8 +247,16 @@ decl_module! { impl Module { /// Get the current set of authorities, along with their respective weights. - pub fn grandpa_authorities() -> Vec<(AuthorityId, AuthorityWeight)> { - Authorities::get() + pub fn grandpa_authorities() -> AuthorityList { + storage::unhashed::get_or_default::(GRANDPA_AUTHORITIES_KEY).into() + } + + /// Set the current set of authorities, along with their respective weights. + fn set_grandpa_authorities(authorities: &AuthorityList) { + storage::unhashed::put( + GRANDPA_AUTHORITIES_KEY, + &VersionedAuthorityList::from(authorities), + ); } /// Schedule GRANDPA to pause starting in the given number of blocks. @@ -293,7 +307,7 @@ impl Module { /// No change should be signaled while any change is pending. Returns /// an error if a change is already pending. pub fn schedule_change( - next_authorities: Vec<(AuthorityId, AuthorityWeight)>, + next_authorities: AuthorityList, in_blocks: T::BlockNumber, forced: Option, ) -> Result { @@ -329,10 +343,20 @@ impl Module { >::deposit_log(log.into()); } - fn initialize_authorities(authorities: &[(AuthorityId, AuthorityWeight)]) { + fn initialize_authorities(authorities: &AuthorityList) { if !authorities.is_empty() { - assert!(Authorities::get().is_empty(), "Authorities are already initialized!"); - Authorities::put(authorities); + assert!( + Self::grandpa_authorities().is_empty(), + "Authorities are already initialized!" + ); + Self::set_grandpa_authorities(authorities); + } + } + + #[cfg(feature = "migrate-authorities")] + fn migrate_authorities() { + if Authorities::exists() { + Self::set_grandpa_authorities(&Authorities::take()); } } } diff --git a/srml/grandpa/src/mock.rs b/srml/grandpa/src/mock.rs index fcacbade20..c6ea207557 100644 --- a/srml/grandpa/src/mock.rs +++ b/srml/grandpa/src/mock.rs @@ -23,7 +23,7 @@ use runtime_io; use support::{impl_outer_origin, impl_outer_event, parameter_types}; use primitives::H256; use codec::{Encode, Decode}; -use crate::{AuthorityId, GenesisConfig, Trait, Module, ConsensusLog}; +use crate::{AuthorityId, AuthorityList, GenesisConfig, Trait, Module, ConsensusLog}; use substrate_finality_grandpa_primitives::GRANDPA_ENGINE_ID; impl_outer_origin!{ @@ -75,7 +75,7 @@ impl_outer_event!{ } } -pub fn to_authorities(vec: Vec<(u64, u64)>) -> Vec<(AuthorityId, u64)> { +pub fn to_authorities(vec: Vec<(u64, u64)>) -> AuthorityList { vec.into_iter() .map(|(id, weight)| (UintAuthorityId(id).to_public_key::(), weight)) .collect() diff --git a/srml/grandpa/src/tests.rs b/srml/grandpa/src/tests.rs index 2efeb4b5bf..3d6a8752c5 100644 --- a/srml/grandpa/src/tests.rs +++ b/srml/grandpa/src/tests.rs @@ -308,3 +308,21 @@ fn time_slot_have_sane_ord() { ]; assert!(FIXTURE.windows(2).all(|f| f[0] < f[1])); } + +#[test] +#[cfg(feature = "migrate-authorities")] +fn authorities_migration() { + use sr_primitives::traits::OnInitialize; + + with_externalities(&mut new_test_ext(vec![]), || { + let authorities = to_authorities(vec![(1, 1), (2, 1), (3, 1)]); + + Authorities::put(authorities.clone()); + assert!(Grandpa::grandpa_authorities().is_empty()); + + Grandpa::on_initialize(1); + + assert!(!Authorities::exists()); + assert_eq!(Grandpa::grandpa_authorities(), authorities); + }); +} -- GitLab From afc630405ad4fcb229bcc0633dfd564e99afedb1 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Thu, 31 Oct 2019 16:34:12 +0100 Subject: [PATCH 151/167] Add the code for compiling node-cli for WASM-browser (#3974) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Extract CLI to separate module in node/cli * Make node/cli compile for WASM * More work on node/cli browser * More work on browser node * More work * More work * Purge a bit the CI script * More clean up * Remove substrate-finality-grandpa from the CI Its tests use tokio, which fails to compile. * Address review * Add rocksdb feature to the service * Fix substrate-service WASM CI * Apply suggestions from code review Co-Authored-By: Bastian Köcher * Don't WASM-compile substrate-service altogether --- .gitlab-ci.yml | 16 +-- Cargo.lock | 31 +++++ core/cli/Cargo.toml | 2 +- core/service/Cargo.toml | 8 +- core/service/src/lib.rs | 5 +- core/service/test/Cargo.toml | 2 +- node/cli/Cargo.toml | 56 ++++++-- node/cli/bin/main.rs | 6 +- node/cli/browser-demo/.gitignore | 1 + node/cli/browser-demo/README.md | 10 ++ node/cli/browser-demo/build.sh | 3 + node/cli/browser-demo/favicon.png | Bin 0 -> 10338 bytes node/cli/browser-demo/index.html | 39 ++++++ node/cli/browser-demo/ws.js | 148 +++++++++++++++++++++ node/cli/build.rs | 2 +- node/cli/src/browser.rs | 159 ++++++++++++++++++++++ node/cli/src/cli.rs | 210 +++++++++++++++++++++++++++++ node/cli/src/lib.rs | 213 +++--------------------------- 18 files changed, 687 insertions(+), 224 deletions(-) create mode 100644 node/cli/browser-demo/.gitignore create mode 100644 node/cli/browser-demo/README.md create mode 100755 node/cli/browser-demo/build.sh create mode 100644 node/cli/browser-demo/favicon.png create mode 100644 node/cli/browser-demo/index.html create mode 100644 node/cli/browser-demo/ws.js create mode 100644 node/cli/src/browser.rs create mode 100644 node/cli/src/cli.rs diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index baca78fd3a..7a0fdb9954 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -202,25 +202,13 @@ check-web-wasm: - time cargo web build -p sr-io - time cargo web build -p sr-primitives - time cargo web build -p sr-std - - time cargo web build -p substrate-chain-spec - time cargo web build -p substrate-client - time cargo web build -p substrate-consensus-aura - time cargo web build -p substrate-consensus-babe - time cargo web build -p substrate-consensus-common - - time cargo web build -p substrate-keyring - - time cargo web build -p substrate-keystore - - time cargo web build -p substrate-executor - - time cargo web build -p substrate-network - - time cargo web build -p substrate-offchain - - time cargo web build -p substrate-panic-handler - - time cargo web build -p substrate-peerset - - time cargo web build -p substrate-primitives - - time cargo web build -p substrate-rpc-servers - - time cargo web build -p substrate-serializer - - time cargo web build -p substrate-state-db - - time cargo web build -p substrate-state-machine - time cargo web build -p substrate-telemetry - - time cargo web build -p substrate-trie + # Note: the command below is a bit weird because several Cargo issues prevent us from compiling the node in a more straight-forward way. + - time cargo build --manifest-path=node/cli/Cargo.toml --no-default-features --features "browser" --target=wasm32-unknown-unknown - sccache -s node-exits: diff --git a/Cargo.lock b/Cargo.lock index 5bee6302ec..c32a690b33 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -468,6 +468,24 @@ dependencies = [ "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "console_error_panic_hook" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "console_log" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "web-sys 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "const-random" version = "0.1.6" @@ -1153,6 +1171,7 @@ dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2377,18 +2396,25 @@ dependencies = [ name = "node-cli" version = "2.0.0" dependencies = [ + "clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "console_error_panic_hook 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "console_log 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "ctrlc 3.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "exit-future 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "futures-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", "hex-literal 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "js-sys 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "kvdb-memorydb 0.1.0 (git+https://github.com/paritytech/parity-common?rev=b0317f649ab2c665b7987b8475878fc4d2e1f81d)", + "libp2p 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "node-executor 2.0.0", "node-primitives 2.0.0", "node-rpc 2.0.0", "node-runtime 2.0.0", "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 2.0.0", @@ -2428,6 +2454,8 @@ dependencies = [ "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", "transaction-factory 0.0.1", "vergen 3.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-futures 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3351,6 +3379,7 @@ dependencies = [ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -6910,6 +6939,8 @@ dependencies = [ "checksum clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "97276801e127ffb46b66ce23f35cc96bd454fa311294bced4bbace7baa8b1d17" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum cmake 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "81fb25b677f8bf1eb325017cb6bb8452f87969db0fedb4f757b297bee78a7c62" +"checksum console_error_panic_hook 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b8d976903543e0c48546a91908f21588a680a8c8f984df9a5d69feccb2b2a211" +"checksum console_log 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1e7871d2947441b0fdd8e2bd1ce2a2f75304f896582c0d572162d48290683c48" "checksum const-random 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7b641a8c9867e341f3295564203b1c250eb8ce6cb6126e007941f78c4d2ed7fe" "checksum const-random-macro 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c750ec12b83377637110d5a57f5ae08e895b06c4b16e2bdbf1a94ef717428c59" "checksum constant_time_eq 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "995a44c877f9212528ccc74b21a232f66ad69001e40ede5bcee2ac9ef2657120" diff --git a/core/cli/Cargo.toml b/core/cli/Cargo.toml index a2723484ad..2298bba0b7 100644 --- a/core/cli/Cargo.toml +++ b/core/cli/Cargo.toml @@ -28,7 +28,7 @@ header-metadata = { package = "substrate-header-metadata", path = "../../core/cl network = { package = "substrate-network", path = "../../core/network" } sr-primitives = { path = "../../core/sr-primitives" } primitives = { package = "substrate-primitives", path = "../../core/primitives" } -service = { package = "substrate-service", path = "../../core/service" } +service = { package = "substrate-service", path = "../../core/service", default-features = false } state-machine = { package = "substrate-state-machine", path = "../../core/state-machine" } substrate-telemetry = { path = "../../core/telemetry" } keyring = { package = "substrate-keyring", path = "../keyring" } diff --git a/core/service/Cargo.toml b/core/service/Cargo.toml index 0d6f279362..1a85ed8de0 100644 --- a/core/service/Cargo.toml +++ b/core/service/Cargo.toml @@ -4,6 +4,12 @@ version = "2.0.0" authors = ["Parity Technologies "] edition = "2018" +[features] +default = ["rocksdb"] +# The RocksDB feature activates the RocksDB database backend. If it is not activated, and you pass +# a path to a database, an error will be produced at runtime. +rocksdb = ["client_db/kvdb-rocksdb"] + [dependencies] derive_more = "0.15.0" futures = "0.1.29" @@ -29,7 +35,7 @@ consensus_common = { package = "substrate-consensus-common", path = "../../core/ network = { package = "substrate-network", path = "../../core/network" } chain-spec = { package = "substrate-chain-spec", path = "../chain-spec" } client = { package = "substrate-client", path = "../../core/client" } -client_db = { package = "substrate-client-db", path = "../../core/client/db", features = ["kvdb-rocksdb"] } +client_db = { package = "substrate-client-db", path = "../../core/client/db" } codec = { package = "parity-scale-codec", version = "1.0.0" } substrate-executor = { path = "../../core/executor" } transaction_pool = { package = "substrate-transaction-pool", path = "../../core/transaction-pool" } diff --git a/core/service/src/lib.rs b/core/service/src/lib.rs index 3057b8ce4d..c46732d511 100644 --- a/core/service/src/lib.rs +++ b/core/service/src/lib.rs @@ -541,15 +541,16 @@ fn start_rpc_servers rpc_servers::RpcHandler components::RpcHandler>( +fn start_rpc_servers rpc_servers::RpcHandler>( _: &Configuration, _: H -) -> Result, error::Error> { +) -> Result, error::Error> { Ok(Box::new(())) } /// An RPC session. Used to perform in-memory RPC queries (ie. RPC queries that don't go through /// the HTTP or WebSockets server). +#[derive(Clone)] pub struct RpcSession { metadata: rpc::Metadata, } diff --git a/core/service/test/Cargo.toml b/core/service/test/Cargo.toml index 872d63415f..4415369a6a 100644 --- a/core/service/test/Cargo.toml +++ b/core/service/test/Cargo.toml @@ -12,7 +12,7 @@ log = "0.4.8" env_logger = "0.7.0" fdlimit = "0.1.1" futures03 = { package = "futures-preview", version = "=0.3.0-alpha.19", features = ["compat"] } -service = { package = "substrate-service", path = "../../../core/service" } +service = { package = "substrate-service", path = "../../../core/service", default-features = false } network = { package = "substrate-network", path = "../../../core/network" } consensus = { package = "substrate-consensus-common", path = "../../../core/consensus/common" } client = { package = "substrate-client", path = "../../../core/client" } diff --git a/node/cli/Cargo.toml b/node/cli/Cargo.toml index b85014eeef..99a4c6aebf 100644 --- a/node/cli/Cargo.toml +++ b/node/cli/Cargo.toml @@ -16,14 +16,15 @@ is-it-maintained-open-issues = { repository = "paritytech/substrate" } [[bin]] name = "substrate" path = "bin/main.rs" +required-features = ["cli"] + +[lib] +crate-type = ["cdylib", "rlib"] [dependencies] log = "0.4.8" -tokio = "0.1.22" futures = "0.1.29" -exit-future = "0.1.4" jsonrpc-core = "13.2.0" -cli = { package = "substrate-cli", path = "../../core/cli" } codec = { package = "parity-scale-codec", version = "1.0.0" } sr-io = { path = "../../core/sr-io" } client = { package = "substrate-client", path = "../../core/client" } @@ -35,7 +36,7 @@ node-primitives = { path = "../primitives" } hex-literal = "0.2.1" substrate-rpc = { package = "substrate-rpc", path = "../../core/rpc" } substrate-basic-authorship = { path = "../../core/basic-authorship" } -substrate-service = { path = "../../core/service" } +substrate-service = { path = "../../core/service", default-features = false } chain-spec = { package = "substrate-chain-spec", path = "../../core/chain-spec" } transaction_pool = { package = "substrate-transaction-pool", path = "../../core/transaction-pool" } network = { package = "substrate-network", path = "../../core/network" } @@ -47,7 +48,6 @@ sr-primitives = { path = "../../core/sr-primitives" } node-executor = { path = "../executor" } substrate-telemetry = { package = "substrate-telemetry", path = "../../core/telemetry" } structopt = "0.3.3" -transaction-factory = { path = "../../test-utils/transaction-factory" } keyring = { package = "substrate-keyring", path = "../../core/keyring" } indices = { package = "srml-indices", path = "../../srml/indices" } timestamp = { package = "srml-timestamp", path = "../../srml/timestamp", default-features = false } @@ -60,9 +60,26 @@ transaction-payment = { package = "srml-transaction-payment", path = "../../srml support = { package = "srml-support", path = "../../srml/support", default-features = false } im_online = { package = "srml-im-online", path = "../../srml/im-online", default-features = false } serde = { version = "1.0.101", features = [ "derive" ] } -client_db = { package = "substrate-client-db", path = "../../core/client/db", features = ["kvdb-rocksdb"] } +client_db = { package = "substrate-client-db", path = "../../core/client/db", default-features = false } offchain = { package = "substrate-offchain", path = "../../core/offchain" } -ctrlc = { version = "3.1.3", features = ["termination"] } + +# CLI-specific dependencies +tokio = { version = "0.1.22", optional = true } +exit-future = { version = "0.1.4", optional = true } +substrate-cli = { path = "../../core/cli", optional = true } +transaction-factory = { path = "../../test-utils/transaction-factory", optional = true } +ctrlc = { version = "3.1.3", features = ["termination"], optional = true } + +# WASM-specific dependencies +libp2p = { version = "0.12.0", default-features = false, optional = true } +clear_on_drop = { version = "0.2.3", features = ["no_cc"], optional = true } # Imported just for the `no_cc` feature +console_error_panic_hook = { version = "0.1.1", optional = true } +console_log = { version = "0.1.2", optional = true } +js-sys = { version = "0.3.22", optional = true } +wasm-bindgen = { version = "0.2.45", optional = true } +wasm-bindgen-futures = { version = "0.3.22", optional = true } +kvdb-memorydb = { git = "https://github.com/paritytech/parity-common", rev="b0317f649ab2c665b7987b8475878fc4d2e1f81d", optional = true } +rand6 = { package = "rand", version = "0.6", features = ["wasm-bindgen"], optional = true } # Imported just for the `wasm-bindgen` feature [dev-dependencies] keystore = { package = "substrate-keystore", path = "../../core/keystore" } @@ -73,6 +90,29 @@ futures03 = { package = "futures-preview", version = "0.3.0-alpha.19" } tempfile = "3.1.0" [build-dependencies] -cli = { package = "substrate-cli", path = "../../core/cli" } +substrate-cli = { package = "substrate-cli", path = "../../core/cli" } structopt = "0.3.3" vergen = "3.0.4" + +[features] +default = ["cli"] +browser = [ + "clear_on_drop", + "console_error_panic_hook", + "console_log", + "js-sys", + "libp2p", + "wasm-bindgen", + "wasm-bindgen-futures", + "kvdb-memorydb", + "rand/wasm-bindgen", + "rand6" +] +cli = [ + "substrate-cli", + "transaction-factory", + "tokio", + "exit-future", + "ctrlc", + "substrate-service/rocksdb" +] diff --git a/node/cli/bin/main.rs b/node/cli/bin/main.rs index 4b07d8c8a4..e4415a2a89 100644 --- a/node/cli/bin/main.rs +++ b/node/cli/bin/main.rs @@ -18,15 +18,15 @@ #![warn(missing_docs)] -use cli::VersionInfo; use futures::sync::oneshot; use futures::{future, Future}; +use substrate_cli::VersionInfo; use std::cell::RefCell; // handles ctrl-c struct Exit; -impl cli::IntoExit for Exit { +impl substrate_cli::IntoExit for Exit { type Exit = future::MapErr, fn(oneshot::Canceled) -> ()>; fn into_exit(self) -> Self::Exit { // can't use signal directly here because CtrlC takes only `Fn`. @@ -43,7 +43,7 @@ impl cli::IntoExit for Exit { } } -fn main() -> Result<(), cli::error::Error> { +fn main() -> Result<(), substrate_cli::error::Error> { let version = VersionInfo { name: "Substrate Node", commit: env!("VERGEN_SHA_SHORT"), diff --git a/node/cli/browser-demo/.gitignore b/node/cli/browser-demo/.gitignore new file mode 100644 index 0000000000..0c6117d9fb --- /dev/null +++ b/node/cli/browser-demo/.gitignore @@ -0,0 +1 @@ +pkg \ No newline at end of file diff --git a/node/cli/browser-demo/README.md b/node/cli/browser-demo/README.md new file mode 100644 index 0000000000..4faebcbc76 --- /dev/null +++ b/node/cli/browser-demo/README.md @@ -0,0 +1,10 @@ +# How to run this demo + +```sh +cargo install wasm-pack # If necessary + +# From the `node/cli` directory (parent from this README) +wasm-pack build --target web --out-dir ./demo/pkg --no-typescript --release -- --no-default-features --features "browser" + +xdg-open index.html +``` diff --git a/node/cli/browser-demo/build.sh b/node/cli/browser-demo/build.sh new file mode 100755 index 0000000000..c16100794a --- /dev/null +++ b/node/cli/browser-demo/build.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env sh +wasm-pack build --target web --out-dir ./browser-demo/pkg --no-typescript --release ./.. -- --no-default-features --features "browser" +python -m SimpleHTTPServer 8000 diff --git a/node/cli/browser-demo/favicon.png b/node/cli/browser-demo/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..8a4548ce34dfa220f612080820cfde778a39cb8f GIT binary patch literal 10338 zcmYLP1yoaS+(wZQfk{a_5mcmyv>+u2qR5bj(d7VXk&w|jQbIxLPKhB5DS^?QA~Be> zGziGpzKj3wJKu9I=j@F4zQ5;ve)Zn>E>cVL2@Mq+6$uFmjk?-nZ4#18f){_3q`)_D zIm|2x$>n3MXF4jp|8W2QeLg-uetv!d0RcflK_MX_VPRnr5fKOg(F;6y@IXvVOdNoO zxP*j+q@<*jl$1088EF|AnTHP_$^wwPz@tZxgej~>gnm} z128Z!Ff=eUG&BNWY;0^|YyvZZ!CuI668y0eJoTwX?Ici?fT1iz@&(H#c`TcMo?D0G^(nZ{ED| zdgJxh>n#9pZ*LzTA739|KVLrp@7}%h_xDHmBLWbJfPjF&z`&rOpx~h3kl^5ukdV;O z(6G?3@UZZR@bHL;h{(vusK}`3sAyz#G!lu7iHV7giH(bmjf;zmkB?7CNJvabe4m*3 z{{8!;q@?8JF(<4>F)0B z>FMq5?d$FB@9P`r?;ji(7#tiN8XO!R8X6fM9vvAO9UU1P9UUJVn;0LToR|QvsmaOd zsi_~+(=$JQ0N2l%nc1H|=VoW;=jMQGVSXOFu&{{5E-qr178h|#OTTcqVf>&8^?Rx3{)-wzqe8cJ_96_xJV=_64TdJb+BN zWTYh5ft@eU`+KYNcD5M{XM?7``7t`@lo-?TqSWw8gC-HkVTpdIuznK{@L`HO%;X5( z5npN=E#+pjd4(c{(Js@-utc}8IBqBXov{8J_{6U^N!lLFkfj7X+1Fy7)$nv6ImVJx z?szijH$G>mSslenblh}AbvmYNFFMuu+U?xF-Dm5u5_I5ROAA7tIsQ2E6d|K5sIz3o$M{LPA|;*R$&mtt|s+o)K?&I~!SYvz&J zUjGn_sjC7^uk`#E;;Xr=-rLo|&?ll9?E9Uu(VJyPzH$BsT7&NGlLW6TR_SA&1=Hth zH8Lf7gWmae?sYz$?uc)d5dX5%++|DERP^5_&yI&);?}a0md`rJgIP==`wy$!v|#5c z&PU@1@^-S5*fhaDO>_Vkv{5(3*Cv`tK>c25fgh(yJ8=3!h%%D1ycF^bWcTT#@|8 z-)Tz2MKd0Ldz^G$1?7bGt;T#B60MjA<6Zc1=3kZ>m@KuSu(?x?<82xa9Q;AErED;w zyTu~iV6?Jgn<3iNnpJ<%N#3t@5v+M?f_LV56HWV`prv&-4)+-PDS%@`+qRQYcl{Ps zPLiMDcrs09FDO6)BPG!!%ryYCh&LY+fCHHupIijy~r}< zAD8;VY8TXy>PTNoj$4g2;qB1WLnb|kqx|;CVqKSEP2Q)G$ko3>H-0*IEU1)c(kVTY z`r_lC4}Zx|4D&L?cz&-I%w?enme1tvsMmYz?s-7Vb%XOItVPGO*z@VS+Mq;X`?wn| zad@{v6gqQF-fJdR$r1nVXvA$IS1)yn1(RRqAOx(Jm4L$Tg60jSnj8f!zB|eOnT8bIQ!mi=P?1()@I&* zOct9!6~1Ek-iT($r;vHIVNB2YTZDzl=fddy7Au0q&WMdte>-IKOJ&DuaJ6drr^Raq zSkvRL2AGLM;l?Wf|I;lQu4W8Gd(Xsf;xFzUnPJXkc8#igt6Ue_6d$Gp(dWA7hNTcvXf2m>OAJxw3PMweYvTYuO3RHmQD4iG7xToc z3Cu-aNpHyzn;@gG&aKumM(=??$YPP&43== z-J_r-ig=)MnPL;r{pNy1Q9Xz0%e3{Y2F%xH-%oamRD5!8rnBUXO`!d_WglwA^O5T+ z&j`muuj83ASAIr z{u6YDe`V*Ue!1pL@T%W^nMvKz_j{kLU>t<(K59S_wuR%|+)Ky=w?R{W)Ke{0_7~-M zLH)me*SifGe%&^~=+JsUaXF!|fqg(|odmZ+Mzas{^dfuhaYf0#iuWD5Jm0Fbh9lx9 z#mgB8#i@?gtf?JfKm)*VLK#vb%&2K~7E`kJE+>d|Tm2#?M$vURmUX)q*MP{t&Xn&r zw1H9M5-+%EudZwJvv6;{>k8eM))9n`ZpMEExv?=zPj-?VCwczU+eS)tX4Tm(o%A$(cELHx zsEws~$`57#yey??x~Evu^$pC7+T#DIYAk{-XL57Ys6~-j<&k3Uw=;g_(T`qMe|N)q z^eYFhI2;MZnlQV^h2kD;Q!3$Uxbwg&Lv^1C0Nw0}jjDU~KqV!eMP09zyfP}3E zraWBw0p|5R>3jwRuo!{F3UK6Apt&N%?H2yU3flg)4^4zrb!o zX2L-FSnL#odt_oX3iP&5={w%q;5NosK@TTYSW_>58GZ5!G=l~T$=SQp9ejW$&WP}Y zm~WXhg3;9&>R>%yY63ExdFBU^$YrKC86_oe?cG*zxlOz)iQYm^Rn-AB%8yG z)n*Q|^sKDch)zS&1~y$!#YhPF=XO@^P8k+tZVEYMwrZEx9uTuw=KZ0C8T!@ccZ_FP z2N+1+-OY{FDoq@HNxof9m(TFz><`am223(g%ac*nnbQAsiVe&%liM*7D405LHBwm2obNuo@ zc22Mm*Y(QtZ~PORR8~AO@)28+PyZUimthUkC!LSToCY{Ib7CBHY^r{1NIJnDBgfY= zx`L-X`^0al!b|tU>+#AQsD99(EkLuXBI@3{gn#n*?Lm$tPddz1!45S(+tbCk86;| z@OONiC{M^q_!px;8SiJ%lsIjL)a!lCOdN#8)Pv!~LHUS2o`b#ATsv*MAj{F7J7t_x z&6R9MKR|sbPdZ5AW%ReI1I;fe`@PElTKSn!dr1FhP}P>3IyHo5r(P)x>hDT>5!9de z8@Obmfb3Y%1H#H5H7*`VJ&`sXCd1H?{%tLJviJS{&D%(g%P>L!BoPBPN9u?f5`F)$ zL>5klKWQ&6f=$^p42$q#W*s(;{+do^IZ_(st_x;1?tWDkLCeab!u^2 z&)mX;Mj{%M+&n+?*7Y^o6N*_D!g#}rsnu^%2eI@#Y$Jov>ujPlUHIUkS6L#snNKjf z-hxDE<`=*n%hlb_P_d?YsUEjf_jduUZQ?EM>6LfTB(d4uazpil5mKcerzO4!-Bxuo z{Iy#@^~WRqDv+(e7S@DRT#!iyf~g%^xL4@XhTF%~IPF&5ztUL;^Y>eBA^BH-SMn3X zCz%Wvw;lr95h-09=#%J79=w4kjO|*h$FD#)HlmAB2kXI%WT5M-8`84B`9*`~aV?^(keUP2oy7TRE`)8|@aMN@)Ip5pHk3p6~-V?0sQ6JAb3BjF<&S{ zjXjelPp=iD;bfff3a{wc%yzS5?=(E*Kf3&p>$T~>P)iPx?T&6XJ|BNaN zezd57S8i|oKMI_|?J4_+-x^>lG_I+A4Y6Mk;VkTajIHiow16duH<r1S+d5iSMp8kekul)g>V zo^;v@D^e{x&wm&mF}QSwa{`DT)m-@7Y*k3*pB$p66u{J=PV-@wUSU6+w#uKk25lKZ z#$p};C*kk)f!$qvW}p!nIdS)qI45(b3ppGRl;T_H3w`IBez|%PmzqjEfk3rj5j&9qU?7EoZZQVed@X zk!v1)ZBkMU9XF8wzOUVQLi!8**Dr)t@NoO6n6JmL!;K0-sfk#B%{Z?&12<`4c8nS> znf*9K?C+YmFUKf$xF1)IgryKk3=0S5-F`TDtl5ImK z7JHbwt(v{*O{P1hA!B(*-viWjorqlo1t8)juWcx%jwqpC3tRWAMD&aoXiOcH^i2Dt zwNL2TcP<+-FM-)iYREW@)?8=lcSPuuMr`Bby?Mj(ApR@+T*x zxk!mBqt68gyA-e?{%};G_u%iAXOTu1QR{t}o47o+X*5$aA^+~Xj zdE|rod<0~m$f%wn6H;2i*_wJu*|;dr7#~^GWkTS#>OWQJxQkPM%}cbYm-^OIOa>tA z2@$K`ojV#;K`ruc`3!y)*lrJ}I`h_`OGE7LQ9L4EHxmSP zlAHuDLG}M`w)U@=X^6GW&z+rE@KOm7;gpEoQ;H?c<02}H zO`rZ6p;sp1%?|hK$^H0%7SqW5O_EiI+a^b^RepGmSN2A55JV{IHmTEQ)l21==wD7= z$zjy?I$bm+tZ5S=)Tt=1}hv&o0(7>d8$J?8pX+ob=(xmYl| zMNX)}=w{TVU5a2t)?T;=s%#T7g#M1vjfDIAboiJ=B#A!i5+mN?Z)Uj2aj_Uc8A=4D zt_t17I6ij$1rf+j8VCzE`g?Pa-kY(I4;Z+dNf>=TKuQP5^FpYsz9mPb)F4 z_~1Bs62juii;}xs+|D@46N&)&Jg1!862Ea5E1pum4~BzQzdc^Lef4g?iL{54d1)ekjGW%G=kBN{{>7f(A@AESh zws(It?_Z?=@)bg_7yUbeX&01L*zh%S-usEgU#i~kP1397xT$#5yLkk$JGVZoiYX#N6wTjDe0+<= zDqK1>Vw-h4P`qMIu3F~{|F+*ng?dDY*Sl|+4=2Nu+N&-)P25E37wk$$vOe{uxO(KH{M>V*J+k@h7LVHO8S(6?VA$k-hW- z)!xT~|B=Hhvk|a}#j5n$U({yCr>@4Ae_B2x!rfL`X5@+WS%4KUXSJV)%=3e23ErjF&4oT3II(28 zilyjGnL7?~tI|W>`%W&u4I{!zIouE5W?GxweB~Wp(eHt*s)f!)dR}T}DKljpTx+<) z*8|b#>7>(TtDBnW0?NVg16~z$qs6BM`AHb`5s}0v?SU`!14Mf!Xv}y^Rqy3b)2aD+ z)ASYatg4RdN%$2w=Q-Ckg!ysKF29e)?L-dL``(sEIcYP0&~>as#g9eVp}>}48t_H? z1MA~(zc_?~`yQW9W$(37GApS@k4#z-SnEFe?+K}W2b);VjK{0jC28YSCln-BF22zE zgp_nH@ox_;AJpDm;)eUe)c;%tSj0!oQ{t%9vY!I8 z`CQb2pzf4kV5-;i&^uRI>yg1fqc7_o{>AFQovw&o7nyMGc)AB7r&ZVo6_!^335fw~ z)5sAnp~Q~)e9Bq1=a+4uOkN}NOE{1Y_vCfB(mrr17t~cHfchXpzM(R5?&M_hhx&e$ zOWirE+dma9VRZi7yDTljKL29#gNfiUG6=A!fB43ylW@muFEb^%Ji1Mu#rR$n0vLjj z5INmooLwK>QVHbuNqpjXZB^^0P%%h0S3~~_(vPgJvfwE zI-C$7aJ6Fkz}$mN)cCf+X4{GzHOyqWIbY9zQQD+@V%=-m_OJiw3%yCjQZ6daxDmQi@*}hl#aTA3`tqL~8eA}EQe!+`xl-GoeeW0C)fbudU=5#2R`V^2@^57+drNm*UV*Rj5*M~cACs;27*+6qTy_~E*30| zqbTPqbez?^W0S3vjf+?K?rC_%0~MfS7aPr*G8R|-P5xqrWFPNTU15d_-yakO3Xz8; z%`U|aV!Rf>f~tiz^c^46G2zH_iwVV1YNBFOYngvSL5lb?pP@x|!Qe#C_6g*+vCXup z{unxfs)<~YUoR1{%b#$9SH6q_HYv#y(cg{l{xF6*V9c?>Bw9zsLERp?6A?sNrcRlYr&fNT{! z215#S8n2At+q1AYfm4`W(Yy}$mh~d&6;son5iXBEuMsdg(eI;{p-@$g<_c4!wPeMcg|MGg+Mf+#He`bkB0JK?yOdM)^>*-wWlKS~ZY^}CxTk=m+XrO$n#1d=KGAr}9DCGkX;n~cL zDF_M`q}N)K*tu=;Ql^lX zO*^w2q1caWX{NV__76zh{g^m~!e8g0&Hz?ehw%qmeXyNd__k&6?lVBMAa0kN*EhiI zpV!hPN9g_O#4Ler5x`s`H_I5B=SR3S__#%4d>}|w-d=}`106ZJ&79qO^#Bw(aY5(@ zlYQ2IgyOv?m+6l9M;z1+ZVL4ZQ{w|W<#}}aj4w=WsRr8RIQaDVnCA9D43tHkbL3k4 z;|=i2qNv#;+V5c53oBEHLZqzPM6q$q<%%>|)YTSBwyOQpa2~k#0B^=$*6Ecsd)A@H zooc@Zf(Cih68~7LNXlQGd#rI1Y6$OK0WXyEme7s_~KB=N(@`=eq zzYzbu6%3r{x=!p*KBPpr{HM0l*ai} zIxOfWkwl%ElRH83T3A`>vmc#b!nyf{lq5%H&TrdyJUsw4Ee!D-Tup-xPcGXTedy4F z(0kWp`JG`F|4X#LfZ|&C;M-!NT73?xfx8r6*~#ugJdlTu4!Z`BzWNW6BWx$6o$~do zE|WX!1JB6Cv9LquJ(T;m`4)zM|_~#mMGJ9-mtW|6|hKTHr%Hto$LtM zWBQKu>YUsZ`Yw!&wpS-`McjX&(H-FFJ;&>Ek4jfnW5uw-w*itk2b|cF0lDaJfdw%V z%~i3H6ElH(7ksuKS7q|$zRM?_HS1w{H8Jq#?ox&4Y2=MXW{gTLqX%|^YkkjN8)Xzn zdJ^0v->S)oF7P@fISIWJ?elf+!@{~xNlvO4L%A!RV2^yrFsCmz0~(dRlIx0$vj7N; zY0L{0g(DNz(#hH{%tN{iy6R1%)mkXY;{KG{pFb-5)GEh-GQkB& zx&jfu4{V*Sq0T>=vO*@m0HP=z#acB z8oz&y6p;m_qRm}oBbdH4zY!Y$nYY$k?%Jj|%D9^)ve{6?8kS`Cp^ZCRvA%=!Vy00% zDZv3S2Rs|n7>;YC9E6oe??-Fxs!60 zScE(sGsk9_2mj%jxlN zbW2lKz;~6dD|f0L0x90?TAa@#HIO}^k+wCg*c>U3ZEgBHF)H3feO>v+(QSO2S~u^1 zYs8J~A}?>J>1gbM*!O6fstcv<%L_3U)Gj*$xuF6UEZJ{DL|iH_p%{q@D~3M2gg`)O zN3$d|mW$L20ge~zrvi)yn1~9?K(440E-ixG4nGO=1(=1%MEs=To>gTc-xklF3>>Oq zgB}t{aG>7ijI!&(v|Q)k>myRckXq5Ez!c;6s)l%{Bb1KB5EbJ1LTlEou5<0qe^zW* z2y(S2+u@mxs|;JFiHI!c8{@bn-M_YNmm4owka3EM0Vm4!z`IxFsV}<}tlY`OfmJ-}<4~#C%tg;VaDcg59pyYHfOUbyeuwzW2E zg;`@kNfyAW`lD>(0L{&@pyFn5ZaUdH?UF*U%iPiT+>#CbVtCU(5xM}8kLy>Xw5G?q+ z=hO$LJ~osa53#is%tIu3edF+91j7VN?>*qAOxmKQg(9{Ictd=sJTJjQv@%#~2@L$> za1La6{QAgPc2VKmK*MVX4t$^}Qfp59-LdlIj$clfI{(N(P}{q0G2-=R%^NkAs2Amf zl~#C*TE*=jG~6a$&lk?M9!@0UNjt#QZgC?2d+U~t#*9ADb3~CYbKzcXOM> zkA2Oy&4tvpKWYL7{IsB&eO7?QB#NClnuE^Q+rE>oM^gZnhG&}tH=n_eU>w&F5r|jN z&)S>4Rajd^21HicpWl%WGY?(S-W24olWU%oE}Le>3JaF#^CRUWn17ykjP<}#-(#X5 zZ6CjX!J9rILttow&%CTmd4RsEHE>Gemslzw7k;P;)7p)oVksZ4oj z6yqEBqrS+rd_4c)?~QA-%jKAfUd@KIRhb3jdR@(!=wy_c35+n#+jzHDU#~B@SG8(m zIqHsHlTp=pNh*J=!I4`heW_`Mf#t*|lSZje!&0PfrM^J<22=3Ub9ueM)Z0O2WjVkv PrbyIPG#^(enFsw3U`DIs literal 0 HcmV?d00001 diff --git a/node/cli/browser-demo/index.html b/node/cli/browser-demo/index.html new file mode 100644 index 0000000000..cf107e6456 --- /dev/null +++ b/node/cli/browser-demo/index.html @@ -0,0 +1,39 @@ + + + + + Substrate node + + + + + diff --git a/node/cli/browser-demo/ws.js b/node/cli/browser-demo/ws.js new file mode 100644 index 0000000000..fa7a499a8a --- /dev/null +++ b/node/cli/browser-demo/ws.js @@ -0,0 +1,148 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +export default () => { + return { + dial: dial, + listen_on: (addr) => { + let err = new Error("Listening on WebSockets is not possible from within a browser"); + err.name = "NotSupportedError"; + throw err; + }, + }; +} + +/// Turns a string multiaddress into a WebSockets string URL. +// TODO: support dns addresses as well +const multiaddr_to_ws = (addr) => { + let parsed = addr.match(/^\/(ip4|ip6|dns4|dns6)\/(.*?)\/tcp\/(.*?)\/(ws|wss|x-parity-ws\/(.*)|x-parity-wss\/(.*))$/); + let proto = 'wss'; + if (parsed[4] == 'ws' || parsed[4] == 'x-parity-ws') { + proto = 'ws'; + } + let url = decodeURIComponent(parsed[5] || parsed[6] || ''); + if (parsed != null) { + if (parsed[1] == 'ip6') { + return proto + "://[" + parsed[2] + "]:" + parsed[3] + url; + } else { + return proto + "://" + parsed[2] + ":" + parsed[3] + url; + } + } + + let err = new Error("Address not supported: " + addr); + err.name = "NotSupportedError"; + throw err; +} + +// Attempt to dial a multiaddress. +const dial = (addr) => { + let ws = new WebSocket(multiaddr_to_ws(addr)); + let reader = read_queue(); + + return new Promise((resolve, reject) => { + // TODO: handle ws.onerror properly after dialing has happened + ws.onerror = (ev) => reject(ev); + ws.onmessage = (ev) => reader.inject_blob(ev.data); + ws.onclose = () => reader.inject_eof(); + ws.onopen = () => resolve({ + read: (function*() { while(ws.readyState == 1) { yield reader.next(); } })(), + write: (data) => { + if (ws.readyState == 1) { + ws.send(data); + return promise_when_ws_finished(ws); + } else { + return Promise.reject("WebSocket is closed"); + } + }, + shutdown: () => {}, + close: () => ws.close() + }); + }); +} + +// Takes a WebSocket object and returns a Promise that resolves when bufferedAmount is 0. +const promise_when_ws_finished = (ws) => { + if (ws.bufferedAmount == 0) { + return Promise.resolve(); + } + + return new Promise((resolve, reject) => { + setTimeout(function check() { + if (ws.bufferedAmount == 0) { + resolve(); + } else { + setTimeout(check, 100); + } + }, 2); + }) +} + +// Creates a queue reading system. +const read_queue = () => { + // State of the queue. + let state = { + // Array of promises resolving to `ArrayBuffer`s, that haven't been transmitted back with + // `next` yet. + queue: new Array(), + // If `resolve` isn't null, it is a "resolve" function of a promise that has already been + // returned by `next`. It should be called with some data. + resolve: null, + }; + + return { + // Inserts a new Blob in the queue. + inject_blob: (blob) => { + if (state.resolve != null) { + var resolve = state.resolve; + state.resolve = null; + + var reader = new FileReader(); + reader.addEventListener("loadend", () => resolve(reader.result)); + reader.readAsArrayBuffer(blob); + } else { + state.queue.push(new Promise((resolve, reject) => { + var reader = new FileReader(); + reader.addEventListener("loadend", () => resolve(reader.result)); + reader.readAsArrayBuffer(blob); + })); + } + }, + + // Inserts an EOF message in the queue. + inject_eof: () => { + if (state.resolve != null) { + var resolve = state.resolve; + state.resolve = null; + resolve(null); + } else { + state.queue.push(Promise.resolve(null)); + } + }, + + // Returns a Promise that yields the next entry as an ArrayBuffer. + next: () => { + if (state.queue.length != 0) { + return state.queue.shift(0); + } else { + if (state.resolve !== null) + throw "Internal error: already have a pending promise"; + return new Promise((resolve, reject) => { + state.resolve = resolve; + }); + } + } + }; +}; diff --git a/node/cli/build.rs b/node/cli/build.rs index 48b57c4600..8ef644eed5 100644 --- a/node/cli/build.rs +++ b/node/cli/build.rs @@ -14,9 +14,9 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -use cli::{NoCustom, CoreParams}; use std::{fs, env, path::Path}; use structopt::{StructOpt, clap::Shell}; +use substrate_cli::{NoCustom, CoreParams}; use vergen::{ConstantsFlags, generate_cargo_keys}; fn main() { diff --git a/node/cli/src/browser.rs b/node/cli/src/browser.rs new file mode 100644 index 0000000000..1c84efa107 --- /dev/null +++ b/node/cli/src/browser.rs @@ -0,0 +1,159 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +use crate::ChainSpec; +use futures::{prelude::*, sync::oneshot, sync::mpsc}; +use libp2p::wasm_ext; +use log::{debug, info}; +use std::sync::Arc; +use substrate_service::{AbstractService, RpcSession, Roles as ServiceRoles, Configuration, config::DatabaseConfig}; +use wasm_bindgen::prelude::*; + +/// Starts the client. +/// +/// You must pass a libp2p transport that supports . +#[wasm_bindgen] +pub fn start_client(wasm_ext: wasm_ext::ffi::Transport) -> Result { + start_inner(wasm_ext) + .map_err(|err| JsValue::from_str(&err.to_string())) +} + +fn start_inner(wasm_ext: wasm_ext::ffi::Transport) -> Result> { + console_error_panic_hook::set_once(); + console_log::init_with_level(log::Level::Info); + + // Build the configuration to pass to the service. + let config = { + let wasm_ext = wasm_ext::ExtTransport::new(wasm_ext); + let chain_spec = ChainSpec::FlamingFir.load().map_err(|e| format!("{:?}", e))?; + let mut config = Configuration::<(), _, _>::default_with_spec(chain_spec); + config.network.transport = network::config::TransportConfig::Normal { + wasm_external_transport: Some(wasm_ext.clone()), + enable_mdns: false, + }; + config.telemetry_external_transport = Some(wasm_ext); + config.roles = ServiceRoles::LIGHT; + config.name = "Browser node".to_string(); + config.database = { + let db = Arc::new(kvdb_memorydb::create(10)); + DatabaseConfig::Custom(db) + }; + config + }; + + info!("Substrate browser node"); + info!(" version {}", config.full_version()); + info!(" by Parity Technologies, 2017-2019"); + info!("Chain specification: {}", config.chain_spec.name()); + info!("Node name: {}", config.name); + info!("Roles: {:?}", config.roles); + + // Create the service. This is the most heavy initialization step. + let mut service = crate::service::new_light(config).map_err(|e| format!("{:?}", e))?; + + // We now dispatch a background task responsible for processing the service. + // + // The main action performed by the code below consists in polling the service with + // `service.poll()`. + // The rest consists in handling RPC requests. + let (rpc_send_tx, mut rpc_send_rx) = mpsc::unbounded::(); + wasm_bindgen_futures::spawn_local(futures::future::poll_fn(move || { + loop { + match rpc_send_rx.poll() { + Ok(Async::Ready(Some(message))) => { + let fut = service.rpc_query(&message.session, &message.rpc_json); + let _ = message.send_back.send(Box::new(fut)); + }, + Ok(Async::NotReady) => break, + Err(_) | Ok(Async::Ready(None)) => return Ok(Async::Ready(())), + } + } + + loop { + match service.poll().map_err(|_| ())? { + Async::Ready(()) => return Ok(Async::Ready(())), + Async::NotReady => break + } + } + + Ok(Async::NotReady) + })); + + Ok(Client { + rpc_send_tx, + }) +} + +/// A running client. +#[wasm_bindgen] +pub struct Client { + rpc_send_tx: mpsc::UnboundedSender, +} + +struct RpcMessage { + rpc_json: String, + session: RpcSession, + send_back: oneshot::Sender, Error = ()>>>, +} + +#[wasm_bindgen] +impl Client { + /// Allows starting an RPC request. Returns a `Promise` containing the result of that request. + #[wasm_bindgen(js_name = "rpcSend")] + pub fn rpc_send(&mut self, rpc: &str) -> js_sys::Promise { + let rpc_session = RpcSession::new(mpsc::channel(1).0); + let (tx, rx) = oneshot::channel(); + let _ = self.rpc_send_tx.unbounded_send(RpcMessage { + rpc_json: rpc.to_owned(), + session: rpc_session, + send_back: tx, + }); + let fut = rx + .map_err(|_| ()) + .and_then(|fut| fut) + .map(|s| JsValue::from_str(&s.unwrap_or(String::new()))) + .map_err(|_| JsValue::NULL); + wasm_bindgen_futures::future_to_promise(fut) + } + + /// Subscribes to an RPC pubsub endpoint. + #[wasm_bindgen(js_name = "rpcSubscribe")] + pub fn rpc_subscribe(&mut self, rpc: &str, callback: js_sys::Function) { + let (tx, rx) = mpsc::channel(4); + let rpc_session = RpcSession::new(tx); + let (fut_tx, fut_rx) = oneshot::channel(); + let _ = self.rpc_send_tx.unbounded_send(RpcMessage { + rpc_json: rpc.to_owned(), + session: rpc_session.clone(), + send_back: fut_tx, + }); + let fut_rx = fut_rx + .map_err(|_| ()) + .and_then(|fut| fut); + wasm_bindgen_futures::spawn_local(fut_rx.then(|_| Ok(()))); + wasm_bindgen_futures::spawn_local(rx.for_each(move |s| { + match callback.call1(&callback, &JsValue::from_str(&s)) { + Ok(_) => Ok(()), + Err(_) => Err(()), + } + }).then(move |v| { + // We need to keep `rpc_session` alive. + debug!("RPC subscription has ended"); + drop(rpc_session); + v + })); + } +} diff --git a/node/cli/src/cli.rs b/node/cli/src/cli.rs new file mode 100644 index 0000000000..2e5d27cec7 --- /dev/null +++ b/node/cli/src/cli.rs @@ -0,0 +1,210 @@ +// Copyright 2018-2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +pub use substrate_cli::error; +use tokio::prelude::Future; +use tokio::runtime::{Builder as RuntimeBuilder, Runtime}; +pub use substrate_cli::{VersionInfo, IntoExit, NoCustom, SharedParams, ExecutionStrategyParam}; +use substrate_service::{AbstractService, Roles as ServiceRoles, Configuration}; +use log::info; +use structopt::{StructOpt, clap::App}; +use substrate_cli::{display_role, parse_and_prepare, AugmentClap, GetLogFilter, ParseAndPrepare}; +use crate::{service, ChainSpec, load_spec}; +use crate::factory_impl::FactoryState; +use transaction_factory::RuntimeAdapter; +use client::ExecutionStrategies; + +/// Custom subcommands. +#[derive(Clone, Debug, StructOpt)] +pub enum CustomSubcommands { + /// The custom factory subcommmand for manufacturing transactions. + #[structopt( + name = "factory", + about = "Manufactures num transactions from Alice to random accounts. \ + Only supported for development or local testnet." + )] + Factory(FactoryCmd), +} + +impl GetLogFilter for CustomSubcommands { + fn get_log_filter(&self) -> Option { + None + } +} + +/// The `factory` command used to generate transactions. +/// Please note: this command currently only works on an empty database! +#[derive(Debug, StructOpt, Clone)] +pub struct FactoryCmd { + /// How often to repeat. This option only has an effect in mode `MasterToNToM`. + #[structopt(long="rounds", default_value = "1")] + pub rounds: u64, + + /// MasterToN: Manufacture `num` transactions from the master account + /// to `num` randomly created accounts, one each. + /// + /// MasterTo1: Manufacture `num` transactions from the master account + /// to exactly one other randomly created account. + /// + /// MasterToNToM: Manufacture `num` transactions from the master account + /// to `num` randomly created accounts. + /// From each of these randomly created accounts manufacture + /// a transaction to another randomly created account. + /// Repeat this `rounds` times. If `rounds` = 1 the behavior + /// is the same as `MasterToN`.{n} + /// A -> B, A -> C, A -> D, ... x `num`{n} + /// B -> E, C -> F, D -> G, ...{n} + /// ... x `rounds` + /// + /// These three modes control manufacturing. + #[structopt(long="mode", default_value = "MasterToN")] + pub mode: transaction_factory::Mode, + + /// Number of transactions to generate. In mode `MasterNToNToM` this is + /// the number of transactions per round. + #[structopt(long="num", default_value = "8")] + pub num: u64, + + #[allow(missing_docs)] + #[structopt(flatten)] + pub shared_params: SharedParams, + + /// The means of execution used when calling into the runtime while importing blocks. + #[structopt( + long = "execution", + value_name = "STRATEGY", + possible_values = &ExecutionStrategyParam::variants(), + case_insensitive = true, + default_value = "NativeElseWasm" + )] + pub execution: ExecutionStrategyParam, +} + +impl AugmentClap for FactoryCmd { + fn augment_clap<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> { + FactoryCmd::augment_clap(app) + } +} + +/// Parse command line arguments into service configuration. +pub fn run(args: I, exit: E, version: substrate_cli::VersionInfo) -> error::Result<()> where + I: IntoIterator, + T: Into + Clone, + E: IntoExit, +{ + type Config = Configuration<(), A, B>; + + match parse_and_prepare::(&version, "substrate-node", args) { + ParseAndPrepare::Run(cmd) => cmd.run(load_spec, exit, + |exit, _cli_args, _custom_args, config: Config<_, _>| { + info!("{}", version.name); + info!(" version {}", config.full_version()); + info!(" by Parity Technologies, 2017-2019"); + info!("Chain specification: {}", config.chain_spec.name()); + info!("Node name: {}", config.name); + info!("Roles: {}", display_role(&config)); + let runtime = RuntimeBuilder::new().name_prefix("main-tokio-").build() + .map_err(|e| format!("{:?}", e))?; + match config.roles { + ServiceRoles::LIGHT => run_until_exit( + runtime, + service::new_light(config)?, + exit + ), + _ => run_until_exit( + runtime, + service::new_full(config)?, + exit + ), + } + }), + ParseAndPrepare::BuildSpec(cmd) => cmd.run(load_spec), + ParseAndPrepare::ExportBlocks(cmd) => cmd.run_with_builder(|config: Config<_, _>| + Ok(new_full_start!(config).0), load_spec, exit), + ParseAndPrepare::ImportBlocks(cmd) => cmd.run_with_builder(|config: Config<_, _>| + Ok(new_full_start!(config).0), load_spec, exit), + ParseAndPrepare::PurgeChain(cmd) => cmd.run(load_spec), + ParseAndPrepare::RevertChain(cmd) => cmd.run_with_builder(|config: Config<_, _>| + Ok(new_full_start!(config).0), load_spec), + ParseAndPrepare::CustomCommand(CustomSubcommands::Factory(cli_args)) => { + let mut config: Config<_, _> = substrate_cli::create_config_with_db_path( + load_spec, + &cli_args.shared_params, + &version, + )?; + config.execution_strategies = ExecutionStrategies { + importing: cli_args.execution.into(), + block_construction: cli_args.execution.into(), + other: cli_args.execution.into(), + ..Default::default() + }; + + match ChainSpec::from(config.chain_spec.id()) { + Some(ref c) if c == &ChainSpec::Development || c == &ChainSpec::LocalTestnet => {}, + _ => panic!("Factory is only supported for development and local testnet."), + } + + let factory_state = FactoryState::new( + cli_args.mode.clone(), + cli_args.num, + cli_args.rounds, + ); + + let service_builder = new_full_start!(config).0; + transaction_factory::factory::, _, _, _, _, _>( + factory_state, + service_builder.client(), + service_builder.select_chain() + .expect("The select_chain is always initialized by new_full_start!; QED") + ).map_err(|e| format!("Error in transaction factory: {}", e))?; + + Ok(()) + } + } +} + +fn run_until_exit( + mut runtime: Runtime, + service: T, + e: E, +) -> error::Result<()> +where + T: AbstractService, + E: IntoExit, +{ + let (exit_send, exit) = exit_future::signal(); + + let informant = substrate_cli::informant::build(&service); + runtime.executor().spawn(exit.until(informant).map(|_| ())); + + // we eagerly drop the service so that the internal exit future is fired, + // but we need to keep holding a reference to the global telemetry guard + let _telemetry = service.telemetry(); + + let service_res = { + let exit = e.into_exit().map_err(|_| error::Error::Other("Exit future failed.".into())); + let service = service.map_err(|err| error::Error::Service(err)); + let select = service.select(exit).map(|_| ()).map_err(|(err, _)| err); + runtime.block_on(select) + }; + + exit_send.fire(); + + // TODO [andre]: timeout this future #1318 + let _ = runtime.shutdown_on_idle().wait(); + + service_res +} diff --git a/node/cli/src/lib.rs b/node/cli/src/lib.rs index 5125ba216a..78660ae92e 100644 --- a/node/cli/src/lib.rs +++ b/node/cli/src/lib.rs @@ -15,26 +15,35 @@ // along with Substrate. If not, see . //! Substrate CLI library. +//! +//! This package has two Cargo features: +//! +//! - `cli` (default): exposes functions that parse command-line options, then start and run the +//! node as a CLI application. +//! +//! - `browser`: exposes the content of the `browser` module, which consists of exported symbols +//! that are meant to be passed through the `wasm-bindgen` utility and called from JavaScript. +//! Despite its name the produced WASM can theoretically also be used from NodeJS, although this +//! hasn't been tested. #![warn(missing_docs)] #![warn(unused_extern_crates)] -pub use cli::error; pub mod chain_spec; + #[macro_use] mod service; +#[cfg(feature = "browser")] +mod browser; +#[cfg(feature = "cli")] +mod cli; +#[cfg(feature = "cli")] mod factory_impl; -use tokio::prelude::Future; -use tokio::runtime::{Builder as RuntimeBuilder, Runtime}; -pub use cli::{VersionInfo, IntoExit, NoCustom, SharedParams, ExecutionStrategyParam}; -use substrate_service::{AbstractService, Roles as ServiceRoles, Configuration}; -use log::info; -use structopt::{StructOpt, clap::App}; -use cli::{display_role, parse_and_prepare, AugmentClap, GetLogFilter, ParseAndPrepare}; -use crate::factory_impl::FactoryState; -use transaction_factory::RuntimeAdapter; -use client::ExecutionStrategies; +#[cfg(feature = "browser")] +pub use browser::*; +#[cfg(feature = "cli")] +pub use cli::*; /// The chain specification option. #[derive(Clone, Debug, PartialEq)] @@ -49,78 +58,6 @@ pub enum ChainSpec { StagingTestnet, } -/// Custom subcommands. -#[derive(Clone, Debug, StructOpt)] -pub enum CustomSubcommands { - /// The custom factory subcommmand for manufacturing transactions. - #[structopt( - name = "factory", - about = "Manufactures num transactions from Alice to random accounts. \ - Only supported for development or local testnet." - )] - Factory(FactoryCmd), -} - -impl GetLogFilter for CustomSubcommands { - fn get_log_filter(&self) -> Option { - None - } -} - -/// The `factory` command used to generate transactions. -/// Please note: this command currently only works on an empty database! -#[derive(Debug, StructOpt, Clone)] -pub struct FactoryCmd { - /// How often to repeat. This option only has an effect in mode `MasterToNToM`. - #[structopt(long="rounds", default_value = "1")] - pub rounds: u64, - - /// MasterToN: Manufacture `num` transactions from the master account - /// to `num` randomly created accounts, one each. - /// - /// MasterTo1: Manufacture `num` transactions from the master account - /// to exactly one other randomly created account. - /// - /// MasterToNToM: Manufacture `num` transactions from the master account - /// to `num` randomly created accounts. - /// From each of these randomly created accounts manufacture - /// a transaction to another randomly created account. - /// Repeat this `rounds` times. If `rounds` = 1 the behavior - /// is the same as `MasterToN`.{n} - /// A -> B, A -> C, A -> D, ... x `num`{n} - /// B -> E, C -> F, D -> G, ...{n} - /// ... x `rounds` - /// - /// These three modes control manufacturing. - #[structopt(long="mode", default_value = "MasterToN")] - pub mode: transaction_factory::Mode, - - /// Number of transactions to generate. In mode `MasterNToNToM` this is - /// the number of transactions per round. - #[structopt(long="num", default_value = "8")] - pub num: u64, - - #[allow(missing_docs)] - #[structopt(flatten)] - pub shared_params: SharedParams, - - /// The means of execution used when calling into the runtime while importing blocks. - #[structopt( - long = "execution", - value_name = "STRATEGY", - possible_values = &ExecutionStrategyParam::variants(), - case_insensitive = true, - default_value = "NativeElseWasm" - )] - pub execution: ExecutionStrategyParam, -} - -impl AugmentClap for FactoryCmd { - fn augment_clap<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> { - FactoryCmd::augment_clap(app) - } -} - /// Get a chain config from a spec setting. impl ChainSpec { pub(crate) fn load(self) -> Result { @@ -149,113 +86,3 @@ fn load_spec(id: &str) -> Result, String> { None => None, }) } - -/// Parse command line arguments into service configuration. -pub fn run(args: I, exit: E, version: cli::VersionInfo) -> error::Result<()> where - I: IntoIterator, - T: Into + Clone, - E: IntoExit, -{ - type Config = Configuration<(), A, B>; - - match parse_and_prepare::(&version, "substrate-node", args) { - ParseAndPrepare::Run(cmd) => cmd.run(load_spec, exit, - |exit, _cli_args, _custom_args, config: Config<_, _>| { - info!("{}", version.name); - info!(" version {}", config.full_version()); - info!(" by Parity Technologies, 2017-2019"); - info!("Chain specification: {}", config.chain_spec.name()); - info!("Node name: {}", config.name); - info!("Roles: {}", display_role(&config)); - let runtime = RuntimeBuilder::new().name_prefix("main-tokio-").build() - .map_err(|e| format!("{:?}", e))?; - match config.roles { - ServiceRoles::LIGHT => run_until_exit( - runtime, - service::new_light(config)?, - exit - ), - _ => run_until_exit( - runtime, - service::new_full(config)?, - exit - ), - } - }), - ParseAndPrepare::BuildSpec(cmd) => cmd.run(load_spec), - ParseAndPrepare::ExportBlocks(cmd) => cmd.run_with_builder(|config: Config<_, _>| - Ok(new_full_start!(config).0), load_spec, exit), - ParseAndPrepare::ImportBlocks(cmd) => cmd.run_with_builder(|config: Config<_, _>| - Ok(new_full_start!(config).0), load_spec, exit), - ParseAndPrepare::PurgeChain(cmd) => cmd.run(load_spec), - ParseAndPrepare::RevertChain(cmd) => cmd.run_with_builder(|config: Config<_, _>| - Ok(new_full_start!(config).0), load_spec), - ParseAndPrepare::CustomCommand(CustomSubcommands::Factory(cli_args)) => { - let mut config: Config<_, _> = cli::create_config_with_db_path( - load_spec, - &cli_args.shared_params, - &version, - )?; - config.execution_strategies = ExecutionStrategies { - importing: cli_args.execution.into(), - block_construction: cli_args.execution.into(), - other: cli_args.execution.into(), - ..Default::default() - }; - - match ChainSpec::from(config.chain_spec.id()) { - Some(ref c) if c == &ChainSpec::Development || c == &ChainSpec::LocalTestnet => {}, - _ => panic!("Factory is only supported for development and local testnet."), - } - - let factory_state = FactoryState::new( - cli_args.mode.clone(), - cli_args.num, - cli_args.rounds, - ); - - let service_builder = new_full_start!(config).0; - transaction_factory::factory::, _, _, _, _, _>( - factory_state, - service_builder.client(), - service_builder.select_chain() - .expect("The select_chain is always initialized by new_full_start!; QED") - ).map_err(|e| format!("Error in transaction factory: {}", e))?; - - Ok(()) - } - } -} - -fn run_until_exit( - mut runtime: Runtime, - service: T, - e: E, -) -> error::Result<()> -where - T: AbstractService, - E: IntoExit, -{ - let (exit_send, exit) = exit_future::signal(); - - let informant = cli::informant::build(&service); - runtime.executor().spawn(exit.until(informant).map(|_| ())); - - // we eagerly drop the service so that the internal exit future is fired, - // but we need to keep holding a reference to the global telemetry guard - let _telemetry = service.telemetry(); - - let service_res = { - let exit = e.into_exit().map_err(|_| error::Error::Other("Exit future failed.".into())); - let service = service.map_err(|err| error::Error::Service(err)); - let select = service.select(exit).map(|_| ()).map_err(|(err, _)| err); - runtime.block_on(select) - }; - - exit_send.fire(); - - // TODO [andre]: timeout this future #1318 - let _ = runtime.shutdown_on_idle().wait(); - - service_res -} -- GitLab From 0c309448458388a96e59bbd4972d3b195c443cad Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Thu, 31 Oct 2019 16:38:53 +0100 Subject: [PATCH 152/167] Remove NetworkSpecialization::on_event (#3976) --- core/network/src/protocol.rs | 4 ---- core/network/src/protocol/specialization.rs | 3 ++- core/network/src/service.rs | 16 ++++++---------- core/network/src/test/mod.rs | 5 ----- 4 files changed, 8 insertions(+), 20 deletions(-) diff --git a/core/network/src/protocol.rs b/core/network/src/protocol.rs index 476113953b..335c2380c8 100644 --- a/core/network/src/protocol.rs +++ b/core/network/src/protocol.rs @@ -515,10 +515,6 @@ impl, H: ExHashT> Protocol { self.context_data.peers.iter().map(|(id, peer)| (id, &peer.info)) } - pub fn on_event(&mut self, event: Event) { - self.specialization.on_event(event); - } - pub fn on_custom_message( &mut self, who: PeerId, diff --git a/core/network/src/protocol/specialization.rs b/core/network/src/protocol/specialization.rs index e2c444ea88..37509eeec0 100644 --- a/core/network/src/protocol/specialization.rs +++ b/core/network/src/protocol/specialization.rs @@ -42,7 +42,8 @@ pub trait NetworkSpecialization: Send + Sync + 'static { ); /// Called when a network-specific event arrives. - fn on_event(&mut self, event: Event); + #[deprecated(note = "This method is never called; please use `with_dht_event_tx` when building the service")] + fn on_event(&mut self, event: Event) {} /// Called on abort. #[deprecated(note = "This method is never called; aborting corresponds to dropping the object")] diff --git a/core/network/src/service.rs b/core/network/src/service.rs index 48ad51bde3..a88c163a69 100644 --- a/core/network/src/service.rs +++ b/core/network/src/service.rs @@ -480,8 +480,8 @@ impl, H: ExHashT> NetworkServic /// Start getting a value from the DHT. /// - /// This will generate either a `ValueFound` or a `ValueNotFound` event and pass it to - /// `on_event` on the network specialization. + /// This will generate either a `ValueFound` or a `ValueNotFound` event and pass it as an + /// item on the [`NetworkWorker`] stream. pub fn get_value(&self, key: &record::Key) { let _ = self .to_worker @@ -490,8 +490,8 @@ impl, H: ExHashT> NetworkServic /// Start putting a value in the DHT. /// - /// This will generate either a `ValuePut` or a `ValuePutFailed` event and pass it to - /// `on_event` on the network specialization. + /// This will generate either a `ValuePut` or a `ValuePutFailed` event and pass it as an + /// item on the [`NetworkWorker`] stream. pub fn put_value(&self, key: record::Key, value: Vec) { let _ = self .to_worker @@ -718,12 +718,8 @@ impl, H: ExHashT> Stream for Ne let outcome = match poll_value { Ok(Async::NotReady) => break, Ok(Async::Ready(Some(BehaviourOut::SubstrateAction(outcome)))) => outcome, - Ok(Async::Ready(Some(BehaviourOut::Dht(ev)))) => { - self.network_service.user_protocol_mut() - .on_event(Event::Dht(ev.clone())); - - return Ok(Async::Ready(Some(Event::Dht(ev)))); - }, + Ok(Async::Ready(Some(BehaviourOut::Dht(ev)))) => + return Ok(Async::Ready(Some(Event::Dht(ev)))), Ok(Async::Ready(None)) => CustomMessageOutcome::None, Err(err) => { error!(target: "sync", "Error in the network: {:?}", err); diff --git a/core/network/src/test/mod.rs b/core/network/src/test/mod.rs index 92e747280b..0c50179f10 100644 --- a/core/network/src/test/mod.rs +++ b/core/network/src/test/mod.rs @@ -124,11 +124,6 @@ impl NetworkSpecialization for DummySpecialization { _peer_id: PeerId, _message: Vec, ) {} - - fn on_event( - &mut self, - _event: crate::specialization::Event - ) {} } pub type PeersFullClient = -- GitLab From 5b24ad6667b3cfdd057d1aea317b1d84e739f037 Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Thu, 31 Oct 2019 16:44:52 +0100 Subject: [PATCH 153/167] and backend reference to rpc builder (#3979) --- core/service/src/builder.rs | 4 ++-- node/cli/src/service.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/service/src/builder.rs b/core/service/src/builder.rs index e39610b702..a9a85faab2 100644 --- a/core/service/src/builder.rs +++ b/core/service/src/builder.rs @@ -568,10 +568,10 @@ impl( self, - rpc_ext_builder: impl FnOnce(Arc, Arc) -> URpc + rpc_ext_builder: impl FnOnce(Arc, Arc, Arc) -> URpc ) -> Result, Error> { - let rpc_extensions = rpc_ext_builder(self.client.clone(), self.transaction_pool.clone()); + let rpc_extensions = rpc_ext_builder(self.client.clone(), self.transaction_pool.clone(), self.backend.clone()); Ok(ServiceBuilder { config: self.config, diff --git a/node/cli/src/service.rs b/node/cli/src/service.rs index 789dfc02fb..9f0726fc83 100644 --- a/node/cli/src/service.rs +++ b/node/cli/src/service.rs @@ -96,7 +96,7 @@ macro_rules! new_full_start { import_setup = Some((block_import, grandpa_link, babe_link)); Ok(import_queue) })? - .with_rpc_extensions(|client, pool| -> RpcExtension { + .with_rpc_extensions(|client, pool, _backend| -> RpcExtension { node_rpc::create(client, pool) })?; @@ -326,7 +326,7 @@ pub fn new_light(config: NodeConfiguration) .with_finality_proof_provider(|client, backend| Ok(Arc::new(GrandpaFinalityProofProvider::new(backend, client)) as _) )? - .with_rpc_extensions(|client, pool| -> RpcExtension { + .with_rpc_extensions(|client, pool, _backend| -> RpcExtension { node_rpc::create(client, pool) })? .build()?; -- GitLab From c90048660bf7df7368e6c6a6c65bdae91b119ba3 Mon Sep 17 00:00:00 2001 From: thiolliere Date: Thu, 31 Oct 2019 19:04:53 +0100 Subject: [PATCH 154/167] Improve doc for storages in srml-support (#3982) * improve doc * Apply suggestions from code review --- srml/support/src/storage/mod.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/srml/support/src/storage/mod.rs b/srml/support/src/storage/mod.rs index 5636d21199..d54ae161ee 100644 --- a/srml/support/src/storage/mod.rs +++ b/srml/support/src/storage/mod.rs @@ -28,6 +28,9 @@ pub mod child; pub mod generator; /// A trait for working with macro-generated storage values under the substrate storage API. +/// +/// Details on implementation can be found at +/// [`generator::StorageValue`] pub trait StorageValue { /// The type that get/take return. type Query; @@ -113,6 +116,9 @@ pub trait StorageValue { } /// A strongly-typed map in storage. +/// +/// Details on implementation can be found at +/// [`generator::StorageMap`] pub trait StorageMap { /// The type that get/take return. type Query; @@ -180,6 +186,9 @@ pub trait StorageMap { /// A strongly-typed linked map in storage. /// /// Similar to `StorageMap` but allows to enumerate other elements and doesn't implement append. +/// +/// Details on implementation can be found at +/// [`generator::StorageLinkedMap`] pub trait StorageLinkedMap { /// The type that get/take return. type Query; @@ -229,6 +238,9 @@ pub trait StorageLinkedMap { /// /// It provides an important ability to efficiently remove all entries /// that have a common first key. +/// +/// Details on implementation can be found at +/// [`generator::StorageDoubleMap`] pub trait StorageDoubleMap { /// The type that get/take returns. type Query; -- GitLab From 97b25edfebeed935779cc8e945fa7b14bf176e6c Mon Sep 17 00:00:00 2001 From: Ashley Date: Thu, 31 Oct 2019 20:33:25 +0000 Subject: [PATCH 155/167] Retire `storage_items!` (#3950) * Retire storage_items * Add storage_items! tests to srml/support/tests * Assimilate genesis config --- core/test-runtime/src/genesismap.rs | 12 +- core/test-runtime/src/system.rs | 29 +- srml/support/src/lib.rs | 1 - srml/support/src/storage/mod.rs | 2 - .../tests/decl_storage.rs} | 291 +----------------- 5 files changed, 43 insertions(+), 292 deletions(-) rename srml/support/{src/storage/storage_items.rs => test/tests/decl_storage.rs} (67%) diff --git a/core/test-runtime/src/genesismap.rs b/core/test-runtime/src/genesismap.rs index a3abf235ff..a02a1df855 100644 --- a/core/test-runtime/src/genesismap.rs +++ b/core/test-runtime/src/genesismap.rs @@ -18,7 +18,7 @@ use std::collections::HashMap; use runtime_io::{blake2_256, twox_128}; -use super::{AuthorityId, AccountId, WASM_BINARY}; +use super::{AuthorityId, AccountId, WASM_BINARY, system}; use codec::{Encode, KeyedVec, Joiner}; use primitives::{ChangesTrieConfiguration, map, storage::well_known_keys}; use sr_primitives::traits::{Block as BlockT, Hash as HashT, Header as HeaderT}; @@ -77,10 +77,16 @@ impl GenesisConfig { map.insert(well_known_keys::CHANGES_TRIE_CONFIG.to_vec(), changes_trie_config.encode()); } map.insert(twox_128(&b"sys:auth"[..])[..].to_vec(), self.authorities.encode()); - // Finally, add the extra storage entries. + // Add the extra storage entries. map.extend(self.extra_storage.clone().into_iter()); - (map, self.child_extra_storage.clone()) + // Assimilate the system genesis config. + let mut storage = (map, self.child_extra_storage.clone()); + let mut config = system::GenesisConfig::default(); + config.authorities = self.authorities.clone(); + config.assimilate_storage(&mut storage); + + storage } } diff --git a/core/test-runtime/src/system.rs b/core/test-runtime/src/system.rs index fc4de0ce4b..f1c75122a0 100644 --- a/core/test-runtime/src/system.rs +++ b/core/test-runtime/src/system.rs @@ -20,12 +20,13 @@ use rstd::prelude::*; use runtime_io::{storage_root, storage_changes_root, blake2_256}; use runtime_support::storage::{self, StorageValue, StorageMap}; -use runtime_support::storage_items; +use runtime_support::{decl_storage, decl_module}; use sr_primitives::{ traits::{Hash as HashT, BlakeTwo256, Header as _}, generic, ApplyError, ApplyResult, transaction_validity::{TransactionValidity, ValidTransaction, InvalidTransaction}, }; use codec::{KeyedVec, Encode}; +use srml_system::Trait; use crate::{ AccountId, BlockNumber, Extrinsic, Transfer, H256 as Hash, Block, Header, Digest, AuthorityId }; @@ -34,14 +35,20 @@ use primitives::storage::well_known_keys; const NONCE_OF: &[u8] = b"nonce:"; const BALANCE_OF: &[u8] = b"balance:"; -storage_items! { - ExtrinsicData: b"sys:xtd" => required map [ u32 => Vec ]; - // The current block number being processed. Set by `execute_block`. - Number: b"sys:num" => BlockNumber; - ParentHash: b"sys:pha" => required Hash; - NewAuthorities: b"sys:new_auth" => Vec; - StorageDigest: b"sys:digest" => Digest; - Authorities get(authorities): b"sys:auth" => default Vec; +decl_module! { + pub struct Module for enum Call where origin: T::Origin {} +} + +decl_storage! { + trait Store for Module as TestRuntime { + ExtrinsicData: map u32 => Vec; + // The current block number being processed. Set by `execute_block`. + Number get(fn number): Option; + ParentHash get(fn parent_hash): Hash; + NewAuthorities get(fn new_authorities): Option>; + StorageDigest get(fn storage_digest): Option; + Authorities get(fn authorities) config(): Vec; + } } pub fn balance_of_key(who: AccountId) -> Vec { @@ -70,6 +77,10 @@ pub fn initialize_block(header: &Header) { } } +pub fn authorities() -> Vec { + Authorities::get() +} + pub fn get_block_number() -> Option { Number::get() } diff --git a/srml/support/src/lib.rs b/srml/support/src/lib.rs index 2a9f66bd52..cfe6487203 100644 --- a/srml/support/src/lib.rs +++ b/srml/support/src/lib.rs @@ -47,7 +47,6 @@ pub use sr_primitives::RuntimeDebug; pub mod debug; #[macro_use] pub mod dispatch; -#[macro_use] pub mod storage; mod hash; #[macro_use] diff --git a/srml/support/src/storage/mod.rs b/srml/support/src/storage/mod.rs index d54ae161ee..f10deb93d2 100644 --- a/srml/support/src/storage/mod.rs +++ b/srml/support/src/storage/mod.rs @@ -20,8 +20,6 @@ use rstd::prelude::*; use codec::{FullCodec, FullEncode, Encode, EncodeAppend, EncodeLike, Decode}; use crate::traits::Len; -#[macro_use] -pub mod storage_items; pub mod unhashed; pub mod hashed; pub mod child; diff --git a/srml/support/src/storage/storage_items.rs b/srml/support/test/tests/decl_storage.rs similarity index 67% rename from srml/support/src/storage/storage_items.rs rename to srml/support/test/tests/decl_storage.rs index 1edf9c03db..c9dd96791b 100644 --- a/srml/support/src/storage/storage_items.rs +++ b/srml/support/test/tests/decl_storage.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2019 Parity Technologies (UK) Ltd. +// Copyright 2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify @@ -14,276 +14,17 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -//! Strongly typed wrappers around values in storage. -//! -//! This crate exports a macro `storage_items!` and traits describing behavior of generated -//! structs. -//! -//! Two kinds of data types are currently supported: -//! - values -//! - maps -//! -//! # Examples: -//! -//! ```rust -//! #[macro_use] -//! extern crate srml_support; -//! -//! type AuthorityId = [u8; 32]; -//! type Balance = u64; -//! pub type SessionKey = [u8; 32]; -//! -//! storage_items! { -//! // public value -//! pub Value: b"putd_key" => SessionKey; -//! // private map. -//! Balances: b"private_map:" => map [AuthorityId => Balance]; -//! } -//! -//!# fn main() { } -//! ``` - -#[doc(hidden)] -pub use crate::rstd::borrow::Borrow; -#[doc(hidden)] -pub use crate::rstd::marker::PhantomData; -#[doc(hidden)] -pub use crate::rstd::boxed::Box; - -#[doc(hidden)] -pub fn id(t: T) -> T { - t -} - -#[doc(hidden)] -pub use Some; - -#[doc(hidden)] -pub fn unwrap_or_default(t: Option) -> T { - t.unwrap_or_else(|| Default::default()) -} - -#[doc(hidden)] -pub fn require(t: Option) -> T { - t.expect("Required values must be in storage") -} - -// FIXME #1466 Remove this in favor of `decl_storage` macro. -/// Declares strongly-typed wrappers around codec-compatible types in storage. -#[macro_export] -macro_rules! storage_items { - // simple values - ($name:ident : $key:expr => $ty:ty; $($t:tt)*) => { - $crate::__storage_items_internal!(() () (OPTION_TYPE Option<$ty>) (id) (id) $name: $key => $ty); - storage_items!($($t)*); - }; - (pub $name:ident : $key:expr => $ty:ty; $($t:tt)*) => { - $crate::__storage_items_internal!((pub) () (OPTION_TYPE Option<$ty>) (id) (id) $name: $key => $ty); - storage_items!($($t)*); - }; - ($name:ident : $key:expr => default $ty:ty; $($t:tt)*) => { - $crate::__storage_items_internal!(() () (RAW_TYPE $ty) (unwrap_or_default) (Some) $name: $key => $ty); - storage_items!($($t)*); - }; - (pub $name:ident : $key:expr => default $ty:ty; $($t:tt)*) => { - $crate::__storage_items_internal!((pub) () (RAW_TYPE $ty) (unwrap_or_default) (Some) $name: $key => $ty); - storage_items!($($t)*); - }; - ($name:ident : $key:expr => required $ty:ty; $($t:tt)*) => { - $crate::__storage_items_internal!(() () (RAW_TYPE $ty) (require) (Some) $name: $key => $ty); - storage_items!($($t)*); - }; - (pub $name:ident : $key:expr => required $ty:ty; $($t:tt)*) => { - $crate::__storage_items_internal!((pub) () (RAW_TYPE $ty) (require) (Some) $name: $key => $ty); - storage_items!($($t)*); - }; - - ($name:ident get($getfn:ident) : $key:expr => $ty:ty; $($t:tt)*) => { - $crate::__storage_items_internal!(() ($getfn) (OPTION_TYPE Option<$ty>) (id) (id) $name: $key => $ty); - storage_items!($($t)*); - }; - (pub $name:ident get($getfn:ident) : $key:expr => $ty:ty; $($t:tt)*) => { - $crate::__storage_items_internal!((pub) ($getfn) (OPTION_TYPE Option<$ty>) (id) (id) $name: $key => $ty); - storage_items!($($t)*); - }; - ($name:ident get($getfn:ident) : $key:expr => default $ty:ty; $($t:tt)*) => { - $crate::__storage_items_internal!(() ($getfn) (RAW_TYPE $ty) (unwrap_or_default) (Some) $name: $key => $ty); - storage_items!($($t)*); - }; - (pub $name:ident get($getfn:ident) : $key:expr => default $ty:ty; $($t:tt)*) => { - $crate::__storage_items_internal!((pub) ($getfn) (RAW_TYPE $ty) (unwrap_or_default) (Some) $name: $key => $ty); - storage_items!($($t)*); - }; - ($name:ident get($getfn:ident) : $key:expr => required $ty:ty; $($t:tt)*) => { - $crate::__storage_items_internal!(() ($getfn) (RAW_TYPE $ty) (require) (Some) $name: $key => $ty); - storage_items!($($t)*); - }; - (pub $name:ident get($getfn:ident) : $key:expr => required $ty:ty; $($t:tt)*) => { - $crate::__storage_items_internal!((pub) ($getfn) (RAW_TYPE $ty) (require) (Some) $name: $key => $ty); - storage_items!($($t)*); - }; - - // maps - ($name:ident : $prefix:expr => map [$kty:ty => $ty:ty]; $($t:tt)*) => { - $crate::__storage_items_internal!(() () (OPTION_TYPE Option<$ty>) (id) (id) $name: $prefix => map [$kty => $ty]); - storage_items!($($t)*); - }; - (pub $name:ident : $prefix:expr => map [$kty:ty => $ty:ty]; $($t:tt)*) => { - $crate::__storage_items_internal!((pub) () (OPTION_TYPE Option<$ty>) (id) (id) $name: $prefix => map [$kty => $ty]); - storage_items!($($t)*); - }; - ($name:ident : $prefix:expr => default map [$kty:ty => $ty:ty]; $($t:tt)*) => { - $crate::__storage_items_internal!(() () (RAW_TYPE $ty) (unwrap_or_default) (Some) $name: $prefix => map [$kty => $ty]); - storage_items!($($t)*); - }; - (pub $name:ident : $prefix:expr => default map [$kty:ty => $ty:ty]; $($t:tt)*) => { - $crate::__storage_items_internal!((pub) () (RAW_TYPE $ty) (unwrap_or_default) (Some) $name: $prefix => map [$kty => $ty]); - storage_items!($($t)*); - }; - ($name:ident : $prefix:expr => required map [$kty:ty => $ty:ty]; $($t:tt)*) => { - $crate::__storage_items_internal!(() () (RAW_TYPE $ty) (require) (Some) $name: $prefix => map [$kty => $ty]); - storage_items!($($t)*); - }; - (pub $name:ident : $prefix:expr => required map [$kty:ty => $ty:ty]; $($t:tt)*) => { - $crate::__storage_items_internal!((pub) () (RAW_TYPE $ty) (require) (Some) $name: $prefix => map [$kty => $ty]); - storage_items!($($t)*); - }; - - ($name:ident get($getfn:ident) : $prefix:expr => map [$kty:ty => $ty:ty]; $($t:tt)*) => { - $crate::__storage_items_internal!(() ($getfn) (OPTION_TYPE Option<$ty>) (id) (id) $name: $prefix => map [$kty => $ty]); - storage_items!($($t)*); - }; - (pub $name:ident get($getfn:ident) : $prefix:expr => map [$kty:ty => $ty:ty]; $($t:tt)*) => { - $crate::__storage_items_internal!((pub) ($getfn) (OPTION_TYPE Option<$ty>) (id) (id) $name: $prefix => map [$kty => $ty]); - storage_items!($($t)*); - }; - ($name:ident get($getfn:ident) : $prefix:expr => default map [$kty:ty => $ty:ty]; $($t:tt)*) => { - $crate::__storage_items_internal!(() ($getfn) (RAW_TYPE $ty) (unwrap_or_default) (Some) $name: $prefix => map [$kty => $ty]); - storage_items!($($t)*); - }; - (pub $name:ident get($getfn:ident) : $prefix:expr => default map [$kty:ty => $ty:ty]; $($t:tt)*) => { - $crate::__storage_items_internal!((pub) ($getfn) (RAW_TYPE $ty) (unwrap_or_default) (Some) $name: $prefix => map [$kty => $ty]); - storage_items!($($t)*); - }; - ($name:ident get($getfn:ident) : $prefix:expr => required map [$kty:ty => $ty:ty]; $($t:tt)*) => { - $crate::__storage_items_internal!(() ($getfn) (RAW_TYPE $ty) (require) (Some) $name: $prefix => map [$kty => $ty]); - storage_items!($($t)*); - }; - (pub $name:ident get($getfn:ident) : $prefix:expr => required map [$kty:ty => $ty:ty]; $($t:tt)*) => { - $crate::__storage_items_internal!((pub) ($getfn) (RAW_TYPE $ty) (require) (Some) $name: $prefix => map [$kty => $ty]); - storage_items!($($t)*); - }; - - () => () -} - -#[macro_export] -#[doc(hidden)] -macro_rules! __storage_items_internal { - // generator for values. - (($($vis:tt)*) ($get_fn:ident) ($wraptype:ident $gettype:ty) ($into_query:ident) ($into_opt_val:ident) $name:ident : $key:expr => $ty:ty) => { - $crate::__storage_items_internal!{ ($($vis)*) () ($wraptype $gettype) ($into_query) ($into_opt_val) $name : $key => $ty } - pub fn $get_fn() -> $gettype { <$name as $crate::storage::StorageValue<$ty>> :: get() } - }; - (($($vis:tt)*) () ($wraptype:ident $gettype:ty) ($into_query:ident) ($into_opt_val:ident) $name:ident : $key:expr => $ty:ty) => { - $($vis)* struct $name; - - impl $crate::storage::generator::StorageValue<$ty> for $name { - type Query = $gettype; - - fn unhashed_key() -> &'static [u8] { - $key - } - - fn from_optional_value_to_query(v: Option<$ty>) -> Self::Query { - $crate::storage::storage_items::$into_query(v) - } - - fn from_query_to_optional_value(v: Self::Query) -> Option<$ty> { - $crate::storage::storage_items::$into_opt_val(v) - } - } - }; - // generator for maps. - (($($vis:tt)*) ($get_fn:ident) ($wraptype:ident $gettype:ty) ($into_query:ident) ($into_opt_val:ident) $name:ident : $prefix:expr => map [$kty:ty => $ty:ty]) => { - $crate::__storage_items_internal!{ ($($vis)*) () ($wraptype $gettype) ($into_query) ($into_opt_val) $name : $prefix => map [$kty => $ty] } - pub fn $get_fn>(key: K) -> $gettype { - <$name as $crate::storage::StorageMap<$kty, $ty>> :: get(key.borrow()) - } - }; - (($($vis:tt)*) () ($wraptype:ident $gettype:ty) ($into_query:ident) ($into_opt_val:ident) $name:ident : $prefix:expr => map [$kty:ty => $ty:ty]) => { - $($vis)* struct $name; - - impl $crate::storage::generator::StorageMap<$kty, $ty> for $name { - type Query = $gettype; - type Hasher = $crate::Blake2_256; - - fn prefix() -> &'static [u8] { - $prefix - } - - fn from_optional_value_to_query(v: Option<$ty>) -> Self::Query { - $crate::storage::storage_items::$into_query(v) - } - - fn from_query_to_optional_value(v: Self::Query) -> Option<$ty> { - $crate::storage::storage_items::$into_opt_val(v) - } - } - }; -} - -#[macro_export] -#[doc(hidden)] -macro_rules! __handle_wrap_internal { - (RAW_TYPE { $($raw:tt)* } { $($option:tt)* }) => { - $($raw)*; - }; - (OPTION_TYPE { $($raw:tt)* } { $($option:tt)* }) => { - $($option)*; - }; -} - -// FIXME: revisit this idiom once we get `type`s in `impl`s. -/*impl Module { - type Now = super::Now; -}*/ - #[cfg(test)] // Do not complain about unused `dispatch` and `dispatch_aux`. #[allow(dead_code)] mod tests { - use crate::metadata::*; - use crate::metadata::StorageHasher; - use crate::rstd::marker::PhantomData; - use crate::codec::{Encode, Decode, EncodeLike}; - - storage_items! { - Value: b"a" => u32; - Map: b"c:" => map [u32 => [u8; 32]]; - } + use support::metadata::*; + use support::metadata::StorageHasher; + use support::rstd::marker::PhantomData; + use support::codec::{Encode, Decode, EncodeLike}; - #[test] - fn value() { - runtime_io::with_storage(&mut Default::default(), || { - assert!(Value::get().is_none()); - Value::put(&100_000); - assert_eq!(Value::get(), Some(100_000)); - Value::kill(); - assert!(Value::get().is_none()); - }) - } - - #[test] - fn map() { - runtime_io::with_storage(&mut Default::default(), || { - assert!(Map::get(&5).is_none()); - Map::insert(&5, &[1; 32]); - assert_eq!(Map::get(&5), Some([1; 32])); - assert_eq!(Map::take(&5), Some([1; 32])); - assert!(Map::get(&5).is_none()); - assert!(Map::get(&999).is_none()); - }) + support::decl_module! { + pub struct Module for enum Call where origin: T::Origin {} } pub trait Trait { @@ -291,11 +32,7 @@ mod tests { type BlockNumber; } - decl_module! { - pub struct Module for enum Call where origin: T::Origin {} - } - - crate::decl_storage! { + support::decl_storage! { trait Store for Module as TestStorage { // non-getters: pub / $default @@ -701,13 +438,13 @@ mod test2 { type BlockNumber; } - decl_module! { + support::decl_module! { pub struct Module for enum Call where origin: T::Origin {} } type PairOf = (T, T); - crate::decl_storage! { + support::decl_storage! { trait Store for Module as TestStorage { SingleDef : u32; PairDef : PairOf; @@ -736,10 +473,10 @@ mod test3 { type Origin; type BlockNumber; } - decl_module! { + support::decl_module! { pub struct Module for enum Call where origin: T::Origin {} } - crate::decl_storage! { + support::decl_storage! { trait Store for Module as Test { Foo get(fn foo) config(initial_foo): u32; } @@ -766,14 +503,14 @@ mod test_append_and_len { type BlockNumber; } - decl_module! { + support::decl_module! { pub struct Module for enum Call where origin: T::Origin {} } #[derive(PartialEq, Eq, Clone, Encode, Decode)] struct NoDef(u32); - crate::decl_storage! { + support::decl_storage! { trait Store for Module as Test { NoDefault: Option; -- GitLab From 7dd7067991655310ed7d115e1f541b5709fc4596 Mon Sep 17 00:00:00 2001 From: Jim Posen Date: Thu, 31 Oct 2019 23:48:04 +0100 Subject: [PATCH 156/167] Revert "grandpa: Use storage proofs for Grandpa authorities (#3734)" (#3983) This reverts commit c3b1a9836c3cde2e1028162091a96efefb9a1d0e. --- Cargo.lock | 1 + core/finality-grandpa/primitives/Cargo.toml | 2 + core/finality-grandpa/primitives/src/lib.rs | 78 +++++------------ core/finality-grandpa/src/authorities.rs | 8 +- core/finality-grandpa/src/aux_schema.rs | 9 +- .../src/communication/tests.rs | 3 +- core/finality-grandpa/src/finality_proof.rs | 86 +++++++++---------- core/finality-grandpa/src/lib.rs | 43 ++++------ core/finality-grandpa/src/light_import.rs | 58 ++++++------- core/finality-grandpa/src/tests.rs | 39 ++++++--- node-template/runtime/src/lib.rs | 9 +- node-template/src/service.rs | 6 +- node/cli/src/service.rs | 16 ++-- node/runtime/src/lib.rs | 11 ++- srml/grandpa/Cargo.toml | 1 - srml/grandpa/src/lib.rs | 66 +++++--------- srml/grandpa/src/mock.rs | 4 +- srml/grandpa/src/tests.rs | 18 ---- 18 files changed, 195 insertions(+), 263 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c32a690b33..342340d801 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5304,6 +5304,7 @@ dependencies = [ "sr-primitives 2.0.0", "sr-std 2.0.0", "substrate-application-crypto 2.0.0", + "substrate-client 2.0.0", ] [[package]] diff --git a/core/finality-grandpa/primitives/Cargo.toml b/core/finality-grandpa/primitives/Cargo.toml index 90d7af5777..02439d4150 100644 --- a/core/finality-grandpa/primitives/Cargo.toml +++ b/core/finality-grandpa/primitives/Cargo.toml @@ -5,6 +5,7 @@ authors = ["Parity Technologies "] edition = "2018" [dependencies] +client = { package = "substrate-client", path = "../../client", default-features = false } app-crypto = { package = "substrate-application-crypto", path = "../../application-crypto", default-features = false } codec = { package = "parity-scale-codec", version = "1.0.0", default-features = false, features = ["derive"] } sr-primitives = { path = "../../sr-primitives", default-features = false } @@ -14,6 +15,7 @@ serde = { version = "1.0.101", optional = true, features = ["derive"] } [features] default = ["std"] std = [ + "client/std", "codec/std", "sr-primitives/std", "rstd/std", diff --git a/core/finality-grandpa/primitives/src/lib.rs b/core/finality-grandpa/primitives/src/lib.rs index 3f5b4cb7f6..27139bbeef 100644 --- a/core/finality-grandpa/primitives/src/lib.rs +++ b/core/finality-grandpa/primitives/src/lib.rs @@ -23,9 +23,9 @@ extern crate alloc; #[cfg(feature = "std")] use serde::Serialize; -use codec::{Encode, Decode, Input, Codec}; +use codec::{Encode, Decode, Codec}; use sr_primitives::{ConsensusEngineId, RuntimeDebug}; -use rstd::borrow::Cow; +use client::decl_runtime_apis; use rstd::vec::Vec; mod app { @@ -46,10 +46,6 @@ pub type AuthoritySignature = app::Signature; /// The `ConsensusEngineId` of GRANDPA. pub const GRANDPA_ENGINE_ID: ConsensusEngineId = *b"FRNK"; -/// The storage key for the current set of weighted Grandpa authorities. -/// The value stored is an encoded VersionedAuthorityList. -pub const GRANDPA_AUTHORITIES_KEY: &'static [u8] = b":grandpa_authorities"; - /// The weight of an authority. pub type AuthorityWeight = u64; @@ -62,15 +58,12 @@ pub type SetId = u64; /// The round indicator. pub type RoundNumber = u64; -/// A list of Grandpa authorities with associated weights. -pub type AuthorityList = Vec<(AuthorityId, AuthorityWeight)>; - /// A scheduled change of authority set. #[cfg_attr(feature = "std", derive(Serialize))] #[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug)] pub struct ScheduledChange { /// The new authorities after the change, along with their respective weights. - pub next_authorities: AuthorityList, + pub next_authorities: Vec<(AuthorityId, AuthorityWeight)>, /// The number of blocks to delay. pub delay: N, } @@ -161,51 +154,24 @@ pub const PENDING_CHANGE_CALL: &str = "grandpa_pending_change"; /// WASM function call to get current GRANDPA authorities. pub const AUTHORITIES_CALL: &str = "grandpa_authorities"; -/// The current version of the stored AuthorityList type. The encoding version MUST be updated any -/// time the AuthorityList type changes. -const AUTHORITIES_VERISON: u8 = 1; - -/// An AuthorityList that is encoded with a version specifier. The encoding version is updated any -/// time the AuthorityList type changes. This ensures that encodings of different versions of an -/// AuthorityList are differentiable. Attempting to decode an authority list with an unknown -/// version will fail. -#[derive(Default)] -pub struct VersionedAuthorityList<'a>(Cow<'a, AuthorityList>); - -impl<'a> From for VersionedAuthorityList<'a> { - fn from(authorities: AuthorityList) -> Self { - VersionedAuthorityList(Cow::Owned(authorities)) - } -} - -impl<'a> From<&'a AuthorityList> for VersionedAuthorityList<'a> { - fn from(authorities: &'a AuthorityList) -> Self { - VersionedAuthorityList(Cow::Borrowed(authorities)) - } -} - -impl<'a> Into for VersionedAuthorityList<'a> { - fn into(self) -> AuthorityList { - self.0.into_owned() - } -} - -impl<'a> Encode for VersionedAuthorityList<'a> { - fn size_hint(&self) -> usize { - (AUTHORITIES_VERISON, self.0.as_ref()).size_hint() - } - - fn using_encoded R>(&self, f: F) -> R { - (AUTHORITIES_VERISON, self.0.as_ref()).using_encoded(f) - } -} - -impl<'a> Decode for VersionedAuthorityList<'a> { - fn decode(value: &mut I) -> Result { - let (version, authorities): (u8, AuthorityList) = Decode::decode(value)?; - if version != AUTHORITIES_VERISON { - return Err("unknown Grandpa authorities version".into()); - } - Ok(authorities.into()) +decl_runtime_apis! { + /// APIs for integrating the GRANDPA finality gadget into runtimes. + /// This should be implemented on the runtime side. + /// + /// This is primarily used for negotiating authority-set changes for the + /// gadget. GRANDPA uses a signaling model of changing authority sets: + /// changes should be signaled with a delay of N blocks, and then automatically + /// applied in the runtime after those N blocks have passed. + /// + /// The consensus protocol will coordinate the handoff externally. + #[api_version(2)] + pub trait GrandpaApi { + /// Get the current GRANDPA authorities and weights. This should not change except + /// for when changes are scheduled and the corresponding delay has passed. + /// + /// When called at block B, it will return the set of authorities that should be + /// used to finalize descendants of this block (B+1, B+2, ...). The block B itself + /// is finalized by the authorities from block B-1. + fn grandpa_authorities() -> Vec<(AuthorityId, AuthorityWeight)>; } } diff --git a/core/finality-grandpa/src/authorities.rs b/core/finality-grandpa/src/authorities.rs index 263f2dc076..9b83c9feb6 100644 --- a/core/finality-grandpa/src/authorities.rs +++ b/core/finality-grandpa/src/authorities.rs @@ -22,7 +22,7 @@ use grandpa::voter_set::VoterSet; use codec::{Encode, Decode}; use log::{debug, info}; use substrate_telemetry::{telemetry, CONSENSUS_INFO}; -use fg_primitives::{AuthorityId, AuthorityList}; +use fg_primitives::AuthorityId; use std::cmp::Ord; use std::fmt::Debug; @@ -86,7 +86,7 @@ pub(crate) struct Status { /// A set of authorities. #[derive(Debug, Clone, Encode, Decode, PartialEq)] pub(crate) struct AuthoritySet { - pub(crate) current_authorities: AuthorityList, + pub(crate) current_authorities: Vec<(AuthorityId, u64)>, pub(crate) set_id: u64, // Tree of pending standard changes across forks. Standard changes are // enacted on finality and must be enacted (i.e. finalized) in-order across @@ -103,7 +103,7 @@ where H: PartialEq, N: Ord, { /// Get a genesis set with given authorities. - pub(crate) fn genesis(initial: AuthorityList) -> Self { + pub(crate) fn genesis(initial: Vec<(AuthorityId, u64)>) -> Self { AuthoritySet { current_authorities: initial, set_id: 0, @@ -390,7 +390,7 @@ pub(crate) enum DelayKind { #[derive(Debug, Clone, Encode, PartialEq)] pub(crate) struct PendingChange { /// The new authorities and weights to apply. - pub(crate) next_authorities: AuthorityList, + pub(crate) next_authorities: Vec<(AuthorityId, u64)>, /// How deep in the chain the announcing block must be /// before the change is applied. pub(crate) delay: N, diff --git a/core/finality-grandpa/src/aux_schema.rs b/core/finality-grandpa/src/aux_schema.rs index 1aed0b95ab..a2b05a0cd6 100644 --- a/core/finality-grandpa/src/aux_schema.rs +++ b/core/finality-grandpa/src/aux_schema.rs @@ -25,7 +25,7 @@ use fork_tree::ForkTree; use grandpa::round::State as RoundState; use sr_primitives::traits::{Block as BlockT, NumberFor}; use log::{info, warn}; -use fg_primitives::{AuthorityList, SetId, RoundNumber}; +use fg_primitives::{AuthorityId, AuthorityWeight, SetId, RoundNumber}; use crate::authorities::{AuthoritySet, SharedAuthoritySet, PendingChange, DelayKind}; use crate::consensus_changes::{SharedConsensusChanges, ConsensusChanges}; @@ -55,7 +55,7 @@ type V0VoterSetState = (RoundNumber, RoundState); #[derive(Debug, Clone, Encode, Decode, PartialEq)] struct V0PendingChange { - next_authorities: AuthorityList, + next_authorities: Vec<(AuthorityId, AuthorityWeight)>, delay: N, canon_height: N, canon_hash: H, @@ -63,7 +63,7 @@ struct V0PendingChange { #[derive(Debug, Clone, Encode, Decode, PartialEq)] struct V0AuthoritySet { - current_authorities: AuthorityList, + current_authorities: Vec<(AuthorityId, AuthorityWeight)>, set_id: SetId, pending_changes: Vec>, } @@ -266,7 +266,7 @@ pub(crate) fn load_persistent( -> ClientResult> where B: AuxStore, - G: FnOnce() -> ClientResult, + G: FnOnce() -> ClientResult>, { let version: Option = load_decode(backend, VERSION_KEY)?; let consensus_changes = load_decode(backend, CONSENSUS_CHANGES_KEY)? @@ -426,7 +426,6 @@ pub(crate) fn load_authorities(backend: &B) #[cfg(test)] mod test { - use fg_primitives::AuthorityId; use primitives::H256; use test_client; use super::*; diff --git a/core/finality-grandpa/src/communication/tests.rs b/core/finality-grandpa/src/communication/tests.rs index af6d842be3..f918f47258 100644 --- a/core/finality-grandpa/src/communication/tests.rs +++ b/core/finality-grandpa/src/communication/tests.rs @@ -28,7 +28,6 @@ use codec::Encode; use sr_primitives::traits::NumberFor; use crate::environment::SharedVoterSetState; -use fg_primitives::AuthorityList; use super::gossip::{self, GossipValidator}; use super::{AuthorityId, VoterSet, Round, SetId}; @@ -201,7 +200,7 @@ fn make_test_network() -> ( ) } -fn make_ids(keys: &[Ed25519Keyring]) -> AuthorityList { +fn make_ids(keys: &[Ed25519Keyring]) -> Vec<(AuthorityId, u64)> { keys.iter() .map(|key| key.clone().public().into()) .map(|id| (id, 1)) diff --git a/core/finality-grandpa/src/finality_proof.rs b/core/finality-grandpa/src/finality_proof.rs index aa7207b422..bd22a7bbac 100644 --- a/core/finality-grandpa/src/finality_proof.rs +++ b/core/finality-grandpa/src/finality_proof.rs @@ -34,14 +34,13 @@ //! finality proof (that finalizes some block C that is ancestor of the B and descendant //! of the U) could be returned. -use std::iter; use std::sync::Arc; use log::{trace, warn}; use client::{ backend::Backend, blockchain::Backend as BlockchainBackend, CallExecutor, Client, error::{Error as ClientError, Result as ClientResult}, - light::fetcher::{FetchChecker, RemoteReadRequest, StorageProof}, + light::fetcher::{FetchChecker, RemoteCallRequest, StorageProof}, ExecutionStrategy, }; use codec::{Encode, Decode}; use grandpa::BlockNumberOps; @@ -49,9 +48,9 @@ use sr_primitives::{ Justification, generic::BlockId, traits::{NumberFor, Block as BlockT, Header as HeaderT, One}, }; -use primitives::{H256, Blake2Hasher, storage::StorageKey}; +use primitives::{H256, Blake2Hasher}; use substrate_telemetry::{telemetry, CONSENSUS_INFO}; -use fg_primitives::{AuthorityId, AuthorityList, VersionedAuthorityList, GRANDPA_AUTHORITIES_KEY}; +use fg_primitives::AuthorityId; use crate::justification::GrandpaJustification; @@ -60,9 +59,9 @@ const MAX_FRAGMENTS_IN_PROOF: usize = 8; /// GRANDPA authority set related methods for the finality proof provider. pub trait AuthoritySetForFinalityProver: Send + Sync { - /// Read GRANDPA_AUTHORITIES_KEY from storage at given block. - fn authorities(&self, block: &BlockId) -> ClientResult; - /// Prove storage read of GRANDPA_AUTHORITIES_KEY at given block. + /// Call GrandpaApi::grandpa_authorities at given block. + fn authorities(&self, block: &BlockId) -> ClientResult>; + /// Prove call of GrandpaApi::grandpa_authorities at given block. fn prove_authorities(&self, block: &BlockId) -> ClientResult; } @@ -73,28 +72,33 @@ impl, RA> AuthoritySetForFinalityProver fo E: CallExecutor + 'static + Clone + Send + Sync, RA: Send + Sync, { - fn authorities(&self, block: &BlockId) -> ClientResult { - let storage_key = StorageKey(GRANDPA_AUTHORITIES_KEY.to_vec()); - self.storage(block, &storage_key)? - .and_then(|encoded| VersionedAuthorityList::decode(&mut encoded.0.as_slice()).ok()) - .map(|versioned| versioned.into()) - .ok_or(ClientError::InvalidAuthoritiesSet) + fn authorities(&self, block: &BlockId) -> ClientResult> { + self.executor().call( + block, + "GrandpaApi_grandpa_authorities", + &[], + ExecutionStrategy::NativeElseWasm, + None, + ).and_then(|call_result| Decode::decode(&mut &call_result[..]) + .map_err(|err| ClientError::CallResultDecode( + "failed to decode GRANDPA authorities set proof".into(), err + ))) } fn prove_authorities(&self, block: &BlockId) -> ClientResult { - self.read_proof(block, iter::once(GRANDPA_AUTHORITIES_KEY)) + self.execution_proof(block, "GrandpaApi_grandpa_authorities",&[]).map(|(_, proof)| proof) } } /// GRANDPA authority set related methods for the finality proof checker. pub trait AuthoritySetForFinalityChecker: Send + Sync { - /// Check storage read proof of GRANDPA_AUTHORITIES_KEY at given block. + /// Check execution proof of Grandpa::grandpa_authorities at given block. fn check_authorities_proof( &self, hash: Block::Hash, header: Block::Header, proof: StorageProof, - ) -> ClientResult; + ) -> ClientResult>; } /// FetchChecker-based implementation of AuthoritySetForFinalityChecker. @@ -104,30 +108,22 @@ impl AuthoritySetForFinalityChecker for Arc ClientResult { - let storage_key = GRANDPA_AUTHORITIES_KEY.to_vec(); - let request = RemoteReadRequest { + ) -> ClientResult> { + let request = RemoteCallRequest { block: hash, header, - keys: vec![storage_key.clone()], + method: "GrandpaApi_grandpa_authorities".into(), + call_data: vec![], retry_count: None, }; - self.check_read_proof(&request, proof) - .and_then(|results| { - let maybe_encoded = results.get(&storage_key) - .expect( - "storage_key is listed in the request keys; \ - check_read_proof must return a value for each requested key; - qed" - ); - maybe_encoded - .as_ref() - .and_then(|encoded| { - VersionedAuthorityList::decode(&mut encoded.as_slice()).ok() - }) - .map(|versioned| versioned.into()) - .ok_or(ClientError::InvalidAuthoritiesSet) + self.check_execution_proof(&request, proof) + .and_then(|authorities| { + let authorities: Vec<(AuthorityId, u64)> = Decode::decode(&mut &authorities[..]) + .map_err(|err| ClientError::CallResultDecode( + "failed to decode GRANDPA authorities set proof".into(), err + ))?; + Ok(authorities.into_iter().collect()) }) } } @@ -193,7 +189,7 @@ pub struct FinalityEffects { /// New authorities set id that should be applied starting from block. pub new_set_id: u64, /// New authorities set that should be applied starting from block. - pub new_authorities: AuthorityList, + pub new_authorities: Vec<(AuthorityId, u64)>, } /// Single fragment of proof-of-finality. @@ -412,7 +408,7 @@ pub(crate) fn prove_finality, B: BlockchainBackend, B>( blockchain: &B, current_set_id: u64, - current_authorities: AuthorityList, + current_authorities: Vec<(AuthorityId, u64)>, authorities_provider: &dyn AuthoritySetForFinalityChecker, remote_proof: Vec, ) -> ClientResult> @@ -431,7 +427,7 @@ pub(crate) fn check_finality_proof, B>( fn do_check_finality_proof, B, J>( blockchain: &B, current_set_id: u64, - current_authorities: AuthorityList, + current_authorities: Vec<(AuthorityId, u64)>, authorities_provider: &dyn AuthoritySetForFinalityChecker, remote_proof: Vec, ) -> ClientResult> @@ -526,12 +522,12 @@ fn check_finality_proof_fragment, B, J>( /// Authorities set from initial authorities set or finality effects. enum AuthoritiesOrEffects { - Authorities(u64, AuthorityList), + Authorities(u64, Vec<(AuthorityId, u64)>), Effects(FinalityEffects
), } impl AuthoritiesOrEffects
{ - pub fn extract_authorities(self) -> (u64, AuthorityList) { + pub fn extract_authorities(self) -> (u64, Vec<(AuthorityId, u64)>) { match self { AuthoritiesOrEffects::Authorities(set_id, authorities) => (set_id, authorities), AuthoritiesOrEffects::Effects(effects) => (effects.new_set_id, effects.new_authorities), @@ -585,10 +581,10 @@ pub(crate) mod tests { impl AuthoritySetForFinalityProver for (GetAuthorities, ProveAuthorities) where - GetAuthorities: Send + Sync + Fn(BlockId) -> ClientResult, + GetAuthorities: Send + Sync + Fn(BlockId) -> ClientResult>, ProveAuthorities: Send + Sync + Fn(BlockId) -> ClientResult, { - fn authorities(&self, block: &BlockId) -> ClientResult { + fn authorities(&self, block: &BlockId) -> ClientResult> { self.0(*block) } @@ -601,14 +597,14 @@ pub(crate) mod tests { impl AuthoritySetForFinalityChecker for ClosureAuthoritySetForFinalityChecker where - Closure: Send + Sync + Fn(H256, Header, StorageProof) -> ClientResult, + Closure: Send + Sync + Fn(H256, Header, StorageProof) -> ClientResult>, { fn check_authorities_proof( &self, hash: H256, header: Header, - proof: StorageProof - ) -> ClientResult { + proof: StorageProof, + ) -> ClientResult> { self.0(hash, header, proof) } } diff --git a/core/finality-grandpa/src/lib.rs b/core/finality-grandpa/src/lib.rs index 67acaa21d7..0decea5811 100644 --- a/core/finality-grandpa/src/lib.rs +++ b/core/finality-grandpa/src/lib.rs @@ -61,7 +61,10 @@ use client::{ use client::blockchain::HeaderBackend; use codec::Encode; use sr_primitives::generic::BlockId; -use sr_primitives::traits::{NumberFor, Block as BlockT, DigestFor, Zero}; +use sr_primitives::traits::{ + NumberFor, Block as BlockT, DigestFor, ProvideRuntimeApi +}; +use fg_primitives::{GrandpaApi, AuthorityPair}; use keystore::KeyStorePtr; use inherents::InherentDataProviders; use consensus_common::SelectChain; @@ -105,7 +108,7 @@ use environment::{Environment, VoterSetState}; use import::GrandpaBlockImport; use until_imported::UntilGlobalMessageBlocksImported; use communication::NetworkBridge; -use fg_primitives::{AuthorityList, AuthorityPair, AuthoritySignature, SetId}; +use fg_primitives::{AuthoritySignature, SetId, AuthorityWeight}; // Re-export these two because it's just so damn convenient. pub use fg_primitives::{AuthorityId, ScheduledChange}; @@ -292,7 +295,7 @@ pub(crate) struct NewAuthoritySet { pub(crate) canon_number: N, pub(crate) canon_hash: H, pub(crate) set_id: SetId, - pub(crate) authorities: AuthorityList, + pub(crate) authorities: Vec<(AuthorityId, AuthorityWeight)>, } /// Commands issued to the voter. @@ -364,30 +367,11 @@ pub struct LinkHalf, RA, SC> { voter_commands_rx: mpsc::UnboundedReceiver>>, } -/// Provider for the Grandpa authority set configured on the genesis block. -pub trait GenesisAuthoritySetProvider { - /// Get the authority set at the genesis block. - fn get(&self) -> Result; -} - -impl, RA> GenesisAuthoritySetProvider for Client - where - B: Backend + Send + Sync + 'static, - E: CallExecutor + 'static + Clone + Send + Sync, - RA: Send + Sync, -{ - fn get(&self) -> Result { - use finality_proof::AuthoritySetForFinalityProver; - - self.authorities(&BlockId::Number(Zero::zero())) - } -} - /// Make block importer and link half necessary to tie the background voter /// to it. -pub fn block_import, RA, SC>( +pub fn block_import, RA, PRA, SC>( client: Arc>, - genesis_authorities_provider: &dyn GenesisAuthoritySetProvider, + api: &PRA, select_chain: SC, ) -> Result<( GrandpaBlockImport, @@ -397,8 +381,12 @@ where B: Backend + 'static, E: CallExecutor + 'static + Clone + Send + Sync, RA: Send + Sync, + PRA: ProvideRuntimeApi, + PRA::Api: GrandpaApi, SC: SelectChain, { + use sr_primitives::traits::Zero; + let chain_info = client.info(); let genesis_hash = chain_info.chain.genesis_hash; @@ -407,11 +395,12 @@ where genesis_hash, >::zero(), || { - let authorities = genesis_authorities_provider.get()?; + let genesis_authorities = api.runtime_api() + .grandpa_authorities(&BlockId::number(Zero::zero()))?; telemetry!(CONSENSUS_DEBUG; "afg.loading_authorities"; - "authorities_len" => ?authorities.len() + "authorities_len" => ?genesis_authorities.len() ); - Ok(authorities) + Ok(genesis_authorities) } )?; diff --git a/core/finality-grandpa/src/light_import.rs b/core/finality-grandpa/src/light_import.rs index 30008b51ec..30af3a06d3 100644 --- a/core/finality-grandpa/src/light_import.rs +++ b/core/finality-grandpa/src/light_import.rs @@ -34,18 +34,17 @@ use consensus_common::{ }; use network::config::{BoxFinalityProofRequestBuilder, FinalityProofRequestBuilder}; use sr_primitives::Justification; -use sr_primitives::traits::{NumberFor, Block as BlockT, Header as HeaderT, DigestFor}; -use fg_primitives::{self, AuthorityList}; +use sr_primitives::traits::{ + NumberFor, Block as BlockT, Header as HeaderT, ProvideRuntimeApi, DigestFor, +}; +use fg_primitives::{self, GrandpaApi, AuthorityId}; use sr_primitives::generic::BlockId; use primitives::{H256, Blake2Hasher}; -use crate::GenesisAuthoritySetProvider; use crate::aux_schema::load_decode; use crate::consensus_changes::ConsensusChanges; use crate::environment::canonical_at_height; -use crate::finality_proof::{ - AuthoritySetForFinalityChecker, ProvableJustification, make_finality_proof_request, -}; +use crate::finality_proof::{AuthoritySetForFinalityChecker, ProvableJustification, make_finality_proof_request}; use crate::justification::GrandpaJustification; /// LightAuthoritySet is saved under this key in aux storage. @@ -54,23 +53,21 @@ const LIGHT_AUTHORITY_SET_KEY: &[u8] = b"grandpa_voters"; const LIGHT_CONSENSUS_CHANGES_KEY: &[u8] = b"grandpa_consensus_changes"; /// Create light block importer. -pub fn light_block_import, RA>( +pub fn light_block_import, RA, PRA>( client: Arc>, backend: Arc, - genesis_authorities_provider: &dyn GenesisAuthoritySetProvider, authority_set_provider: Arc>, + api: Arc, ) -> Result, ClientError> where B: Backend + 'static, E: CallExecutor + 'static + Clone + Send + Sync, RA: Send + Sync, + PRA: ProvideRuntimeApi, + PRA::Api: GrandpaApi, { let info = client.info(); - let import_data = load_aux_import_data( - info.chain.finalized_hash, - &*client, - genesis_authorities_provider, - )?; + let import_data = load_aux_import_data(info.chain.finalized_hash, &*client, api)?; Ok(GrandpaLightBlockImport { client, backend, @@ -113,7 +110,7 @@ struct LightImportData> { #[derive(Debug, Encode, Decode)] struct LightAuthoritySet { set_id: u64, - authorities: AuthorityList, + authorities: Vec<(AuthorityId, u64)>, } impl, RA> GrandpaLightBlockImport { @@ -197,7 +194,7 @@ impl, RA> FinalityProofImport impl LightAuthoritySet { /// Get a genesis set with given authorities. - pub fn genesis(initial: AuthorityList) -> Self { + pub fn genesis(initial: Vec<(AuthorityId, u64)>) -> Self { LightAuthoritySet { set_id: fg_primitives::SetId::default(), authorities: initial, @@ -210,12 +207,12 @@ impl LightAuthoritySet { } /// Get latest authorities set. - pub fn authorities(&self) -> AuthorityList { + pub fn authorities(&self) -> Vec<(AuthorityId, u64)> { self.authorities.clone() } /// Set new authorities set. - pub fn update(&mut self, set_id: u64, authorities: AuthorityList) { + pub fn update(&mut self, set_id: u64, authorities: Vec<(AuthorityId, u64)>) { self.set_id = set_id; std::mem::replace(&mut self.authorities, authorities); } @@ -475,14 +472,17 @@ fn do_finalize_block>( } /// Load light import aux data from the store. -fn load_aux_import_data>( +fn load_aux_import_data, PRA>( last_finalized: Block::Hash, aux_store: &B, - genesis_authorities_provider: &dyn GenesisAuthoritySetProvider, + api: Arc, ) -> Result, ClientError> where B: AuxStore, + PRA: ProvideRuntimeApi, + PRA::Api: GrandpaApi, { + use sr_primitives::traits::Zero; let authority_set = match load_decode(aux_store, LIGHT_AUTHORITY_SET_KEY)? { Some(authority_set) => authority_set, None => { @@ -490,7 +490,7 @@ fn load_aux_import_data>( from genesis on what appears to be first startup."); // no authority set on disk: fetch authorities from genesis state - let genesis_authorities = genesis_authorities_provider.get()?; + let genesis_authorities = api.runtime_api().grandpa_authorities(&BlockId::number(Zero::zero()))?; let authority_set = LightAuthoritySet::genesis(genesis_authorities); let encoded = authority_set.encode(); @@ -546,7 +546,6 @@ fn on_post_finalization_error(error: ClientError, value_type: &str) -> Consensus pub mod tests { use super::*; use consensus_common::ForkChoiceStrategy; - use fg_primitives::AuthorityId; use primitives::{H256, crypto::Public}; use test_client::client::in_mem::Blockchain as InMemoryAuxStore; use test_client::runtime::{Block, Header}; @@ -623,19 +622,20 @@ pub mod tests { } /// Creates light block import that ignores justifications that came outside of finality proofs. - pub fn light_block_import_without_justifications, RA>( + pub fn light_block_import_without_justifications, RA, PRA>( client: Arc>, backend: Arc, - genesis_authorities_provider: &dyn GenesisAuthoritySetProvider, authority_set_provider: Arc>, + api: Arc, ) -> Result, ClientError> where B: Backend + 'static, E: CallExecutor + 'static + Clone + Send + Sync, RA: Send + Sync, + PRA: ProvideRuntimeApi, + PRA::Api: GrandpaApi, { - light_block_import(client, backend, genesis_authorities_provider, authority_set_provider) - .map(NoJustificationsImport) + light_block_import(client, backend, authority_set_provider, api).map(NoJustificationsImport) } fn import_block( @@ -729,14 +729,14 @@ pub mod tests { #[test] fn aux_data_updated_on_start() { let aux_store = InMemoryAuxStore::::new(); - let api = TestApi::new(vec![(AuthorityId::from_slice(&[1; 32]), 1)]); + let api = Arc::new(TestApi::new(vec![(AuthorityId::from_slice(&[1; 32]), 1)])); // when aux store is empty initially assert!(aux_store.get_aux(LIGHT_AUTHORITY_SET_KEY).unwrap().is_none()); assert!(aux_store.get_aux(LIGHT_CONSENSUS_CHANGES_KEY).unwrap().is_none()); // it is updated on importer start - load_aux_import_data(Default::default(), &aux_store, &api).unwrap(); + load_aux_import_data(Default::default(), &aux_store, api).unwrap(); assert!(aux_store.get_aux(LIGHT_AUTHORITY_SET_KEY).unwrap().is_some()); assert!(aux_store.get_aux(LIGHT_CONSENSUS_CHANGES_KEY).unwrap().is_some()); } @@ -744,7 +744,7 @@ pub mod tests { #[test] fn aux_data_loaded_on_restart() { let aux_store = InMemoryAuxStore::::new(); - let api = TestApi::new(vec![(AuthorityId::from_slice(&[1; 32]), 1)]); + let api = Arc::new(TestApi::new(vec![(AuthorityId::from_slice(&[1; 32]), 1)])); // when aux store is non-empty initially let mut consensus_changes = ConsensusChanges::::empty(); @@ -766,7 +766,7 @@ pub mod tests { ).unwrap(); // importer uses it on start - let data = load_aux_import_data(Default::default(), &aux_store, &api).unwrap(); + let data = load_aux_import_data(Default::default(), &aux_store, api).unwrap(); assert_eq!(data.authority_set.authorities(), vec![(AuthorityId::from_slice(&[42; 32]), 2)]); assert_eq!(data.consensus_changes.pending_changes(), &[(42, Default::default())]); } diff --git a/core/finality-grandpa/src/tests.rs b/core/finality-grandpa/src/tests.rs index 93c08a9661..2339379a60 100644 --- a/core/finality-grandpa/src/tests.rs +++ b/core/finality-grandpa/src/tests.rs @@ -39,7 +39,7 @@ use codec::Decode; use sr_primitives::traits::{ApiRef, ProvideRuntimeApi, Header as HeaderT}; use sr_primitives::generic::{BlockId, DigestItem}; use primitives::{NativeOrEncoded, ExecutionContext, crypto::Public}; -use fg_primitives::{GRANDPA_ENGINE_ID, AuthorityList}; +use fg_primitives::{GRANDPA_ENGINE_ID, AuthorityId}; use state_machine::{backend::InMemory, prove_read, read_proof_check}; use authorities::AuthoritySet; @@ -137,8 +137,8 @@ impl TestNetFactory for GrandpaTestNet { let import = light_block_import_without_justifications( client.clone(), backend.clone(), - &self.test_config, authorities_provider, + Arc::new(self.test_config.clone()) ).expect("Could not create block import for fresh peer."); let finality_proof_req_builder = import.0.create_finality_proof_request_builder(); let proof_import = Box::new(import.clone()); @@ -188,24 +188,26 @@ impl Future for Exit { #[derive(Default, Clone)] pub(crate) struct TestApi { - genesis_authorities: AuthorityList, + genesis_authorities: Vec<(AuthorityId, u64)>, } impl TestApi { - pub fn new(genesis_authorities: AuthorityList) -> Self { + pub fn new(genesis_authorities: Vec<(AuthorityId, u64)>) -> Self { TestApi { genesis_authorities, } } } -pub(crate) struct RuntimeApi; +pub(crate) struct RuntimeApi { + inner: TestApi, +} impl ProvideRuntimeApi for TestApi { type Api = RuntimeApi; fn runtime_api<'a>(&'a self) -> ApiRef<'a, Self::Api> { - RuntimeApi.into() + RuntimeApi { inner: self.clone() }.into() } } @@ -262,15 +264,26 @@ impl ApiExt for RuntimeApi { } } -impl GenesisAuthoritySetProvider for TestApi { - fn get(&self) -> Result { - Ok(self.genesis_authorities.clone()) +impl GrandpaApi for RuntimeApi { + fn GrandpaApi_grandpa_authorities_runtime_api_impl( + &self, + _: &BlockId, + _: ExecutionContext, + _: Option<()>, + _: Vec, + ) -> Result>> { + Ok(self.inner.genesis_authorities.clone()).map(NativeOrEncoded::Native) } } impl AuthoritySetForFinalityProver for TestApi { - fn authorities(&self, _block: &BlockId) -> Result { - Ok(self.genesis_authorities.clone()) + fn authorities(&self, block: &BlockId) -> Result> { + let runtime_api = RuntimeApi { inner: self.clone() }; + runtime_api.GrandpaApi_grandpa_authorities_runtime_api_impl(block, ExecutionContext::Syncing, None, Vec::new()) + .map(|v| match v { + NativeOrEncoded::Native(value) => value, + _ => unreachable!("only providing native values"), + }) } fn prove_authorities(&self, block: &BlockId) -> Result { @@ -290,7 +303,7 @@ impl AuthoritySetForFinalityChecker for TestApi { _hash: ::Hash, header: ::Header, proof: StorageProof, - ) -> Result { + ) -> Result> { let results = read_proof_check::( *header.state_root(), proof, vec![b"authorities"] ) @@ -307,7 +320,7 @@ impl AuthoritySetForFinalityChecker for TestApi { const TEST_GOSSIP_DURATION: Duration = Duration::from_millis(500); -fn make_ids(keys: &[Ed25519Keyring]) -> AuthorityList { +fn make_ids(keys: &[Ed25519Keyring]) -> Vec<(AuthorityId, u64)> { keys.iter().map(|key| key.clone().public().into()).map(|id| (id, 1)).collect() } diff --git a/node-template/runtime/src/lib.rs b/node-template/runtime/src/lib.rs index 5b440cdd9b..c0cd2cf337 100644 --- a/node-template/runtime/src/lib.rs +++ b/node-template/runtime/src/lib.rs @@ -23,7 +23,8 @@ use client::{ runtime_api as client_api, impl_runtime_apis }; use aura_primitives::sr25519::AuthorityId as AuraId; -use grandpa::AuthorityId as GrandpaId; +use grandpa::{AuthorityId as GrandpaId, AuthorityWeight as GrandpaWeight}; +use grandpa::fg_primitives; use version::RuntimeVersion; #[cfg(feature = "std")] use version::NativeVersion; @@ -352,4 +353,10 @@ impl_runtime_apis! { opaque::SessionKeys::generate(seed) } } + + impl fg_primitives::GrandpaApi for Runtime { + fn grandpa_authorities() -> Vec<(GrandpaId, GrandpaWeight)> { + Grandpa::grandpa_authorities() + } + } } diff --git a/node-template/src/service.rs b/node-template/src/service.rs index 7967a1d2d4..398795325f 100644 --- a/node-template/src/service.rs +++ b/node-template/src/service.rs @@ -48,7 +48,7 @@ macro_rules! new_full_start { .ok_or_else(|| substrate_service::Error::SelectChainRequired)?; let (grandpa_block_import, grandpa_link) = - grandpa::block_import::<_, _, _, runtime::RuntimeApi, _>( + grandpa::block_import::<_, _, _, runtime::RuntimeApi, _, _>( client.clone(), &*client, select_chain )?; @@ -197,8 +197,8 @@ pub fn new_light(config: Configuration( - client.clone(), backend, &*client.clone(), Arc::new(fetch_checker), + let grandpa_block_import = grandpa::light_block_import::<_, _, _, RuntimeApi, _>( + client.clone(), backend, Arc::new(fetch_checker), client.clone() )?; let finality_proof_import = grandpa_block_import.clone(); let finality_proof_request_builder = diff --git a/node/cli/src/service.rs b/node/cli/src/service.rs index 9f0726fc83..0905659114 100644 --- a/node/cli/src/service.rs +++ b/node/cli/src/service.rs @@ -69,11 +69,10 @@ macro_rules! new_full_start { .with_import_queue(|_config, client, mut select_chain, _transaction_pool| { let select_chain = select_chain.take() .ok_or_else(|| substrate_service::Error::SelectChainRequired)?; - let (grandpa_block_import, grandpa_link) = grandpa::block_import( - client.clone(), - &*client, - select_chain, - )?; + let (grandpa_block_import, grandpa_link) = + grandpa::block_import::<_, _, _, node_runtime::RuntimeApi, _, _>( + client.clone(), &*client, select_chain + )?; let justification_import = grandpa_block_import.clone(); let (block_import, babe_link) = babe::block_import( @@ -292,11 +291,8 @@ pub fn new_light(config: NodeConfiguration) let fetch_checker = fetcher .map(|fetcher| fetcher.checker().clone()) .ok_or_else(|| "Trying to start light import queue without active fetch checker")?; - let grandpa_block_import = grandpa::light_block_import::<_, _, _, RuntimeApi>( - client.clone(), - backend, - &*client, - Arc::new(fetch_checker), + let grandpa_block_import = grandpa::light_block_import::<_, _, _, RuntimeApi, _>( + client.clone(), backend, Arc::new(fetch_checker), client.clone() )?; let finality_proof_import = grandpa_block_import.clone(); diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index adee13775d..a0ee20988e 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -29,6 +29,7 @@ use node_primitives::{ AccountId, AccountIndex, Balance, BlockNumber, Hash, Index, Moment, Signature, }; +use grandpa::fg_primitives; use client::{ block_builder::api::{self as block_builder_api, InherentData, CheckInherentsResult}, runtime_api as client_api, impl_runtime_apis @@ -45,7 +46,7 @@ use version::RuntimeVersion; #[cfg(any(feature = "std", test))] use version::NativeVersion; use primitives::OpaqueMetadata; -use grandpa::AuthorityId as GrandpaId; +use grandpa::{AuthorityId as GrandpaId, AuthorityWeight as GrandpaWeight}; use im_online::sr25519::{AuthorityId as ImOnlineId}; use transaction_payment_rpc_runtime_api::RuntimeDispatchInfo; use contracts_rpc_runtime_api::ContractExecResult; @@ -80,7 +81,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // and set impl_version to equal spec_version. If only runtime // implementation changes and behavior does not, then leave spec_version as // is and increment impl_version. - spec_version: 191, + spec_version: 190, impl_version: 191, apis: RUNTIME_API_VERSIONS, }; @@ -610,6 +611,12 @@ impl_runtime_apis! { } } + impl fg_primitives::GrandpaApi for Runtime { + fn grandpa_authorities() -> Vec<(GrandpaId, GrandpaWeight)> { + Grandpa::grandpa_authorities() + } + } + impl babe_primitives::BabeApi for Runtime { fn configuration() -> babe_primitives::BabeConfiguration { // The choice of `c` parameter (where `1 - c` represents the diff --git a/srml/grandpa/Cargo.toml b/srml/grandpa/Cargo.toml index 21b48d3cdc..4b494cfeff 100644 --- a/srml/grandpa/Cargo.toml +++ b/srml/grandpa/Cargo.toml @@ -35,4 +35,3 @@ std = [ "session/std", "finality-tracker/std", ] -migrate-authorities = [] diff --git a/srml/grandpa/src/lib.rs b/srml/grandpa/src/lib.rs index b635b88521..f3e876f2c4 100644 --- a/srml/grandpa/src/lib.rs +++ b/srml/grandpa/src/lib.rs @@ -21,6 +21,9 @@ //! //! In the future, it will also handle misbehavior reports, and on-chain //! finality notifications. +//! +//! For full integration with GRANDPA, the `GrandpaApi` should be implemented. +//! The necessary items are re-exported via the `fg_primitives` crate. #![cfg_attr(not(feature = "std"), no_std)] @@ -29,7 +32,9 @@ pub use substrate_finality_grandpa_primitives as fg_primitives; use rstd::prelude::*; use codec::{self as codec, Encode, Decode, Error}; -use support::{decl_event, decl_storage, decl_module, dispatch::Result, storage}; +use support::{ + decl_event, decl_storage, decl_module, dispatch::Result, +}; use sr_primitives::{ generic::{DigestItem, OpaqueDigestItemId}, traits::Zero, Perbill, }; @@ -37,10 +42,8 @@ use sr_staking_primitives::{ SessionIndex, offence::{Offence, Kind}, }; -use fg_primitives::{ - GRANDPA_AUTHORITIES_KEY, GRANDPA_ENGINE_ID, ScheduledChange, ConsensusLog, SetId, RoundNumber, -}; -pub use fg_primitives::{AuthorityId, AuthorityList, AuthorityWeight, VersionedAuthorityList}; +use fg_primitives::{GRANDPA_ENGINE_ID, ScheduledChange, ConsensusLog, SetId, RoundNumber}; +pub use fg_primitives::{AuthorityId, AuthorityWeight}; use system::{ensure_signed, DigestOf}; mod mock; @@ -61,7 +64,7 @@ pub struct OldStoredPendingChange { /// The delay in blocks until it will be applied. pub delay: N, /// The next authority set. - pub next_authorities: AuthorityList, + pub next_authorities: Vec<(AuthorityId, AuthorityWeight)>, } /// A stored pending change. @@ -72,7 +75,7 @@ pub struct StoredPendingChange { /// The delay in blocks until it will be applied. pub delay: N, /// The next authority set. - pub next_authorities: AuthorityList, + pub next_authorities: Vec<(AuthorityId, AuthorityWeight)>, /// If defined it means the change was forced and the given block number /// indicates the median last finalized block when the change was signaled. pub forced: Option, @@ -123,7 +126,7 @@ pub enum StoredState { decl_event!( pub enum Event { /// New authority set has been applied. - NewAuthorities(AuthorityList), + NewAuthorities(Vec<(AuthorityId, AuthorityWeight)>), /// Current authority set has been paused. Paused, /// Current authority set has been resumed. @@ -133,12 +136,8 @@ decl_event!( decl_storage! { trait Store for Module as GrandpaFinality { - /// DEPRECATED - /// - /// This used to store the current authority set, which has been migrated to the well-known - /// GRANDPA_AUTHORITES_KEY unhashed key. - #[cfg(feature = "migrate-authorities")] - pub(crate) Authorities get(fn authorities): AuthorityList; + /// The current authority set. + Authorities get(fn authorities): Vec<(AuthorityId, AuthorityWeight)>; /// State of the current authority set. State get(fn state): StoredState = StoredState::Live; @@ -160,7 +159,7 @@ decl_storage! { SetIdSession get(fn session_for_set): map SetId => Option; } add_extra_genesis { - config(authorities): AuthorityList; + config(authorities): Vec<(AuthorityId, AuthorityWeight)>; build(|config| Module::::initialize_authorities(&config.authorities)) } } @@ -175,11 +174,6 @@ decl_module! { // FIXME: https://github.com/paritytech/substrate/issues/1112 } - fn on_initialize() { - #[cfg(feature = "migrate-authorities")] - Self::migrate_authorities(); - } - fn on_finalize(block_number: T::BlockNumber) { // check for scheduled pending authority set changes if let Some(pending_change) = >::get() { @@ -205,7 +199,7 @@ decl_module! { // enact the change if we've reached the enacting block if block_number == pending_change.scheduled_at + pending_change.delay { - Self::set_grandpa_authorities(&pending_change.next_authorities); + Authorities::put(&pending_change.next_authorities); Self::deposit_event( Event::NewAuthorities(pending_change.next_authorities) ); @@ -247,16 +241,8 @@ decl_module! { impl Module { /// Get the current set of authorities, along with their respective weights. - pub fn grandpa_authorities() -> AuthorityList { - storage::unhashed::get_or_default::(GRANDPA_AUTHORITIES_KEY).into() - } - - /// Set the current set of authorities, along with their respective weights. - fn set_grandpa_authorities(authorities: &AuthorityList) { - storage::unhashed::put( - GRANDPA_AUTHORITIES_KEY, - &VersionedAuthorityList::from(authorities), - ); + pub fn grandpa_authorities() -> Vec<(AuthorityId, AuthorityWeight)> { + Authorities::get() } /// Schedule GRANDPA to pause starting in the given number of blocks. @@ -307,7 +293,7 @@ impl Module { /// No change should be signaled while any change is pending. Returns /// an error if a change is already pending. pub fn schedule_change( - next_authorities: AuthorityList, + next_authorities: Vec<(AuthorityId, AuthorityWeight)>, in_blocks: T::BlockNumber, forced: Option, ) -> Result { @@ -343,20 +329,10 @@ impl Module { >::deposit_log(log.into()); } - fn initialize_authorities(authorities: &AuthorityList) { + fn initialize_authorities(authorities: &[(AuthorityId, AuthorityWeight)]) { if !authorities.is_empty() { - assert!( - Self::grandpa_authorities().is_empty(), - "Authorities are already initialized!" - ); - Self::set_grandpa_authorities(authorities); - } - } - - #[cfg(feature = "migrate-authorities")] - fn migrate_authorities() { - if Authorities::exists() { - Self::set_grandpa_authorities(&Authorities::take()); + assert!(Authorities::get().is_empty(), "Authorities are already initialized!"); + Authorities::put(authorities); } } } diff --git a/srml/grandpa/src/mock.rs b/srml/grandpa/src/mock.rs index c6ea207557..fcacbade20 100644 --- a/srml/grandpa/src/mock.rs +++ b/srml/grandpa/src/mock.rs @@ -23,7 +23,7 @@ use runtime_io; use support::{impl_outer_origin, impl_outer_event, parameter_types}; use primitives::H256; use codec::{Encode, Decode}; -use crate::{AuthorityId, AuthorityList, GenesisConfig, Trait, Module, ConsensusLog}; +use crate::{AuthorityId, GenesisConfig, Trait, Module, ConsensusLog}; use substrate_finality_grandpa_primitives::GRANDPA_ENGINE_ID; impl_outer_origin!{ @@ -75,7 +75,7 @@ impl_outer_event!{ } } -pub fn to_authorities(vec: Vec<(u64, u64)>) -> AuthorityList { +pub fn to_authorities(vec: Vec<(u64, u64)>) -> Vec<(AuthorityId, u64)> { vec.into_iter() .map(|(id, weight)| (UintAuthorityId(id).to_public_key::(), weight)) .collect() diff --git a/srml/grandpa/src/tests.rs b/srml/grandpa/src/tests.rs index 3d6a8752c5..2efeb4b5bf 100644 --- a/srml/grandpa/src/tests.rs +++ b/srml/grandpa/src/tests.rs @@ -308,21 +308,3 @@ fn time_slot_have_sane_ord() { ]; assert!(FIXTURE.windows(2).all(|f| f[0] < f[1])); } - -#[test] -#[cfg(feature = "migrate-authorities")] -fn authorities_migration() { - use sr_primitives::traits::OnInitialize; - - with_externalities(&mut new_test_ext(vec![]), || { - let authorities = to_authorities(vec![(1, 1), (2, 1), (3, 1)]); - - Authorities::put(authorities.clone()); - assert!(Grandpa::grandpa_authorities().is_empty()); - - Grandpa::on_initialize(1); - - assert!(!Authorities::exists()); - assert_eq!(Grandpa::grandpa_authorities(), authorities); - }); -} -- GitLab From c63610a5b7d134b735297c9504a6ea29470b3943 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Fri, 1 Nov 2019 10:25:35 +0100 Subject: [PATCH 157/167] Print warning again if polling network is too long (#3984) --- core/service/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/service/src/lib.rs b/core/service/src/lib.rs index c46732d511..d09fcb093b 100644 --- a/core/service/src/lib.rs +++ b/core/service/src/lib.rs @@ -459,7 +459,7 @@ fn build_network_future< let polling_dur = before_polling.elapsed(); log!( target: "service", - if polling_dur >= Duration::from_millis(50) { Level::Debug } else { Level::Trace }, + if polling_dur >= Duration::from_secs(1) { Level::Warn } else { Level::Trace }, "Polling the network future took {:?}", polling_dur ); -- GitLab From 595f18e6d40cf92a7a591c72e3093142516c9067 Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Fri, 1 Nov 2019 11:07:46 +0000 Subject: [PATCH 158/167] Add events for im_online (#3991) * Add AllGood event for im_online * Another event just in case. * Bump runtime --- core/network/src/protocol.rs | 1 - core/network/src/protocol/specialization.rs | 2 +- .../src/generic/checked_extrinsic.rs | 3 +- node/runtime/src/lib.rs | 2 +- srml/im-online/src/lib.rs | 67 ++++++++----------- srml/im-online/src/tests.rs | 30 ++++----- 6 files changed, 47 insertions(+), 58 deletions(-) diff --git a/core/network/src/protocol.rs b/core/network/src/protocol.rs index 335c2380c8..6afb4c8b11 100644 --- a/core/network/src/protocol.rs +++ b/core/network/src/protocol.rs @@ -35,7 +35,6 @@ use sr_primitives::traits::{ }; use message::{BlockAnnounce, BlockAttributes, Direction, FromBlock, Message, RequestId}; use message::generic::{Message as GenericMessage, ConsensusMessage}; -use event::Event; use consensus_gossip::{ConsensusGossip, MessageRecipient as GossipMessageRecipient}; use light_dispatch::{LightDispatch, LightDispatchNetwork, RequestData}; use specialization::NetworkSpecialization; diff --git a/core/network/src/protocol/specialization.rs b/core/network/src/protocol/specialization.rs index 37509eeec0..1a15c47c87 100644 --- a/core/network/src/protocol/specialization.rs +++ b/core/network/src/protocol/specialization.rs @@ -43,7 +43,7 @@ pub trait NetworkSpecialization: Send + Sync + 'static { /// Called when a network-specific event arrives. #[deprecated(note = "This method is never called; please use `with_dht_event_tx` when building the service")] - fn on_event(&mut self, event: Event) {} + fn on_event(&mut self, _event: Event) {} /// Called on abort. #[deprecated(note = "This method is never called; aborting corresponds to dropping the object")] diff --git a/core/sr-primitives/src/generic/checked_extrinsic.rs b/core/sr-primitives/src/generic/checked_extrinsic.rs index 1e030ea1d8..510a7ac8c8 100644 --- a/core/sr-primitives/src/generic/checked_extrinsic.rs +++ b/core/sr-primitives/src/generic/checked_extrinsic.rs @@ -36,8 +36,7 @@ pub struct CheckedExtrinsic { pub function: Call, } -impl traits::Applyable -for +impl traits::Applyable for CheckedExtrinsic where AccountId: Member + MaybeDisplay, diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index a0ee20988e..5cf6663904 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -81,7 +81,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // and set impl_version to equal spec_version. If only runtime // implementation changes and behavior does not, then leave spec_version as // is and increment impl_version. - spec_version: 190, + spec_version: 191, impl_version: 191, apis: RUNTIME_API_VERSIONS, }; diff --git a/srml/im-online/src/lib.rs b/srml/im-online/src/lib.rs index 46e26ff32f..fa970f4997 100644 --- a/srml/im-online/src/lib.rs +++ b/srml/im-online/src/lib.rs @@ -37,7 +37,7 @@ //! //! ### Public Functions //! -//! - `is_online_in_current_session` - True if the validator sent a heartbeat in the current session. +//! - `is_online` - True if the validator sent a heartbeat in the current session. //! //! ## Usage //! @@ -52,7 +52,7 @@ //! pub struct Module for enum Call where origin: T::Origin { //! pub fn is_online(origin, authority_index: u32) -> Result { //! let _sender = ensure_signed(origin)?; -//! let _is_online = >::is_online_in_current_session(authority_index); +//! let _is_online = >::is_online(authority_index); //! Ok(()) //! } //! } @@ -200,9 +200,14 @@ pub trait Trait: system::Trait + session::historical::Trait { decl_event!( pub enum Event where ::AuthorityId, + IdentificationTuple = IdentificationTuple, { /// A new heartbeat was received from `AuthorityId` HeartbeatReceived(AuthorityId), + /// At the end of the session, no offence was committed. + AllGood, + /// At the end of the session, at least once validator was found to be offline. + SomeOffline(Vec), } ); @@ -217,7 +222,7 @@ decl_storage! { /// For each session index, we keep a mapping of `AuthIndex` /// to `offchain::OpaqueNetworkState`. ReceivedHeartbeats get(fn received_heartbeats): double_map SessionIndex, - blake2_256(AuthIndex) => Vec; + blake2_256(AuthIndex) => Option>; /// For each session index, we keep a mapping of `T::ValidatorId` to the /// number of blocks authored by the given authority. @@ -249,8 +254,8 @@ decl_module! { &heartbeat.authority_index ); let keys = Keys::::get(); - let public = keys.get(heartbeat.authority_index as usize); - if let (true, Some(public)) = (!exists, public) { + let maybe_public = keys.get(heartbeat.authority_index as usize); + if let (false, Some(public)) = (exists, maybe_public) { let signature_valid = heartbeat.using_encoded(|encoded_heartbeat| { public.verify(&encoded_heartbeat, &signature) }); @@ -300,7 +305,7 @@ impl Module { /// `authority_index` in the authorities series or if the authority has /// authored at least one block, during the current session. Otherwise /// `false`. - pub fn is_online_in_current_session(authority_index: AuthIndex) -> bool { + pub fn is_online(authority_index: AuthIndex) -> bool { let current_validators = >::validators(); if authority_index >= current_validators.len() as u32 { @@ -309,10 +314,10 @@ impl Module { let authority = ¤t_validators[authority_index as usize]; - Self::is_online_in_current_session_aux(authority_index, authority) + Self::is_online_aux(authority_index, authority) } - fn is_online_in_current_session_aux(authority_index: AuthIndex, authority: &T::ValidatorId) -> bool { + fn is_online_aux(authority_index: AuthIndex, authority: &T::ValidatorId) -> bool { let current_session = >::current_index(); ::exists(¤t_session, &authority_index) || @@ -507,27 +512,16 @@ impl session::OneSessionHandler for Module { } fn on_before_session_ending() { - let mut unresponsive = vec![]; - - let current_session = >::current_index(); - + let session_index = >::current_index(); let keys = Keys::::get(); let current_validators = >::validators(); - for (auth_idx, validator_id) in current_validators.into_iter().enumerate() { - if !Self::is_online_in_current_session_aux(auth_idx as u32, &validator_id) { - let full_identification = T::FullIdentificationOf::convert(validator_id.clone()) - .expect( - "we got the validator_id from current_validators; - current_validators is set of currently acting validators; - the mapping between the validator id and its full identification should be valid; - thus `FullIdentificationOf::convert` can't return `None`; - qed", - ); - - unresponsive.push((validator_id, full_identification)); - } - } + let offenders = current_validators.into_iter().enumerate() + .filter(|(index, id)| + !Self::is_online_aux(*index as u32, id) + ).filter_map(|(_, id)| + T::FullIdentificationOf::convert(id.clone()).map(|full_id| (id, full_id)) + ).collect::>>(); // Remove all received heartbeats and number of authored blocks from the // current session, they have already been processed and won't be needed @@ -535,18 +529,15 @@ impl session::OneSessionHandler for Module { ::remove_prefix(&>::current_index()); >::remove_prefix(&>::current_index()); - if unresponsive.is_empty() { - return; - } - - let validator_set_count = keys.len() as u32; - let offence = UnresponsivenessOffence { - session_index: current_session, - validator_set_count, - offenders: unresponsive, - }; + if offenders.is_empty() { + Self::deposit_event(RawEvent::AllGood); + } else { + Self::deposit_event(RawEvent::SomeOffline(offenders.clone())); - T::ReportUnresponsiveness::report_offence(vec![], offence); + let validator_set_count = keys.len() as u32; + let offence = UnresponsivenessOffence { session_index, validator_set_count, offenders }; + T::ReportUnresponsiveness::report_offence(vec![], offence); + } } fn on_disabled(_i: usize) { @@ -559,7 +550,7 @@ impl support::unsigned::ValidateUnsigned for Module { fn validate_unsigned(call: &Self::Call) -> TransactionValidity { if let Call::heartbeat(heartbeat, signature) = call { - if >::is_online_in_current_session(heartbeat.authority_index) { + if >::is_online(heartbeat.authority_index) { // we already received a heartbeat for this authority return InvalidTransaction::Stale.into(); } diff --git a/srml/im-online/src/tests.rs b/srml/im-online/src/tests.rs index 42c1aa0227..57f2e4008b 100644 --- a/srml/im-online/src/tests.rs +++ b/srml/im-online/src/tests.rs @@ -134,25 +134,25 @@ fn should_mark_online_validator_when_heartbeat_is_received() { assert_eq!(Session::current_index(), 2); assert_eq!(Session::validators(), vec![1, 2, 3]); - assert!(!ImOnline::is_online_in_current_session(0)); - assert!(!ImOnline::is_online_in_current_session(1)); - assert!(!ImOnline::is_online_in_current_session(2)); + assert!(!ImOnline::is_online(0)); + assert!(!ImOnline::is_online(1)); + assert!(!ImOnline::is_online(2)); // when let _ = heartbeat(1, 2, 0, 1.into()).unwrap(); // then - assert!(ImOnline::is_online_in_current_session(0)); - assert!(!ImOnline::is_online_in_current_session(1)); - assert!(!ImOnline::is_online_in_current_session(2)); + assert!(ImOnline::is_online(0)); + assert!(!ImOnline::is_online(1)); + assert!(!ImOnline::is_online(2)); // and when let _ = heartbeat(1, 2, 2, 3.into()).unwrap(); // then - assert!(ImOnline::is_online_in_current_session(0)); - assert!(!ImOnline::is_online_in_current_session(1)); - assert!(ImOnline::is_online_in_current_session(2)); + assert!(ImOnline::is_online(0)); + assert!(!ImOnline::is_online(1)); + assert!(ImOnline::is_online(2)); }); } @@ -233,14 +233,14 @@ fn should_cleanup_received_heartbeats_on_session_end() { let _ = heartbeat(1, 2, 0, 1.into()).unwrap(); // the heartbeat is stored - assert!(!ImOnline::received_heartbeats(&2, &0).is_empty()); + assert!(!ImOnline::received_heartbeats(&2, &0).is_none()); advance_session(); // after the session has ended we have already processed the heartbeat // message, so any messages received on the previous session should have // been pruned. - assert!(ImOnline::received_heartbeats(&2, &0).is_empty()); + assert!(ImOnline::received_heartbeats(&2, &0).is_none()); }); } @@ -260,7 +260,7 @@ fn should_mark_online_validator_when_block_is_authored() { assert_eq!(Session::validators(), vec![1, 2, 3]); for i in 0..3 { - assert!(!ImOnline::is_online_in_current_session(i)); + assert!(!ImOnline::is_online(i)); } // when @@ -268,8 +268,8 @@ fn should_mark_online_validator_when_block_is_authored() { ImOnline::note_uncle(2, 0); // then - assert!(ImOnline::is_online_in_current_session(0)); - assert!(ImOnline::is_online_in_current_session(1)); - assert!(!ImOnline::is_online_in_current_session(2)); + assert!(ImOnline::is_online(0)); + assert!(ImOnline::is_online(1)); + assert!(!ImOnline::is_online(2)); }); } -- GitLab From f237d8c9dc130d1a1b845b70ebd6516141b79e18 Mon Sep 17 00:00:00 2001 From: Weiliang Li Date: Fri, 1 Nov 2019 20:55:29 +0900 Subject: [PATCH 159/167] authority-discovery: futures 03 Future (#3848) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * authority-discovery: futures 03 Future * make ci happy * use futures timer instead of tokio timer * Update core/authority-discovery/src/lib.rs Co-Authored-By: Bastian Köcher * remove tokio 01 runtime * trigger build * kill futures01 * rename futures --- Cargo.lock | 5 +- core/authority-discovery/Cargo.toml | 5 +- core/authority-discovery/src/error.rs | 2 - core/authority-discovery/src/lib.rs | 117 ++++++++++++-------------- 4 files changed, 57 insertions(+), 72 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 342340d801..0180f3fe6a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4827,7 +4827,8 @@ version = "2.0.0" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "derive_more 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-timer 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libp2p 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4842,8 +4843,6 @@ dependencies = [ "substrate-peerset 2.0.0", "substrate-primitives 2.0.0", "substrate-test-runtime-client 2.0.0", - "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/core/authority-discovery/Cargo.toml b/core/authority-discovery/Cargo.toml index 7283e07f89..c4cab438f4 100644 --- a/core/authority-discovery/Cargo.toml +++ b/core/authority-discovery/Cargo.toml @@ -14,7 +14,7 @@ bytes = "0.4.12" client = { package = "substrate-client", path = "../../core/client" } codec = { package = "parity-scale-codec", default-features = false, version = "1.0.3" } derive_more = "0.15.0" -futures = "0.1.29" +futures-preview = "0.3.0-alpha.19" libp2p = { version = "0.12.0", default-features = false, features = ["secp256k1", "libp2p-websocket"] } log = "0.4.8" network = { package = "substrate-network", path = "../../core/network" } @@ -22,10 +22,9 @@ primitives = { package = "substrate-primitives", path = "../primitives" } prost = "0.5.0" serde_json = "1.0.41" sr-primitives = { path = "../../core/sr-primitives" } -tokio-timer = "0.2.11" +futures-timer = "0.4" [dev-dependencies] parking_lot = "0.9.0" peerset = { package = "substrate-peerset", path = "../../core/peerset" } test-client = { package = "substrate-test-runtime-client", path = "../../core/test-runtime/client" } -tokio = "0.1.22" diff --git a/core/authority-discovery/src/error.rs b/core/authority-discovery/src/error.rs index e8c1ad9705..dca50cc0be 100644 --- a/core/authority-discovery/src/error.rs +++ b/core/authority-discovery/src/error.rs @@ -42,6 +42,4 @@ pub enum Error { Decoding(prost::DecodeError), /// Failed to parse a libp2p multi address. ParsingMultiaddress(libp2p::core::multiaddr::Error), - /// Tokio timer error. - PollingTokioTimer(tokio_timer::Error) } diff --git a/core/authority-discovery/src/lib.rs b/core/authority-discovery/src/lib.rs index 8e2663d210..ce6445d08f 100644 --- a/core/authority-discovery/src/lib.rs +++ b/core/authority-discovery/src/lib.rs @@ -42,23 +42,29 @@ //! 3. Validates the signatures of the retrieved key value pairs. //! //! 4. Adds the retrieved external addresses as priority nodes to the peerset. +use std::collections::{HashMap, HashSet}; +use std::convert::TryInto; +use std::iter::FromIterator; +use std::marker::PhantomData; +use std::pin::Pin; +use std::sync::Arc; +use std::time::Duration; + +use futures::channel::mpsc::Receiver; +use futures::stream::StreamExt; +use futures::task::{Context, Poll}; +use futures::Future; +use futures_timer::Interval; use authority_discovery_primitives::{AuthorityDiscoveryApi, AuthorityId, Signature}; use client::{blockchain::HeaderBackend, runtime_api::StorageProof}; use error::{Error, Result}; -use futures::{prelude::*, sync::mpsc::Receiver}; use log::{debug, error, log_enabled, warn}; use network::specialization::NetworkSpecialization; use network::{DhtEvent, ExHashT}; use prost::Message; use sr_primitives::generic::BlockId; use sr_primitives::traits::{Block as BlockT, ProvideRuntimeApi}; -use std::collections::{HashMap, HashSet}; -use std::convert::TryInto; -use std::iter::FromIterator; -use std::marker::PhantomData; -use std::sync::Arc; -use std::time::{Duration, Instant}; mod error; /// Dht payload schemas generated from Protobuf definitions via Prost crate in build.rs. @@ -81,9 +87,9 @@ where dht_event_rx: Receiver, /// Interval to be proactive, publishing own addresses. - publish_interval: tokio_timer::Interval, + publish_interval: Interval, /// Interval on which to query for addresses of other authorities. - query_interval: tokio_timer::Interval, + query_interval: Interval, /// The network peerset interface for priority groups lets us only set an entire group, but we retrieve the /// addresses of other authorities one by one from the network. To use the peerset interface we need to cache the @@ -96,27 +102,26 @@ where impl AuthorityDiscovery where - Block: BlockT + 'static, + Block: BlockT + Unpin + 'static, Network: NetworkProvider, Client: ProvideRuntimeApi + Send + Sync + 'static + HeaderBackend, ::Api: AuthorityDiscoveryApi, + Self: Future, { /// Return a new authority discovery. pub fn new( client: Arc, network: Arc, - dht_event_rx: futures::sync::mpsc::Receiver, - ) -> AuthorityDiscovery { + dht_event_rx: Receiver, + ) -> Self { // Kademlia's default time-to-live for Dht records is 36h, republishing records every 24h. Given that a node // could restart at any point in time, one can not depend on the republishing process, thus publishing own // external addresses should happen on an interval < 36h. - let publish_interval = - tokio_timer::Interval::new(Instant::now(), Duration::from_secs(12 * 60 * 60)); + let publish_interval = Interval::new(Duration::from_secs(12 * 60 * 60)); // External addresses of other authorities can change at any given point in time. The interval on which to query // for external addresses of other authorities is a trade off between efficiency and performance. - let query_interval = - tokio_timer::Interval::new(Instant::now(), Duration::from_secs(10 * 60)); + let query_interval = Interval::new(Duration::from_secs(10 * 60)); let address_cache = HashMap::new(); @@ -191,8 +196,8 @@ where Ok(()) } - fn handle_dht_events(&mut self) -> Result<()> { - while let Ok(Async::Ready(Some(event))) = self.dht_event_rx.poll() { + fn handle_dht_events(&mut self, cx: &mut Context) -> Result<()> { + while let Poll::Ready(Some(event)) = self.dht_event_rx.poll_next_unpin(cx) { match event { DhtEvent::ValueFound(v) => { if log_enabled!(log::Level::Debug) { @@ -202,15 +207,17 @@ where self.handle_dht_value_found_event(v)?; } - DhtEvent::ValueNotFound(hash) => { - warn!(target: "sub-authority-discovery", "Value for hash '{:?}' not found on Dht.", hash) - } - DhtEvent::ValuePut(hash) => { - debug!(target: "sub-authority-discovery", "Successfully put hash '{:?}' on Dht.", hash) - } - DhtEvent::ValuePutFailed(hash) => { - warn!(target: "sub-authority-discovery", "Failed to put hash '{:?}' on Dht.", hash) - } + DhtEvent::ValueNotFound(hash) => warn!( + target: "sub-authority-discovery", + "Value for hash '{:?}' not found on Dht.", hash + ), + DhtEvent::ValuePut(hash) => debug!( + target: "sub-authority-discovery", + "Successfully put hash '{:?}' on Dht.", hash), + DhtEvent::ValuePutFailed(hash) => warn!( + target: "sub-authority-discovery", + "Failed to put hash '{:?}' on Dht.", hash + ), } } @@ -291,53 +298,36 @@ where } } -impl futures::Future for AuthorityDiscovery +impl Future for AuthorityDiscovery where - Block: BlockT + 'static, + Block: BlockT + Unpin + 'static, Network: NetworkProvider, Client: ProvideRuntimeApi + Send + Sync + 'static + HeaderBackend, ::Api: AuthorityDiscoveryApi, { - type Item = (); - type Error = (); + type Output = (); - fn poll(&mut self) -> futures::Poll { + fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll { let mut inner = || -> Result<()> { // Process incoming events before triggering new ones. - self.handle_dht_events()?; + self.handle_dht_events(cx)?; - if let Async::Ready(_) = self - .publish_interval - .poll() - .map_err(Error::PollingTokioTimer)? - { + if let Poll::Ready(_) = self.publish_interval.poll_next_unpin(cx) { // Make sure to call interval.poll until it returns Async::NotReady once. Otherwise, in case one of the // function calls within this block do a `return`, we don't call `interval.poll` again and thereby the // underlying Tokio task is never registered with Tokio's Reactor to be woken up on the next interval // tick. - while let Async::Ready(_) = self - .publish_interval - .poll() - .map_err(Error::PollingTokioTimer)? - {} + while let Poll::Ready(_) = self.publish_interval.poll_next_unpin(cx) {} self.publish_own_ext_addresses()?; } - if let Async::Ready(_) = self - .query_interval - .poll() - .map_err(Error::PollingTokioTimer)? - { + if let Poll::Ready(_) = self.query_interval.poll_next_unpin(cx) { // Make sure to call interval.poll until it returns Async::NotReady once. Otherwise, in case one of the // function calls within this block do a `return`, we don't call `interval.poll` again and thereby the // underlying Tokio task is never registered with Tokio's Reactor to be woken up on the next interval // tick. - while let Async::Ready(_) = self - .query_interval - .poll() - .map_err(Error::PollingTokioTimer)? - {} + while let Poll::Ready(_) = self.query_interval.poll_next_unpin(cx) {} self.request_addresses_of_others()?; } @@ -351,7 +341,7 @@ where }; // Make sure to always return NotReady as this is a long running task with the same lifetime as the node itself. - Ok(futures::Async::NotReady) + Poll::Pending } } @@ -415,13 +405,14 @@ fn hash_authority_id(id: &[u8]) -> Result { mod tests { use super::*; use client::runtime_api::{ApiExt, Core, RuntimeVersion}; + use futures::channel::mpsc::channel; + use futures::executor::block_on; use futures::future::poll_fn; use primitives::{ExecutionContext, NativeOrEncoded}; use sr_primitives::traits::Zero; use sr_primitives::traits::{ApiRef, Block as BlockT, NumberFor, ProvideRuntimeApi}; use std::sync::{Arc, Mutex}; use test_client::runtime::Block; - use tokio::runtime::current_thread; #[derive(Clone)] struct TestApi {} @@ -611,7 +602,7 @@ mod tests { #[test] fn publish_own_ext_addresses_puts_record_on_dht() { - let (_dht_event_tx, dht_event_rx) = futures::sync::mpsc::channel(1000); + let (_dht_event_tx, dht_event_rx) = channel(1000); let test_api = Arc::new(TestApi {}); let network: Arc = Arc::new(Default::default()); @@ -626,7 +617,7 @@ mod tests { #[test] fn request_addresses_of_others_triggers_dht_get_query() { - let (_dht_event_tx, dht_event_rx) = futures::sync::mpsc::channel(1000); + let (_dht_event_tx, dht_event_rx) = channel(1000); let test_api = Arc::new(TestApi {}); let network: Arc = Arc::new(Default::default()); @@ -643,7 +634,7 @@ mod tests { fn handle_dht_events_with_value_found_should_call_set_priority_group() { // Create authority discovery. - let (mut dht_event_tx, dht_event_rx) = futures::sync::mpsc::channel(1000); + let (mut dht_event_tx, dht_event_rx) = channel(1000); let test_api = Arc::new(TestApi {}); let network: Arc = Arc::new(Default::default()); @@ -674,9 +665,8 @@ mod tests { dht_event_tx.try_send(dht_event).unwrap(); // Make authority discovery handle the event. - - let f = || { - authority_discovery.handle_dht_events().unwrap(); + let f = |cx: &mut Context<'_>| -> Poll<()> { + authority_discovery.handle_dht_events(cx).unwrap(); // Expect authority discovery to set the priority set. assert_eq!(network.set_priority_group_call.lock().unwrap().len(), 1); @@ -689,10 +679,9 @@ mod tests { ) ); - Ok(Async::Ready(())) + Poll::Ready(()) }; - let mut runtime = current_thread::Runtime::new().unwrap(); - runtime.block_on(poll_fn::<(), (), _>(f)).unwrap(); + let _ = block_on(poll_fn(f)); } } -- GitLab From c297536350046048b736834409452530c88a3e99 Mon Sep 17 00:00:00 2001 From: Jim Posen Date: Fri, 1 Nov 2019 13:32:14 +0100 Subject: [PATCH 160/167] Integrate Wasmtime for runtime execution (#3869) * executor: Use non wasmi-specific execution in tests. * executor: Move all runtime execution tests into tests file. * executor: Use test_case macro to easily execute tests with different Wasm execution methods. * executor: Convert errors to strings with Display, not Debug. * node-executor: Rewrite benchmarks with criterion. They were not passing compilation before and criterion seems to be more widely used in Substrate. * executor: Begin implementation of Wasm runtime. The implementation demonstrates the outline of the execution, but does not link against the external host functions. * executor: Define and implement basic FunctionExecutor. The SandboxCapabilities::invoke is still left unimplemented. * executor: Implement host function trampoline generation. * executor: Instantiate and link runtime module to env module. * executor: Provide input data during wasmtime execution. * executor: Implement SandboxCapabilites::invoke for wasmtime executor. * executor: Integrate and test wasmtime execution method. * executor: Improve FunctionExecution error messages. * Scope the unsafe blocks to be smaller. * Rename TrampolineState to EnvState. * Let EnvState own its own compiler instead of unsafe lifetime cast. * Refactor out some common wasmi/wasmtime logic. * Typos and cosmetic changes. * More trampoline comments. * Cargo.lock update. * cli: CLI option for running Substrate with compiled Wasm execution. * executor: Switch dependency from fork to official wasmtime repo. * Quiet down cranelift logs. * Explicitly catch panics during host calls. We do this to ensure that panics do not cross language boundaries. * Additional checks and clarifications in make_trampoline. * Fixes after merge from master and panic safety for wasmtime instantiation. --- Cargo.lock | 466 ++++++++++++++++++ Cargo.toml | 1 + core/cli/Cargo.toml | 5 + core/cli/src/lib.rs | 1 + core/cli/src/params.rs | 21 +- core/executor/Cargo.toml | 20 + core/executor/src/error.rs | 23 +- core/executor/src/integration_tests/mod.rs | 441 +++++++++++++++++ .../executor/src/integration_tests/sandbox.rs | 363 ++++++++++++++ core/executor/src/lib.rs | 4 + core/executor/src/sandbox.rs | 291 ----------- core/executor/src/wasm_runtime.rs | 9 + core/executor/src/wasm_utils.rs | 13 + core/executor/src/wasmi_execution.rs | 355 +------------ .../src/wasmtime/function_executor.rs | 387 +++++++++++++++ core/executor/src/wasmtime/mod.rs | 24 + core/executor/src/wasmtime/runtime.rs | 398 +++++++++++++++ core/executor/src/wasmtime/trampoline.rs | 329 +++++++++++++ core/executor/src/wasmtime/util.rs | 113 +++++ core/service/Cargo.toml | 3 + core/wasm-interface/src/lib.rs | 14 +- node/cli/Cargo.toml | 6 + node/executor/Cargo.toml | 10 +- node/executor/benches/bench.rs | 196 ++++++++ node/executor/src/lib.rs | 21 - 25 files changed, 2862 insertions(+), 652 deletions(-) create mode 100644 core/executor/src/integration_tests/mod.rs create mode 100644 core/executor/src/integration_tests/sandbox.rs create mode 100644 core/executor/src/wasmtime/function_executor.rs create mode 100644 core/executor/src/wasmtime/mod.rs create mode 100644 core/executor/src/wasmtime/runtime.rs create mode 100644 core/executor/src/wasmtime/trampoline.rs create mode 100644 core/executor/src/wasmtime/util.rs create mode 100644 node/executor/benches/bench.rs diff --git a/Cargo.lock b/Cargo.lock index 0180f3fe6a..e002312288 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -188,6 +188,16 @@ dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "bincode" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "bindgen" version = "0.47.3" @@ -244,6 +254,16 @@ dependencies = [ "constant_time_eq 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "blake2b_simd" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "constant_time_eq 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "block-buffer" version = "0.2.0" @@ -523,6 +543,89 @@ name = "core-foundation-sys" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "cranelift-bforest" +version = "0.46.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cranelift-entity 0.46.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cranelift-codegen" +version = "0.46.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cranelift-bforest 0.46.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cranelift-codegen-meta 0.46.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cranelift-codegen-shared 0.46.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cranelift-entity 0.46.1 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "target-lexicon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cranelift-codegen-meta" +version = "0.46.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cranelift-codegen-shared 0.46.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cranelift-entity 0.46.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cranelift-codegen-shared" +version = "0.46.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cranelift-entity" +version = "0.46.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cranelift-frontend" +version = "0.46.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cranelift-codegen 0.46.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "target-lexicon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cranelift-native" +version = "0.46.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cranelift-codegen 0.46.1 (registry+https://github.com/rust-lang/crates.io-index)", + "raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "target-lexicon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cranelift-wasm" +version = "0.46.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cranelift-codegen 0.46.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cranelift-entity 0.46.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cranelift-frontend 0.46.1 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmparser 0.39.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "crc32fast" version = "1.2.0" @@ -777,6 +880,26 @@ dependencies = [ "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "directories" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "dirs-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "dirs-sys" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_users 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "dns-parser" version = "0.8.0" @@ -865,6 +988,25 @@ dependencies = [ "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "errno" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "errno-dragonfly 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "error-chain" version = "0.12.1" @@ -883,6 +1025,20 @@ dependencies = [ "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "faerie" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)", + "indexmap 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "scroll 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", + "string-interner 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "target-lexicon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "failure" version = "0.1.6" @@ -908,6 +1064,11 @@ name = "fake-simd" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "fallible-iterator" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "fdlimit" version = "0.1.1" @@ -916,6 +1077,15 @@ dependencies = [ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "file-per-thread-logger" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "finality-grandpa" version = "0.9.0" @@ -1174,6 +1344,18 @@ dependencies = [ "wasm-bindgen 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "gimli" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "fallible-iterator 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "indexmap 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "glob" version = "0.2.11" @@ -1196,6 +1378,16 @@ dependencies = [ "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "goblin" +version = "0.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "scroll 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "h2" version = "0.1.26" @@ -2205,6 +2397,14 @@ dependencies = [ "linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "mach" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "malloc_size_of_derive" version = "0.1.0" @@ -2462,6 +2662,7 @@ dependencies = [ name = "node-executor" version = "2.0.0" dependencies = [ + "criterion 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "node-primitives 2.0.0", "node-runtime 2.0.0", "node-testing 2.0.0", @@ -3052,6 +3253,11 @@ name = "pkg-config" version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "plain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "ppv-lite86" version = "0.2.5" @@ -3426,6 +3632,16 @@ dependencies = [ "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "raw-cpuid" +version = "6.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rayon" version = "1.2.0" @@ -3461,6 +3677,17 @@ name = "redox_syscall" version = "0.1.56" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "redox_users" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", + "rust-argon2 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ref_thread_local" version = "0.0.0" @@ -3490,6 +3717,17 @@ name = "regex-syntax" version = "0.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "region" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "mach 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "remove_dir_all" version = "0.5.2" @@ -3540,6 +3778,16 @@ dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rust-argon2" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "blake2b_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rustc-demangle" version = "0.1.16" @@ -3652,6 +3900,25 @@ name = "scopeguard" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "scroll" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "scroll_derive 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "scroll_derive" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "sct" version = "0.5.0" @@ -4745,6 +5012,14 @@ dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "string-interner" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "strsim" version = "0.8.0" @@ -5224,6 +5499,11 @@ name = "substrate-executor" version = "2.0.0" dependencies = [ "assert_matches 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cranelift-codegen 0.46.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cranelift-entity 0.46.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cranelift-frontend 0.46.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cranelift-native 0.46.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cranelift-wasm 0.46.1 (registry+https://github.com/rust-lang/crates.io-index)", "derive_more 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "hex-literal 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -5244,9 +5524,13 @@ dependencies = [ "substrate-state-machine 2.0.0", "substrate-trie 2.0.0", "substrate-wasm-interface 2.0.0", + "test-case 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "tiny-keccak 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", "wasmi 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmtime-environ 0.2.0 (git+https://github.com/CraneStation/wasmtime.git?rev=71dd73d6)", + "wasmtime-jit 0.2.0 (git+https://github.com/CraneStation/wasmtime.git?rev=71dd73d6)", + "wasmtime-runtime 0.2.0 (git+https://github.com/CraneStation/wasmtime.git?rev=71dd73d6)", ] [[package]] @@ -5958,6 +6242,16 @@ name = "take_mut" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "target-lexicon" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "target_info" version = "0.1.0" @@ -5993,6 +6287,18 @@ dependencies = [ "wincolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "test-case" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "textwrap" version = "0.11.0" @@ -6509,6 +6815,11 @@ name = "version_check" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "version_check" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "void" version = "1.0.2" @@ -6680,6 +6991,95 @@ dependencies = [ "parity-wasm 0.40.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "wasmparser" +version = "0.39.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "wasmtime-debug" +version = "0.2.0" +source = "git+https://github.com/CraneStation/wasmtime.git?rev=71dd73d6#71dd73d672deb325664e3c9cd4ee7acebed5fb95" +dependencies = [ + "cranelift-codegen 0.46.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cranelift-entity 0.46.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cranelift-wasm 0.46.1 (registry+https://github.com/rust-lang/crates.io-index)", + "faerie 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "gimli 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)", + "target-lexicon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmparser 0.39.2 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmtime-environ 0.2.0 (git+https://github.com/CraneStation/wasmtime.git?rev=71dd73d6)", +] + +[[package]] +name = "wasmtime-environ" +version = "0.2.0" +source = "git+https://github.com/CraneStation/wasmtime.git?rev=71dd73d6#71dd73d672deb325664e3c9cd4ee7acebed5fb95" +dependencies = [ + "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bincode 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cranelift-codegen 0.46.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cranelift-entity 0.46.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cranelift-wasm 0.46.1 (registry+https://github.com/rust-lang/crates.io-index)", + "directories 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "errno 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "file-per-thread-logger 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "indexmap 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "zstd 0.4.28+zstd.1.4.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "wasmtime-jit" +version = "0.2.0" +source = "git+https://github.com/CraneStation/wasmtime.git?rev=71dd73d6#71dd73d672deb325664e3c9cd4ee7acebed5fb95" +dependencies = [ + "cranelift-codegen 0.46.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cranelift-entity 0.46.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cranelift-frontend 0.46.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cranelift-wasm 0.46.1 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "region 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "target-lexicon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmparser 0.39.2 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmtime-debug 0.2.0 (git+https://github.com/CraneStation/wasmtime.git?rev=71dd73d6)", + "wasmtime-environ 0.2.0 (git+https://github.com/CraneStation/wasmtime.git?rev=71dd73d6)", + "wasmtime-runtime 0.2.0 (git+https://github.com/CraneStation/wasmtime.git?rev=71dd73d6)", +] + +[[package]] +name = "wasmtime-runtime" +version = "0.2.0" +source = "git+https://github.com/CraneStation/wasmtime.git?rev=71dd73d6#71dd73d672deb325664e3c9cd4ee7acebed5fb95" +dependencies = [ + "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", + "cranelift-codegen 0.46.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cranelift-entity 0.46.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cranelift-wasm 0.46.1 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "indexmap 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "region 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmtime-environ 0.2.0 (git+https://github.com/CraneStation/wasmtime.git?rev=71dd73d6)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "web-sys" version = "0.3.28" @@ -6882,6 +7282,33 @@ dependencies = [ "synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "zstd" +version = "0.4.28+zstd.1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "zstd-safe 1.4.13+zstd.1.4.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "zstd-safe" +version = "1.4.13+zstd.1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "zstd-sys 1.4.13+zstd.1.4.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "zstd-sys" +version = "1.4.13+zstd.1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", + "glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", +] + [metadata] "checksum adler32 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5d2e7343e7fc9de883d1b0341e0b13970f764c14101234857d2ddafa1cb1cac2" "checksum aes-ctr 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d2e5b0458ea3beae0d1d8c0f3946564f8e10f90646cf78c06b4351052058d1ee" @@ -6906,12 +7333,14 @@ dependencies = [ "checksum base58 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5024ee8015f02155eee35c711107ddd9a9bf3cb689cf2a9089c97e79b6e1ae83" "checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" "checksum base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" +"checksum bincode 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8ab639324e3ee8774d296864fbc0dbbb256cf1a41c490b94cba90c082915f92" "checksum bindgen 0.47.3 (registry+https://github.com/rust-lang/crates.io-index)" = "df683a55b54b41d5ea8ebfaebb5aa7e6b84e3f3006a78f010dadc9ca88469260" "checksum bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8a606a02debe2813760609f57a64a2ffd27d9fdf5b2f133eaca0b248dd92cdd2" "checksum bitmask 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5da9b3d9f6f585199287a473f4f8dfab6566cf827d15c00c219f53c645687ead" "checksum bitvec 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9633b74910e1870f50f5af189b08487195cdb83c0e27a71d6f64d5e09dd0538b" "checksum blake2 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "94cb07b0da6a73955f8fb85d24c466778e70cda767a568229b104f0264089330" "checksum blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400" +"checksum blake2b_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)" = "5850aeee1552f495dd0250014cf64b82b7c8879a89d83b33bbdace2cc4f63182" "checksum block-buffer 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1339a1042f5d9f295737ad4d9a6ab6bf81c84a933dba110b9200cd6d1448b814" "checksum block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" "checksum block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1c924d49bd09e7c06003acda26cd9742e796e34282ec6c1189404dee0c1f4774" @@ -6946,6 +7375,14 @@ dependencies = [ "checksum constant_time_eq 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "995a44c877f9212528ccc74b21a232f66ad69001e40ede5bcee2ac9ef2657120" "checksum core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "25b9e03f145fd4f2bf705e07b900cd41fc636598fe5dc452fd0db1441c3f496d" "checksum core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b" +"checksum cranelift-bforest 0.46.1 (registry+https://github.com/rust-lang/crates.io-index)" = "18c97588946d3e5fe11f8e34ebf8cc65fd3fda50f3ffa2e80c98b2748058f00f" +"checksum cranelift-codegen 0.46.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3255935da50302bcb0f7109f2fef27f44b46f1c797dfa7db971379261023adcd" +"checksum cranelift-codegen-meta 0.46.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd57265ef5e6ff253c378b6261ed8c2e6cb1b15e91624540dbd09b1e5a40e9ca" +"checksum cranelift-codegen-shared 0.46.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c093398d21f9493ab29445191362592ef621f497e56a8efb15bdf80471978b7a" +"checksum cranelift-entity 0.46.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e915fa58d2a75e3c4b768b7e4760282889915c3fcd9ccb2ad2b3ebec99654a78" +"checksum cranelift-frontend 0.46.1 (registry+https://github.com/rust-lang/crates.io-index)" = "46963952cda267bd0177b3f036e50038cd56e7b4c5b09a455b02df727e0f2a16" +"checksum cranelift-native 0.46.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7ba8a2d69ddd4729199a321bc2f4020e1969a088b468ed6a29dc7a69350be76e" +"checksum cranelift-wasm 0.46.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5a802357a6a016bf4c1dcdc6d73a650640eb3b613cc098a1a044a6c3731ca264" "checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" "checksum criterion 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "0363053954f3e679645fc443321ca128b7b950a6fe288cf5f9335cc22ee58394" "checksum criterion 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "938703e165481c8d612ea3479ac8342e5615185db37765162e762ec3523e2fc6" @@ -6971,6 +7408,8 @@ dependencies = [ "checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" "checksum digest 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e5b29bf156f3f4b3c4f610a25ff69370616ae6e0657d416de22645483e72af0a" "checksum digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" +"checksum directories 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "551a778172a450d7fc12e629ca3b0428d00f6afa9a43da1b630d54604e97371c" +"checksum dirs-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b" "checksum dns-parser 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c4d33be9473d06f75f58220f71f7a9317aca647dc061dbd3c361b0bef505fbea" "checksum doc-comment 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "923dea538cea0aa3025e8685b20d6ee21ef99c4f77e954a30febbaac5ec73a97" "checksum ed25519-dalek 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d07e8b8a8386c3b89a7a4b329fdfa4cb545de2545e9e2ebbc3dd3929253e426" @@ -6981,12 +7420,17 @@ dependencies = [ "checksum env_logger 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "39ecdb7dd54465526f0a56d666e3b2dd5f3a218665a030b6e4ad9e70fa95d8fa" "checksum environmental 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "34f8467a0284de039e6bd0e25c14519538462ba5beb548bb1f03e645097837a8" "checksum erased-serde 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3beee4bc16478a1b26f2e80ad819a52d24745e292f521a63c16eea5f74b7eb60" +"checksum errno 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c2a071601ed01b988f896ab14b95e67335d1eeb50190932a1320f7fe3cadc84e" +"checksum errno-dragonfly 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "14ca354e36190500e1e1fb267c647932382b54053c50b14970856c0b00a35067" "checksum error-chain 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3ab49e9dcb602294bc42f9a7dfc9bc6e936fca4418ea300dbfb84fe16de0b7d9" "checksum exit-future 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d8013f441e38e31c670e7f34ec8f1d5d3a2bd9d303c1ff83976ca886005e8f48" +"checksum faerie 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "875d78b92b2a4d9e1e2c7eeccfa30a327d2ee6434db3beb8fd6fd92f41898bc4" "checksum failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f8273f13c977665c5db7eb2b99ae520952fe5ac831ae4cd09d80c4c7042b5ed9" "checksum failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0bc225b78e0391e4b8683440bf2e63c2deeeb2ce5189eab46e2b68c6d3725d08" "checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" +"checksum fallible-iterator 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" "checksum fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b1ee15a7050e5580b3712877157068ea713b245b080ff302ae2ca973cfcd9baa" +"checksum file-per-thread-logger 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8505b75b31ef7285168dd237c4a7db3c1f3e0927e7d314e670bc98e854272fe9" "checksum finality-grandpa 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9681c1f75941ea47584573dd2bc10558b2067d460612945887e00744e43393be" "checksum fixed-hash 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "516877b7b9a1cc2d0293cbce23cd6203f0edbfd4090e6ca4489fecb5aa73050e" "checksum fixed-hash 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6357b15872f8126e4ea7cf79d579473f132ccd2de239494ad1bf4aa892faea68" @@ -7016,9 +7460,11 @@ dependencies = [ "checksum get_if_addrs 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "abddb55a898d32925f3148bd281174a68eeb68bbfd9a5938a57b18f506ee4ef7" "checksum get_if_addrs-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0d04f9fb746cf36b191c00f3ede8bde9c8e64f9f4b05ae2694a9ccf5e3f5ab48" "checksum getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "473a1265acc8ff1e808cd0a1af8cee3c2ee5200916058a2ca113c29f2d903571" +"checksum gimli 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)" = "162d18ae5f2e3b90a993d202f1ba17a5633c2484426f8bcae201f86194bacd00" "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" "checksum glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" "checksum globset 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "925aa2cac82d8834e2b2a4415b6f6879757fb5c0928fc445ae76461a12eed8f2" +"checksum goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)" = "e3fa261d919c1ae9d1e4533c4a2f99e10938603c4208d56c05bec7a872b661b0" "checksum h2 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)" = "a5b34c246847f938a410a03c5458c7fee2274436675e76d8b903c08efc29c462" "checksum hash-db 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d23bd4e7b5eda0d0f3a307e8b381fdc8ba9000f26fbe912250c0a4cc3956364a" "checksum hash256-std-hasher 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)" = "92c171d55b98633f4ed3860808f004099b36c1cc29c42cfc53aa8591b21efcf2" @@ -7107,6 +7553,7 @@ dependencies = [ "checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" "checksum lru-cache 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" +"checksum mach 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "86dd2487cdfea56def77b88438a2c915fb45113c5319bfe7e14306ca4cd0b0e1" "checksum malloc_size_of_derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "35adee9ed962cf7d07d62cb58bc45029f3227f5b5b86246caa8632f06c187bc3" "checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" "checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" @@ -7170,6 +7617,7 @@ dependencies = [ "checksum petgraph 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3659d1ee90221741f65dd128d9998311b0e40c5d3c23a62445938214abce4f" "checksum pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5894c618ce612a3fa23881b152b608bafb8c56cfc22f434a3ba3120b40f7b587" "checksum pkg-config 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "72d5370d90f49f70bd033c3d75e87fc529fbfff9d6f7cccef07d6170079d91ea" +"checksum plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" "checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b" "checksum pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f81e1644e1b54f5a68959a29aa86cde704219254669da328ecfdf6a1f09d427" "checksum primitive-types 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "83ef7b3b965c0eadcb6838f34f827e1dfb2939bdd5ebd43f9647e009b12b0371" @@ -7210,19 +7658,23 @@ dependencies = [ "checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" "checksum rand_xoshiro 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "03b418169fb9c46533f326efd6eed2576699c44ca92d3052a066214a8d828929" "checksum rand_xoshiro 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0e18c91676f670f6f0312764c759405f13afb98d5d73819840cf72a518487bff" +"checksum raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "30a9d219c32c9132f7be513c18be77c9881c7107d2ab5569d205a6a0f0e6dc7d" "checksum rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "83a27732a533a1be0a0035a111fe76db89ad312f6f0347004c220c57f209a123" "checksum rayon-core 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "98dcf634205083b17d0861252431eb2acbfb698ab7478a2d20de07954f47ec7b" "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" "checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" +"checksum redox_users 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4ecedbca3bf205f8d8f5c2b44d83cd0690e39ee84b951ed649e9f1841132b66d" "checksum ref_thread_local 0.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d813022b2e00774a48eaf43caaa3c20b45f040ba8cbf398e2e8911a06668dbe6" "checksum regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc220bd33bdce8f093101afe22a037b8eb0e5af33592e6a9caafff0d4cb81cbd" "checksum regex-automata 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "92b73c2a1770c255c240eaa4ee600df1704a38dc3feaa6e949e7fcd4f8dc09f9" "checksum regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "11a7e20d1cce64ef2fed88b66d347f88bd9babb82845b2b858f3edbf59a4f716" +"checksum region 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "448e868c6e4cfddfa49b6a72c95906c04e8547465e9536575b95c70a4044f856" "checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" "checksum rhododendron 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "36542aafc2429a4c010fafa079a20dee953b663cb2427f51d86cf1d436846b4d" "checksum ring 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)" = "426bc186e3e95cac1e4a4be125a4aca7e84c2d616ffc02244eef36e2a60a093c" "checksum rocksdb 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f1651697fefd273bfb4fd69466cc2a9d20de557a0213b97233b22b5e95924b5e" "checksum rpassword 4.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f072d931f11a96546efd97642e1e75e807345aced86b947f9239102f262d0fcd" +"checksum rust-argon2 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4ca4eaef519b494d1f2848fc602d18816fed808a981aedf4f1f00ceb7c9d32cf" "checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" "checksum rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "403bb3a286107a04825a5f82e1270acc1e14028d3d554d7a1e08914549575ab8" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" @@ -7237,6 +7689,8 @@ dependencies = [ "checksum schnorrkel 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)" = "eacd8381b3c37840c9c9f40472af529e49975bdcbc24f83c31059fd6539023d3" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" "checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" +"checksum scroll 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2f84d114ef17fd144153d608fba7c446b0145d038985e7a8cc5d08bb0ce20383" +"checksum scroll_derive 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8f1aa96c45e7f5a91cb7fabe7b279f02fea7126239fc40b732316e8b6a2d0fcb" "checksum sct 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f5adf8fbd58e1b1b52699dc8bed2630faecb6d8c7bee77d009d6bbe4af569b9" "checksum security-framework 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eee63d0f4a9ec776eeb30e220f0bc1e092c3ad744b2a379e3993070364d3adc2" "checksum security-framework-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9636f8989cbf61385ae4824b98c1aaa54c994d7d8b41f11c601ed799f0549a56" @@ -7269,6 +7723,7 @@ dependencies = [ "checksum static_slice 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "92a7e0c5e3dfb52e8fbe0e63a1b947bbb17b4036408b151353c4491374931362" "checksum stream-cipher 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8131256a5896cabcf5eb04f4d6dacbe1aefda854b0d9896e09cb58829ec5638c" "checksum string 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d24114bfcceb867ca7f71a0d3fe45d45619ec47a6fbfa98cb14e14250bfa5d6d" +"checksum string-interner 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd710eadff449a1531351b0e43eb81ea404336fa2f56c777427ab0e32a4cf183" "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" "checksum structopt 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6d4f66a4c0ddf7aee4677995697366de0749b0139057342eccbb609b12d0affc" "checksum structopt-derive 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8fe0c13e476b4e21ff7f5c4ace3818b6d7bdc16897c31c73862471bc1663acae" @@ -7284,10 +7739,12 @@ dependencies = [ "checksum synstructure 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f085a5855930c0441ca1288cf044ea4aecf4f43a91668abdb870b4ba546a203" "checksum sysinfo 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d5bd3b813d94552a8033c650691645f8dd5a63d614dddd62428a95d3931ef7b6" "checksum take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" +"checksum target-lexicon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7975cb2c6f37d77b190bc5004a2bb015971464756fde9514651a525ada2a741a" "checksum target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c63f48baada5c52e65a29eef93ab4f8982681b67f9e8d29c7b05abcfec2b9ffe" "checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" "checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" "checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e" +"checksum test-case 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a605baa797821796a751f4a959e1206079b24a4b7e1ed302b7d785d81a9276c9" "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" "checksum threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e2f0c90a5f3459330ac8bc0d2f879c693bb7a2f59689c1083fc4ef83834da865" @@ -7341,6 +7798,7 @@ dependencies = [ "checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" "checksum vergen 3.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6aba5e34f93dc7051dfad05b98a18e9156f27e7b431fe1d2398cb6061c0a1dba" "checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" +"checksum version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" "checksum wabt 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3c5c5c1286c6e578416982609f47594265f9d489f9b836157d403ad605a46693" "checksum wabt-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "af5d153dc96aad7dc13ab90835b892c69867948112d95299e522d370c4e13a08" @@ -7358,6 +7816,11 @@ dependencies = [ "checksum wasm-timer 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "aa3e01d234bb71760e685cfafa5e2c96f8ad877c161a721646356651069e26ac" "checksum wasmi 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f31d26deb2d9a37e6cfed420edce3ed604eab49735ba89035e13c98f9a528313" "checksum wasmi-validation 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6bc0356e3df56e639fc7f7d8a99741915531e27ed735d911ed83d7e1339c8188" +"checksum wasmparser 0.39.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e5083b449454f7de0b15f131eee17de54b5a71dcb9adcf11df2b2f78fad0cd82" +"checksum wasmtime-debug 0.2.0 (git+https://github.com/CraneStation/wasmtime.git?rev=71dd73d6)" = "" +"checksum wasmtime-environ 0.2.0 (git+https://github.com/CraneStation/wasmtime.git?rev=71dd73d6)" = "" +"checksum wasmtime-jit 0.2.0 (git+https://github.com/CraneStation/wasmtime.git?rev=71dd73d6)" = "" +"checksum wasmtime-runtime 0.2.0 (git+https://github.com/CraneStation/wasmtime.git?rev=71dd73d6)" = "" "checksum web-sys 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)" = "c84440699cd02ca23bed6f045ffb1497bc18a3c2628bd13e2093186faaaacf6b" "checksum webpki 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4f7e1cd7900a3a6b65a3e8780c51a3e6b59c0e2c55c6dc69578c288d69f7d082" "checksum webpki-roots 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c10fa4212003ba19a564f25cd8ab572c6791f99a03cc219c13ed35ccab00de0e" @@ -7380,3 +7843,6 @@ dependencies = [ "checksum zeroize 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4090487fa66630f7b166fba2bbb525e247a5449f41c468cc1d98f8ae6ac03120" "checksum zeroize 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "45af6a010d13e4cf5b54c94ba5a2b2eba5596b9e46bf5875612d332a1f2b3f86" "checksum zeroize_derive 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "080616bd0e31f36095288bb0acdf1f78ef02c2fa15527d7e993f2a6c7591643e" +"checksum zstd 0.4.28+zstd.1.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f4e716acaad66f2daf2526f37a1321674a8814c0b37a366ebe6c97a699f85ddc" +"checksum zstd-safe 1.4.13+zstd.1.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bfe4d3b26a0790201848865663e8ffabf091e126e548bc9710ccfa95621ece48" +"checksum zstd-sys 1.4.13+zstd.1.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fadc8ebe858f056ab82dffb9d93850b841603bdf663db7cf5e3dbd7f34cc55b2" diff --git a/Cargo.toml b/Cargo.toml index 31a08f4eaf..5e1238866b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -108,3 +108,4 @@ members = [ [profile.release] # Substrate runtime requires unwinding. panic = "unwind" + diff --git a/core/cli/Cargo.toml b/core/cli/Cargo.toml index 2298bba0b7..9fb528e66c 100644 --- a/core/cli/Cargo.toml +++ b/core/cli/Cargo.toml @@ -38,3 +38,8 @@ rpassword = "4.0.1" [dev-dependencies] tempdir = "0.3.7" + +[features] +wasmtime = [ + "service/wasmtime", +] diff --git a/core/cli/src/lib.rs b/core/cli/src/lib.rs index 7b96788433..4638db8993 100644 --- a/core/cli/src/lib.rs +++ b/core/cli/src/lib.rs @@ -897,6 +897,7 @@ fn init_logger(pattern: &str) { // Disable info logging by default for some modules: builder.filter(Some("ws"), log::LevelFilter::Off); builder.filter(Some("hyper"), log::LevelFilter::Warn); + builder.filter(Some("cranelift_wasm"), log::LevelFilter::Warn); // Enable info for others. builder.filter(None, log::LevelFilter::Info); diff --git a/core/cli/src/params.rs b/core/cli/src/params.rs index 007bdabf0b..cac6cc1079 100644 --- a/core/cli/src/params.rs +++ b/core/cli/src/params.rs @@ -50,6 +50,19 @@ arg_enum! { pub enum WasmExecutionMethod { // Uses an interpreter. Interpreted, + // Uses a compiled runtime. + Compiled, + } +} + +impl WasmExecutionMethod { + /// Returns list of variants that are not disabled by feature flags. + fn enabled_variants() -> Vec<&'static str> { + Self::variants() + .iter() + .cloned() + .filter(|&name| cfg!(feature = "wasmtime") || name != "Compiled") + .collect() } } @@ -57,6 +70,12 @@ impl Into for WasmExecutionMethod { fn into(self) -> service::config::WasmExecutionMethod { match self { WasmExecutionMethod::Interpreted => service::config::WasmExecutionMethod::Interpreted, + #[cfg(feature = "wasmtime")] + WasmExecutionMethod::Compiled => service::config::WasmExecutionMethod::Compiled, + #[cfg(not(feature = "wasmtime"))] + WasmExecutionMethod::Compiled => panic!( + "Substrate must be compiled with \"wasmtime\" feature for compiled Wasm execution" + ), } } } @@ -429,7 +448,7 @@ pub struct RunCmd { #[structopt( long = "wasm-execution", value_name = "METHOD", - possible_values = &WasmExecutionMethod::variants(), + possible_values = &WasmExecutionMethod::enabled_variants(), case_insensitive = true, default_value = "Interpreted" )] diff --git a/core/executor/Cargo.toml b/core/executor/Cargo.toml index cf3ea4ff7a..c5604d50e4 100644 --- a/core/executor/Cargo.toml +++ b/core/executor/Cargo.toml @@ -23,6 +23,15 @@ log = "0.4.8" libsecp256k1 = "0.3.0" tiny-keccak = "1.5.0" +cranelift-codegen = { version = "0.46.1", optional = true } +cranelift-entity = { version = "0.46.1", optional = true } +cranelift-frontend = { version = "0.46.1", optional = true } +cranelift-native = { version = "0.46.1", optional = true } +cranelift-wasm = { version = "0.46.1", optional = true } +wasmtime-environ = { version = "0.2", optional = true, git = "https://github.com/CraneStation/wasmtime.git", rev = "71dd73d6" } +wasmtime-jit = { version = "0.2", optional = true, git = "https://github.com/CraneStation/wasmtime.git", rev = "71dd73d6" } +wasmtime-runtime = { version = "0.2", optional = true, git = "https://github.com/CraneStation/wasmtime.git", rev = "71dd73d6" } + [dev-dependencies] assert_matches = "1.3.0" wabt = "0.9.2" @@ -31,7 +40,18 @@ runtime-test = { package = "substrate-runtime-test", path = "runtime-test" } substrate-client = { path = "../client" } substrate-offchain = { path = "../offchain/" } state_machine = { package = "substrate-state-machine", path = "../state-machine" } +test-case = "0.3.3" [features] default = [] wasm-extern-trace = [] +wasmtime = [ + "cranelift-codegen", + "cranelift-entity", + "cranelift-frontend", + "cranelift-native", + "cranelift-wasm", + "wasmtime-environ", + "wasmtime-jit", + "wasmtime-runtime", +] diff --git a/core/executor/src/error.rs b/core/executor/src/error.rs index e1221bea54..83168d598e 100644 --- a/core/executor/src/error.rs +++ b/core/executor/src/error.rs @@ -18,6 +18,8 @@ use serializer; use wasmi; +#[cfg(feature = "wasmtime")] +use wasmtime_jit::{ActionError, SetupError}; /// Result type alias. pub type Result = std::result::Result; @@ -31,6 +33,9 @@ pub enum Error { Trap(wasmi::Trap), /// Wasmi loading/instantiating error Wasmi(wasmi::Error), + /// Wasmtime action error + #[cfg(feature = "wasmtime")] + Wasmtime(ActionError), /// Error in the API. Parameter is an error message. ApiError(String), /// Method is not found @@ -75,9 +80,9 @@ pub enum Error { /// Someone tried to allocate more memory than the allowed maximum per allocation. #[display(fmt="Requested allocation size is too large")] RequestedAllocationTooLarge, - /// Executing the given function failed with the given error. - #[display(fmt="Function execution failed with: {}", _0)] - FunctionExecution(String), + /// Execution of a host function failed. + #[display(fmt="Host function {} execution failed with: {}", _0, _1)] + FunctionExecution(String, String), } impl std::error::Error for Error { @@ -116,6 +121,16 @@ pub enum WasmError { InvalidModule, /// Wasm code could not be deserialized. CantDeserializeWasm, + /// The module does not export a linear memory named `memory`. + InvalidMemory, + /// The number of heap pages requested is disallowed by the module. + InvalidHeapPages, /// Instantiation error. - Instantiation(Error), + Instantiation(String), + /// The compiler does not support the host machine as a target. + #[cfg(feature = "wasmtime")] + MissingCompilerSupport(&'static str), + /// Wasmtime setup error. + #[cfg(feature = "wasmtime")] + WasmtimeSetup(SetupError), } diff --git a/core/executor/src/integration_tests/mod.rs b/core/executor/src/integration_tests/mod.rs new file mode 100644 index 0000000000..640795f8f0 --- /dev/null +++ b/core/executor/src/integration_tests/mod.rs @@ -0,0 +1,441 @@ +// Copyright 2017-2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +mod sandbox; + +use codec::{Encode, Decode}; +use hex_literal::hex; +use primitives::{ + Blake2Hasher, blake2_128, blake2_256, ed25519, sr25519, map, Pair, offchain::OffchainExt, + traits::Externalities, +}; +use runtime_test::WASM_BINARY; +use state_machine::TestExternalities as CoreTestExternalities; +use substrate_offchain::testing; +use test_case::test_case; +use trie::{TrieConfiguration, trie_types::Layout}; + +use crate::{WasmExecutionMethod, call_in_wasm}; + +pub type TestExternalities = CoreTestExternalities; + +#[test_case(WasmExecutionMethod::Interpreted)] +#[cfg_attr(feature = "wasmtime", test_case(WasmExecutionMethod::Compiled))] +fn returning_should_work(wasm_method: WasmExecutionMethod) { + let mut ext = TestExternalities::default(); + let mut ext = ext.ext(); + let test_code = WASM_BINARY; + + let output = call_in_wasm( + "test_empty_return", + &[], + wasm_method, + &mut ext, + &test_code[..], + 8, + ).unwrap(); + assert_eq!(output, vec![0u8; 0]); +} + +#[test_case(WasmExecutionMethod::Interpreted)] +#[cfg_attr(feature = "wasmtime", test_case(WasmExecutionMethod::Compiled))] +fn panicking_should_work(wasm_method: WasmExecutionMethod) { + let mut ext = TestExternalities::default(); + let mut ext = ext.ext(); + let test_code = WASM_BINARY; + + let output = call_in_wasm( + "test_panic", + &[], + wasm_method, + &mut ext, + &test_code[..], + 8, + ); + assert!(output.is_err()); + + let output = call_in_wasm( + "test_conditional_panic", + &[0], + wasm_method, + &mut ext, + &test_code[..], + 8, + ); + assert_eq!(Decode::decode(&mut &output.unwrap()[..]), Ok(Vec::::new())); + + let output = call_in_wasm( + "test_conditional_panic", + &vec![2].encode(), + wasm_method, + &mut ext, + &test_code[..], + 8, + ); + assert!(output.is_err()); +} + +#[test_case(WasmExecutionMethod::Interpreted)] +#[cfg_attr(feature = "wasmtime", test_case(WasmExecutionMethod::Compiled))] +fn storage_should_work(wasm_method: WasmExecutionMethod) { + let mut ext = TestExternalities::default(); + + { + let mut ext = ext.ext(); + ext.set_storage(b"foo".to_vec(), b"bar".to_vec()); + let test_code = WASM_BINARY; + + let output = call_in_wasm( + "test_data_in", + &b"Hello world".to_vec().encode(), + wasm_method, + &mut ext, + &test_code[..], + 8, + ).unwrap(); + + assert_eq!(output, b"all ok!".to_vec().encode()); + } + + let expected = TestExternalities::new((map![ + b"input".to_vec() => b"Hello world".to_vec(), + b"foo".to_vec() => b"bar".to_vec(), + b"baz".to_vec() => b"bar".to_vec() + ], map![])); + assert_eq!(ext, expected); +} + +#[test_case(WasmExecutionMethod::Interpreted)] +#[cfg_attr(feature = "wasmtime", test_case(WasmExecutionMethod::Compiled))] +fn clear_prefix_should_work(wasm_method: WasmExecutionMethod) { + let mut ext = TestExternalities::default(); + { + let mut ext = ext.ext(); + ext.set_storage(b"aaa".to_vec(), b"1".to_vec()); + ext.set_storage(b"aab".to_vec(), b"2".to_vec()); + ext.set_storage(b"aba".to_vec(), b"3".to_vec()); + ext.set_storage(b"abb".to_vec(), b"4".to_vec()); + ext.set_storage(b"bbb".to_vec(), b"5".to_vec()); + let test_code = WASM_BINARY; + + // This will clear all entries which prefix is "ab". + let output = call_in_wasm( + "test_clear_prefix", + &b"ab".to_vec().encode(), + wasm_method, + &mut ext, + &test_code[..], + 8, + ).unwrap(); + + assert_eq!(output, b"all ok!".to_vec().encode()); + } + + let expected = TestExternalities::new((map![ + b"aaa".to_vec() => b"1".to_vec(), + b"aab".to_vec() => b"2".to_vec(), + b"bbb".to_vec() => b"5".to_vec() + ], map![])); + assert_eq!(expected, ext); +} + +#[test_case(WasmExecutionMethod::Interpreted)] +#[cfg_attr(feature = "wasmtime", test_case(WasmExecutionMethod::Compiled))] +fn blake2_256_should_work(wasm_method: WasmExecutionMethod) { + let mut ext = TestExternalities::default(); + let mut ext = ext.ext(); + let test_code = WASM_BINARY; + assert_eq!( + call_in_wasm( + "test_blake2_256", + &[0], + wasm_method, + &mut ext, + &test_code[..], + 8, + ).unwrap(), + blake2_256(&b""[..]).to_vec().encode(), + ); + assert_eq!( + call_in_wasm( + "test_blake2_256", + &b"Hello world!".to_vec().encode(), + wasm_method, + &mut ext, + &test_code[..], + 8, + ).unwrap(), + blake2_256(&b"Hello world!"[..]).to_vec().encode(), + ); +} + +#[test_case(WasmExecutionMethod::Interpreted)] +#[cfg_attr(feature = "wasmtime", test_case(WasmExecutionMethod::Compiled))] +fn blake2_128_should_work(wasm_method: WasmExecutionMethod) { + let mut ext = TestExternalities::default(); + let mut ext = ext.ext(); + let test_code = WASM_BINARY; + assert_eq!( + call_in_wasm( + "test_blake2_128", + &[0], + wasm_method, + &mut ext, + &test_code[..], + 8, + ).unwrap(), + blake2_128(&b""[..]).to_vec().encode(), + ); + assert_eq!( + call_in_wasm( + "test_blake2_128", + &b"Hello world!".to_vec().encode(), + wasm_method, + &mut ext, + &test_code[..], + 8, + ).unwrap(), + blake2_128(&b"Hello world!"[..]).to_vec().encode(), + ); +} + +#[test_case(WasmExecutionMethod::Interpreted)] +#[cfg_attr(feature = "wasmtime", test_case(WasmExecutionMethod::Compiled))] +fn twox_256_should_work(wasm_method: WasmExecutionMethod) { + let mut ext = TestExternalities::default(); + let mut ext = ext.ext(); + let test_code = WASM_BINARY; + assert_eq!( + call_in_wasm( + "test_twox_256", + &[0], + wasm_method, + &mut ext, + &test_code[..], + 8, + ).unwrap(), + hex!( + "99e9d85137db46ef4bbea33613baafd56f963c64b1f3685a4eb4abd67ff6203a" + ).to_vec().encode(), + ); + assert_eq!( + call_in_wasm( + "test_twox_256", + &b"Hello world!".to_vec().encode(), + wasm_method, + &mut ext, + &test_code[..], + 8, + ).unwrap(), + hex!( + "b27dfd7f223f177f2a13647b533599af0c07f68bda23d96d059da2b451a35a74" + ).to_vec().encode(), + ); +} + +#[test_case(WasmExecutionMethod::Interpreted)] +#[cfg_attr(feature = "wasmtime", test_case(WasmExecutionMethod::Compiled))] +fn twox_128_should_work(wasm_method: WasmExecutionMethod) { + let mut ext = TestExternalities::default(); + let mut ext = ext.ext(); + let test_code = WASM_BINARY; + assert_eq!( + call_in_wasm( + "test_twox_128", + &[0], + wasm_method, + &mut ext, + &test_code[..], + 8, + ).unwrap(), + hex!("99e9d85137db46ef4bbea33613baafd5").to_vec().encode(), + ); + assert_eq!( + call_in_wasm( + "test_twox_128", + &b"Hello world!".to_vec().encode(), + wasm_method, + &mut ext, + &test_code[..], + 8, + ).unwrap(), + hex!("b27dfd7f223f177f2a13647b533599af").to_vec().encode(), + ); +} + +#[test_case(WasmExecutionMethod::Interpreted)] +#[cfg_attr(feature = "wasmtime", test_case(WasmExecutionMethod::Compiled))] +fn ed25519_verify_should_work(wasm_method: WasmExecutionMethod) { + let mut ext = TestExternalities::default(); + let mut ext = ext.ext(); + let test_code = WASM_BINARY; + let key = ed25519::Pair::from_seed(&blake2_256(b"test")); + let sig = key.sign(b"all ok!"); + let mut calldata = vec![]; + calldata.extend_from_slice(key.public().as_ref()); + calldata.extend_from_slice(sig.as_ref()); + + assert_eq!( + call_in_wasm( + "test_ed25519_verify", + &calldata.encode(), + wasm_method, + &mut ext, + &test_code[..], + 8, + ).unwrap(), + true.encode(), + ); + + let other_sig = key.sign(b"all is not ok!"); + let mut calldata = vec![]; + calldata.extend_from_slice(key.public().as_ref()); + calldata.extend_from_slice(other_sig.as_ref()); + + assert_eq!( + call_in_wasm( + "test_ed25519_verify", + &calldata.encode(), + wasm_method, + &mut ext, + &test_code[..], + 8, + ).unwrap(), + false.encode(), + ); +} + +#[test_case(WasmExecutionMethod::Interpreted)] +#[cfg_attr(feature = "wasmtime", test_case(WasmExecutionMethod::Compiled))] +fn sr25519_verify_should_work(wasm_method: WasmExecutionMethod) { + let mut ext = TestExternalities::default(); + let mut ext = ext.ext(); + let test_code = WASM_BINARY; + let key = sr25519::Pair::from_seed(&blake2_256(b"test")); + let sig = key.sign(b"all ok!"); + let mut calldata = vec![]; + calldata.extend_from_slice(key.public().as_ref()); + calldata.extend_from_slice(sig.as_ref()); + + assert_eq!( + call_in_wasm( + "test_sr25519_verify", + &calldata.encode(), + wasm_method, + &mut ext, + &test_code[..], + 8, + ).unwrap(), + true.encode(), + ); + + let other_sig = key.sign(b"all is not ok!"); + let mut calldata = vec![]; + calldata.extend_from_slice(key.public().as_ref()); + calldata.extend_from_slice(other_sig.as_ref()); + + assert_eq!( + call_in_wasm( + "test_sr25519_verify", + &calldata.encode(), + wasm_method, + &mut ext, + &test_code[..], + 8, + ).unwrap(), + false.encode(), + ); +} + +#[test_case(WasmExecutionMethod::Interpreted)] +#[cfg_attr(feature = "wasmtime", test_case(WasmExecutionMethod::Compiled))] +fn ordered_trie_root_should_work(wasm_method: WasmExecutionMethod) { + let mut ext = TestExternalities::default(); + let mut ext = ext.ext(); + let trie_input = vec![b"zero".to_vec(), b"one".to_vec(), b"two".to_vec()]; + let test_code = WASM_BINARY; + assert_eq!( + call_in_wasm( + "test_ordered_trie_root", + &[0], + wasm_method, + &mut ext, + &test_code[..], + 8, + ).unwrap(), + Layout::::ordered_trie_root(trie_input.iter()).as_bytes().encode(), + ); +} + +#[test_case(WasmExecutionMethod::Interpreted)] +#[cfg_attr(feature = "wasmtime", test_case(WasmExecutionMethod::Compiled))] +fn offchain_local_storage_should_work(wasm_method: WasmExecutionMethod) { + use substrate_client::backend::OffchainStorage; + + let mut ext = TestExternalities::default(); + let (offchain, state) = testing::TestOffchainExt::new(); + ext.register_extension(OffchainExt::new(offchain)); + let test_code = WASM_BINARY; + let mut ext = ext.ext(); + assert_eq!( + call_in_wasm( + "test_offchain_local_storage", + &[0], + wasm_method, + &mut ext, + &test_code[..], + 8, + ).unwrap(), + true.encode(), + ); + assert_eq!(state.read().persistent_storage.get(b"", b"test"), Some(vec![])); +} + +#[test_case(WasmExecutionMethod::Interpreted)] +#[cfg_attr(feature = "wasmtime", test_case(WasmExecutionMethod::Compiled))] +fn offchain_http_should_work(wasm_method: WasmExecutionMethod) { + let mut ext = TestExternalities::default(); + let (offchain, state) = testing::TestOffchainExt::new(); + ext.register_extension(OffchainExt::new(offchain)); + state.write().expect_request( + 0, + testing::PendingRequest { + method: "POST".into(), + uri: "http://localhost:12345".into(), + body: vec![1, 2, 3, 4], + headers: vec![("X-Auth".to_owned(), "test".to_owned())], + sent: true, + response: Some(vec![1, 2, 3]), + response_headers: vec![("X-Auth".to_owned(), "hello".to_owned())], + ..Default::default() + }, + ); + + let test_code = WASM_BINARY; + let mut ext = ext.ext(); + assert_eq!( + call_in_wasm( + "test_offchain_http", + &[0], + wasm_method, + &mut ext, + &test_code[..], + 8, + ).unwrap(), + true.encode(), + ); +} + diff --git a/core/executor/src/integration_tests/sandbox.rs b/core/executor/src/integration_tests/sandbox.rs new file mode 100644 index 0000000000..e4a1a0254d --- /dev/null +++ b/core/executor/src/integration_tests/sandbox.rs @@ -0,0 +1,363 @@ +// Copyright 2018-2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +use codec::Encode; +use runtime_test::WASM_BINARY; +use test_case::test_case; +use wabt; + +use crate::{WasmExecutionMethod, call_in_wasm}; +use crate::integration_tests::TestExternalities; + +#[test_case(WasmExecutionMethod::Interpreted)] +#[cfg_attr(feature = "wasmtime", test_case(WasmExecutionMethod::Compiled))] +fn sandbox_should_work(wasm_method: WasmExecutionMethod) { + let mut ext = TestExternalities::default(); + let mut ext = ext.ext(); + let test_code = WASM_BINARY; + + let code = wabt::wat2wasm(r#" + (module + (import "env" "assert" (func $assert (param i32))) + (import "env" "inc_counter" (func $inc_counter (param i32) (result i32))) + (func (export "call") + (drop + (call $inc_counter (i32.const 5)) + ) + + (call $inc_counter (i32.const 3)) + ;; current counter value is on the stack + + ;; check whether current == 8 + i32.const 8 + i32.eq + + call $assert + ) + ) + "#).unwrap().encode(); + + assert_eq!( + call_in_wasm( + "test_sandbox", + &code, + wasm_method, + &mut ext, + &test_code[..], + 8, + ).unwrap(), + true.encode(), + ); +} + +#[test_case(WasmExecutionMethod::Interpreted)] +#[cfg_attr(feature = "wasmtime", test_case(WasmExecutionMethod::Compiled))] +fn sandbox_trap(wasm_method: WasmExecutionMethod) { + let mut ext = TestExternalities::default(); + let mut ext = ext.ext(); + let test_code = WASM_BINARY; + + let code = wabt::wat2wasm(r#" + (module + (import "env" "assert" (func $assert (param i32))) + (func (export "call") + i32.const 0 + call $assert + ) + ) + "#).unwrap(); + + assert_eq!( + call_in_wasm( + "test_sandbox", + &code, + wasm_method, + &mut ext, + &test_code[..], + 8, + ).unwrap(), + vec![0], + ); +} + +#[test_case(WasmExecutionMethod::Interpreted)] +#[cfg_attr(feature = "wasmtime", test_case(WasmExecutionMethod::Compiled))] +fn sandbox_should_trap_when_heap_exhausted(wasm_method: WasmExecutionMethod) { + let mut ext = TestExternalities::default(); + let mut ext = ext.ext(); + let test_code = WASM_BINARY; + + let code = wabt::wat2wasm(r#" + (module + (import "env" "assert" (func $assert (param i32))) + (func (export "call") + i32.const 0 + call $assert + ) + ) + "#).unwrap().encode(); + + let res = call_in_wasm( + "test_exhaust_heap", + &code, + wasm_method, + &mut ext, + &test_code[..], + 8, + ); + assert!(res.is_err()); + if let Err(err) = res { + assert!(err.to_string().contains("Allocator ran out of space")); + } +} + +#[test_case(WasmExecutionMethod::Interpreted)] +#[cfg_attr(feature = "wasmtime", test_case(WasmExecutionMethod::Compiled))] +fn start_called(wasm_method: WasmExecutionMethod) { + let mut ext = TestExternalities::default(); + let mut ext = ext.ext(); + let test_code = WASM_BINARY; + + let code = wabt::wat2wasm(r#" + (module + (import "env" "assert" (func $assert (param i32))) + (import "env" "inc_counter" (func $inc_counter (param i32) (result i32))) + + ;; Start function + (start $start) + (func $start + ;; Increment counter by 1 + (drop + (call $inc_counter (i32.const 1)) + ) + ) + + (func (export "call") + ;; Increment counter by 1. The current value is placed on the stack. + (call $inc_counter (i32.const 1)) + + ;; Counter is incremented twice by 1, once there and once in `start` func. + ;; So check the returned value is equal to 2. + i32.const 2 + i32.eq + call $assert + ) + ) + "#).unwrap().encode(); + + assert_eq!( + call_in_wasm( + "test_sandbox", + &code, + wasm_method, + &mut ext, + &test_code[..], + 8, + ).unwrap(), + true.encode(), + ); +} + +#[test_case(WasmExecutionMethod::Interpreted)] +#[cfg_attr(feature = "wasmtime", test_case(WasmExecutionMethod::Compiled))] +fn invoke_args(wasm_method: WasmExecutionMethod) { + let mut ext = TestExternalities::default(); + let mut ext = ext.ext(); + let test_code = WASM_BINARY; + + let code = wabt::wat2wasm(r#" + (module + (import "env" "assert" (func $assert (param i32))) + + (func (export "call") (param $x i32) (param $y i64) + ;; assert that $x = 0x12345678 + (call $assert + (i32.eq + (get_local $x) + (i32.const 0x12345678) + ) + ) + + (call $assert + (i64.eq + (get_local $y) + (i64.const 0x1234567887654321) + ) + ) + ) + ) + "#).unwrap().encode(); + + assert_eq!( + call_in_wasm( + "test_sandbox_args", + &code, + wasm_method, + &mut ext, + &test_code[..], + 8, + ).unwrap(), + true.encode(), + ); +} + +#[test_case(WasmExecutionMethod::Interpreted)] +#[cfg_attr(feature = "wasmtime", test_case(WasmExecutionMethod::Compiled))] +fn return_val(wasm_method: WasmExecutionMethod) { + let mut ext = TestExternalities::default(); + let mut ext = ext.ext(); + let test_code = WASM_BINARY; + + let code = wabt::wat2wasm(r#" + (module + (func (export "call") (param $x i32) (result i32) + (i32.add + (get_local $x) + (i32.const 1) + ) + ) + ) + "#).unwrap().encode(); + + assert_eq!( + call_in_wasm( + "test_sandbox_return_val", + &code, + wasm_method, + &mut ext, + &test_code[..], + 8, + ).unwrap(), + true.encode(), + ); +} + +#[test_case(WasmExecutionMethod::Interpreted)] +#[cfg_attr(feature = "wasmtime", test_case(WasmExecutionMethod::Compiled))] +fn unlinkable_module(wasm_method: WasmExecutionMethod) { + let mut ext = TestExternalities::default(); + let mut ext = ext.ext(); + let test_code = WASM_BINARY; + + let code = wabt::wat2wasm(r#" + (module + (import "env" "non-existent" (func)) + + (func (export "call") + ) + ) + "#).unwrap().encode(); + + assert_eq!( + call_in_wasm( + "test_sandbox_instantiate", + &code, + wasm_method, + &mut ext, + &test_code[..], + 8, + ).unwrap(), + 1u8.encode(), + ); +} + +#[test_case(WasmExecutionMethod::Interpreted)] +#[cfg_attr(feature = "wasmtime", test_case(WasmExecutionMethod::Compiled))] +fn corrupted_module(wasm_method: WasmExecutionMethod) { + let mut ext = TestExternalities::default(); + let mut ext = ext.ext(); + let test_code = WASM_BINARY; + + // Corrupted wasm file + let code = vec![0u8, 0, 0, 0, 1, 0, 0, 0].encode(); + + assert_eq!( + call_in_wasm( + "test_sandbox_instantiate", + &code, + wasm_method, + &mut ext, + &test_code[..], + 8, + ).unwrap(), + 1u8.encode(), + ); +} + +#[test_case(WasmExecutionMethod::Interpreted)] +#[cfg_attr(feature = "wasmtime", test_case(WasmExecutionMethod::Compiled))] +fn start_fn_ok(wasm_method: WasmExecutionMethod) { + let mut ext = TestExternalities::default(); + let mut ext = ext.ext(); + let test_code = WASM_BINARY; + + let code = wabt::wat2wasm(r#" + (module + (func (export "call") + ) + + (func $start + ) + + (start $start) + ) + "#).unwrap().encode(); + + assert_eq!( + call_in_wasm( + "test_sandbox_instantiate", + &code, + wasm_method, + &mut ext, + &test_code[..], + 8, + ).unwrap(), + 0u8.encode(), + ); +} + +#[test_case(WasmExecutionMethod::Interpreted)] +#[cfg_attr(feature = "wasmtime", test_case(WasmExecutionMethod::Compiled))] +fn start_fn_traps(wasm_method: WasmExecutionMethod) { + let mut ext = TestExternalities::default(); + let mut ext = ext.ext(); + let test_code = WASM_BINARY; + + let code = wabt::wat2wasm(r#" + (module + (func (export "call") + ) + + (func $start + unreachable + ) + + (start $start) + ) + "#).unwrap().encode(); + + assert_eq!( + call_in_wasm( + "test_sandbox_instantiate", + &code, + wasm_method, + &mut ext, + &test_code[..], + 8, + ).unwrap(), + 2u8.encode(), + ); +} diff --git a/core/executor/src/lib.rs b/core/executor/src/lib.rs index ac98388cd7..f053718b3a 100644 --- a/core/executor/src/lib.rs +++ b/core/executor/src/lib.rs @@ -38,6 +38,10 @@ mod sandbox; mod allocator; mod host_interface; mod wasm_runtime; +#[cfg(feature = "wasmtime")] +mod wasmtime; +#[cfg(test)] +mod integration_tests; pub mod error; pub use wasmi; diff --git a/core/executor/src/sandbox.rs b/core/executor/src/sandbox.rs index e1e9e0db95..87edae8c30 100644 --- a/core/executor/src/sandbox.rs +++ b/core/executor/src/sandbox.rs @@ -582,294 +582,3 @@ impl Store { instance_idx as u32 } } - -#[cfg(test)] -mod tests { - use super::*; - use primitives::{Blake2Hasher, traits::Externalities}; - use crate::wasm_runtime::WasmRuntime; - use crate::wasmi_execution; - use state_machine::TestExternalities as CoreTestExternalities; - use wabt; - use runtime_test::WASM_BINARY; - - type TestExternalities = CoreTestExternalities; - - fn call_wasm( - ext: &mut E, - heap_pages: u64, - code: &[u8], - method: &str, - data: &[u8], - ) -> Result> { - let mut instance = wasmi_execution::create_instance(ext, code, heap_pages) - .map_err(|err| err.to_string())?; - instance.call(ext, method, data) - } - - #[test] - fn sandbox_should_work() { - let mut ext = TestExternalities::default(); - let mut ext = ext.ext(); - let test_code = WASM_BINARY; - - let code = wabt::wat2wasm(r#" - (module - (import "env" "assert" (func $assert (param i32))) - (import "env" "inc_counter" (func $inc_counter (param i32) (result i32))) - (func (export "call") - (drop - (call $inc_counter (i32.const 5)) - ) - - (call $inc_counter (i32.const 3)) - ;; current counter value is on the stack - - ;; check whether current == 8 - i32.const 8 - i32.eq - - call $assert - ) - ) - "#).unwrap().encode(); - - assert_eq!( - call_wasm(&mut ext, 8, &test_code[..], "test_sandbox", &code).unwrap(), - true.encode(), - ); - } - - #[test] - fn sandbox_trap() { - let mut ext = TestExternalities::default(); - let mut ext = ext.ext(); - let test_code = WASM_BINARY; - - let code = wabt::wat2wasm(r#" - (module - (import "env" "assert" (func $assert (param i32))) - (func (export "call") - i32.const 0 - call $assert - ) - ) - "#).unwrap(); - - assert_eq!( - call_wasm(&mut ext, 8, &test_code[..], "test_sandbox", &code).unwrap(), - vec![0], - ); - } - - #[test] - fn sandbox_should_trap_when_heap_exhausted() { - let mut ext = TestExternalities::default(); - let mut ext = ext.ext(); - let test_code = WASM_BINARY; - - let code = wabt::wat2wasm(r#" - (module - (import "env" "assert" (func $assert (param i32))) - (func (export "call") - i32.const 0 - call $assert - ) - ) - "#).unwrap().encode(); - - let res = call_wasm(&mut ext, 8, &test_code[..], "test_exhaust_heap", &code); - assert_eq!(res.is_err(), true); - if let Err(err) = res { - assert_eq!( - format!("{}", err), - format!( - "{}", - wasmi::Error::Trap(Error::FunctionExecution("AllocatorOutOfSpace".into()).into()), - ), - ); - } - } - - #[test] - fn start_called() { - let mut ext = TestExternalities::default(); - let mut ext = ext.ext(); - let test_code = WASM_BINARY; - - let code = wabt::wat2wasm(r#" - (module - (import "env" "assert" (func $assert (param i32))) - (import "env" "inc_counter" (func $inc_counter (param i32) (result i32))) - - ;; Start function - (start $start) - (func $start - ;; Increment counter by 1 - (drop - (call $inc_counter (i32.const 1)) - ) - ) - - (func (export "call") - ;; Increment counter by 1. The current value is placed on the stack. - (call $inc_counter (i32.const 1)) - - ;; Counter is incremented twice by 1, once there and once in `start` func. - ;; So check the returned value is equal to 2. - i32.const 2 - i32.eq - call $assert - ) - ) - "#).unwrap().encode(); - - assert_eq!( - call_wasm(&mut ext, 8, &test_code[..], "test_sandbox", &code).unwrap(), - true.encode(), - ); - } - - #[test] - fn invoke_args() { - let mut ext = TestExternalities::default(); - let mut ext = ext.ext(); - let test_code = WASM_BINARY; - - let code = wabt::wat2wasm(r#" - (module - (import "env" "assert" (func $assert (param i32))) - - (func (export "call") (param $x i32) (param $y i64) - ;; assert that $x = 0x12345678 - (call $assert - (i32.eq - (get_local $x) - (i32.const 0x12345678) - ) - ) - - (call $assert - (i64.eq - (get_local $y) - (i64.const 0x1234567887654321) - ) - ) - ) - ) - "#).unwrap().encode(); - - assert_eq!( - call_wasm(&mut ext, 8, &test_code[..], "test_sandbox_args", &code).unwrap(), - true.encode(), - ); - } - - #[test] - fn return_val() { - let mut ext = TestExternalities::default(); - let mut ext = ext.ext(); - let test_code = WASM_BINARY; - - let code = wabt::wat2wasm(r#" - (module - (func (export "call") (param $x i32) (result i32) - (i32.add - (get_local $x) - (i32.const 1) - ) - ) - ) - "#).unwrap().encode(); - - assert_eq!( - call_wasm(&mut ext, 8, &test_code[..], "test_sandbox_return_val", &code).unwrap(), - true.encode(), - ); - } - - #[test] - fn unlinkable_module() { - let mut ext = TestExternalities::default(); - let mut ext = ext.ext(); - let test_code = WASM_BINARY; - - let code = wabt::wat2wasm(r#" - (module - (import "env" "non-existent" (func)) - - (func (export "call") - ) - ) - "#).unwrap().encode(); - - assert_eq!( - call_wasm(&mut ext, 8, &test_code[..], "test_sandbox_instantiate", &code).unwrap(), - 1u8.encode(), - ); - } - - #[test] - fn corrupted_module() { - let mut ext = TestExternalities::default(); - let mut ext = ext.ext(); - let test_code = WASM_BINARY; - - // Corrupted wasm file - let code = vec![0u8, 0, 0, 0, 1, 0, 0, 0].encode(); - - assert_eq!( - call_wasm(&mut ext, 8, &test_code[..], "test_sandbox_instantiate", &code).unwrap(), - 1u8.encode(), - ); - } - - #[test] - fn start_fn_ok() { - let mut ext = TestExternalities::default(); - let mut ext = ext.ext(); - let test_code = WASM_BINARY; - - let code = wabt::wat2wasm(r#" - (module - (func (export "call") - ) - - (func $start - ) - - (start $start) - ) - "#).unwrap().encode(); - - assert_eq!( - call_wasm(&mut ext, 8, &test_code[..], "test_sandbox_instantiate", &code).unwrap(), - 0u8.encode(), - ); - } - - #[test] - fn start_fn_traps() { - let mut ext = TestExternalities::default(); - let mut ext = ext.ext(); - let test_code = WASM_BINARY; - - let code = wabt::wat2wasm(r#" - (module - (func (export "call") - ) - - (func $start - unreachable - ) - - (start $start) - ) - "#).unwrap().encode(); - - assert_eq!( - call_wasm(&mut ext, 8, &test_code[..], "test_sandbox_instantiate", &code).unwrap(), - 2u8.encode(), - ); - } -} diff --git a/core/executor/src/wasm_runtime.rs b/core/executor/src/wasm_runtime.rs index 29a6c51e39..447dbadde5 100644 --- a/core/executor/src/wasm_runtime.rs +++ b/core/executor/src/wasm_runtime.rs @@ -21,6 +21,8 @@ use crate::error::{Error, WasmError}; use crate::wasmi_execution; +#[cfg(feature = "wasmtime")] +use crate::wasmtime; use log::{trace, warn}; use codec::Decode; use primitives::{storage::well_known_keys, traits::Externalities, H256}; @@ -51,6 +53,9 @@ pub trait WasmRuntime { pub enum WasmExecutionMethod { /// Uses the Wasmi interpreter. Interpreted, + /// Uses the Wasmtime compiled runtime. + #[cfg(feature = "wasmtime")] + Compiled, } /// Cache for the runtimes. @@ -181,6 +186,10 @@ pub fn create_wasm_runtime_with_code( WasmExecutionMethod::Interpreted => wasmi_execution::create_instance(ext, code, heap_pages) .map(|runtime| -> Box { Box::new(runtime) }), + #[cfg(feature = "wasmtime")] + WasmExecutionMethod::Compiled => + wasmtime::create_instance(ext, code, heap_pages) + .map(|runtime| -> Box { Box::new(runtime) }), } } diff --git a/core/executor/src/wasm_utils.rs b/core/executor/src/wasm_utils.rs index b217350ac6..6c1b1ebc50 100644 --- a/core/executor/src/wasm_utils.rs +++ b/core/executor/src/wasm_utils.rs @@ -16,6 +16,8 @@ //! Utilities for defining the wasm host environment. +use wasm_interface::{Pointer, WordSize}; + /// Converts arguments into respective WASM types. #[macro_export] macro_rules! convert_args { @@ -171,3 +173,14 @@ macro_rules! impl_wasm_host_interface { } ); } + +/// Runtime API functions return an i64 which encodes a pointer in the least-significant 32 bits +/// and a length in the most-significant 32 bits. This interprets the returned value as a pointer, +/// length tuple. +pub fn interpret_runtime_api_result(retval: i64) -> (Pointer, WordSize) { + let ptr = >::new(retval as u32); + // The first cast to u64 is necessary so that the right shift does not sign-extend. + let len = ((retval as u64) >> 32) as WordSize; + (ptr, len) +} + diff --git a/core/executor/src/wasmi_execution.rs b/core/executor/src/wasmi_execution.rs index a83729b4b6..b6af30b7ee 100644 --- a/core/executor/src/wasmi_execution.rs +++ b/core/executor/src/wasmi_execution.rs @@ -27,6 +27,7 @@ use primitives::{sandbox as sandbox_primitives, traits::Externalities}; use crate::host_interface::SubstrateExternals; use crate::sandbox; use crate::allocator; +use crate::wasm_utils::interpret_runtime_api_result; use crate::wasm_runtime::WasmRuntime; use log::trace; use parity_wasm::elements::{deserialize_buffer, DataSegment, Instruction, Module as RawModule}; @@ -110,24 +111,24 @@ impl sandbox::SandboxCapabilities for FunctionExecutor { impl FunctionContext for FunctionExecutor { fn read_memory_into(&self, address: Pointer, dest: &mut [u8]) -> WResult<()> { - self.memory.get_into(address.into(), dest).map_err(|e| format!("{:?}", e)) + self.memory.get_into(address.into(), dest).map_err(|e| e.to_string()) } fn write_memory(&mut self, address: Pointer, data: &[u8]) -> WResult<()> { - self.memory.set(address.into(), data).map_err(|e| format!("{:?}", e)) + self.memory.set(address.into(), data).map_err(|e| e.to_string()) } fn allocate_memory(&mut self, size: WordSize) -> WResult> { let heap = &mut self.heap; self.memory.with_direct_access_mut(|mem| { - heap.allocate(mem, size).map_err(|e| format!("{:?}", e)) + heap.allocate(mem, size).map_err(|e| e.to_string()) }) } fn deallocate_memory(&mut self, ptr: Pointer) -> WResult<()> { let heap = &mut self.heap; self.memory.with_direct_access_mut(|mem| { - heap.deallocate(mem, ptr).map_err(|e| format!("{:?}", e)) + heap.deallocate(mem, ptr).map_err(|e| e.to_string()) }) } @@ -138,13 +139,13 @@ impl FunctionContext for FunctionExecutor { impl Sandbox for FunctionExecutor { fn memory_get( - &self, + &mut self, memory_id: MemoryId, offset: WordSize, buf_ptr: Pointer, buf_len: WordSize, ) -> WResult { - let sandboxed_memory = self.sandbox_store.memory(memory_id).map_err(|e| format!("{:?}", e))?; + let sandboxed_memory = self.sandbox_store.memory(memory_id).map_err(|e| e.to_string())?; match MemoryInstance::transfer( &sandboxed_memory, @@ -165,7 +166,7 @@ impl Sandbox for FunctionExecutor { val_ptr: Pointer, val_len: WordSize, ) -> WResult { - let sandboxed_memory = self.sandbox_store.memory(memory_id).map_err(|e| format!("{:?}", e))?; + let sandboxed_memory = self.sandbox_store.memory(memory_id).map_err(|e| e.to_string())?; match MemoryInstance::transfer( &self.memory, @@ -180,7 +181,7 @@ impl Sandbox for FunctionExecutor { } fn memory_teardown(&mut self, memory_id: MemoryId) -> WResult<()> { - self.sandbox_store.memory_teardown(memory_id).map_err(|e| format!("{:?}", e)) + self.sandbox_store.memory_teardown(memory_id).map_err(|e| e.to_string()) } fn memory_new( @@ -188,7 +189,7 @@ impl Sandbox for FunctionExecutor { initial: u32, maximum: u32, ) -> WResult { - self.sandbox_store.new_memory(initial, maximum).map_err(|e| format!("{:?}", e)) + self.sandbox_store.new_memory(initial, maximum).map_err(|e| e.to_string()) } fn invoke( @@ -209,7 +210,7 @@ impl Sandbox for FunctionExecutor { .map(Into::into) .collect::>(); - let instance = self.sandbox_store.instance(instance_id).map_err(|e| format!("{:?}", e))?; + let instance = self.sandbox_store.instance(instance_id).map_err(|e| e.to_string())?; let result = instance.invoke(export_name, &args, self, state); match result { @@ -229,7 +230,7 @@ impl Sandbox for FunctionExecutor { } fn instance_teardown(&mut self, instance_id: u32) -> WResult<()> { - self.sandbox_store.instance_teardown(instance_id).map_err(|e| format!("{:?}", e)) + self.sandbox_store.instance_teardown(instance_id).map_err(|e| e.to_string()) } fn instance_new( @@ -309,7 +310,7 @@ impl wasmi::Externals for FunctionExecutor { )?; function.execute(self, &mut args) - .map_err(Error::FunctionExecution) + .map_err(|msg| Error::FunctionExecution(function.name().to_string(), msg)) .map_err(wasmi::Trap::from) .map(|v| v.map(Into::into)) } @@ -356,10 +357,9 @@ fn call_in_wasm_module( Ok(vec![I32(offset as i32), I32(data.len() as i32)]) }, |res, memory| { - if let Some(I64(r)) = res { - let offset = r as u32; - let length = (r as u64 >> 32) as usize; - memory.get(offset, length).map_err(|_| Error::Runtime).map(Some) + if let Some(I64(retval)) = res { + let (ptr, length) = interpret_runtime_api_result(retval); + memory.get(ptr.into(), length as usize).map_err(|_| Error::Runtime).map(Some) } else { Ok(None) } @@ -614,7 +614,7 @@ pub fn create_instance(ext: &mut E, code: &[u8], heap_pages: u // Instantiate this module. let instance = instantiate_module(heap_pages as usize, &module) - .map_err(WasmError::Instantiation)?; + .map_err(|e| WasmError::Instantiation(e.to_string()))?; // Take state snapshot before executing anything. let state_snapshot = StateSnapshot::take(&instance, data_segments, heap_pages) @@ -627,11 +627,12 @@ pub fn create_instance(ext: &mut E, code: &[u8], heap_pages: u let mut ext = AssertUnwindSafe(ext); let call_instance = AssertUnwindSafe(&instance); - let version = crate::native_executor::safe_call( + let version_result = crate::native_executor::safe_call( move || call_in_wasm_module(&mut **ext, *call_instance, "Core_version", &[]) - .ok() - .and_then(|v| RuntimeVersion::decode(&mut v.as_slice()).ok()) - ).map_err(WasmError::Instantiation)?; + ).map_err(|_| WasmError::Instantiation("panic in call to get runtime version".to_string()))?; + let version = version_result + .ok() + .and_then(|v| RuntimeVersion::decode(&mut v.as_slice()).ok()); Ok(WasmiRuntime { instance, @@ -654,315 +655,3 @@ fn extract_data_segments(wasm_code: &[u8]) -> Result, WasmError .to_vec(); Ok(segments) } - -#[cfg(test)] -mod tests { - use super::*; - - use state_machine::TestExternalities as CoreTestExternalities; - use hex_literal::hex; - use primitives::{ - Blake2Hasher, blake2_128, blake2_256, ed25519, sr25519, map, Pair, offchain::OffchainExt, - }; - use runtime_test::WASM_BINARY; - use substrate_offchain::testing; - use trie::{TrieConfiguration, trie_types::Layout}; - use codec::{Encode, Decode}; - - type TestExternalities = CoreTestExternalities; - - fn call( - ext: &mut E, - heap_pages: u64, - code: &[u8], - method: &str, - data: &[u8], - ) -> Result, Error> { - let mut instance = create_instance(ext, code, heap_pages) - .map_err(|err| err.to_string())?; - instance.call(ext, method, data) - } - - #[test] - fn returning_should_work() { - let mut ext = TestExternalities::default(); - let mut ext = ext.ext(); - let test_code = WASM_BINARY; - - let output = call(&mut ext, 8, &test_code[..], "test_empty_return", &[]).unwrap(); - assert_eq!(output, vec![0u8; 0]); - } - - #[test] - fn panicking_should_work() { - let mut ext = TestExternalities::default(); - let mut ext = ext.ext(); - let test_code = WASM_BINARY; - - let output = call(&mut ext, 8, &test_code[..], "test_panic", &[]); - assert!(output.is_err()); - - let output = call(&mut ext, 8, &test_code[..], "test_conditional_panic", &[0]); - assert_eq!(Decode::decode(&mut &output.unwrap()[..]), Ok(Vec::::new())); - - let output = call(&mut ext, 8, &test_code[..], "test_conditional_panic", &vec![2].encode()); - assert!(output.is_err()); - } - - #[test] - fn storage_should_work() { - let mut ext = TestExternalities::default(); - - { - let mut ext = ext.ext(); - ext.set_storage(b"foo".to_vec(), b"bar".to_vec()); - let test_code = WASM_BINARY; - - let output = call( - &mut ext, - 8, - &test_code[..], - "test_data_in", - &b"Hello world".to_vec().encode(), - ).unwrap(); - - assert_eq!(output, b"all ok!".to_vec().encode()); - } - - let expected = TestExternalities::new((map![ - b"input".to_vec() => b"Hello world".to_vec(), - b"foo".to_vec() => b"bar".to_vec(), - b"baz".to_vec() => b"bar".to_vec() - ], map![])); - assert_eq!(ext, expected); - } - - #[test] - fn clear_prefix_should_work() { - let mut ext = TestExternalities::default(); - { - let mut ext = ext.ext(); - ext.set_storage(b"aaa".to_vec(), b"1".to_vec()); - ext.set_storage(b"aab".to_vec(), b"2".to_vec()); - ext.set_storage(b"aba".to_vec(), b"3".to_vec()); - ext.set_storage(b"abb".to_vec(), b"4".to_vec()); - ext.set_storage(b"bbb".to_vec(), b"5".to_vec()); - let test_code = WASM_BINARY; - - // This will clear all entries which prefix is "ab". - let output = call( - &mut ext, - 8, - &test_code[..], - "test_clear_prefix", - &b"ab".to_vec().encode(), - ).unwrap(); - - assert_eq!(output, b"all ok!".to_vec().encode()); - } - - let expected = TestExternalities::new((map![ - b"aaa".to_vec() => b"1".to_vec(), - b"aab".to_vec() => b"2".to_vec(), - b"bbb".to_vec() => b"5".to_vec() - ], map![])); - assert_eq!(expected, ext); - } - - #[test] - fn blake2_256_should_work() { - let mut ext = TestExternalities::default(); - let mut ext = ext.ext(); - let test_code = WASM_BINARY; - assert_eq!( - call(&mut ext, 8, &test_code[..], "test_blake2_256", &[0]).unwrap(), - blake2_256(&b""[..]).to_vec().encode(), - ); - assert_eq!( - call( - &mut ext, - 8, - &test_code[..], - "test_blake2_256", - &b"Hello world!".to_vec().encode(), - ).unwrap(), - blake2_256(&b"Hello world!"[..]).to_vec().encode(), - ); - } - - #[test] - fn blake2_128_should_work() { - let mut ext = TestExternalities::default(); - let mut ext = ext.ext(); - let test_code = WASM_BINARY; - assert_eq!( - call(&mut ext, 8, &test_code[..], "test_blake2_128", &[0]).unwrap(), - blake2_128(&b""[..]).to_vec().encode(), - ); - assert_eq!( - call( - &mut ext, - 8, - &test_code[..], - "test_blake2_128", - &b"Hello world!".to_vec().encode(), - ).unwrap(), - blake2_128(&b"Hello world!"[..]).to_vec().encode(), - ); - } - - #[test] - fn twox_256_should_work() { - let mut ext = TestExternalities::default(); - let mut ext = ext.ext(); - let test_code = WASM_BINARY; - assert_eq!( - call(&mut ext, 8, &test_code[..], "test_twox_256", &[0]).unwrap(), - hex!( - "99e9d85137db46ef4bbea33613baafd56f963c64b1f3685a4eb4abd67ff6203a" - ).to_vec().encode(), - ); - assert_eq!( - call( - &mut ext, - 8, - &test_code[..], - "test_twox_256", - &b"Hello world!".to_vec().encode(), - ).unwrap(), - hex!( - "b27dfd7f223f177f2a13647b533599af0c07f68bda23d96d059da2b451a35a74" - ).to_vec().encode(), - ); - } - - #[test] - fn twox_128_should_work() { - let mut ext = TestExternalities::default(); - let mut ext = ext.ext(); - let test_code = WASM_BINARY; - assert_eq!( - call(&mut ext, 8, &test_code[..], "test_twox_128", &[0]).unwrap(), - hex!("99e9d85137db46ef4bbea33613baafd5").to_vec().encode(), - ); - assert_eq!( - call( - &mut ext, - 8, - &test_code[..], - "test_twox_128", - &b"Hello world!".to_vec().encode(), - ).unwrap(), - hex!("b27dfd7f223f177f2a13647b533599af").to_vec().encode(), - ); - } - - #[test] - fn ed25519_verify_should_work() { - let mut ext = TestExternalities::default(); - let mut ext = ext.ext(); - let test_code = WASM_BINARY; - let key = ed25519::Pair::from_seed(&blake2_256(b"test")); - let sig = key.sign(b"all ok!"); - let mut calldata = vec![]; - calldata.extend_from_slice(key.public().as_ref()); - calldata.extend_from_slice(sig.as_ref()); - - assert_eq!( - call(&mut ext, 8, &test_code[..], "test_ed25519_verify", &calldata.encode()).unwrap(), - true.encode(), - ); - - let other_sig = key.sign(b"all is not ok!"); - let mut calldata = vec![]; - calldata.extend_from_slice(key.public().as_ref()); - calldata.extend_from_slice(other_sig.as_ref()); - - assert_eq!( - call(&mut ext, 8, &test_code[..], "test_ed25519_verify", &calldata.encode()).unwrap(), - false.encode(), - ); - } - - #[test] - fn sr25519_verify_should_work() { - let mut ext = TestExternalities::default(); - let mut ext = ext.ext(); - let test_code = WASM_BINARY; - let key = sr25519::Pair::from_seed(&blake2_256(b"test")); - let sig = key.sign(b"all ok!"); - let mut calldata = vec![]; - calldata.extend_from_slice(key.public().as_ref()); - calldata.extend_from_slice(sig.as_ref()); - - assert_eq!( - call(&mut ext, 8, &test_code[..], "test_sr25519_verify", &calldata.encode()).unwrap(), - true.encode(), - ); - - let other_sig = key.sign(b"all is not ok!"); - let mut calldata = vec![]; - calldata.extend_from_slice(key.public().as_ref()); - calldata.extend_from_slice(other_sig.as_ref()); - - assert_eq!( - call(&mut ext, 8, &test_code[..], "test_sr25519_verify", &calldata.encode()).unwrap(), - false.encode(), - ); - } - - #[test] - fn ordered_trie_root_should_work() { - let mut ext = TestExternalities::default(); - let mut ext = ext.ext(); - let trie_input = vec![b"zero".to_vec(), b"one".to_vec(), b"two".to_vec()]; - let test_code = WASM_BINARY; - assert_eq!( - call(&mut ext, 8, &test_code[..], "test_ordered_trie_root", &[0]).unwrap(), - Layout::::ordered_trie_root(trie_input.iter()).as_bytes().encode(), - ); - } - - #[test] - fn offchain_local_storage_should_work() { - use substrate_client::backend::OffchainStorage; - - let mut ext = TestExternalities::default(); - let (offchain, state) = testing::TestOffchainExt::new(); - ext.register_extension(OffchainExt::new(offchain)); - let test_code = WASM_BINARY; - let mut ext = ext.ext(); - assert_eq!( - call(&mut ext, 8, &test_code[..], "test_offchain_local_storage", &[0]).unwrap(), - true.encode(), - ); - assert_eq!(state.read().persistent_storage.get(b"", b"test"), Some(vec![])); - } - - #[test] - fn offchain_http_should_work() { - let mut ext = TestExternalities::default(); - let (offchain, state) = testing::TestOffchainExt::new(); - ext.register_extension(OffchainExt::new(offchain)); - state.write().expect_request( - 0, - testing::PendingRequest { - method: "POST".into(), - uri: "http://localhost:12345".into(), - body: vec![1, 2, 3, 4], - headers: vec![("X-Auth".to_owned(), "test".to_owned())], - sent: true, - response: Some(vec![1, 2, 3]), - response_headers: vec![("X-Auth".to_owned(), "hello".to_owned())], - ..Default::default() - }, - ); - - let test_code = WASM_BINARY; - let mut ext = ext.ext(); - assert_eq!( - call(&mut ext, 8, &test_code[..], "test_offchain_http", &[0]).unwrap(), - true.encode(), - ); - } -} diff --git a/core/executor/src/wasmtime/function_executor.rs b/core/executor/src/wasmtime/function_executor.rs new file mode 100644 index 0000000000..5dc8f42b28 --- /dev/null +++ b/core/executor/src/wasmtime/function_executor.rs @@ -0,0 +1,387 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +use crate::allocator::FreeingBumpHeapAllocator; +use crate::error::{Error, Result}; +use crate::sandbox::{self, SandboxCapabilities, SupervisorFuncIndex}; +use crate::wasmtime::util::{ + checked_range, cranelift_ir_signature, read_memory_into, write_memory_from, +}; + +use codec::{Decode, Encode}; +use cranelift_codegen::ir; +use cranelift_codegen::isa::TargetFrontendConfig; +use log::trace; +use primitives::sandbox as sandbox_primitives; +use std::{cmp, mem, ptr}; +use wasmtime_environ::translate_signature; +use wasmtime_jit::{ActionError, Compiler}; +use wasmtime_runtime::{Export, VMCallerCheckedAnyfunc, VMContext, wasmtime_call_trampoline}; +use wasm_interface::{ + FunctionContext, MemoryId, Pointer, Result as WResult, Sandbox, Signature, Value, ValueType, + WordSize, +}; + +/// Wrapper type for pointer to a Wasm table entry. +/// +/// The wrapper type is used to ensure that the function reference is valid as it must be unsafely +/// dereferenced from within the safe method `::invoke`. +#[derive(Clone, Copy)] +pub struct SupervisorFuncRef(*const VMCallerCheckedAnyfunc); + +/// The state required to construct a FunctionExecutor context. The context only lasts for one host +/// call, whereas the state is maintained for the duration of a Wasm runtime call, which may make +/// many different host calls that must share state. +/// +/// This is stored as part of the host state of the "env" Wasmtime instance. +pub struct FunctionExecutorState { + sandbox_store: sandbox::Store, + heap: FreeingBumpHeapAllocator, +} + +impl FunctionExecutorState { + /// Constructs a new `FunctionExecutorState`. + pub fn new(heap_base: u32) -> Self { + FunctionExecutorState { + sandbox_store: sandbox::Store::new(), + heap: FreeingBumpHeapAllocator::new(heap_base), + } + } + + /// Returns a mutable reference to the heap allocator. + pub fn heap(&mut self) -> &mut FreeingBumpHeapAllocator { + &mut self.heap + } +} + +/// A `FunctionExecutor` implements `FunctionContext` for making host calls from a Wasmtime +/// runtime. The `FunctionExecutor` exists only for the lifetime of the call and borrows state from +/// a longer-living `FunctionExecutorState`. +pub struct FunctionExecutor<'a> { + compiler: &'a mut Compiler, + sandbox_store: &'a mut sandbox::Store, + heap: &'a mut FreeingBumpHeapAllocator, + memory: &'a mut [u8], + table: Option<&'a [VMCallerCheckedAnyfunc]>, +} + +impl<'a> FunctionExecutor<'a> { + /// Construct a new `FunctionExecutor`. + /// + /// The vmctx MUST come from a call to a function in the "env" module. + /// The state MUST be looked up from the host state of the "env" module. + pub unsafe fn new( + vmctx: *mut VMContext, + compiler: &'a mut Compiler, + state: &'a mut FunctionExecutorState, + ) -> Result + { + let memory = match (*vmctx).lookup_global_export("memory") { + Some(Export::Memory { definition, vmctx: _, memory: _ }) => + std::slice::from_raw_parts_mut( + (*definition).base, + (*definition).current_length, + ), + _ => return Err(Error::InvalidMemoryReference), + }; + let table = match (*vmctx).lookup_global_export("__indirect_function_table") { + Some(Export::Table { definition, vmctx: _, table: _ }) => + Some(std::slice::from_raw_parts( + (*definition).base as *const VMCallerCheckedAnyfunc, + (*definition).current_elements as usize, + )), + _ => None, + }; + Ok(FunctionExecutor { + compiler, + sandbox_store: &mut state.sandbox_store, + heap: &mut state.heap, + memory, + table, + }) + } +} + +impl<'a> SandboxCapabilities for FunctionExecutor<'a> { + type SupervisorFuncRef = SupervisorFuncRef; + + fn store(&self) -> &sandbox::Store { + &self.sandbox_store + } + + fn store_mut(&mut self) -> &mut sandbox::Store { + &mut self.sandbox_store + } + + fn allocate(&mut self, len: WordSize) -> Result> { + self.heap.allocate(self.memory, len) + } + + fn deallocate(&mut self, ptr: Pointer) -> Result<()> { + self.heap.deallocate(self.memory, ptr) + } + + fn write_memory(&mut self, ptr: Pointer, data: &[u8]) -> Result<()> { + write_memory_from(self.memory, ptr, data) + } + + fn read_memory(&self, ptr: Pointer, len: WordSize) -> Result> { + let mut output = vec![0; len as usize]; + read_memory_into(self.memory, ptr, output.as_mut())?; + Ok(output) + } + + fn invoke( + &mut self, + dispatch_thunk: &Self::SupervisorFuncRef, + invoke_args_ptr: Pointer, + invoke_args_len: WordSize, + state: u32, + func_idx: SupervisorFuncIndex, + ) -> Result + { + let func_ptr = unsafe { (*dispatch_thunk.0).func_ptr }; + let vmctx = unsafe { (*dispatch_thunk.0).vmctx }; + + // The following code is based on the wasmtime_jit::Context::invoke. + let value_size = mem::size_of::(); + let (signature, mut values_vec) = generate_signature_and_args( + &[ + Value::I32(u32::from(invoke_args_ptr) as i32), + Value::I32(invoke_args_len as i32), + Value::I32(state as i32), + Value::I32(usize::from(func_idx) as i32), + ], + Some(ValueType::I64), + self.compiler.frontend_config(), + ); + + // Get the trampoline to call for this function. + let exec_code_buf = self.compiler + .get_published_trampoline(func_ptr, &signature, value_size) + .map_err(ActionError::Setup) + .map_err(Error::Wasmtime)?; + + // Call the trampoline. + if let Err(message) = unsafe { + wasmtime_call_trampoline( + vmctx, + exec_code_buf, + values_vec.as_mut_ptr() as *mut u8, + ) + } { + return Err(Error::Other(message)); + } + + // Load the return value out of `values_vec`. + Ok(unsafe { ptr::read(values_vec.as_ptr() as *const i64) }) + } +} + +impl<'a> FunctionContext for FunctionExecutor<'a> { + fn read_memory_into(&self, address: Pointer, dest: &mut [u8]) -> WResult<()> { + read_memory_into(self.memory, address, dest).map_err(|e| e.to_string()) + } + + fn write_memory(&mut self, address: Pointer, data: &[u8]) -> WResult<()> { + write_memory_from(self.memory, address, data).map_err(|e| e.to_string()) + } + + fn allocate_memory(&mut self, size: WordSize) -> WResult> { + self.heap.allocate(self.memory, size).map_err(|e| e.to_string()) + } + + fn deallocate_memory(&mut self, ptr: Pointer) -> WResult<()> { + self.heap.deallocate(self.memory, ptr).map_err(|e| e.to_string()) + } + + fn sandbox(&mut self) -> &mut dyn Sandbox { + self + } +} + +impl<'a> Sandbox for FunctionExecutor<'a> { + fn memory_get( + &mut self, + memory_id: MemoryId, + offset: WordSize, + buf_ptr: Pointer, + buf_len: WordSize, + ) -> WResult + { + let sandboxed_memory = self.sandbox_store.memory(memory_id) + .map_err(|e| e.to_string())?; + sandboxed_memory.with_direct_access(|memory| { + let len = buf_len as usize; + let src_range = match checked_range(offset as usize, len, memory.len()) { + Some(range) => range, + None => return Ok(sandbox_primitives::ERR_OUT_OF_BOUNDS), + }; + let dst_range = match checked_range(buf_ptr.into(), len, self.memory.len()) { + Some(range) => range, + None => return Ok(sandbox_primitives::ERR_OUT_OF_BOUNDS), + }; + &mut self.memory[dst_range].copy_from_slice(&memory[src_range]); + Ok(sandbox_primitives::ERR_OK) + }) + } + + fn memory_set( + &mut self, + memory_id: MemoryId, + offset: WordSize, + val_ptr: Pointer, + val_len: WordSize, + ) -> WResult + { + let sandboxed_memory = self.sandbox_store.memory(memory_id) + .map_err(|e| e.to_string())?; + sandboxed_memory.with_direct_access_mut(|memory| { + let len = val_len as usize; + let src_range = match checked_range(val_ptr.into(), len, self.memory.len()) { + Some(range) => range, + None => return Ok(sandbox_primitives::ERR_OUT_OF_BOUNDS), + }; + let dst_range = match checked_range(offset as usize, len, memory.len()) { + Some(range) => range, + None => return Ok(sandbox_primitives::ERR_OUT_OF_BOUNDS), + }; + &mut memory[dst_range].copy_from_slice(&self.memory[src_range]); + Ok(sandbox_primitives::ERR_OK) + }) + } + + fn memory_teardown(&mut self, memory_id: MemoryId) + -> WResult<()> + { + self.sandbox_store.memory_teardown(memory_id).map_err(|e| e.to_string()) + } + + fn memory_new(&mut self, initial: u32, maximum: MemoryId) -> WResult { + self.sandbox_store.new_memory(initial, maximum).map_err(|e| e.to_string()) + } + + fn invoke( + &mut self, + instance_id: u32, + export_name: &str, + args: &[u8], + return_val: Pointer, + return_val_len: u32, + state: u32, + ) -> WResult { + trace!(target: "sr-sandbox", "invoke, instance_idx={}", instance_id); + + // Deserialize arguments and convert them into wasmi types. + let args = Vec::::decode(&mut &args[..]) + .map_err(|_| "Can't decode serialized arguments for the invocation")? + .into_iter() + .map(Into::into) + .collect::>(); + + let instance = self.sandbox_store.instance(instance_id).map_err(|e| e.to_string())?; + let result = instance.invoke(export_name, &args, self, state); + + match result { + Ok(None) => Ok(sandbox_primitives::ERR_OK), + Ok(Some(val)) => { + // Serialize return value and write it back into the memory. + sandbox_primitives::ReturnValue::Value(val.into()).using_encoded(|val| { + if val.len() > return_val_len as usize { + Err("Return value buffer is too small")?; + } + FunctionContext::write_memory(self, return_val, val)?; + Ok(sandbox_primitives::ERR_OK) + }) + } + Err(_) => Ok(sandbox_primitives::ERR_EXECUTION), + } + } + + fn instance_teardown(&mut self, instance_id: u32) -> WResult<()> { + self.sandbox_store.instance_teardown(instance_id).map_err(|e| e.to_string()) + } + + fn instance_new(&mut self, dispatch_thunk_id: u32, wasm: &[u8], raw_env_def: &[u8], state: u32) + -> WResult + { + // Extract a dispatch thunk from instance's table by the specified index. + let dispatch_thunk = { + let table = self.table.as_ref() + .ok_or_else(|| "Runtime doesn't have a table; sandbox is unavailable")?; + let func_ref = table.get(dispatch_thunk_id as usize) + .ok_or_else(|| "dispatch_thunk_idx is out of the table bounds")?; + SupervisorFuncRef(func_ref) + }; + + let instance_idx_or_err_code = + match sandbox::instantiate(self, dispatch_thunk, wasm, raw_env_def, state) { + Ok(instance_idx) => instance_idx, + Err(sandbox::InstantiationError::StartTrapped) => + sandbox_primitives::ERR_EXECUTION, + Err(_) => sandbox_primitives::ERR_MODULE, + }; + + Ok(instance_idx_or_err_code as u32) + } +} + +// The storage for a Wasmtime invocation argument. +#[derive(Debug, Default, Copy, Clone)] +#[repr(C, align(8))] +struct VMInvokeArgument([u8; 8]); + +fn generate_signature_and_args( + args: &[Value], + result_type: Option, + frontend_config: TargetFrontendConfig, +) -> (ir::Signature, Vec) +{ + // This code is based on the wasmtime_jit::Context::invoke. + + let param_types = args.iter() + .map(|arg| arg.value_type()) + .collect::>(); + let signature = translate_signature( + cranelift_ir_signature( + Signature::new(param_types, result_type), + &frontend_config.default_call_conv + ), + frontend_config.pointer_type() + ); + + let mut values_vec = vec![ + VMInvokeArgument::default(); + cmp::max(args.len(), result_type.iter().len()) + ]; + + // Store the argument values into `values_vec`. + for (index, arg) in args.iter().enumerate() { + unsafe { + let ptr = values_vec.as_mut_ptr().add(index); + + match arg { + Value::I32(x) => ptr::write(ptr as *mut i32, *x), + Value::I64(x) => ptr::write(ptr as *mut i64, *x), + Value::F32(x) => ptr::write(ptr as *mut u32, *x), + Value::F64(x) => ptr::write(ptr as *mut u64, *x), + } + } + } + + (signature, values_vec) +} + diff --git a/core/executor/src/wasmtime/mod.rs b/core/executor/src/wasmtime/mod.rs new file mode 100644 index 0000000000..7f442417ab --- /dev/null +++ b/core/executor/src/wasmtime/mod.rs @@ -0,0 +1,24 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +///! Defines a `WasmRuntime` that uses the Wasmtime JIT to execute. + +mod function_executor; +mod runtime; +mod trampoline; +mod util; + +pub use runtime::create_instance; diff --git a/core/executor/src/wasmtime/runtime.rs b/core/executor/src/wasmtime/runtime.rs new file mode 100644 index 0000000000..fa360773fb --- /dev/null +++ b/core/executor/src/wasmtime/runtime.rs @@ -0,0 +1,398 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +//! Defines the compiled Wasm runtime that uses Wasmtime internally. + +use crate::error::{Error, Result, WasmError}; +use crate::host_interface::SubstrateExternals; +use crate::wasm_runtime::WasmRuntime; +use crate::wasm_utils::interpret_runtime_api_result; +use crate::wasmtime::function_executor::FunctionExecutorState; +use crate::wasmtime::trampoline::{EnvState, make_trampoline}; +use crate::wasmtime::util::{cranelift_ir_signature, read_memory_into, write_memory_from}; +use crate::{Externalities, RuntimeVersion}; + +use codec::Decode; +use cranelift_codegen::ir; +use cranelift_codegen::isa::TargetIsa; +use cranelift_entity::{EntityRef, PrimaryMap}; +use cranelift_frontend::FunctionBuilderContext; +use cranelift_wasm::DefinedFuncIndex; +use std::cell::RefCell; +use std::collections::HashMap; +use std::convert::TryFrom; +use std::panic::AssertUnwindSafe; +use std::rc::Rc; +use wasm_interface::{HostFunctions, Pointer, WordSize}; +use wasmtime_environ::{Module, translate_signature}; +use wasmtime_jit::{ + ActionOutcome, ActionError, CodeMemory, CompilationStrategy, CompiledModule, Compiler, Context, + SetupError, RuntimeValue, +}; +use wasmtime_runtime::{Export, Imports, InstanceHandle, VMFunctionBody}; + +/// A `WasmRuntime` implementation using the Wasmtime JIT to compile the runtime module to native +/// and execute the compiled code. +pub struct WasmtimeRuntime { + module: CompiledModule, + context: Context, + max_heap_pages: Option, + heap_pages: u32, + version: Option, +} + +impl WasmRuntime for WasmtimeRuntime { + fn update_heap_pages(&mut self, heap_pages: u64) -> bool { + match heap_pages_valid(heap_pages, self.max_heap_pages) { + Some(heap_pages) => { + self.heap_pages = heap_pages; + true + } + None => false, + } + } + + fn call(&mut self, ext: &mut dyn Externalities, method: &str, data: &[u8]) -> Result> { + call_method( + &mut self.context, + &mut self.module, + ext, + method, + data, + self.heap_pages, + ) + } + + fn version(&self) -> Option { + self.version.clone() + } +} + +/// Create a new `WasmtimeRuntime` given the code. This function performs translation from Wasm to +/// machine code, which can be computationally heavy. +pub fn create_instance(ext: &mut E, code: &[u8], heap_pages: u64) + -> std::result::Result +{ + let (mut compiled_module, mut context) = create_compiled_unit(code)?; + + // Inspect the module for the min and max memory sizes. + let (min_memory_size, max_memory_size) = { + let module = compiled_module.module_ref(); + let memory_index = match module.exports.get("memory") { + Some(wasmtime_environ::Export::Memory(memory_index)) => *memory_index, + _ => return Err(WasmError::InvalidMemory), + }; + let memory_plan = module.memory_plans.get(memory_index) + .expect("memory_index is retrieved from the module's exports map; qed"); + (memory_plan.memory.minimum, memory_plan.memory.maximum) + }; + + // Check that heap_pages is within the allowed range. + let max_heap_pages = max_memory_size.map(|max| max.saturating_sub(min_memory_size)); + let heap_pages = heap_pages_valid(heap_pages, max_heap_pages) + .ok_or_else(|| WasmError::InvalidHeapPages)?; + + // Call to determine runtime version. + let version_result = { + // `ext` is already implicitly handled as unwind safe, as we store it in a global variable. + let mut ext = AssertUnwindSafe(ext); + + // The following unwind safety assertions are OK because if the method call panics, the + // context and compiled module will be dropped. + let mut context = AssertUnwindSafe(&mut context); + let mut compiled_module = AssertUnwindSafe(&mut compiled_module); + crate::native_executor::safe_call(move || { + call_method( + &mut **context, + &mut **compiled_module, + &mut **ext, + "Core_version", + &[], + heap_pages + ) + }).map_err(|_| { + WasmError::Instantiation("panic in call to get runtime version".to_string()) + })? + }; + let version = version_result + .ok() + .and_then(|v| RuntimeVersion::decode(&mut v.as_slice()).ok()); + + Ok(WasmtimeRuntime { + module: compiled_module, + context, + max_heap_pages, + heap_pages, + version, + }) +} + +fn create_compiled_unit(code: &[u8]) + -> std::result::Result<(CompiledModule, Context), WasmError> +{ + let compilation_strategy = CompilationStrategy::Cranelift; + + let compiler = new_compiler(compilation_strategy)?; + let mut context = Context::new(Box::new(compiler)); + + // Enable/disable producing of debug info. + context.set_debug_info(false); + + // Instantiate and link the env module. + let global_exports = context.get_global_exports(); + let compiler = new_compiler(compilation_strategy)?; + let env_module = instantiate_env_module(global_exports, compiler)?; + context.name_instance("env".to_owned(), env_module); + + // Compile the wasm module. + let module = context.compile_module(&code) + .map_err(WasmError::WasmtimeSetup)?; + + Ok((module, context)) +} + +/// Call a function inside a precompiled Wasm module. +fn call_method( + context: &mut Context, + module: &mut CompiledModule, + ext: &mut dyn Externalities, + method: &str, + data: &[u8], + heap_pages: u32, +) -> Result> { + // Old exports get clobbered in `InstanceHandle::new` if we don't explicitly remove them first. + // + // The global exports mechanism is temporary in Wasmtime and expected to be removed. + // https://github.com/CraneStation/wasmtime/issues/332 + clear_globals(&mut *context.get_global_exports().borrow_mut()); + + let mut instance = module.instantiate() + .map_err(SetupError::Instantiate) + .map_err(ActionError::Setup) + .map_err(Error::Wasmtime)?; + + // Ideally there would be a way to set the heap pages during instantiation rather than + // growing the memory after the fact. Currently this may require an additional mmap and copy. + // However, the wasmtime API doesn't support modifying the size of memory on instantiation + // at this time. + grow_memory(&mut instance, heap_pages)?; + + // Initialize the function executor state. + let heap_base = get_heap_base(&instance)?; + let executor_state = FunctionExecutorState::new(heap_base); + reset_env_state_and_take_trap(context, Some(executor_state))?; + + // Write the input data into guest memory. + let (data_ptr, data_len) = inject_input_data(context, &mut instance, data)?; + let args = [RuntimeValue::I32(u32::from(data_ptr) as i32), RuntimeValue::I32(data_len as i32)]; + + // Invoke the function in the runtime. + let outcome = externalities::set_and_run_with_externalities(ext, || { + context + .invoke(&mut instance, method, &args[..]) + .map_err(Error::Wasmtime) + })?; + let trap_error = reset_env_state_and_take_trap(context, None)?; + let (output_ptr, output_len) = match outcome { + ActionOutcome::Returned { values } => match values.as_slice() { + [RuntimeValue::I64(retval)] => + interpret_runtime_api_result(*retval), + _ => return Err(Error::InvalidReturn), + } + ActionOutcome::Trapped { message } => + return Err(trap_error.unwrap_or_else(|| + format!("Wasm execution trapped: {}", message).into() + )), + }; + + // Read the output data from guest memory. + let mut output = vec![0; output_len as usize]; + let memory = get_memory_mut(&mut instance)?; + read_memory_into(memory, output_ptr, &mut output)?; + Ok(output) +} + +/// The implementation is based on wasmtime_wasi::instantiate_wasi. +fn instantiate_env_module( + global_exports: Rc>>>, + compiler: Compiler, +) -> std::result::Result +{ + let isa = target_isa()?; + let pointer_type = isa.pointer_type(); + let call_conv = isa.default_call_conv(); + + let mut fn_builder_ctx = FunctionBuilderContext::new(); + let mut module = Module::new(); + let mut finished_functions = >::new(); + let mut code_memory = CodeMemory::new(); + + for function in SubstrateExternals::functions().iter() { + let sig = translate_signature( + cranelift_ir_signature(function.signature(), &call_conv), + pointer_type + ); + let sig_id = module.signatures.push(sig.clone()); + let func_id = module.functions.push(sig_id); + module + .exports + .insert(function.name().to_string(), wasmtime_environ::Export::Function(func_id)); + + let trampoline = make_trampoline( + isa.as_ref(), + &mut code_memory, + &mut fn_builder_ctx, + func_id.index() as u32, + &sig, + )?; + finished_functions.push(trampoline); + } + + code_memory.publish(); + + let imports = Imports::none(); + let data_initializers = Vec::new(); + let signatures = PrimaryMap::new(); + let env_state = EnvState::new::(code_memory, compiler); + + let result = InstanceHandle::new( + Rc::new(module), + global_exports, + finished_functions.into_boxed_slice(), + imports, + &data_initializers, + signatures.into_boxed_slice(), + None, + Box::new(env_state), + ); + result.map_err(|e| WasmError::WasmtimeSetup(SetupError::Instantiate(e))) +} + +/// Build a new TargetIsa for the host machine. +fn target_isa() -> std::result::Result, WasmError> { + let isa_builder = cranelift_native::builder() + .map_err(WasmError::MissingCompilerSupport)?; + let flag_builder = cranelift_codegen::settings::builder(); + Ok(isa_builder.finish(cranelift_codegen::settings::Flags::new(flag_builder))) +} + +fn new_compiler(strategy: CompilationStrategy) -> std::result::Result { + let isa = target_isa()?; + Ok(Compiler::new(isa, strategy)) +} + +fn clear_globals(global_exports: &mut HashMap>) { + global_exports.remove("memory"); + global_exports.remove("__heap_base"); + global_exports.remove("__indirect_function_table"); +} + +fn grow_memory(instance: &mut InstanceHandle, pages: u32) -> Result<()> { + // This is safe to wrap in an unsafe block as: + // - The result of the `lookup_immutable` call is not mutated + // - The definition pointer is returned by a lookup on a valid instance + let memory_index = unsafe { + match instance.lookup_immutable("memory") { + Some(Export::Memory { definition, vmctx: _, memory: _ }) => + instance.memory_index(&*definition), + _ => return Err(Error::InvalidMemoryReference), + } + }; + instance.memory_grow(memory_index, pages) + .map(|_| ()) + .ok_or_else(|| "requested heap_pages would exceed maximum memory size".into()) +} + +fn get_env_state(context: &mut Context) -> Result<&mut EnvState> { + let env_instance = context.get_instance("env") + .map_err(|err| format!("cannot find \"env\" module: {}", err))?; + env_instance + .host_state() + .downcast_mut::() + .ok_or_else(|| "cannot get \"env\" module host state".into()) +} + +fn reset_env_state_and_take_trap( + context: &mut Context, + executor_state: Option, +) -> Result> +{ + let env_state = get_env_state(context)?; + env_state.executor_state = executor_state; + Ok(env_state.take_trap()) +} + +fn inject_input_data( + context: &mut Context, + instance: &mut InstanceHandle, + data: &[u8], +) -> Result<(Pointer, WordSize)> { + let env_state = get_env_state(context)?; + let executor_state = env_state.executor_state + .as_mut() + .ok_or_else(|| "cannot get \"env\" module executor state")?; + + let memory = get_memory_mut(instance)?; + + let data_len = data.len() as WordSize; + let data_ptr = executor_state.heap().allocate(memory, data_len)?; + write_memory_from(memory, data_ptr, data)?; + Ok((data_ptr, data_len)) +} + +fn get_memory_mut(instance: &mut InstanceHandle) -> Result<&mut [u8]> { + match instance.lookup("memory") { + // This is safe to wrap in an unsafe block as: + // - The definition pointer is returned by a lookup on a valid instance and thus points to + // a valid memory definition + Some(Export::Memory { definition, vmctx: _, memory: _ }) => unsafe { + Ok(std::slice::from_raw_parts_mut( + (*definition).base, + (*definition).current_length, + )) + }, + _ => Err(Error::InvalidMemoryReference), + } +} + +fn get_heap_base(instance: &InstanceHandle) -> Result { + // This is safe to wrap in an unsafe block as: + // - The result of the `lookup_immutable` call is not mutated + // - The definition pointer is returned by a lookup on a valid instance + // - The defined value is checked to be an I32, which can be read safely as a u32 + unsafe { + match instance.lookup_immutable("__heap_base") { + Some(Export::Global { definition, vmctx: _, global }) + if global.ty == ir::types::I32 => + Ok(*(*definition).as_u32()), + _ => return Err(Error::HeapBaseNotFoundOrInvalid), + } + } +} + +/// Checks whether the heap_pages parameter is within the valid range and converts it to a u32. +/// Returns None if heaps_pages in not in range. +fn heap_pages_valid(heap_pages: u64, max_heap_pages: Option) + -> Option +{ + let heap_pages = u32::try_from(heap_pages).ok()?; + if let Some(max_heap_pages) = max_heap_pages { + if heap_pages > max_heap_pages { + return None; + } + } + Some(heap_pages) +} diff --git a/core/executor/src/wasmtime/trampoline.rs b/core/executor/src/wasmtime/trampoline.rs new file mode 100644 index 0000000000..7abc59faa5 --- /dev/null +++ b/core/executor/src/wasmtime/trampoline.rs @@ -0,0 +1,329 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +//! The trampoline is the dynamically generated entry point to a runtime host call. +//! +//! This code is based on and large parts are copied from wasmtime's +//! wasmtime-api/src/trampoline/func.rs. + +use cranelift_codegen::{Context, binemit, ir, isa}; +use cranelift_codegen::ir::{InstBuilder, StackSlotData, StackSlotKind, TrapCode}; +use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext}; +use wasmtime_jit::{CodeMemory, Compiler}; +use wasmtime_runtime::{VMContext, VMFunctionBody}; +use wasm_interface::{HostFunctions, Function, Value, ValueType}; +use std::{cmp, panic, ptr}; + +use crate::error::{Error, WasmError}; +use crate::wasmtime::function_executor::{FunctionExecutorState, FunctionExecutor}; + +const CALL_SUCCESS: u32 = 0; +const CALL_FAILED_WITH_ERROR: u32 = 1; +const CALL_WITH_BAD_HOST_STATE: u32 = 2; +const CALL_PANICKED: u32 = 3; + +/// A code to trap with that indicates a host call error. +const TRAP_USER_CODE: u16 = 0; + +/// The only Wasm types allowed in host function signatures (I32, I64, F32, F64) are all +/// represented in at most 8 bytes. +const MAX_WASM_TYPE_SIZE: usize = 8; + +/// The top-level host state of the "env" module. This state is used by the trampoline function to +/// construct a `FunctionExecutor` which can execute the host call. +pub struct EnvState { + externals: &'static [&'static dyn Function], + compiler: Compiler, + // The code memory must be kept around on the state to prevent it from being dropped. + #[allow(dead_code)] + code_memory: CodeMemory, + trap: Option, + /// The executor state stored across host calls during a single Wasm runtime call. + /// During a runtime call, this MUST be `Some`. + pub executor_state: Option, +} + +impl EnvState { + /// Construct a new `EnvState` which owns the given code memory. + pub fn new(code_memory: CodeMemory, compiler: Compiler) -> Self { + EnvState { + externals: HF::functions(), + trap: None, + compiler, + code_memory, + executor_state: None, + } + } + + /// Resets the trap error to None and returns the current value. + pub fn take_trap(&mut self) -> Option { + self.trap.take() + } +} + +/// This is called by the dynamically generated trampoline taking the function index and reference +/// to the call arguments on the stack as arguments. Returns zero on success and a non-zero value +/// on failure. +unsafe extern "C" fn stub_fn(vmctx: *mut VMContext, func_index: u32, values_vec: *mut i64) -> u32 { + let result = panic::catch_unwind(|| { + if let Some(state) = (*vmctx).host_state().downcast_mut::() { + match stub_fn_inner( + vmctx, + state.externals, + &mut state.compiler, + state.executor_state.as_mut(), + func_index, + values_vec, + ) { + Ok(()) => CALL_SUCCESS, + Err(err) => { + state.trap = Some(err); + CALL_FAILED_WITH_ERROR + } + } + } else { + // Well, we can't even set a trap message, so we'll just exit without one. + CALL_WITH_BAD_HOST_STATE + } + }); + result.unwrap_or(CALL_PANICKED) +} + +/// Implements most of the logic in `stub_fn` but returning a `Result` instead of an integer error +/// for the sake of readability. +unsafe fn stub_fn_inner( + vmctx: *mut VMContext, + externals: &[&dyn Function], + compiler: &mut Compiler, + executor_state: Option<&mut FunctionExecutorState>, + func_index: u32, + values_vec: *mut i64, +) -> Result<(), Error> +{ + let func = externals.get(func_index as usize) + .ok_or_else(|| format!("call to undefined external function with index {}", func_index))?; + let executor_state = executor_state + .ok_or_else(|| "executor state is None during call to external function")?; + + // Build the external function context. + let mut context = FunctionExecutor::new(vmctx, compiler, executor_state)?; + + let signature = func.signature(); + + // Read the arguments from the stack. + let mut args = signature.args.iter() + .enumerate() + .map(|(i, ¶m_type)| read_value_from(values_vec.offset(i as isize), param_type)); + + // Execute and write output back to the stack. + let return_val = func.execute(&mut context, &mut args) + .map_err(|e| Error::FunctionExecution(func.name().to_string(), e))?; + if let Some(val) = return_val { + write_value_to(values_vec, val); + } + + Ok(()) +} + +/// Create a trampoline for invoking a host function. +/// +/// The trampoline is a dynamically generated entry point to a runtime host call. The function is +/// generated by manually constructing Cranelift IR and using the Cranelift compiler. The +/// trampoline embeds the function index as a constant and delegates to a stub function in Rust, +/// which takes the function index and a memory reference to the stack arguments and return value +/// slots. +/// +/// This code is of modified copy of wasmtime's wasmtime-api/src/trampoline/func.rs. +pub fn make_trampoline( + isa: &dyn isa::TargetIsa, + code_memory: &mut CodeMemory, + fn_builder_ctx: &mut FunctionBuilderContext, + func_index: u32, + signature: &ir::Signature, +) -> Result<*const VMFunctionBody, WasmError> { + // Mostly reverse copy of the similar method from wasmtime's + // wasmtime-jit/src/compiler.rs. + let pointer_type = isa.pointer_type(); + let mut stub_sig = ir::Signature::new(isa.frontend_config().default_call_conv); + + // Ensure that the first parameter of the generated function is the `VMContext` pointer. + assert_eq!( + signature.params[0], + ir::AbiParam::special(pointer_type, ir::ArgumentPurpose::VMContext) + ); + + // Add the `vmctx` parameter. + stub_sig.params.push(ir::AbiParam::special( + pointer_type, + ir::ArgumentPurpose::VMContext, + )); + + // Add the `func_index` parameter. + stub_sig.params.push(ir::AbiParam::new(ir::types::I32)); + + // Add the `values_vec` parameter. + stub_sig.params.push(ir::AbiParam::new(pointer_type)); + + // Add error/trap return. + stub_sig.returns.push(ir::AbiParam::new(ir::types::I32)); + + // Each parameter and return value gets a 64-bit (8-byte) wide slot on the stack, as that is + // large enough to fit all Wasm primitive types that can be used in host function signatures. + // The `VMContext` pointer, which is a parameter of the function signature, is excluded as it + // is passed directly to the stub function rather than being looked up on the caller stack from + // the `values_vec` pointer. + let values_vec_len = cmp::max(signature.params.len() - 1, signature.returns.len()); + let values_vec_size = (MAX_WASM_TYPE_SIZE * values_vec_len) as u32; + + let mut context = Context::new(); + context.func = + ir::Function::with_name_signature(ir::ExternalName::user(0, 0), signature.clone()); + + let ss = context.func.create_stack_slot(StackSlotData::new( + StackSlotKind::ExplicitSlot, + values_vec_size, + )); + + { + let mut builder = FunctionBuilder::new(&mut context.func, fn_builder_ctx); + let block0 = builder.create_ebb(); + + builder.append_ebb_params_for_function_params(block0); + builder.switch_to_block(block0); + builder.seal_block(block0); + + let values_vec_ptr_val = builder.ins().stack_addr(pointer_type, ss, 0); + let mflags = ir::MemFlags::trusted(); + for i in 1..signature.params.len() { + let val = builder.func.dfg.ebb_params(block0)[i]; + builder.ins().store( + mflags, + val, + values_vec_ptr_val, + ((i - 1) * MAX_WASM_TYPE_SIZE) as i32, + ); + } + + let vmctx_ptr_val = builder.func.dfg.ebb_params(block0)[0]; + let func_index_val = builder.ins().iconst(ir::types::I32, func_index as i64); + + let callee_args = vec![vmctx_ptr_val, func_index_val, values_vec_ptr_val]; + + let new_sig = builder.import_signature(stub_sig.clone()); + + let callee_value = builder + .ins() + .iconst(pointer_type, stub_fn as *const VMFunctionBody as i64); + let call = builder + .ins() + .call_indirect(new_sig, callee_value, &callee_args); + + let call_result = builder.func.dfg.inst_results(call)[0]; + builder.ins().trapnz(call_result, TrapCode::User(TRAP_USER_CODE)); + + let mflags = ir::MemFlags::trusted(); + let mut results = Vec::new(); + for (i, r) in signature.returns.iter().enumerate() { + let load = builder.ins().load( + r.value_type, + mflags, + values_vec_ptr_val, + (i * MAX_WASM_TYPE_SIZE) as i32, + ); + results.push(load); + } + builder.ins().return_(&results); + builder.finalize() + } + + let mut code_buf: Vec = Vec::new(); + let mut reloc_sink = RelocSink; + let mut trap_sink = binemit::NullTrapSink {}; + let mut stackmap_sink = binemit::NullStackmapSink {}; + context + .compile_and_emit( + isa, + &mut code_buf, + &mut reloc_sink, + &mut trap_sink, + &mut stackmap_sink, + ) + .map_err(|e| WasmError::Instantiation(format!("failed to compile trampoline: {}", e)))?; + + let func_ref = code_memory + .allocate_copy_of_byte_slice(&code_buf) + .map_err(|e| WasmError::Instantiation(format!("failed to allocate code memory: {}", e)))?; + + Ok(func_ref.as_ptr()) +} + +/// We don't expect trampoline compilation to produce any relocations, so +/// this `RelocSink` just asserts that it doesn't recieve any. +struct RelocSink; + +impl binemit::RelocSink for RelocSink { + fn reloc_ebb( + &mut self, + _offset: binemit::CodeOffset, + _reloc: binemit::Reloc, + _ebb_offset: binemit::CodeOffset, + ) { + panic!("trampoline compilation should not produce ebb relocs"); + } + fn reloc_external( + &mut self, + _offset: binemit::CodeOffset, + _reloc: binemit::Reloc, + _name: &ir::ExternalName, + _addend: binemit::Addend, + ) { + panic!("trampoline compilation should not produce external symbol relocs"); + } + fn reloc_constant( + &mut self, + _code_offset: binemit::CodeOffset, + _reloc: binemit::Reloc, + _constant_offset: ir::ConstantOffset, + ) { + panic!("trampoline compilation should not produce constant relocs"); + } + fn reloc_jt( + &mut self, + _offset: binemit::CodeOffset, + _reloc: binemit::Reloc, + _jt: ir::JumpTable, + ) { + panic!("trampoline compilation should not produce jump table relocs"); + } +} + +unsafe fn write_value_to(p: *mut i64, val: Value) { + match val { + Value::I32(i) => ptr::write(p as *mut i32, i), + Value::I64(i) => ptr::write(p as *mut i64, i), + Value::F32(u) => ptr::write(p as *mut u32, u), + Value::F64(u) => ptr::write(p as *mut u64, u), + } +} + +unsafe fn read_value_from(p: *const i64, ty: ValueType) -> Value { + match ty { + ValueType::I32 => Value::I32(ptr::read(p as *const i32)), + ValueType::I64 => Value::I64(ptr::read(p as *const i64)), + ValueType::F32 => Value::F32(ptr::read(p as *const u32)), + ValueType::F64 => Value::F64(ptr::read(p as *const u64)), + } +} diff --git a/core/executor/src/wasmtime/util.rs b/core/executor/src/wasmtime/util.rs new file mode 100644 index 0000000000..874ccc8c85 --- /dev/null +++ b/core/executor/src/wasmtime/util.rs @@ -0,0 +1,113 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +use crate::error::{Error, Result}; + +use cranelift_codegen::{ir, isa}; +use std::ops::Range; +use wasm_interface::{Pointer, Signature, ValueType}; + +/// Read data from a slice of memory into a destination buffer. +/// +/// Returns an error if the read would go out of the memory bounds. +pub fn read_memory_into(memory: &[u8], address: Pointer, dest: &mut [u8]) -> Result<()> { + let range = checked_range(address.into(), dest.len(), memory.len()) + .ok_or_else(|| Error::Other("memory read is out of bounds".into()))?; + dest.copy_from_slice(&memory[range]); + Ok(()) +} + +/// Write data to a slice of memory. +/// +/// Returns an error if the write would go out of the memory bounds. +pub fn write_memory_from(memory: &mut [u8], address: Pointer, data: &[u8]) -> Result<()> { + let range = checked_range(address.into(), data.len(), memory.len()) + .ok_or_else(|| Error::Other("memory write is out of bounds".into()))?; + &mut memory[range].copy_from_slice(data); + Ok(()) +} + +/// Construct a range from an offset to a data length after the offset. +/// Returns None if the end of the range would exceed some maximum offset. +pub fn checked_range(offset: usize, len: usize, max: usize) -> Option> { + let end = offset.checked_add(len)?; + if end <= max { + Some(offset..end) + } else { + None + } +} + +/// Convert a wasm_interface Signature into a cranelift_codegen Signature. +pub fn cranelift_ir_signature(signature: Signature, call_conv: &isa::CallConv) -> ir::Signature { + ir::Signature { + params: signature.args.iter() + .map(cranelift_ir_type) + .map(ir::AbiParam::new) + .collect(), + returns: signature.return_value.iter() + .map(cranelift_ir_type) + .map(ir::AbiParam::new) + .collect(), + call_conv: call_conv.clone(), + } +} + +/// Convert a wasm_interface ValueType into a cranelift_codegen Type. +pub fn cranelift_ir_type(value_type: &ValueType) -> ir::types::Type { + match value_type { + ValueType::I32 => ir::types::I32, + ValueType::I64 => ir::types::I64, + ValueType::F32 => ir::types::F32, + ValueType::F64 => ir::types::F64, + } +} + +#[cfg(test)] +mod tests { + use super::*; + use assert_matches::assert_matches; + + #[test] + fn test_read_memory_into() { + let mut memory = [0; 20]; + let mut dest = [0; 5]; + + &mut memory[15..20].copy_from_slice(b"hello"); + + read_memory_into(&memory[..], Pointer::new(15), &mut dest[..]).unwrap(); + + // Test that out of bounds read fails. + assert_matches!( + read_memory_into(&memory[..], Pointer::new(16), &mut dest[..]), + Err(Error::Other(_)) + ) + } + + #[test] + fn test_write_memory_from() { + let mut memory = [0; 20]; + let data = b"hello"; + + write_memory_from(&mut memory[..], Pointer::new(15), data).unwrap(); + + // Test that out of bounds write fails. + assert_matches!( + write_memory_from(&mut memory[..], Pointer::new(16), data), + Err(Error::Other(_)) + ) + } +} diff --git a/core/service/Cargo.toml b/core/service/Cargo.toml index 1a85ed8de0..3d40550c8c 100644 --- a/core/service/Cargo.toml +++ b/core/service/Cargo.toml @@ -9,6 +9,9 @@ default = ["rocksdb"] # The RocksDB feature activates the RocksDB database backend. If it is not activated, and you pass # a path to a database, an error will be produced at runtime. rocksdb = ["client_db/kvdb-rocksdb"] +wasmtime = [ + "substrate-executor/wasmtime", +] [dependencies] derive_more = "0.15.0" diff --git a/core/wasm-interface/src/lib.rs b/core/wasm-interface/src/lib.rs index 1e67260638..83689ddc81 100644 --- a/core/wasm-interface/src/lib.rs +++ b/core/wasm-interface/src/lib.rs @@ -49,6 +49,18 @@ pub enum Value { F64(u64), } +impl Value { + /// Returns the type of this value. + pub fn value_type(&self) -> ValueType { + match self { + Value::I32(_) => ValueType::I32, + Value::I64(_) => ValueType::I64, + Value::F32(_) => ValueType::F32, + Value::F64(_) => ValueType::F64, + } + } +} + /// Provides `Sealed` trait to prevent implementing trait `PointerType` outside of this crate. mod private { pub trait Sealed {} @@ -212,7 +224,7 @@ pub type MemoryId = u32; pub trait Sandbox { /// Get sandbox memory from the `memory_id` instance at `offset` into the given buffer. fn memory_get( - &self, + &mut self, memory_id: MemoryId, offset: WordSize, buf_ptr: Pointer, diff --git a/node/cli/Cargo.toml b/node/cli/Cargo.toml index 99a4c6aebf..5e55d5c208 100644 --- a/node/cli/Cargo.toml +++ b/node/cli/Cargo.toml @@ -116,3 +116,9 @@ cli = [ "ctrlc", "substrate-service/rocksdb" ] +wasmtime = [ + "cli", + "node-executor/wasmtime", + "substrate-cli/wasmtime", + "substrate-service/wasmtime", +] diff --git a/node/executor/Cargo.toml b/node/executor/Cargo.toml index 1908443ca9..93f29910ed 100644 --- a/node/executor/Cargo.toml +++ b/node/executor/Cargo.toml @@ -31,7 +31,15 @@ contracts = { package = "srml-contracts", path = "../../srml/contracts" } grandpa = { package = "srml-grandpa", path = "../../srml/grandpa" } indices = { package = "srml-indices", path = "../../srml/indices" } wabt = "0.9.2" +criterion = "0.3.0" [features] -benchmarks = [] +wasmtime = [ + "substrate-executor/wasmtime", +] stress-test = [] + +[[bench]] +name = "bench" +harness = false + diff --git a/node/executor/benches/bench.rs b/node/executor/benches/bench.rs new file mode 100644 index 0000000000..e72c28467f --- /dev/null +++ b/node/executor/benches/bench.rs @@ -0,0 +1,196 @@ +// Copyright 2018-2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +use codec::{Decode, Encode}; +use criterion::{BatchSize, Criterion, criterion_group, criterion_main}; +use node_executor::Executor; +use node_primitives::{BlockNumber, Hash}; +use node_runtime::{ + Block, BuildStorage, Call, CheckedExtrinsic, GenesisConfig, Header, UncheckedExtrinsic, +}; +use node_runtime::constants::currency::*; +use node_testing::keyring::*; +use primitives::{Blake2Hasher, NativeOrEncoded, NeverNativeValue}; +use primitives::storage::well_known_keys; +use primitives::traits::CodeExecutor; +use runtime_support::Hashable; +use state_machine::TestExternalities as CoreTestExternalities; +use substrate_executor::{NativeExecutor, RuntimeInfo, WasmExecutionMethod, Externalities}; + +criterion_group!(benches, bench_execute_block); +criterion_main!(benches); + +/// The wasm runtime code. +const COMPACT_CODE: &[u8] = node_runtime::WASM_BINARY; + +const GENESIS_HASH: [u8; 32] = [69u8; 32]; + +const VERSION: u32 = node_runtime::VERSION.spec_version; + +const HEAP_PAGES: u64 = 20; + +type TestExternalities = CoreTestExternalities; + +#[derive(Debug)] +enum ExecutionMethod { + Native, + Wasm(WasmExecutionMethod), +} + +fn sign(xt: CheckedExtrinsic) -> UncheckedExtrinsic { + node_testing::keyring::sign(xt, VERSION, GENESIS_HASH) +} + +fn new_test_ext(genesis_config: &GenesisConfig) -> TestExternalities { + let mut test_ext = TestExternalities::new_with_code( + COMPACT_CODE, + genesis_config.build_storage().unwrap(), + ); + test_ext.ext().place_storage(well_known_keys::HEAP_PAGES.to_vec(), Some(HEAP_PAGES.encode())); + test_ext +} + +fn construct_block( + executor: &NativeExecutor, + ext: &mut E, + number: BlockNumber, + parent_hash: Hash, + extrinsics: Vec, +) -> (Vec, Hash) { + use trie::{TrieConfiguration, trie_types::Layout}; + + // sign extrinsics. + let extrinsics = extrinsics.into_iter().map(sign).collect::>(); + + // calculate the header fields that we can. + let extrinsics_root = Layout::::ordered_trie_root( + extrinsics.iter().map(Encode::encode) + ).to_fixed_bytes() + .into(); + + let header = Header { + parent_hash, + number, + extrinsics_root, + state_root: Default::default(), + digest: Default::default(), + }; + + // execute the block to get the real header. + executor.call::<_, NeverNativeValue, fn() -> _>( + ext, + "Core_initialize_block", + &header.encode(), + true, + None, + ).0.unwrap(); + + for i in extrinsics.iter() { + executor.call::<_, NeverNativeValue, fn() -> _>( + ext, + "BlockBuilder_apply_extrinsic", + &i.encode(), + true, + None, + ).0.unwrap(); + } + + let header = match executor.call::<_, NeverNativeValue, fn() -> _>( + ext, + "BlockBuilder_finalize_block", + &[0u8;0], + true, + None, + ).0.unwrap() { + NativeOrEncoded::Native(_) => unreachable!(), + NativeOrEncoded::Encoded(h) => Header::decode(&mut &h[..]).unwrap(), + }; + + let hash = header.blake2_256(); + (Block { header, extrinsics }.encode(), hash.into()) +} + + +fn test_blocks(genesis_config: &GenesisConfig, executor: &NativeExecutor) + -> Vec<(Vec, Hash)> +{ + let mut test_ext = new_test_ext(genesis_config); + let mut block1_extrinsics = vec![ + CheckedExtrinsic { + signed: None, + function: Call::Timestamp(timestamp::Call::set(42 * 1000)), + }, + ]; + block1_extrinsics.extend((0..20).map(|i| { + CheckedExtrinsic { + signed: Some((alice(), signed_extra(i, 0))), + function: Call::Balances(balances::Call::transfer(bob().into(), 1 * DOLLARS)), + } + })); + let block1 = construct_block( + executor, + &mut test_ext.ext(), + 1, + GENESIS_HASH.into(), + block1_extrinsics, + ); + + vec![block1] +} + +fn bench_execute_block(c: &mut Criterion) { + c.bench_function_over_inputs( + "execute blocks", + |b, strategy| { + let genesis_config = node_testing::genesis::config(false, Some(COMPACT_CODE)); + let (use_native, wasm_method) = match strategy { + ExecutionMethod::Native => (true, WasmExecutionMethod::Interpreted), + ExecutionMethod::Wasm(wasm_method) => (false, *wasm_method), + }; + let executor = NativeExecutor::new(wasm_method, None); + + // Get the runtime version to initialize the runtimes cache. + { + let mut test_ext = new_test_ext(&genesis_config); + executor.runtime_version(&mut test_ext.ext()); + } + + let blocks = test_blocks(&genesis_config, &executor); + + b.iter_batched_ref( + || new_test_ext(&genesis_config), + |test_ext| { + for block in blocks.iter() { + executor.call::<_, NeverNativeValue, fn() -> _>( + &mut test_ext.ext(), + "Core_execute_block", + &block.0, + use_native, + None, + ).0.unwrap(); + } + }, + BatchSize::LargeInput, + ); + }, + vec![ + ExecutionMethod::Native, + ExecutionMethod::Wasm(WasmExecutionMethod::Interpreted), + #[cfg(feature = "wasmtime")] + ExecutionMethod::Wasm(WasmExecutionMethod::Compiled), + ], + ); +} diff --git a/node/executor/src/lib.rs b/node/executor/src/lib.rs index 39727d1d55..fe43fc8ff0 100644 --- a/node/executor/src/lib.rs +++ b/node/executor/src/lib.rs @@ -17,10 +17,6 @@ //! A `CodeExecutor` specialization which uses natively compiled runtime when the wasm to be //! executed is equivalent to the natively compiled code. -#![cfg_attr(feature = "benchmarks", feature(test))] - -#[cfg(feature = "benchmarks")] extern crate test; - pub use substrate_executor::NativeExecutor; use substrate_executor::native_executor_instance; @@ -1208,21 +1204,4 @@ mod tests { block_number += 1; } } - - #[cfg(feature = "benchmarks")] - mod benches { - use super::*; - use test::Bencher; - - #[bench] - fn wasm_execute_block(b: &mut Bencher) { - let (block1, block2) = blocks(); - - b.iter(|| { - let mut t = new_test_ext(COMPACT_CODE, false); - WasmExecutor::new().call(&mut t, "Core_execute_block", &block1.0).unwrap(); - WasmExecutor::new().call(&mut t, "Core_execute_block", &block2.0).unwrap(); - }); - } - } } -- GitLab From 964eeb6bba6d6b98d5d9ea30b09bd06048740053 Mon Sep 17 00:00:00 2001 From: Caio Date: Fri, 1 Nov 2019 11:28:19 -0300 Subject: [PATCH 161/167] Implement Debug for some structures (#3941) * Implement Debug for some structures `NetworkConfiguration`, `TransportConfig`, `NodeKeyConfig` and `Secret`. Needs a new release of the `rust-libp2p` crate. This PR is just a reminder. * Explicitly separate `std` and `core` * Add manual implementation for Secret --- core/network/src/config.rs | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/core/network/src/config.rs b/core/network/src/config.rs index 445d4427bd..be01b90c36 100644 --- a/core/network/src/config.rs +++ b/core/network/src/config.rs @@ -28,12 +28,11 @@ use crate::service::{ExHashT, TransactionPool}; use bitflags::bitflags; use consensus::{block_validation::BlockAnnounceValidator, import_queue::ImportQueue}; use sr_primitives::traits::{Block as BlockT}; -use std::sync::Arc; use libp2p::identity::{Keypair, ed25519}; use libp2p::wasm_ext; use libp2p::{PeerId, Multiaddr, multiaddr}; -use std::error::Error; -use std::{io::{self, Write}, iter, fmt, fs, net::Ipv4Addr, path::{Path, PathBuf}}; +use core::{fmt, iter}; +use std::{error::Error, fs, io::{self, Write}, net::Ipv4Addr, path::{Path, PathBuf}, sync::Arc}; use zeroize::Zeroize; /// Network initialization parameters. @@ -234,7 +233,7 @@ impl From for ParseErr { } /// Network service configuration. -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct NetworkConfiguration { /// Directory path to store general network configuration. None means nothing will be saved. pub config_path: Option, @@ -317,7 +316,7 @@ impl NetworkConfiguration { } /// Configuration for the transport layer. -#[derive(Clone)] +#[derive(Clone, Debug)] pub enum TransportConfig { /// Normal transport mode. Normal { @@ -362,7 +361,7 @@ impl NonReservedPeerMode { /// The configuration of a node's secret key, describing the type of key /// and how it is obtained. A node's identity keypair is the result of /// the evaluation of the node key configuration. -#[derive(Clone)] +#[derive(Clone, Debug)] pub enum NodeKeyConfig { /// A Ed25519 secret key configuration. Ed25519(Secret) @@ -386,6 +385,16 @@ pub enum Secret { New } +impl fmt::Debug for Secret { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Secret::Input(_) => f.debug_tuple("Secret::Input").finish(), + Secret::File(path) => f.debug_tuple("Secret::File").field(path).finish(), + Secret::New => f.debug_tuple("Secret::New").finish(), + } + } +} + impl NodeKeyConfig { /// Evaluate a `NodeKeyConfig` to obtain an identity `Keypair`: /// -- GitLab From a2191eed81d1cf960e502088fe0efbc34105a9cd Mon Sep 17 00:00:00 2001 From: Marcio Diaz Date: Fri, 1 Nov 2019 16:17:38 +0100 Subject: [PATCH 162/167] Possible fix to storage cache (#3989) * Comment local_cache propagation * Add test * Deny cache when modifications are unknown * Fix indentation --- core/client/db/src/storage_cache.rs | 70 ++++++++++++++++++++++------- 1 file changed, 53 insertions(+), 17 deletions(-) diff --git a/core/client/db/src/storage_cache.rs b/core/client/db/src/storage_cache.rs index af8c9e379c..8c81e44ba6 100644 --- a/core/client/db/src/storage_cache.rs +++ b/core/client/db/src/storage_cache.rs @@ -22,6 +22,7 @@ use parking_lot::{Mutex, RwLock, RwLockUpgradableReadGuard}; use linked_hash_map::{LinkedHashMap, Entry}; use hash_db::Hasher; use sr_primitives::traits::{Block as BlockT, Header}; +use primitives::hexdisplay::HexDisplay; use state_machine::{backend::Backend as StateBackend, TrieBackend}; use log::trace; use super::{StorageCollection, ChildStorageCollection}; @@ -168,7 +169,7 @@ impl Cache { trace!("Reverting enacted block {:?}", block); m.is_canon = true; for a in &m.storage { - trace!("Reverting enacted key {:?}", a); + trace!("Reverting enacted key {:?}", HexDisplay::from(a)); self.lru_storage.remove(a); } for a in &m.child_storage { @@ -188,7 +189,7 @@ impl Cache { trace!("Retracting block {:?}", block); m.is_canon = false; for a in &m.storage { - trace!("Retracted key {:?}", a); + trace!("Retracted key {:?}", HexDisplay::from(a)); self.lru_storage.remove(a); } for a in &m.child_storage { @@ -416,21 +417,16 @@ impl, B: BlockT> CachingState { key: Option<&[u8]>, child_key: Option<&ChildStorageKey>, parent_hash: &Option, - modifications: - &VecDeque> + modifications: &VecDeque> ) -> bool { let mut parent = match *parent_hash { None => { - trace!("Cache lookup skipped for {:?}: no parent hash", key); + trace!("Cache lookup skipped for {:?}: no parent hash", key.as_ref().map(HexDisplay::from)); return false; } Some(ref parent) => parent, }; - if modifications.is_empty() { - trace!("Cache lookup allowed for {:?}", key); - return true; - } // Ignore all storage modified in later blocks // Modifications contains block ordered by the number // We search for our parent in that list first and then for @@ -445,7 +441,7 @@ impl, B: BlockT> CachingState { } if let Some(key) = key { if m.storage.contains(key) { - trace!("Cache lookup skipped for {:?}: modified in a later block", key); + trace!("Cache lookup skipped for {:?}: modified in a later block", HexDisplay::from(&key)); return false; } } @@ -456,7 +452,7 @@ impl, B: BlockT> CachingState { } } } - trace!("Cache lookup skipped for {:?}: parent hash is unknown", key); + trace!("Cache lookup skipped for {:?}: parent hash is unknown", key.as_ref().map(HexDisplay::from)); false } @@ -475,17 +471,17 @@ impl, B: BlockT> StateBackend for CachingState< let local_cache = self.cache.local_cache.upgradable_read(); // Note that local cache makes that lru is not refreshed if let Some(entry) = local_cache.storage.get(key).cloned() { - trace!("Found in local cache: {:?}", key); + trace!("Found in local cache: {:?}", HexDisplay::from(&key)); return Ok(entry) } let mut cache = self.cache.shared_cache.lock(); if Self::is_allowed(Some(key), None, &self.cache.parent_hash, &cache.modifications) { if let Some(entry) = cache.lru_storage.get(key).map(|a| a.clone()) { - trace!("Found in shared cache: {:?}", key); + trace!("Found in shared cache: {:?}", HexDisplay::from(&key)); return Ok(entry) } } - trace!("Cache miss: {:?}", key); + trace!("Cache miss: {:?}", HexDisplay::from(&key)); let value = self.state.storage(key)?; RwLockUpgradableReadGuard::upgrade(local_cache).storage.insert(key.to_vec(), value.clone()); Ok(value) @@ -494,17 +490,17 @@ impl, B: BlockT> StateBackend for CachingState< fn storage_hash(&self, key: &[u8]) -> Result, Self::Error> { let local_cache = self.cache.local_cache.upgradable_read(); if let Some(entry) = local_cache.hashes.get(key).cloned() { - trace!("Found hash in local cache: {:?}", key); + trace!("Found hash in local cache: {:?}", HexDisplay::from(&key)); return Ok(entry) } let mut cache = self.cache.shared_cache.lock(); if Self::is_allowed(Some(key), None, &self.cache.parent_hash, &cache.modifications) { if let Some(entry) = cache.lru_hashes.get(key).map(|a| a.0.clone()) { - trace!("Found hash in shared cache: {:?}", key); + trace!("Found hash in shared cache: {:?}", HexDisplay::from(&key)); return Ok(entry) } } - trace!("Cache hash miss: {:?}", key); + trace!("Cache hash miss: {:?}", HexDisplay::from(&key)); let hash = self.state.storage_hash(key)?; RwLockUpgradableReadGuard::upgrade(local_cache).hashes.insert(key.to_vec(), hash.clone()); Ok(hash) @@ -728,4 +724,44 @@ mod tests { // 32 key, 2 byte size assert_eq!(shared.lock().used_storage_cache_size(), 34 /* bytes */); } + + #[test] + fn fix_storage_mismatch_issue() { + let _ = ::env_logger::try_init(); + let root_parent = H256::random(); + + let key = H256::random()[..].to_vec(); + + let h0 = H256::random(); + let h1 = H256::random(); + + let shared = new_shared_cache::(256*1024, (0, 1)); + let mut s = CachingState::new(InMemory::::default(), shared.clone(), Some(root_parent.clone())); + s.cache.sync_cache(&[], &[], vec![(key.clone(), Some(vec![2]))], vec![], Some(h0.clone()), Some(0), || true); + + let mut s = CachingState::new(InMemory::::default(), shared.clone(), Some(h0.clone())); + s.cache.sync_cache(&[], &[], vec![(key.clone(), Some(vec![3]))], vec![], Some(h1.clone()), Some(1), || true); + + let mut s = CachingState::new(InMemory::::default(), shared.clone(), Some(h1.clone())); + assert_eq!(s.storage(&key).unwrap(), Some(vec![3])); + + // Restart (or unknown block?), clear caches. + { + let mut cache = s.cache.shared_cache.lock(); + let cache = &mut *cache; + cache.lru_storage.clear(); + cache.lru_hashes.clear(); + cache.lru_child_storage.clear(); + cache.modifications.clear(); + } + + // New value is written because of cache miss. + s.cache.local_cache.write().storage.insert(key.clone(), Some(vec![42])); + + // New value is propagated. + s.cache.sync_cache(&[], &[], vec![], vec![], None, None, || true); + + let s = CachingState::new(InMemory::::default(), shared.clone(), Some(h1.clone())); + assert_eq!(s.storage(&key).unwrap(), None); + } } -- GitLab From cf90ba6fa73cbc07e21c5778c75a3243d22d6b43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Fri, 1 Nov 2019 17:14:21 +0100 Subject: [PATCH 163/167] Don't panic in Offchain test context, when we are already panicking (#3996) --- core/offchain/src/testing.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/offchain/src/testing.rs b/core/offchain/src/testing.rs index e1cc7f71a3..3f4415efa7 100644 --- a/core/offchain/src/testing.rs +++ b/core/offchain/src/testing.rs @@ -119,7 +119,8 @@ impl State { impl Drop for State { fn drop(&mut self) { - if !self.expected_requests.is_empty() { + // If we panic! while we are already in a panic, the test dies with an illegal instruction. + if !self.expected_requests.is_empty() && !std::thread::panicking() { panic!("Unfulfilled expected requests: {:?}", self.expected_requests); } } -- GitLab From 72d5321a174e8660f207e87db9db4e1764aa4486 Mon Sep 17 00:00:00 2001 From: Jim Posen Date: Fri, 1 Nov 2019 18:22:28 +0100 Subject: [PATCH 164/167] executor: Move runtime version caching out of WasmRuntime interface. (#3993) * executor: Move runtime caching out of WasmRuntime interface. The runtime version is now fetched and cached at a higher level, not within the WasmRuntime trait implementations. * executor: Require successful querying of runtime version. --- core/executor/src/lib.rs | 1 - core/executor/src/native_executor.rs | 22 ++++----- core/executor/src/wasm_runtime.rs | 65 ++++++++++++++++++--------- core/executor/src/wasmi_execution.rs | 27 ++--------- core/executor/src/wasmtime/runtime.rs | 40 ++--------------- 5 files changed, 57 insertions(+), 98 deletions(-) diff --git a/core/executor/src/lib.rs b/core/executor/src/lib.rs index f053718b3a..d6d666dd28 100644 --- a/core/executor/src/lib.rs +++ b/core/executor/src/lib.rs @@ -73,7 +73,6 @@ pub fn call_in_wasm( heap_pages: u64, ) -> error::Result> { let mut instance = wasm_runtime::create_wasm_runtime_with_code( - ext, execution_method, heap_pages, code, diff --git a/core/executor/src/native_executor.rs b/core/executor/src/native_executor.rs index 082f0ba2ad..0fb84d9972 100644 --- a/core/executor/src/native_executor.rs +++ b/core/executor/src/native_executor.rs @@ -110,12 +110,13 @@ impl NativeExecutor { ext: &mut E, f: impl for<'a> FnOnce( AssertUnwindSafe<&'a mut (dyn WasmRuntime + 'static)>, + &'a RuntimeVersion, AssertUnwindSafe<&'a mut E>, ) -> Result>, ) -> Result where E: Externalities { RUNTIMES_CACHE.with(|cache| { let mut cache = cache.borrow_mut(); - let (runtime, code_hash) = cache.fetch_runtime( + let (runtime, version, code_hash) = cache.fetch_runtime( ext, self.fallback_method, self.default_heap_pages, @@ -124,7 +125,7 @@ impl NativeExecutor { let runtime = AssertUnwindSafe(runtime); let ext = AssertUnwindSafe(ext); - match f(runtime, ext) { + match f(runtime, version, ext) { Ok(res) => res, Err(e) => { cache.invalidate_runtime(self.fallback_method, code_hash); @@ -155,8 +156,8 @@ impl RuntimeInfo for NativeExecutor { &self, ext: &mut E, ) -> Option { - match self.with_runtime(ext, |runtime, _ext| Ok(Ok(runtime.version()))) { - Ok(version) => version, + match self.with_runtime(ext, |_runtime, version, _ext| Ok(Ok(version.clone()))) { + Ok(version) => Some(version), Err(e) => { warn!(target: "executor", "Failed to fetch runtime: {:?}", e); None @@ -182,13 +183,10 @@ impl CodeExecutor for NativeExecutor { native_call: Option, ) -> (Result>, bool){ let mut used_native = false; - let result = self.with_runtime(ext, |mut runtime, mut ext| { - let onchain_version = runtime.version(); + let result = self.with_runtime(ext, |mut runtime, onchain_version, mut ext| { match ( use_native, - onchain_version - .as_ref() - .map_or(false, |v| v.can_call_with(&self.native_version.runtime_version)), + onchain_version.can_call_with(&self.native_version.runtime_version), native_call, ) { (_, false, _) => { @@ -197,8 +195,6 @@ impl CodeExecutor for NativeExecutor { "Request for native execution failed (native: {}, chain: {})", self.native_version.runtime_version, onchain_version - .as_ref() - .map_or_else(||"".into(), |v| format!("{}", v)) ); safe_call( @@ -216,8 +212,6 @@ impl CodeExecutor for NativeExecutor { "Request for native execution with native call succeeded (native: {}, chain: {}).", self.native_version.runtime_version, onchain_version - .as_ref() - .map_or_else(||"".into(), |v| format!("{}", v)) ); used_native = true; @@ -234,7 +228,7 @@ impl CodeExecutor for NativeExecutor { target: "executor", "Request for native execution succeeded (native: {}, chain: {})", self.native_version.runtime_version, - onchain_version.as_ref().map_or_else(||"".into(), |v| format!("{}", v)) + onchain_version ); used_native = true; diff --git a/core/executor/src/wasm_runtime.rs b/core/executor/src/wasm_runtime.rs index 447dbadde5..caaa01c430 100644 --- a/core/executor/src/wasm_runtime.rs +++ b/core/executor/src/wasm_runtime.rs @@ -27,7 +27,7 @@ use log::{trace, warn}; use codec::Decode; use primitives::{storage::well_known_keys, traits::Externalities, H256}; use runtime_version::RuntimeVersion; -use std::{collections::hash_map::{Entry, HashMap}}; +use std::{collections::hash_map::{Entry, HashMap}, panic::AssertUnwindSafe}; /// The Substrate Wasm runtime. pub trait WasmRuntime { @@ -40,12 +40,6 @@ pub trait WasmRuntime { /// Call a method in the Substrate runtime by name. Returns the encoded result on success. fn call(&mut self, ext: &mut dyn Externalities, method: &str, data: &[u8]) -> Result, Error>; - - /// Returns the version of this runtime. - /// - /// Returns `None` if the runtime doesn't provide the information or there was an error - /// while fetching it. - fn version(&self) -> Option; } /// Specification of different methods of executing the runtime Wasm code. @@ -58,6 +52,13 @@ pub enum WasmExecutionMethod { Compiled, } +/// A Wasm runtime object along with its cached runtime version. +struct VersionedRuntime { + runtime: Box, + /// Runtime version according to `Core_version`. + version: RuntimeVersion, +} + /// Cache for the runtimes. /// /// When an instance is requested for the first time it is added to this cache. Metadata is kept @@ -74,7 +75,7 @@ pub struct RuntimesCache { /// A cache of runtime instances along with metadata, ready to be reused. /// /// Instances are keyed by the Wasm execution method and the hash of their code. - instances: HashMap<(WasmExecutionMethod, [u8; 32]), Result, WasmError>>, + instances: HashMap<(WasmExecutionMethod, [u8; 32]), Result>, } impl RuntimesCache { @@ -97,8 +98,7 @@ impl RuntimesCache { /// # Parameters /// /// `ext` - Externalities to use for the runtime. This is used for setting - /// up an initial runtime instance. The parameter is only needed for calling - /// into the Wasm module to find out the `Core_version`. + /// up an initial runtime instance. /// /// `default_heap_pages` - Number of 64KB pages to allocate for Wasm execution. /// @@ -118,7 +118,7 @@ impl RuntimesCache { ext: &mut E, wasm_method: WasmExecutionMethod, default_heap_pages: u64, - ) -> Result<(&mut (dyn WasmRuntime + 'static), H256), Error> { + ) -> Result<(&mut (dyn WasmRuntime + 'static), &RuntimeVersion, H256), Error> { let code_hash = ext .original_storage_hash(well_known_keys::CODE) .ok_or(Error::InvalidCode("`CODE` not found in storage.".into()))?; @@ -132,12 +132,12 @@ impl RuntimesCache { Entry::Occupied(o) => { let result = o.into_mut(); if let Ok(ref mut cached_runtime) = result { - if !cached_runtime.update_heap_pages(heap_pages) { + if !cached_runtime.runtime.update_heap_pages(heap_pages) { trace!( target: "runtimes_cache", "heap_pages were changed. Reinstantiating the instance", ); - *result = create_wasm_runtime(ext, wasm_method, heap_pages); + *result = create_versioned_wasm_runtime(ext, wasm_method, heap_pages); if let Err(ref err) = result { warn!(target: "runtimes_cache", "cannot create a runtime: {:?}", err); } @@ -147,7 +147,7 @@ impl RuntimesCache { }, Entry::Vacant(v) => { trace!(target: "runtimes_cache", "no instance found in cache, creating now."); - let result = create_wasm_runtime(ext, wasm_method, heap_pages); + let result = create_versioned_wasm_runtime(ext, wasm_method, heap_pages); if let Err(ref err) = result { warn!(target: "runtimes_cache", "cannot create a runtime: {:?}", err); } @@ -156,7 +156,7 @@ impl RuntimesCache { }; result.as_mut() - .map(|runtime| (runtime.as_mut(), code_hash)) + .map(|entry| (entry.runtime.as_mut(), &entry.version, code_hash)) .map_err(|ref e| Error::InvalidCode(format!("{:?}", e))) } @@ -176,30 +176,51 @@ impl RuntimesCache { } /// Create a wasm runtime with the given `code`. -pub fn create_wasm_runtime_with_code( - ext: &mut E, +pub fn create_wasm_runtime_with_code( wasm_method: WasmExecutionMethod, heap_pages: u64, code: &[u8], ) -> Result, WasmError> { match wasm_method { WasmExecutionMethod::Interpreted => - wasmi_execution::create_instance(ext, code, heap_pages) + wasmi_execution::create_instance(code, heap_pages) .map(|runtime| -> Box { Box::new(runtime) }), #[cfg(feature = "wasmtime")] WasmExecutionMethod::Compiled => - wasmtime::create_instance(ext, code, heap_pages) + wasmtime::create_instance(code, heap_pages) .map(|runtime| -> Box { Box::new(runtime) }), } } -fn create_wasm_runtime( +fn create_versioned_wasm_runtime( ext: &mut E, wasm_method: WasmExecutionMethod, heap_pages: u64, -) -> Result, WasmError> { +) -> Result { let code = ext .original_storage(well_known_keys::CODE) .ok_or(WasmError::CodeNotFound)?; - create_wasm_runtime_with_code(ext, wasm_method, heap_pages, &code) + let mut runtime = create_wasm_runtime_with_code(wasm_method, heap_pages, &code)?; + + // Call to determine runtime version. + let version_result = { + // `ext` is already implicitly handled as unwind safe, as we store it in a global variable. + let mut ext = AssertUnwindSafe(ext); + + // The following unwind safety assertion is OK because if the method call panics, the + // runtime will be dropped. + let mut runtime = AssertUnwindSafe(runtime.as_mut()); + crate::native_executor::safe_call( + move || runtime.call(&mut **ext, "Core_version", &[]) + ).map_err(|_| WasmError::Instantiation("panic in call to get runtime version".into()))? + }; + let encoded_version = version_result + .map_err(|e| WasmError::Instantiation(format!("failed to call \"Core_version\": {}", e)))?; + let version = RuntimeVersion::decode(&mut encoded_version.as_slice()) + .map_err(|_| WasmError::Instantiation("failed to decode \"Core_version\" result".into()))?; + + Ok(VersionedRuntime { + runtime, + version, + }) } diff --git a/core/executor/src/wasmi_execution.rs b/core/executor/src/wasmi_execution.rs index b6af30b7ee..dcd6ae8909 100644 --- a/core/executor/src/wasmi_execution.rs +++ b/core/executor/src/wasmi_execution.rs @@ -16,7 +16,7 @@ //! Implementation of a Wasm runtime using the Wasmi interpreter. -use std::{str, mem, panic::AssertUnwindSafe}; +use std::{str, mem}; use wasmi::{ Module, ModuleInstance, MemoryInstance, MemoryRef, TableRef, ImportsBuilder, ModuleRef, memory_units::Pages, RuntimeValue::{I32, I64, self}, @@ -31,7 +31,6 @@ use crate::wasm_utils::interpret_runtime_api_result; use crate::wasm_runtime::WasmRuntime; use log::trace; use parity_wasm::elements::{deserialize_buffer, DataSegment, Instruction, Module as RawModule}; -use runtime_version::RuntimeVersion; use wasm_interface::{ FunctionContext, HostFunctions, Pointer, WordSize, Sandbox, MemoryId, Result as WResult, }; @@ -553,15 +552,11 @@ impl StateSnapshot { } } -/// A runtime along with its version and initial state snapshot. +/// A runtime along with its initial state snapshot. #[derive(Clone)] pub struct WasmiRuntime { /// A wasm module instance. instance: ModuleRef, - /// Runtime version according to `Core_version`. - /// - /// Can be `None` if the runtime doesn't expose this function. - version: Option, /// The snapshot of the instance's state taken just after the instantiation. state_snapshot: StateSnapshot, } @@ -595,15 +590,9 @@ impl WasmRuntime for WasmiRuntime { call_in_wasm_module(ext, module, method, data) }) } - - fn version(&self) -> Option { - self.version.clone() - } } -pub fn create_instance(ext: &mut E, code: &[u8], heap_pages: u64) - -> Result -{ +pub fn create_instance(code: &[u8], heap_pages: u64) -> Result { let module = Module::from_buffer(&code).map_err(|_| WasmError::InvalidModule)?; // Extract the data segments from the wasm code. @@ -625,18 +614,8 @@ pub fn create_instance(ext: &mut E, code: &[u8], heap_pages: u ", ); - let mut ext = AssertUnwindSafe(ext); - let call_instance = AssertUnwindSafe(&instance); - let version_result = crate::native_executor::safe_call( - move || call_in_wasm_module(&mut **ext, *call_instance, "Core_version", &[]) - ).map_err(|_| WasmError::Instantiation("panic in call to get runtime version".to_string()))?; - let version = version_result - .ok() - .and_then(|v| RuntimeVersion::decode(&mut v.as_slice()).ok()); - Ok(WasmiRuntime { instance, - version, state_snapshot, }) } diff --git a/core/executor/src/wasmtime/runtime.rs b/core/executor/src/wasmtime/runtime.rs index fa360773fb..da668e9c30 100644 --- a/core/executor/src/wasmtime/runtime.rs +++ b/core/executor/src/wasmtime/runtime.rs @@ -23,9 +23,8 @@ use crate::wasm_utils::interpret_runtime_api_result; use crate::wasmtime::function_executor::FunctionExecutorState; use crate::wasmtime::trampoline::{EnvState, make_trampoline}; use crate::wasmtime::util::{cranelift_ir_signature, read_memory_into, write_memory_from}; -use crate::{Externalities, RuntimeVersion}; +use crate::Externalities; -use codec::Decode; use cranelift_codegen::ir; use cranelift_codegen::isa::TargetIsa; use cranelift_entity::{EntityRef, PrimaryMap}; @@ -34,7 +33,6 @@ use cranelift_wasm::DefinedFuncIndex; use std::cell::RefCell; use std::collections::HashMap; use std::convert::TryFrom; -use std::panic::AssertUnwindSafe; use std::rc::Rc; use wasm_interface::{HostFunctions, Pointer, WordSize}; use wasmtime_environ::{Module, translate_signature}; @@ -51,7 +49,6 @@ pub struct WasmtimeRuntime { context: Context, max_heap_pages: Option, heap_pages: u32, - version: Option, } impl WasmRuntime for WasmtimeRuntime { @@ -75,18 +72,14 @@ impl WasmRuntime for WasmtimeRuntime { self.heap_pages, ) } - - fn version(&self) -> Option { - self.version.clone() - } } /// Create a new `WasmtimeRuntime` given the code. This function performs translation from Wasm to /// machine code, which can be computationally heavy. -pub fn create_instance(ext: &mut E, code: &[u8], heap_pages: u64) +pub fn create_instance(code: &[u8], heap_pages: u64) -> std::result::Result { - let (mut compiled_module, mut context) = create_compiled_unit(code)?; + let (compiled_module, context) = create_compiled_unit(code)?; // Inspect the module for the min and max memory sizes. let (min_memory_size, max_memory_size) = { @@ -105,38 +98,11 @@ pub fn create_instance(ext: &mut E, code: &[u8], heap_pages: u let heap_pages = heap_pages_valid(heap_pages, max_heap_pages) .ok_or_else(|| WasmError::InvalidHeapPages)?; - // Call to determine runtime version. - let version_result = { - // `ext` is already implicitly handled as unwind safe, as we store it in a global variable. - let mut ext = AssertUnwindSafe(ext); - - // The following unwind safety assertions are OK because if the method call panics, the - // context and compiled module will be dropped. - let mut context = AssertUnwindSafe(&mut context); - let mut compiled_module = AssertUnwindSafe(&mut compiled_module); - crate::native_executor::safe_call(move || { - call_method( - &mut **context, - &mut **compiled_module, - &mut **ext, - "Core_version", - &[], - heap_pages - ) - }).map_err(|_| { - WasmError::Instantiation("panic in call to get runtime version".to_string()) - })? - }; - let version = version_result - .ok() - .and_then(|v| RuntimeVersion::decode(&mut v.as_slice()).ok()); - Ok(WasmtimeRuntime { module: compiled_module, context, max_heap_pages, heap_pages, - version, }) } -- GitLab From d556560026c3e4c273078c23028210986f21ec93 Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Fri, 1 Nov 2019 18:51:06 +0100 Subject: [PATCH 165/167] Move config path generation into the service config for reusability (#3978) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Move config path generation into the service config for reusability * Make NoCostum Default and fix tests * Apply suggestions from code review Co-Authored-By: Bastian Köcher * remove function not used anymore * Make path into an option * remove database_path function and call it directly * remove helper functions, use consts --- core/cli/src/lib.rs | 111 ++++++++++++----------------------- core/cli/src/params.rs | 2 +- core/service/src/builder.rs | 10 +++- core/service/src/config.rs | 25 ++++++-- core/service/test/src/lib.rs | 3 +- node-template/src/cli.rs | 2 +- node/cli/src/browser.rs | 2 +- node/cli/src/cli.rs | 2 +- 8 files changed, 71 insertions(+), 86 deletions(-) diff --git a/core/cli/src/lib.rs b/core/cli/src/lib.rs index 4638db8993..e445addf5d 100644 --- a/core/cli/src/lib.rs +++ b/core/cli/src/lib.rs @@ -65,6 +65,13 @@ use lazy_static::lazy_static; use futures::Future; use substrate_telemetry::TelemetryEndpoints; +/// default sub directory to store network config +const DEFAULT_NETWORK_CONFIG_PATH : &'static str = "network"; +/// default sub directory to store database +const DEFAULT_DB_CONFIG_PATH : &'static str = "db"; +/// default sub directory for the key store +const DEFAULT_KEYSTORE_CONFIG_PATH : &'static str = "keystore"; + /// The maximum number of characters for a node name. const NODE_NAME_MAX_LENGTH: usize = 32; @@ -307,18 +314,36 @@ pub struct ParseAndPrepareBuildSpec<'a> { impl<'a> ParseAndPrepareBuildSpec<'a> { /// Runs the command and build the chain specs. - pub fn run( + pub fn run( self, spec_factory: S ) -> error::Result<()> where S: FnOnce(&str) -> Result>, String>, + C: Default, G: RuntimeGenesis, E: ChainSpecExtension, { info!("Building chain spec"); let raw_output = self.params.raw; let mut spec = load_spec(&self.params.shared_params, spec_factory)?; - with_default_boot_node(&mut spec, self.params, self.version)?; + + if spec.boot_nodes().is_empty() && !self.params.disable_default_bootnode { + let base_path = base_path(&self.params.shared_params, self.version); + let cfg = service::Configuration::::default_with_spec_and_base_path(spec.clone(), Some(base_path)); + let node_key = node_key_config( + self.params.node_key_params, + &Some(cfg.in_chain_config_dir(DEFAULT_NETWORK_CONFIG_PATH).expect("We provided a base_path")) + )?; + let keys = node_key.into_keypair()?; + let peer_id = keys.public().into_peer_id(); + let addr = build_multiaddr![ + Ip4([127, 0, 0, 1]), + Tcp(30333u16), + P2p(peer_id) + ]; + spec.add_boot_node(addr) + } + let json = service::chain_ops::build_spec(spec, raw_output)?; print!("{}", json); @@ -558,16 +583,13 @@ fn fill_transaction_pool_configuration( /// Fill the given `NetworkConfiguration` by looking at the cli parameters. fn fill_network_configuration( cli: NetworkConfigurationParams, - base_path: &Path, - chain_spec_id: &str, + config_path: PathBuf, config: &mut NetworkConfiguration, client_id: String, is_dev: bool, ) -> error::Result<()> { config.boot_nodes.extend(cli.bootnodes.into_iter()); - config.config_path = Some( - network_path(&base_path, chain_spec_id).to_string_lossy().into() - ); + config.config_path = Some(config_path.to_string_lossy().into()); config.net_config_path = config.config_path.clone(); config.reserved_nodes.extend(cli.reserved_nodes.into_iter()); @@ -642,7 +664,8 @@ where S: FnOnce(&str) -> Result>, String>, { let spec = load_spec(&cli.shared_params, spec_factory)?; - let mut config = service::Configuration::default_with_spec(spec.clone()); + let base_path = base_path(&cli.shared_params, &version); + let mut config = service::Configuration::default_with_spec_and_base_path(spec.clone(), Some(base_path)); fill_config_keystore_password(&mut config, &cli)?; @@ -666,14 +689,10 @@ where )? } - let base_path = base_path(&cli.shared_params, version); - - config.keystore_path = cli.keystore_path.unwrap_or_else( - || keystore_path(&base_path, config.chain_spec.id()) - ); + config.keystore_path = cli.keystore_path.or_else(|| config.in_chain_config_dir(DEFAULT_KEYSTORE_CONFIG_PATH)); config.database = DatabaseConfig::Path { - path: db_path(&base_path, config.chain_spec.id()), + path: config.in_chain_config_dir(DEFAULT_DB_CONFIG_PATH).expect("We provided a base_path."), cache_size: cli.database_cache_size, }; config.state_cache_size = cli.state_cache_size; @@ -740,8 +759,7 @@ where let client_id = config.client_id(); fill_network_configuration( cli.network_config, - &base_path, - spec.id(), + config.in_chain_config_dir(DEFAULT_NETWORK_CONFIG_PATH).expect("We provided a basepath"), &mut config.network, client_id, is_dev, @@ -792,39 +810,6 @@ where Ok(config) } -// -// IANA unassigned port ranges that we could use: -// 6717-6766 Unassigned -// 8504-8553 Unassigned -// 9556-9591 Unassigned -// 9803-9874 Unassigned -// 9926-9949 Unassigned - -fn with_default_boot_node( - spec: &mut ChainSpec, - cli: BuildSpecCmd, - version: &VersionInfo, -) -> error::Result<()> -where - G: RuntimeGenesis, - E: ChainSpecExtension, -{ - if spec.boot_nodes().is_empty() && !cli.disable_default_bootnode { - let base_path = base_path(&cli.shared_params, version); - let storage_path = network_path(&base_path, spec.id()); - let node_key = node_key_config(cli.node_key_params, &Some(storage_path))?; - let keys = node_key.into_keypair()?; - let peer_id = keys.public().into_peer_id(); - let addr = build_multiaddr![ - Ip4([127, 0, 0, 1]), - Tcp(30333u16), - P2p(peer_id) - ]; - spec.add_boot_node(addr) - } - Ok(()) -} - /// Creates a configuration including the database path. pub fn create_config_with_db_path( spec_factory: S, cli: &SharedParams, version: &VersionInfo, @@ -838,9 +823,9 @@ where let spec = load_spec(cli, spec_factory)?; let base_path = base_path(cli, version); - let mut config = service::Configuration::default_with_spec(spec.clone()); + let mut config = service::Configuration::default_with_spec_and_base_path(spec.clone(), Some(base_path)); config.database = DatabaseConfig::Path { - path: db_path(&base_path, spec.id()), + path: config.in_chain_config_dir(DEFAULT_DB_CONFIG_PATH).expect("We provided a base_path."), cache_size: None, }; @@ -866,30 +851,6 @@ fn parse_address( Ok(address) } -fn keystore_path(base_path: &Path, chain_id: &str) -> PathBuf { - let mut path = base_path.to_owned(); - path.push("chains"); - path.push(chain_id); - path.push("keystore"); - path -} - -fn db_path(base_path: &Path, chain_id: &str) -> PathBuf { - let mut path = base_path.to_owned(); - path.push("chains"); - path.push(chain_id); - path.push("db"); - path -} - -fn network_path(base_path: &Path, chain_id: &str) -> PathBuf { - let mut path = base_path.to_owned(); - path.push("chains"); - path.push(chain_id); - path.push("network"); - path -} - fn init_logger(pattern: &str) { use ansi_term::Colour; diff --git a/core/cli/src/params.rs b/core/cli/src/params.rs index cac6cc1079..d0a2352416 100644 --- a/core/cli/src/params.rs +++ b/core/cli/src/params.rs @@ -854,7 +854,7 @@ impl GetLogFilter for CoreParams where CC: GetLogFilter { /// A special commandline parameter that expands to nothing. /// Should be used as custom subcommand/run arguments if no custom values are required. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Default)] pub struct NoCustom {} impl StructOpt for NoCustom { diff --git a/core/service/src/builder.rs b/core/service/src/builder.rs index a9a85faab2..03db6e385b 100644 --- a/core/service/src/builder.rs +++ b/core/service/src/builder.rs @@ -155,7 +155,10 @@ where TGen: RuntimeGenesis, TCSExt: Extension { (), TFullBackend, >, Error> { - let keystore = Keystore::open(config.keystore_path.clone(), config.keystore_password.clone())?; + let keystore = Keystore::open( + config.keystore_path.clone().ok_or("No basepath configured")?, + config.keystore_password.clone() + )?; let executor = NativeExecutor::::new( config.wasm_method, @@ -236,7 +239,10 @@ where TGen: RuntimeGenesis, TCSExt: Extension { (), TLightBackend, >, Error> { - let keystore = Keystore::open(config.keystore_path.clone(), config.keystore_password.clone())?; + let keystore = Keystore::open( + config.keystore_path.clone().ok_or("No basepath configured")?, + config.keystore_password.clone() + )?; let executor = NativeExecutor::::new( config.wasm_method, diff --git a/core/service/src/config.rs b/core/service/src/config.rs index 21acae3cab..e9f002c21f 100644 --- a/core/service/src/config.rs +++ b/core/service/src/config.rs @@ -43,8 +43,10 @@ pub struct Configuration { pub transaction_pool: transaction_pool::txpool::Options, /// Network configuration. pub network: NetworkConfiguration, + /// Path to the base configuration directory. + pub config_dir: Option, /// Path to key files. - pub keystore_path: PathBuf, + pub keystore_path: Option, /// Configuration for the database. pub database: DatabaseConfig, /// Size of internal state cache in Bytes @@ -118,18 +120,19 @@ impl Configuration where G: RuntimeGenesis, E: Extension, { - /// Create default config for given chain spec. - pub fn default_with_spec(chain_spec: ChainSpec) -> Self { + /// Create a default config for given chain spec and path to configuration dir + pub fn default_with_spec_and_base_path(chain_spec: ChainSpec, config_dir: Option) -> Self { let mut configuration = Configuration { impl_name: "parity-substrate", impl_version: "0.0.0", impl_commit: "", chain_spec, + config_dir: config_dir.clone(), name: Default::default(), roles: Roles::FULL, transaction_pool: Default::default(), network: Default::default(), - keystore_path: Default::default(), + keystore_path: config_dir.map(|c| c.join("keystore")), database: DatabaseConfig::Path { path: Default::default(), cache_size: Default::default(), @@ -161,6 +164,9 @@ impl Configuration where configuration } +} + +impl Configuration { /// Returns full version string of this configuration. pub fn full_version(&self) -> String { full_version_from_strs(self.impl_version, self.impl_commit) @@ -170,6 +176,17 @@ impl Configuration where pub fn client_id(&self) -> String { format!("{}/v{}", self.impl_name, self.full_version()) } + + /// Generate a PathBuf to sub in the chain configuration directory + /// if given + pub fn in_chain_config_dir(&self, sub: &str) -> Option { + self.config_dir.clone().map(|mut path| { + path.push("chains"); + path.push(self.chain_spec.id()); + path.push(sub); + path + }) + } } /// Returns platform info diff --git a/core/service/test/src/lib.rs b/core/service/test/src/lib.rs index 27f03e0963..c147f80510 100644 --- a/core/service/test/src/lib.rs +++ b/core/service/test/src/lib.rs @@ -169,8 +169,9 @@ fn node_config ( roles: role, transaction_pool: Default::default(), network: network_config, - keystore_path: root.join("key"), + keystore_path: Some(root.join("key")), keystore_password: None, + config_dir: Some(root.clone()), database: DatabaseConfig::Path { path: root.join("db"), cache_size: None diff --git a/node-template/src/cli.rs b/node-template/src/cli.rs index ceb51504e2..ec463a236b 100644 --- a/node-template/src/cli.rs +++ b/node-template/src/cli.rs @@ -39,7 +39,7 @@ pub fn run(args: I, exit: E, version: VersionInfo) -> error::Result<()> ), } }), - ParseAndPrepare::BuildSpec(cmd) => cmd.run(load_spec), + ParseAndPrepare::BuildSpec(cmd) => cmd.run::(load_spec), ParseAndPrepare::ExportBlocks(cmd) => cmd.run_with_builder(|config: Config<_>| Ok(new_full_start!(config).0), load_spec, exit), ParseAndPrepare::ImportBlocks(cmd) => cmd.run_with_builder(|config: Config<_>| diff --git a/node/cli/src/browser.rs b/node/cli/src/browser.rs index 1c84efa107..702d67b55a 100644 --- a/node/cli/src/browser.rs +++ b/node/cli/src/browser.rs @@ -39,7 +39,7 @@ fn start_inner(wasm_ext: wasm_ext::ffi::Transport) -> Result::default_with_spec(chain_spec); + let mut config = Configuration::<(), _, _>::default_with_spec_and_base_path(chain_spec, None); config.network.transport = network::config::TransportConfig::Normal { wasm_external_transport: Some(wasm_ext.clone()), enable_mdns: false, diff --git a/node/cli/src/cli.rs b/node/cli/src/cli.rs index 2e5d27cec7..4bddb50b4b 100644 --- a/node/cli/src/cli.rs +++ b/node/cli/src/cli.rs @@ -131,7 +131,7 @@ pub fn run(args: I, exit: E, version: substrate_cli::VersionInfo) -> er ), } }), - ParseAndPrepare::BuildSpec(cmd) => cmd.run(load_spec), + ParseAndPrepare::BuildSpec(cmd) => cmd.run::(load_spec), ParseAndPrepare::ExportBlocks(cmd) => cmd.run_with_builder(|config: Config<_, _>| Ok(new_full_start!(config).0), load_spec, exit), ParseAndPrepare::ImportBlocks(cmd) => cmd.run_with_builder(|config: Config<_, _>| -- GitLab From 17aab52ac70b67719b636c16148fef3be9582383 Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Fri, 1 Nov 2019 19:32:01 +0100 Subject: [PATCH 166/167] expose offchain worker storage prefix (#3977) * expose offchain worker storage prefix * add docs * move STORAGE_PREFIX to primitives --- core/offchain/primitives/src/lib.rs | 3 +++ core/offchain/src/api.rs | 2 +- core/offchain/src/lib.rs | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/core/offchain/primitives/src/lib.rs b/core/offchain/primitives/src/lib.rs index dda08ae43f..79fed8cb34 100644 --- a/core/offchain/primitives/src/lib.rs +++ b/core/offchain/primitives/src/lib.rs @@ -22,6 +22,9 @@ use client::decl_runtime_apis; use sr_primitives::traits::NumberFor; +/// Local Storage Prefix used by the Offchain Worker API to +pub const STORAGE_PREFIX: &[u8] = b"storage"; + decl_runtime_apis! { /// The offchain worker api. pub trait OffchainWorkerApi { diff --git a/core/offchain/src/api.rs b/core/offchain/src/api.rs index 35b6e20df2..b4d55e5f06 100644 --- a/core/offchain/src/api.rs +++ b/core/offchain/src/api.rs @@ -30,6 +30,7 @@ use primitives::offchain::{ Externalities as OffchainExt, HttpRequestId, Timestamp, HttpRequestStatus, HttpError, OpaqueNetworkState, OpaquePeerId, OpaqueMultiaddr, StorageKind, }; +pub use offchain_primitives::STORAGE_PREFIX; use sr_primitives::{generic::BlockId, traits::{self, Extrinsic}}; use transaction_pool::txpool::{Pool, ChainApi}; @@ -71,7 +72,6 @@ fn unavailable_yet(name: &str) -> R { } const LOCAL_DB: &str = "LOCAL (fork-aware) DB"; -const STORAGE_PREFIX: &[u8] = b"storage"; impl OffchainExt for Api where diff --git a/core/offchain/src/lib.rs b/core/offchain/src/lib.rs index a335ca5380..6914729589 100644 --- a/core/offchain/src/lib.rs +++ b/core/offchain/src/lib.rs @@ -53,7 +53,7 @@ mod api; pub mod testing; -pub use offchain_primitives::OffchainWorkerApi; +pub use offchain_primitives::{OffchainWorkerApi, STORAGE_PREFIX}; /// An offchain workers manager. pub struct OffchainWorkers { -- GitLab From ec7c6cf1779b88e75137ef6f6f7bf67ecd0f75a5 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Fri, 1 Nov 2019 22:22:37 +0100 Subject: [PATCH 167/167] Optional serde for phragmen support (#3994) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add serde to phragmen * Update lock file * and bump a version * and bump a version again * Apply suggestions from code review Co-Authored-By: Bastian Köcher * revert impl-tarit for tuple update * revert session. * Revert "revert session." This reverts commit 98086c9db56677068db85f74320868b2c10d1c00. * Revert "revert impl-tarit for tuple update" This reverts commit 28a7fddee2e09c5785b19883f743065e0be8f331. --- Cargo.lock | 1 + core/chain-spec/Cargo.toml | 2 +- core/phragmen/Cargo.toml | 4 +++- core/phragmen/src/lib.rs | 1 + core/sr-primitives/Cargo.toml | 2 +- srml/authorship/Cargo.toml | 2 +- srml/finality-tracker/Cargo.toml | 2 +- srml/support/Cargo.toml | 2 +- srml/system/Cargo.toml | 2 +- srml/timestamp/Cargo.toml | 2 +- 10 files changed, 12 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e002312288..897a0701f9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5748,6 +5748,7 @@ name = "substrate-phragmen" version = "2.0.0" dependencies = [ "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 2.0.0", "sr-primitives 2.0.0", "sr-std 2.0.0", diff --git a/core/chain-spec/Cargo.toml b/core/chain-spec/Cargo.toml index b4d9d004e4..1ab78a18dd 100644 --- a/core/chain-spec/Cargo.toml +++ b/core/chain-spec/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" [dependencies] substrate-chain-spec-derive = { path = "./derive" } -impl-trait-for-tuples = "0.1.2" +impl-trait-for-tuples = "0.1.3" network = { package = "substrate-network", path = "../../core/network" } primitives = { package = "substrate-primitives", path = "../primitives" } serde = { version = "1.0.101", features = ["derive"] } diff --git a/core/phragmen/Cargo.toml b/core/phragmen/Cargo.toml index e10be1d92d..5ee6d3b3c2 100644 --- a/core/phragmen/Cargo.toml +++ b/core/phragmen/Cargo.toml @@ -5,8 +5,9 @@ authors = ["Parity Technologies "] edition = "2018" [dependencies] -sr-primitives = { path = "../sr-primitives", default-features = false } +serde = { version = "1.0.101", optional = true, features = ["derive"] } rstd = { package = "sr-std", path = "../sr-std", default-features = false } +sr-primitives = { path = "../sr-primitives", default-features = false } [dev-dependencies] runtime-io ={ package = "sr-io", path = "../sr-io" } @@ -16,6 +17,7 @@ rand = "0.7.2" [features] default = ["std"] std = [ + "serde", "rstd/std", "sr-primitives/std", ] diff --git a/core/phragmen/src/lib.rs b/core/phragmen/src/lib.rs index 8c8401bed6..a4287773b5 100644 --- a/core/phragmen/src/lib.rs +++ b/core/phragmen/src/lib.rs @@ -116,6 +116,7 @@ pub struct PhragmenResult { /// This, at the current version, resembles the `Exposure` defined in the staking SRML module, yet /// they do not necessarily have to be the same. #[derive(Default, RuntimeDebug)] +#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] pub struct Support { /// The amount of support as the effect of self-vote. pub own: ExtendedBalance, diff --git a/core/sr-primitives/Cargo.toml b/core/sr-primitives/Cargo.toml index d330301426..1b1434b919 100644 --- a/core/sr-primitives/Cargo.toml +++ b/core/sr-primitives/Cargo.toml @@ -15,7 +15,7 @@ runtime_io = { package = "sr-io", path = "../sr-io", default-features = false } log = { version = "0.4.8", optional = true } paste = "0.1.6" rand = { version = "0.7.2", optional = true } -impl-trait-for-tuples = "0.1.2" +impl-trait-for-tuples = "0.1.3" [dev-dependencies] serde_json = "1.0.41" diff --git a/srml/authorship/Cargo.toml b/srml/authorship/Cargo.toml index e860be2f64..a59976c699 100644 --- a/srml/authorship/Cargo.toml +++ b/srml/authorship/Cargo.toml @@ -14,7 +14,7 @@ sr-primitives = { path = "../../core/sr-primitives", default-features = false } support = { package = "srml-support", path = "../support", default-features = false } system = { package = "srml-system", path = "../system", default-features = false } runtime-io ={ package = "sr-io", path = "../../core/sr-io", default-features = false } -impl-trait-for-tuples = "0.1.2" +impl-trait-for-tuples = "0.1.3" [features] default = ["std"] diff --git a/srml/finality-tracker/Cargo.toml b/srml/finality-tracker/Cargo.toml index 7e3439e0fe..a881b2906f 100644 --- a/srml/finality-tracker/Cargo.toml +++ b/srml/finality-tracker/Cargo.toml @@ -12,7 +12,7 @@ rstd = { package = "sr-std", path = "../../core/sr-std", default-features = fals sr-primitives = { path = "../../core/sr-primitives", default-features = false } support = { package = "srml-support", path = "../support", default-features = false } srml-system = { path = "../system", default-features = false } -impl-trait-for-tuples = "0.1.2" +impl-trait-for-tuples = "0.1.3" [dev-dependencies] primitives = { package = "substrate-primitives", path = "../../core/primitives", default-features = false } diff --git a/srml/support/Cargo.toml b/srml/support/Cargo.toml index 2b8c4cb9f9..46ebebc7d3 100644 --- a/srml/support/Cargo.toml +++ b/srml/support/Cargo.toml @@ -18,7 +18,7 @@ srml-support-procedural = { package = "srml-support-procedural", path = "./proce paste = "0.1.6" once_cell = { version = "0.2.4", default-features = false, optional = true } bitmask = { version = "0.5.0", default-features = false } -impl-trait-for-tuples = "0.1.2" +impl-trait-for-tuples = "0.1.3" [dev-dependencies] pretty_assertions = "0.6.1" diff --git a/srml/system/Cargo.toml b/srml/system/Cargo.toml index a9ce6b3f8c..52570617a1 100644 --- a/srml/system/Cargo.toml +++ b/srml/system/Cargo.toml @@ -14,7 +14,7 @@ runtime-io ={ package = "sr-io", path = "../../core/sr-io", default-features = f sr-primitives = { path = "../../core/sr-primitives", default-features = false } sr-version = { path = "../../core/sr-version", default-features = false } support = { package = "srml-support", path = "../support", default-features = false } -impl-trait-for-tuples = "0.1.2" +impl-trait-for-tuples = "0.1.3" [dev-dependencies] criterion = "0.2.11" diff --git a/srml/timestamp/Cargo.toml b/srml/timestamp/Cargo.toml index 939fb72566..d8eab64f9f 100644 --- a/srml/timestamp/Cargo.toml +++ b/srml/timestamp/Cargo.toml @@ -12,7 +12,7 @@ sr-primitives = { path = "../../core/sr-primitives", default-features = false } inherents = { package = "substrate-inherents", path = "../../core/inherents", default-features = false } support = { package = "srml-support", path = "../support", default-features = false } system = { package = "srml-system", path = "../system", default-features = false } -impl-trait-for-tuples = "0.1.2" +impl-trait-for-tuples = "0.1.3" [dev-dependencies] runtime-io ={ package = "sr-io", path = "../../core/sr-io" } -- GitLab