diff --git a/polkadot/Cargo.lock b/polkadot/Cargo.lock index ce62da6696..3505bf379a 100644 --- a/polkadot/Cargo.lock +++ b/polkadot/Cargo.lock @@ -464,7 +464,7 @@ dependencies = [ "cfg-if", "clang-sys", "clap", - "env_logger", + "env_logger 0.7.1", "lazy_static", "lazycell", "log 0.4.11", @@ -1312,7 +1312,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" dependencies = [ "atty", - "humantime", + "humantime 1.3.0", + "log 0.4.11", + "regex", + "termcolor", +] + +[[package]] +name = "env_logger" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54532e3223c5af90a6a757c90b5c5521564b07e5e7a958681bcd2afad421cdcd" +dependencies = [ + "atty", + "humantime 2.0.1", "log 0.4.11", "regex", "termcolor", @@ -1454,7 +1467,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b3937f028664bd0e13df401ba49a4567ccda587420365823242977f06609ed1" dependencies = [ - "env_logger", + "env_logger 0.7.1", "log 0.4.11", ] @@ -2268,6 +2281,12 @@ dependencies = [ "quick-error", ] +[[package]] +name = "humantime" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c1ad908cc71012b7bea4d0c53ba96a8cba9962f048fa68d143376143d863b7a" + [[package]] name = "hyper" version = "0.12.35" @@ -4763,7 +4782,7 @@ version = "0.1.0" dependencies = [ "assert_matches", "bitvec", - "env_logger", + "env_logger 0.7.1", "futures 0.3.5", "futures-timer 3.0.2", "log 0.4.11", @@ -4794,7 +4813,7 @@ dependencies = [ "assert_matches", "bitvec", "derive_more 0.99.11", - "env_logger", + "env_logger 0.7.1", "futures 0.3.5", "futures-timer 3.0.2", "log 0.4.11", @@ -4848,7 +4867,7 @@ version = "0.1.0" dependencies = [ "assert_matches", "derive_more 0.99.11", - "env_logger", + "env_logger 0.7.1", "futures 0.3.5", "futures-timer 3.0.2", "log 0.4.11", @@ -4932,7 +4951,7 @@ version = "0.1.0" dependencies = [ "assert_matches", "derive_more 0.99.11", - "env_logger", + "env_logger 0.7.1", "futures 0.3.5", "futures-timer 3.0.2", "kvdb", @@ -5177,7 +5196,7 @@ dependencies = [ "assert_matches", "async-trait", "derive_more 0.99.11", - "env_logger", + "env_logger 0.7.1", "futures 0.3.5", "futures-timer 3.0.2", "log 0.4.11", @@ -5485,7 +5504,7 @@ dependencies = [ name = "polkadot-service" version = "0.8.3" dependencies = [ - "env_logger", + "env_logger 0.8.1", "frame-benchmarking", "frame-system-rpc-runtime-api", "futures 0.3.5", @@ -5506,7 +5525,7 @@ dependencies = [ "polkadot-primitives", "polkadot-rpc", "polkadot-runtime", - "polkadot-test-runtime-client", + "polkadot-test-client", "rococo-v1-runtime", "sc-authority-discovery", "sc-block-builder", @@ -5581,6 +5600,29 @@ dependencies = [ "sp-core", ] +[[package]] +name = "polkadot-test-client" +version = "0.8.25" +dependencies = [ + "parity-scale-codec", + "polkadot-primitives", + "polkadot-test-runtime", + "polkadot-test-service", + "sc-block-builder", + "sc-consensus", + "sc-service", + "sp-api", + "sp-blockchain", + "sp-consensus", + "sp-core", + "sp-inherents", + "sp-keyring", + "sp-runtime", + "sp-state-machine", + "sp-timestamp", + "substrate-test-client", +] + [[package]] name = "polkadot-test-runtime" version = "0.8.25" @@ -5640,32 +5682,9 @@ dependencies = [ "tiny-keccak 1.5.0", ] -[[package]] -name = "polkadot-test-runtime-client" -version = "2.0.0" -dependencies = [ - "futures 0.3.5", - "pallet-timestamp", - "parity-scale-codec", - "polkadot-primitives", - "polkadot-runtime-common", - "polkadot-test-runtime", - "polkadot-test-service", - "sc-block-builder", - "sc-client-api", - "sc-consensus", - "sc-light", - "sc-service", - "sp-api", - "sp-blockchain", - "sp-core", - "sp-runtime", - "substrate-test-client", -] - [[package]] name = "polkadot-test-service" -version = "0.8.2" +version = "0.8.25" dependencies = [ "frame-benchmarking", "frame-system", diff --git a/polkadot/Cargo.toml b/polkadot/Cargo.toml index 9217bd442f..2b48f30bc1 100644 --- a/polkadot/Cargo.toml +++ b/polkadot/Cargo.toml @@ -35,7 +35,6 @@ members = [ "runtime/rococo-v1", "runtime/westend", "runtime/test-runtime", - "runtime/test-runtime/client", "statement-table", "validation", "xcm", @@ -64,8 +63,8 @@ members = [ "node/subsystem", "node/subsystem-test-helpers", "node/subsystem-util", - "node/test-service", - + "node/test/client", + "node/test/service", "parachain/test-parachains", "parachain/test-parachains/adder", ] diff --git a/polkadot/node/service/Cargo.toml b/polkadot/node/service/Cargo.toml index 77040e9ed7..6029b849c6 100644 --- a/polkadot/node/service/Cargo.toml +++ b/polkadot/node/service/Cargo.toml @@ -73,9 +73,8 @@ rococo-runtime = { package = "rococo-v1-runtime", path = "../../runtime/rococo-v westend-runtime = { path = "../../runtime/westend" } [dev-dependencies] -polkadot-test-runtime-client = { path = "../../runtime/test-runtime/client" } -sc-block-builder = { git = "https://github.com/paritytech/substrate", branch = "master" } -env_logger = "0.7.0" +polkadot-test-client = { path = "../test/client" } +env_logger = "0.8.1" [features] default = ["db", "full-node"] diff --git a/polkadot/node/service/src/grandpa_support.rs b/polkadot/node/service/src/grandpa_support.rs index a683052f54..b34044469e 100644 --- a/polkadot/node/service/src/grandpa_support.rs +++ b/polkadot/node/service/src/grandpa_support.rs @@ -232,37 +232,29 @@ pub(crate) fn kusama_hard_forks() -> Vec<( #[cfg(test)] mod tests { use grandpa::VotingRule; - use polkadot_test_runtime_client::prelude::*; - use polkadot_test_runtime_client::sp_consensus::BlockOrigin; - use sc_block_builder::BlockBuilderProvider; + use polkadot_test_client::{ + TestClientBuilder, TestClientBuilderExt, DefaultTestClientBuilderExt, InitPolkadotBlockBuilder, + ClientBlockImportExt, + }; use sp_blockchain::HeaderBackend; - use sp_runtime::generic::BlockId; - use sp_runtime::traits::Header; + use sp_runtime::{generic::BlockId, traits::Header}; + use consensus_common::BlockOrigin; use std::sync::Arc; #[test] fn grandpa_pause_voting_rule_works() { let _ = env_logger::try_init(); - let client = Arc::new(polkadot_test_runtime_client::new()); + let client = Arc::new(TestClientBuilder::new().build()); let mut push_blocks = { let mut client = client.clone(); - let mut base = 0; move |n| { - for i in 0..n { - let mut builder = client.new_block(Default::default()).unwrap(); - - for extrinsic in polkadot_test_runtime_client::needed_extrinsics(base + i) { - builder.push(extrinsic).unwrap() - } - - let block = builder.build().unwrap().block; + for _ in 0..n { + let block = client.init_polkadot_block_builder().build().unwrap().block; client.import(BlockOrigin::Own, block).unwrap(); } - - base += n; } }; diff --git a/polkadot/runtime/test-runtime/client/Cargo.toml b/polkadot/node/test/client/Cargo.toml similarity index 55% rename from polkadot/runtime/test-runtime/client/Cargo.toml rename to polkadot/node/test/client/Cargo.toml index ce00e4a51d..60d5184a51 100644 --- a/polkadot/runtime/test-runtime/client/Cargo.toml +++ b/polkadot/node/test/client/Cargo.toml @@ -1,29 +1,30 @@ [package] -name = "polkadot-test-runtime-client" -version = "2.0.0" +name = "polkadot-test-client" +version = "0.8.25" authors = ["Parity Technologies "] edition = "2018" -license = "GPL-3.0" [dependencies] -futures = "0.3.1" -codec = { package = "parity-scale-codec", version = "1.3.4" } +codec = { package = "parity-scale-codec", version = "1.3.4", default-features = false, features = ["derive"] } # Polkadot dependencies +polkadot-test-runtime = { path = "../../../runtime/test-runtime" } +polkadot-test-service = { path = "../service" } polkadot-primitives = { path = "../../../primitives" } -polkadot-runtime-common = { path = "../../common" } -polkadot-test-runtime = { path = ".." } -polkadot-test-service = { path = "../../../node/test-service" } # Substrate dependencies -pallet-timestamp = { git = "https://github.com/paritytech/substrate", branch = "master" } -sc-block-builder = { git = "https://github.com/paritytech/substrate", branch = "master" } -sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "master" } -sc-consensus = { git = "https://github.com/paritytech/substrate", branch = "master" } -sc-light = { git = "https://github.com/paritytech/substrate", branch = "master" } -sc-service = { git = "https://github.com/paritytech/substrate", branch = "master", features = ["test-helpers"], default-features = false } -sp-api = { git = "https://github.com/paritytech/substrate", branch = "master" } -sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "master" } -sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } -sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" } substrate-test-client = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-service = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-block-builder = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-consensus = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-inherents = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-api = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-timestamp = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-consensus = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-state-machine = { git = "https://github.com/paritytech/substrate", branch = "master" } + +[dev-dependencies] +sp-keyring = { git = "https://github.com/paritytech/substrate", branch = "master" } diff --git a/polkadot/node/test/client/src/block_builder.rs b/polkadot/node/test/client/src/block_builder.rs new file mode 100644 index 0000000000..f377bf6c16 --- /dev/null +++ b/polkadot/node/test/client/src/block_builder.rs @@ -0,0 +1,102 @@ +// Copyright 2020 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot 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. + +// Polkadot 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 Polkadot. If not, see . + +use crate::{Client, FullBackend}; +use polkadot_test_runtime::{GetLastTimestamp, UncheckedExtrinsic}; +use polkadot_primitives::v1::Block; +use sp_runtime::generic::BlockId; +use sp_api::ProvideRuntimeApi; +use sc_block_builder::{BlockBuilderProvider, BlockBuilder}; +use sp_state_machine::BasicExternalities; +use codec::{Encode, Decode}; + +/// An extension for the test client to init a Polkadot specific block builder. +pub trait InitPolkadotBlockBuilder { + /// Init a Polkadot specific block builder that works for the test runtime. + /// + /// This will automatically create and push the inherents for you to make the block valid for the test runtime. + fn init_polkadot_block_builder(&self) -> sc_block_builder::BlockBuilder; + + /// Init a Polkadot specific block builder at a specific block that works for the test runtime. + /// + /// Same as [`InitPolkadotBlockBuilder::init_polkadot_block_builder`] besides that it takes a [`BlockId`] to say + /// which should be the parent block of the block that is being build. + fn init_polkadot_block_builder_at( + &self, + at: &BlockId, + ) -> sc_block_builder::BlockBuilder; +} + +impl InitPolkadotBlockBuilder for Client { + fn init_polkadot_block_builder( + &self, + ) -> BlockBuilder { + let chain_info = self.chain_info(); + self.init_polkadot_block_builder_at(&BlockId::Hash(chain_info.best_hash)) + } + + fn init_polkadot_block_builder_at( + &self, + at: &BlockId, + ) -> BlockBuilder { + let mut block_builder = self.new_block_at(at, Default::default(), false) + .expect("Creates new block builder for test runtime"); + + let mut inherent_data = sp_inherents::InherentData::new(); + let last_timestamp = self + .runtime_api() + .get_last_timestamp(&at) + .expect("Get last timestamp"); + + // `MinimumPeriod` is a storage parameter type that requires externalities to access the value. + let minimum_period = BasicExternalities::new_empty() + .execute_with(|| polkadot_test_runtime::MinimumPeriod::get()); + + let timestamp = last_timestamp + minimum_period; + + inherent_data + .put_data(sp_timestamp::INHERENT_IDENTIFIER, ×tamp) + .expect("Put timestamp failed"); + + let inherents = block_builder.create_inherents(inherent_data).expect("Creates inherents"); + + inherents.into_iter().for_each(|ext| block_builder.push(ext).expect("Pushes inherent")); + + block_builder + } +} + +/// Polkadot specific extensions for the [`BlockBuilder`]. +pub trait BlockBuilderExt { + /// Push a Polkadot test runtime specific extrinsic to the block. + /// + /// This will internally use the [`BlockBuilder::push`] method, but this method expects a opaque extrinsic. So, + /// we provide this wrapper which converts a test runtime specific extrinsic to a opaque extrinsic and pushes it to + /// the block. + /// + /// Returns the result of the application of the extrinsic. + fn push_polkadot_extrinsic(&mut self, ext: UncheckedExtrinsic) -> Result<(), sp_blockchain::Error>; +} + +impl BlockBuilderExt for BlockBuilder<'_, Block, Client, FullBackend> { + fn push_polkadot_extrinsic(&mut self, ext: UncheckedExtrinsic) -> Result<(), sp_blockchain::Error> { + let encoded = ext.encode(); + self.push( + Decode::decode(&mut &encoded[..]) + .expect("The runtime specific extrinsic always decodes to an opaque extrinsic; qed"), + ) + } +} diff --git a/polkadot/node/test/client/src/lib.rs b/polkadot/node/test/client/src/lib.rs new file mode 100644 index 0000000000..d3312e06ca --- /dev/null +++ b/polkadot/node/test/client/src/lib.rs @@ -0,0 +1,117 @@ +// Copyright 2020 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot 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. + +// Polkadot 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 Polkadot. If not, see . + +//! A Polkadot test client. +//! +//! This test client is using the Polkadot test runtime. + +mod block_builder; + +use polkadot_primitives::v1::Block; +use sc_service::client; +use sp_core::storage::Storage; +use sp_runtime::BuildStorage; + +pub use block_builder::*; +pub use substrate_test_client::*; +pub use polkadot_test_service::{ + Client, construct_extrinsic, construct_transfer_extrinsic, PolkadotTestExecutor, FullBackend, +}; +pub use polkadot_test_runtime as runtime; + +/// Test client executor. +pub type Executor = client::LocalCallExecutor>; + +/// Test client builder for Polkadot. +pub type TestClientBuilder = substrate_test_client::TestClientBuilder; + +/// LongestChain type for the test runtime/client. +pub type LongestChain = sc_consensus::LongestChain; + +/// Parameters of test-client builder with test-runtime. +#[derive(Default)] +pub struct GenesisParameters; + +impl substrate_test_client::GenesisInit for GenesisParameters { + fn genesis_storage(&self) -> Storage { + polkadot_test_service::chain_spec::polkadot_local_testnet_genesis() + .build_storage() + .expect("Builds test runtime genesis storage") + } +} + +/// A `test-runtime` extensions to `TestClientBuilder`. +pub trait TestClientBuilderExt: Sized { + /// Build the test client. + fn build(self) -> Client { + self.build_with_longest_chain().0 + } + + /// Build the test client and longest chain selector. + fn build_with_longest_chain(self) -> (Client, LongestChain); +} + +impl TestClientBuilderExt for TestClientBuilder { + fn build_with_longest_chain(self) -> (Client, LongestChain) { + self.build_with_native_executor(None) + } +} + +/// A `TestClientBuilder` with default backend and executor. +pub trait DefaultTestClientBuilderExt: Sized { + /// Create new `TestClientBuilder` + fn new() -> Self; +} + +impl DefaultTestClientBuilderExt for TestClientBuilder { + fn new() -> Self { + Self::with_default_backend() + } +} + +#[cfg(test)] +mod tests{ + use super::*; + use sp_consensus::BlockOrigin; + + #[test] + fn ensure_test_client_can_build_and_import_block() { + let mut client = TestClientBuilder::new().build(); + + let block_builder = client.init_polkadot_block_builder(); + let block = block_builder.build().expect("Finalizes the block").block; + + client.import(BlockOrigin::Own, block).expect("Imports the block"); + } + + #[test] + fn ensure_test_client_can_push_extrinsic() { + let mut client = TestClientBuilder::new().build(); + + let transfer = construct_transfer_extrinsic( + &client, + sp_keyring::Sr25519Keyring::Alice, + sp_keyring::Sr25519Keyring::Bob, + 1000, + ); + let mut block_builder = client.init_polkadot_block_builder(); + block_builder.push_polkadot_extrinsic(transfer).expect("Pushes extrinsic"); + + let block = block_builder.build().expect("Finalizes the block").block; + + client.import(BlockOrigin::Own, block).expect("Imports the block"); + } +} diff --git a/polkadot/node/test-service/Cargo.toml b/polkadot/node/test/service/Cargo.toml similarity index 86% rename from polkadot/node/test-service/Cargo.toml rename to polkadot/node/test/service/Cargo.toml index 4b1a0a922e..d139f470a7 100644 --- a/polkadot/node/test-service/Cargo.toml +++ b/polkadot/node/test/service/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-test-service" -version = "0.8.2" +version = "0.8.25" authors = ["Parity Technologies "] edition = "2018" @@ -13,13 +13,13 @@ rand = "0.7.3" tempfile = "3.1.0" # Polkadot dependencies -polkadot-overseer = { path = "../overseer" } -polkadot-primitives = { path = "../../primitives" } -polkadot-rpc = { path = "../../rpc" } -polkadot-runtime-common = { path = "../../runtime/common" } -polkadot-service = { path = "../service" } -polkadot-test-runtime = { path = "../../runtime/test-runtime" } -polkadot-runtime-parachains = { path = "../../runtime/parachains" } +polkadot-overseer = { path = "../../overseer" } +polkadot-primitives = { path = "../../../primitives" } +polkadot-rpc = { path = "../../../rpc" } +polkadot-runtime-common = { path = "../../../runtime/common" } +polkadot-service = { path = "../../service" } +polkadot-test-runtime = { path = "../../../runtime/test-runtime" } +polkadot-runtime-parachains = { path = "../../../runtime/parachains" } # Substrate dependencies authority-discovery = { package = "sc-authority-discovery", git = "https://github.com/paritytech/substrate", branch = "master" } @@ -32,6 +32,7 @@ grandpa = { package = "sc-finality-grandpa", git = "https://github.com/paritytec grandpa_primitives = { package = "sp-finality-grandpa", git = "https://github.com/paritytech/substrate", branch = "master" } inherents = { package = "sp-inherents", git = "https://github.com/paritytech/substrate", branch = "master" } pallet-staking = { git = "https://github.com/paritytech/substrate", branch = "master" } +pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master" } pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", branch = "master" } sc-chain-spec = { git = "https://github.com/paritytech/substrate", branch = "master" } sc-cli = { git = "https://github.com/paritytech/substrate", branch = "master" } diff --git a/polkadot/node/test-service/src/chain_spec.rs b/polkadot/node/test/service/src/chain_spec.rs similarity index 91% rename from polkadot/node/test-service/src/chain_spec.rs rename to polkadot/node/test/service/src/chain_spec.rs index 93a614b7d3..e677d0b9ac 100644 --- a/polkadot/node/test-service/src/chain_spec.rs +++ b/polkadot/node/test/service/src/chain_spec.rs @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . +//! Chain specifications for the test runtime. + use babe_primitives::AuthorityId as BabeId; use grandpa::AuthorityId as GrandpaId; use pallet_staking::Forcing; @@ -21,22 +23,22 @@ use polkadot_primitives::v0::{ValidatorId, AccountId}; use polkadot_service::chain_spec::{get_account_id_from_seed, get_from_seed, Extensions}; use polkadot_test_runtime::constants::currency::DOTS; use sc_chain_spec::{ChainSpec, ChainType}; -use sp_core::{sr25519, ChangesTrieConfiguration}; +use sp_core::sr25519; use sp_runtime::Perbill; const DEFAULT_PROTOCOL_ID: &str = "dot"; -/// The `ChainSpec parametrised for polkadot runtime`. +/// The `ChainSpec` parametrized for polkadot test runtime. pub type PolkadotChainSpec = service::GenericChainSpec; -/// Polkadot local testnet config (multivalidator Alice + Bob) +/// Local testnet config (multivalidator Alice + Bob) pub fn polkadot_local_testnet_config() -> PolkadotChainSpec { PolkadotChainSpec::from_genesis( "Local Testnet", "local_testnet", ChainType::Local, - || polkadot_local_testnet_genesis(None), + || polkadot_local_testnet_genesis(), vec![], None, Some(DEFAULT_PROTOCOL_ID), @@ -45,10 +47,8 @@ pub fn polkadot_local_testnet_config() -> PolkadotChainSpec { ) } -/// Polkadot local testnet genesis config (multivalidator Alice + Bob) -pub fn polkadot_local_testnet_genesis( - changes_trie_config: Option, -) -> polkadot_test_runtime::GenesisConfig { +/// Local testnet genesis config (multivalidator Alice + Bob) +pub fn polkadot_local_testnet_genesis() -> polkadot_test_runtime::GenesisConfig { polkadot_testnet_genesis( vec![ get_authority_keys_from_seed("Alice"), @@ -57,7 +57,6 @@ pub fn polkadot_local_testnet_genesis( ], get_account_id_from_seed::("Alice"), None, - changes_trie_config, ) } @@ -96,7 +95,6 @@ fn polkadot_testnet_genesis( initial_authorities: Vec<(AccountId, AccountId, BabeId, GrandpaId, ValidatorId)>, root_key: AccountId, endowed_accounts: Option>, - changes_trie_config: Option, ) -> polkadot_test_runtime::GenesisConfig { use polkadot_test_runtime as polkadot; @@ -108,7 +106,7 @@ fn polkadot_testnet_genesis( polkadot::GenesisConfig { frame_system: Some(polkadot::SystemConfig { code: polkadot::WASM_BINARY.expect("Wasm binary must be built for testing").to_vec(), - changes_trie_config, + ..Default::default() }), pallet_indices: Some(polkadot::IndicesConfig { indices: vec![] }), pallet_balances: Some(polkadot::BalancesConfig { diff --git a/polkadot/node/test-service/src/lib.rs b/polkadot/node/test/service/src/lib.rs similarity index 73% rename from polkadot/node/test-service/src/lib.rs rename to polkadot/node/test/service/src/lib.rs index f17ab6bca7..106e3ff724 100644 --- a/polkadot/node/test-service/src/lib.rs +++ b/polkadot/node/test/service/src/lib.rs @@ -18,20 +18,20 @@ #![warn(missing_docs)] -mod chain_spec; +pub mod chain_spec; pub use chain_spec::*; use futures::future::Future; use polkadot_overseer::OverseerHandler; -use polkadot_primitives::v1::{Block, Id as ParaId, HeadData, ValidationCode}; +use polkadot_primitives::v1::{Id as ParaId, HeadData, ValidationCode, Balance}; use polkadot_runtime_common::BlockHashCount; use polkadot_service::{ - new_full, NewFull, FullClient, AbstractClient, ClientHandle, ExecuteWithClient, + new_full, NewFull, FullClient, ClientHandle, ExecuteWithClient, }; -use polkadot_test_runtime::{Runtime, SignedExtra, SignedPayload, VERSION, ParasSudoWrapperCall}; +use polkadot_test_runtime::{Runtime, SignedExtra, SignedPayload, VERSION, ParasSudoWrapperCall, UncheckedExtrinsic}; use polkadot_runtime_parachains::paras::ParaGenesisArgs; use sc_chain_spec::ChainSpec; -use sc_client_api::{execution_extensions::ExecutionStrategies, BlockchainEvents}; +use sc_client_api::execution_extensions::ExecutionStrategies; use sc_executor::native_executor_instance; use sc_informant::OutputFormat; use sc_network::{ @@ -43,11 +43,11 @@ use service::{ error::Error as ServiceError, RpcHandlers, TaskExecutor, TaskManager, }; -use service::{BasePath, Configuration, Role, TFullBackend}; +use service::{BasePath, Configuration, Role}; use sp_arithmetic::traits::SaturatedConversion; use sp_blockchain::HeaderBackend; use sp_keyring::Sr25519Keyring; -use sp_runtime::{codec::Encode, generic}; +use sp_runtime::{codec::Encode, generic, traits::IdentifyAccount, MultiSigner}; use sp_state_machine::BasicExternalities; use std::sync::Arc; use substrate_test_client::{BlockchainEventsExt, RpcHandlersExt, RpcTransactionOutput, RpcTransactionError}; @@ -59,13 +59,18 @@ native_executor_instance!( frame_benchmarking::benchmarking::HostFunctions, ); +/// The client type being used by the test service. +pub type Client = FullClient; + +pub use polkadot_service::FullBackend; + /// Create a new Polkadot test service for a full node. #[sc_cli::prefix_logs_with(config.network.node_name.as_str())] pub fn polkadot_test_new_full( config: Configuration, authority_discovery_disabled: bool, ) -> Result< - NewFull>>, + NewFull>, ServiceError, > { new_full::( @@ -76,7 +81,7 @@ pub fn polkadot_test_new_full( } /// A wrapper for the test client that implements `ClientHandle`. -pub struct TestClient(pub Arc>); +pub struct TestClient(pub Arc); impl ClientHandle for TestClient { fn execute_with(&self, t: T) -> T::Output { @@ -195,10 +200,7 @@ pub fn run_test_node( key: Sr25519Keyring, storage_update_func: impl Fn(), boot_nodes: Vec, -) -> PolkadotTestNode< - TaskManager, - impl AbstractClient>, -> { +) -> PolkadotTestNode { let config = node_config(storage_update_func, task_executor, key, boot_nodes); let multiaddr = config.network.listen_addresses[0].clone(); let authority_discovery_disabled = true; @@ -219,11 +221,11 @@ pub fn run_test_node( } /// A Polkadot test node instance used for testing. -pub struct PolkadotTestNode { +pub struct PolkadotTestNode { /// TaskManager's instance. - pub task_manager: S, + pub task_manager: TaskManager, /// Client's instance. - pub client: Arc, + pub client: Arc, /// The overseer handler. pub overseer_handler: OverseerHandler, /// The `MultiaddrWithPeerId` to this node. This is useful if you want to pass it as "boot node" to other nodes. @@ -232,55 +234,14 @@ pub struct PolkadotTestNode { pub rpc_handlers: RpcHandlers, } -impl PolkadotTestNode -where - C: HeaderBackend, -{ - /// Send a transaction through RPCHandlers to call a function. - pub async fn call_function( +impl PolkadotTestNode { + /// Send an extrinsic to this node. + pub async fn send_extrinsic( &self, function: impl Into, caller: Sr25519Keyring, ) -> Result { - let function = function.into(); - let current_block_hash = self.client.info().best_hash; - let current_block = self.client.info().best_number.saturated_into(); - let genesis_block = self.client.hash(0).unwrap().unwrap(); - let nonce = 0; - let period = BlockHashCount::get() - .checked_next_power_of_two() - .map(|c| c / 2) - .unwrap_or(2) as u64; - let tip = 0; - let extra: SignedExtra = ( - frame_system::CheckSpecVersion::::new(), - frame_system::CheckTxVersion::::new(), - frame_system::CheckGenesis::::new(), - frame_system::CheckEra::::from(generic::Era::mortal(period, current_block)), - frame_system::CheckNonce::::from(nonce), - frame_system::CheckWeight::::new(), - pallet_transaction_payment::ChargeTransactionPayment::::from(tip), - ); - let raw_payload = SignedPayload::from_raw( - function.clone(), - extra.clone(), - ( - VERSION.spec_version, - VERSION.transaction_version, - genesis_block, - current_block_hash, - (), - (), - (), - ), - ); - let signature = raw_payload.using_encoded(|e| caller.sign(e)); - let extrinsic = polkadot_test_runtime::UncheckedExtrinsic::new_signed( - function.clone(), - polkadot_test_runtime::Address::Id(caller.public().into()), - polkadot_primitives::v0::Signature::Sr25519(signature.clone()), - extra.clone(), - ); + let extrinsic = construct_extrinsic(&*self.client, function, caller); self.rpc_handlers.send_transaction(extrinsic.into()).await } @@ -301,17 +262,76 @@ where }, ); - self.call_function(call, Sr25519Keyring::Alice).await.map(drop) + self.send_extrinsic(call, Sr25519Keyring::Alice).await.map(drop) } -} -impl PolkadotTestNode -where - C: BlockchainEvents, -{ /// Wait for `count` blocks to be imported in the node and then exit. This function will not return if no blocks /// are ever created, thus you should restrict the maximum amount of time of the test execution. pub fn wait_for_blocks(&self, count: usize) -> impl Future { self.client.wait_for_blocks(count) } } + +/// Construct an extrinsic that can be applied to the test runtime. +pub fn construct_extrinsic( + client: &Client, + function: impl Into, + caller: Sr25519Keyring, +) -> UncheckedExtrinsic { + let function = function.into(); + let current_block_hash = client.info().best_hash; + let current_block = client.info().best_number.saturated_into(); + let genesis_block = client.hash(0).unwrap().unwrap(); + let nonce = 0; + let period = BlockHashCount::get() + .checked_next_power_of_two() + .map(|c| c / 2) + .unwrap_or(2) as u64; + let tip = 0; + let extra: SignedExtra = ( + frame_system::CheckSpecVersion::::new(), + frame_system::CheckTxVersion::::new(), + frame_system::CheckGenesis::::new(), + frame_system::CheckEra::::from(generic::Era::mortal(period, current_block)), + frame_system::CheckNonce::::from(nonce), + frame_system::CheckWeight::::new(), + pallet_transaction_payment::ChargeTransactionPayment::::from(tip), + ); + let raw_payload = SignedPayload::from_raw( + function.clone(), + extra.clone(), + ( + VERSION.spec_version, + VERSION.transaction_version, + genesis_block, + current_block_hash, + (), + (), + (), + ), + ); + let signature = raw_payload.using_encoded(|e| caller.sign(e)); + UncheckedExtrinsic::new_signed( + function.clone(), + polkadot_test_runtime::Address::Id(caller.public().into()), + polkadot_primitives::v0::Signature::Sr25519(signature.clone()), + extra.clone(), + ) +} + +/// Construct a transfer extrinsic. +pub fn construct_transfer_extrinsic( + client: &Client, + origin: sp_keyring::AccountKeyring, + dest: sp_keyring::AccountKeyring, + value: Balance, +) -> UncheckedExtrinsic { + let function = polkadot_test_runtime::Call::Balances( + pallet_balances::Call::transfer( + MultiSigner::from(dest.public()).into_account().into(), + value, + ), + ); + + construct_extrinsic(client, function, origin) +} diff --git a/polkadot/node/test-service/tests/build-blocks.rs b/polkadot/node/test/service/tests/build-blocks.rs similarity index 100% rename from polkadot/node/test-service/tests/build-blocks.rs rename to polkadot/node/test/service/tests/build-blocks.rs diff --git a/polkadot/node/test-service/tests/call-function.rs b/polkadot/node/test/service/tests/call-function.rs similarity index 96% rename from polkadot/node/test-service/tests/call-function.rs rename to polkadot/node/test/service/tests/call-function.rs index af62bcf5db..184755627f 100644 --- a/polkadot/node/test-service/tests/call-function.rs +++ b/polkadot/node/test/service/tests/call-function.rs @@ -26,7 +26,7 @@ async fn call_function_actually_work(task_executor: TaskExecutor) { Default::default(), 1, )); - let output = alice.call_function(function, Bob).await.unwrap(); + let output = alice.send_extrinsic(function, Bob).await.unwrap(); let res = output.result.expect("return value expected"); let json = serde_json::from_str::(res.as_str()).expect("valid JSON"); diff --git a/polkadot/runtime/test-runtime/client/src/lib.rs b/polkadot/runtime/test-runtime/client/src/lib.rs deleted file mode 100644 index 698de3d3cf..0000000000 --- a/polkadot/runtime/test-runtime/client/src/lib.rs +++ /dev/null @@ -1,343 +0,0 @@ -// Copyright 2020 Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot 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. - -// Polkadot 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 Polkadot. If not, see . - -//! Client testing utilities. - -#![warn(missing_docs)] - -use std::sync::Arc; -use std::collections::BTreeMap; -use std::convert::TryFrom; -pub use substrate_test_client::*; -pub use polkadot_test_runtime as runtime; - -use sp_core::{ChangesTrieConfiguration, map, twox_128}; -use sp_core::storage::{ChildInfo, Storage, StorageChild}; -use polkadot_test_runtime::GenesisConfig; -use polkadot_test_service::polkadot_local_testnet_genesis; -use sp_runtime::{ - traits::{Block as BlockT, Header as HeaderT, Hash as HashT, HashFor}, - BuildStorage, -}; -use sc_consensus::LongestChain; -use sc_client_api::light::{RemoteCallRequest, RemoteBodyRequest}; -use sc_service::client::{ - genesis, Client as SubstrateClient, LocalCallExecutor -}; -use sc_light::{ - call_executor::GenesisCallExecutor, backend as light_backend, - new_light_blockchain, new_light_backend, -}; - -/// A prelude to import in tests. -pub mod prelude { - // Trait extensions - pub use super::{ClientExt, ClientBlockImportExt}; - // Client structs - pub use super::{ - TestClient, TestClientBuilder, Backend, LightBackend, - Executor, LightExecutor, LocalExecutor, NativeExecutor, WasmExecutionMethod, - }; - // Keyring - pub use super::{AccountKeyring, Sr25519Keyring}; -} - -sc_executor::native_executor_instance! { - pub LocalExecutor, - polkadot_test_runtime::api::dispatch, - polkadot_test_runtime::native_version, -} - -/// Test client database backend. -pub type Backend = substrate_test_client::Backend; - -/// Test client executor. -pub type Executor = LocalCallExecutor< - Backend, - NativeExecutor, ->; - -/// Test client light database backend. -pub type LightBackend = substrate_test_client::LightBackend; - -/// Test client light executor. -pub type LightExecutor = GenesisCallExecutor< - LightBackend, - LocalCallExecutor< - light_backend::Backend< - sc_client_db::light::LightStorage, - HashFor - >, - NativeExecutor - > ->; - -/// Parameters of test-client builder with test-runtime. -#[derive(Default)] -pub struct GenesisParameters { - changes_trie_config: Option, - extra_storage: Storage, -} - -impl GenesisParameters { - fn genesis_config(&self) -> GenesisConfig { - let config = polkadot_local_testnet_genesis(self.changes_trie_config.clone()); - config.assimilate_storage(&mut self.extra_storage.clone()).expect("Adding `system::GensisConfig` to the genesis"); - - config - } -} - -fn additional_storage_with_genesis(genesis_block: &polkadot_test_runtime::Block) -> BTreeMap, Vec> { - map![ - twox_128(&b"latest"[..]).to_vec() => genesis_block.hash().as_fixed_bytes().to_vec() - ] -} - -impl substrate_test_client::GenesisInit for GenesisParameters { - fn genesis_storage(&self) -> Storage { - use codec::Encode; - - let mut storage = self.genesis_config().build_storage().unwrap(); - - let child_roots = storage.children_default.iter().map(|(sk, child_content)| { - let state_root = <<::Header as HeaderT>::Hashing as HashT>::trie_root( - child_content.data.clone().into_iter().collect() - ); - (sk.clone(), state_root.encode()) - }); - let state_root = <<::Header as HeaderT>::Hashing as HashT>::trie_root( - storage.top.clone().into_iter().chain(child_roots).collect() - ); - let block: runtime::Block = genesis::construct_genesis_block(state_root); - storage.top.extend(additional_storage_with_genesis(&block)); - - storage - } -} - -/// A `TestClient` with `test-runtime` builder. -pub type TestClientBuilder = substrate_test_client::TestClientBuilder< - polkadot_test_runtime::Block, - E, - B, - GenesisParameters, ->; - -/// Test client type with `LocalExecutor` and generic Backend. -pub type Client = SubstrateClient< - B, - LocalCallExecutor>, - polkadot_test_runtime::Block, - polkadot_test_runtime::RuntimeApi, ->; - -/// A test client with default backend. -pub type TestClient = Client; - -/// A `TestClientBuilder` with default backend and executor. -pub trait DefaultTestClientBuilderExt: Sized { - /// Create new `TestClientBuilder` - fn new() -> Self; -} - -impl DefaultTestClientBuilderExt for TestClientBuilder { - fn new() -> Self { - Self::with_default_backend() - } -} - -/// A `test-runtime` extensions to `TestClientBuilder`. -pub trait TestClientBuilderExt: Sized { - /// Returns a mutable reference to the genesis parameters. - fn genesis_init_mut(&mut self) -> &mut GenesisParameters; - - /// Set changes trie configuration for genesis. - fn changes_trie_config(mut self, config: Option) -> Self { - self.genesis_init_mut().changes_trie_config = config; - self - } - - /// Add an extra value into the genesis storage. - /// - /// # Panics - /// - /// Panics if the key is empty. - fn add_extra_child_storage>, K: Into>, V: Into>>( - mut self, - storage_key: SK, - child_info: ChildInfo, - key: K, - value: V, - ) -> Self { - let storage_key = storage_key.into(); - let key = key.into(); - assert!(!storage_key.is_empty()); - assert!(!key.is_empty()); - self.genesis_init_mut().extra_storage.children_default - .entry(storage_key) - .or_insert_with(|| StorageChild { - data: Default::default(), - child_info: child_info.to_owned(), - }).data.insert(key, value.into()); - self - } - - /// Add an extra child value into the genesis storage. - /// - /// # Panics - /// - /// Panics if the key is empty. - fn add_extra_storage>, V: Into>>(mut self, key: K, value: V) -> Self { - let key = key.into(); - assert!(!key.is_empty()); - self.genesis_init_mut().extra_storage.top.insert(key, value.into()); - self - } - - /// Build the test client. - fn build(self) -> Client { - self.build_with_longest_chain().0 - } - - /// Build the test client and longest chain selector. - fn build_with_longest_chain(self) -> (Client, LongestChain); - - /// Build the test client and the backend. - fn build_with_backend(self) -> (Client, Arc); -} - -impl TestClientBuilderExt for TestClientBuilder< - LocalCallExecutor>, - Backend -> { - fn genesis_init_mut(&mut self) -> &mut GenesisParameters { - Self::genesis_init_mut(self) - } - - fn build_with_longest_chain(self) -> (Client, LongestChain) { - self.build_with_native_executor(None) - } - - fn build_with_backend(self) -> (Client, Arc) { - let backend = self.backend(); - (self.build_with_native_executor(None).0, backend) - } -} - -/// Type of optional fetch callback. -type MaybeFetcherCallback = Option Result + Send + Sync>>; - -/// Implementation of light client fetcher used in tests. -#[derive(Default)] -pub struct LightFetcher { - call: MaybeFetcherCallback, Vec>, - body: MaybeFetcherCallback, Vec>, -} - -impl LightFetcher { - /// Sets remote call callback. - pub fn with_remote_call( - self, - call: MaybeFetcherCallback, Vec>, - ) -> Self { - LightFetcher { - call, - body: self.body, - } - } - - /// Sets remote body callback. - pub fn with_remote_body( - self, - body: MaybeFetcherCallback, Vec>, - ) -> Self { - LightFetcher { - call: self.call, - body, - } - } -} - -/// Creates new client instance used for tests. -pub fn new() -> Client { - TestClientBuilder::new().build() -} - -/// Creates new light client instance used for tests. -pub fn new_light() -> ( - SubstrateClient< - LightBackend, - LightExecutor, - polkadot_test_runtime::Block, - polkadot_test_runtime::RuntimeApi - >, - Arc, -) { - - let storage = sc_client_db::light::LightStorage::new_test(); - let blockchain =new_light_blockchain(storage); - let backend = new_light_backend(blockchain.clone()); - let executor = new_native_executor(); - let local_call_executor = LocalCallExecutor::new( - backend.clone(), - executor, - Box::new(sp_core::testing::TaskExecutor::new()), - Default::default() - ); - let call_executor = LightExecutor::new( - backend.clone(), - local_call_executor, - ); - - ( - TestClientBuilder::with_backend(backend.clone()) - .build_with_executor(call_executor) - .0, - backend, - ) -} - -/// Creates new light client fetcher used for tests. -pub fn new_light_fetcher() -> LightFetcher { - LightFetcher::default() -} - -/// Create a new native executor. -pub fn new_native_executor() -> sc_executor::NativeExecutor { - sc_executor::NativeExecutor::new(sc_executor::WasmExecutionMethod::Interpreted, None, 8) -} - -/// Extrinsics that must be included in each block. -/// -/// The index of the block must be provided to calculate a valid timestamp for the block. The value starts at 0 and -/// should be incremented by one for every block produced. -pub fn needed_extrinsics( - i: u64, -) -> Vec { - let timestamp = std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH) - .expect("now always later than unix epoch; qed") - .as_millis() + (i * polkadot_test_runtime::constants::time::SLOT_DURATION / 2) as u128; - - vec![ - polkadot_test_runtime::UncheckedExtrinsic { - function: polkadot_test_runtime::Call::Timestamp(pallet_timestamp::Call::set( - u64::try_from(timestamp).expect("unexpected big timestamp"), - )), - signature: None, - } - ] -} diff --git a/polkadot/runtime/test-runtime/src/lib.rs b/polkadot/runtime/test-runtime/src/lib.rs index ee98b272c7..3656d3d728 100644 --- a/polkadot/runtime/test-runtime/src/lib.rs +++ b/polkadot/runtime/test-runtime/src/lib.rs @@ -104,6 +104,13 @@ pub fn native_version() -> NativeVersion { } } +sp_api::decl_runtime_apis! { + pub trait GetLastTimestamp { + /// Returns the last timestamp of a runtime. + fn get_last_timestamp() -> u64; + } +} + parameter_types! { pub const Version: RuntimeVersion = VERSION; } @@ -736,4 +743,10 @@ sp_api::impl_runtime_apis! { TransactionPayment::query_info(uxt, len) } } + + impl crate::GetLastTimestamp for Runtime { + fn get_last_timestamp() -> u64 { + Timestamp::now() + } + } }