Commit 183d971e authored by Cecile Tonglet's avatar Cecile Tonglet
Browse files

Merge commit 3f8cfb7d (conflicts)

parents 778c8756 3f8cfb7d
This diff is collapsed.
......@@ -53,6 +53,7 @@ members = [
"node/service",
"node/subsystem",
"node/test-helpers/subsystem",
"node/test-service",
"parachain/test-parachains",
"parachain/test-parachains/adder",
......
......@@ -29,7 +29,7 @@ fn prepare_good_block() -> (TestClient, Hash, u64, PeerId, IncomingBlock<Block>)
let mut client = polkadot_test_runtime_client::new();
let mut builder = client.new_block(Default::default()).unwrap();
let extrinsics = polkadot_test_runtime_client::needed_extrinsics(vec![]);
let extrinsics = polkadot_test_runtime_client::needed_extrinsics(vec![], 0);
for extrinsic in &extrinsics {
builder.push(extrinsic.clone()).unwrap();
......
......@@ -250,17 +250,21 @@ mod tests {
let mut push_blocks = {
let mut client = client.clone();
let mut base = 0;
move |n| {
for _ in 0..n {
for i in 0..n {
let mut builder = client.new_block(Default::default()).unwrap();
for extrinsic in polkadot_test_runtime_client::needed_extrinsics(vec![]) {
for extrinsic in polkadot_test_runtime_client::needed_extrinsics(vec![], base + i) {
builder.push(extrinsic).unwrap()
}
let block = builder.build().unwrap().block;
client.import(BlockOrigin::Own, block).unwrap();
}
base += n;
}
};
......
[package]
name = "polkadot-test-service"
version = "0.8.2"
authors = ["Parity Technologies <admin@parity.io>"]
edition = "2018"
[dependencies]
futures = "0.3.4"
futures01 = { package = "futures", version = "0.1.29" }
hex = "0.4"
log = "0.4.8"
rand = "0.7.3"
tempfile = "3.1.0"
# Polkadot dependencies
av_store = { package = "polkadot-availability-store", path = "../../availability-store" }
consensus = { package = "polkadot-validation", path = "../../validation" }
polkadot-network = { path = "../../network" }
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" }
# Substrate dependencies
authority-discovery = { package = "sc-authority-discovery", git = "https://github.com/paritytech/substrate", rev = "b9d96fabd2462cb42862fd0a117ed42bb98401aa" }
babe = { package = "sc-consensus-babe", git = "https://github.com/paritytech/substrate", rev = "b9d96fabd2462cb42862fd0a117ed42bb98401aa" }
babe-primitives = { package = "sp-consensus-babe", git = "https://github.com/paritytech/substrate", rev = "b9d96fabd2462cb42862fd0a117ed42bb98401aa" }
consensus_common = { package = "sp-consensus", git = "https://github.com/paritytech/substrate", rev = "b9d96fabd2462cb42862fd0a117ed42bb98401aa" }
frame-benchmarking = { git = "https://github.com/paritytech/substrate", rev = "b9d96fabd2462cb42862fd0a117ed42bb98401aa" }
frame-system = { git = "https://github.com/paritytech/substrate", rev = "b9d96fabd2462cb42862fd0a117ed42bb98401aa" }
grandpa = { package = "sc-finality-grandpa", git = "https://github.com/paritytech/substrate", rev = "b9d96fabd2462cb42862fd0a117ed42bb98401aa" }
grandpa_primitives = { package = "sp-finality-grandpa", git = "https://github.com/paritytech/substrate", rev = "b9d96fabd2462cb42862fd0a117ed42bb98401aa" }
inherents = { package = "sp-inherents", git = "https://github.com/paritytech/substrate", rev = "b9d96fabd2462cb42862fd0a117ed42bb98401aa" }
pallet-staking = { git = "https://github.com/paritytech/substrate", rev = "b9d96fabd2462cb42862fd0a117ed42bb98401aa" }
pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", rev = "b9d96fabd2462cb42862fd0a117ed42bb98401aa" }
sc-chain-spec = { git = "https://github.com/paritytech/substrate", rev = "b9d96fabd2462cb42862fd0a117ed42bb98401aa" }
sc-client-api = { git = "https://github.com/paritytech/substrate", rev = "b9d96fabd2462cb42862fd0a117ed42bb98401aa" }
sc-consensus = { git = "https://github.com/paritytech/substrate", rev = "b9d96fabd2462cb42862fd0a117ed42bb98401aa" }
sc-executor = { git = "https://github.com/paritytech/substrate", rev = "b9d96fabd2462cb42862fd0a117ed42bb98401aa" }
sc-informant = { git = "https://github.com/paritytech/substrate", rev = "b9d96fabd2462cb42862fd0a117ed42bb98401aa" }
sc-network = { git = "https://github.com/paritytech/substrate", rev = "b9d96fabd2462cb42862fd0a117ed42bb98401aa" }
sc-transaction-pool = { git = "https://github.com/paritytech/substrate", rev = "b9d96fabd2462cb42862fd0a117ed42bb98401aa" }
service = { package = "sc-service", git = "https://github.com/paritytech/substrate", rev = "b9d96fabd2462cb42862fd0a117ed42bb98401aa", default-features = false }
sp-arithmetic = { git = "https://github.com/paritytech/substrate", rev = "b9d96fabd2462cb42862fd0a117ed42bb98401aa" }
sp-blockchain = { git = "https://github.com/paritytech/substrate", rev = "b9d96fabd2462cb42862fd0a117ed42bb98401aa" }
sp-core = { git = "https://github.com/paritytech/substrate", rev = "b9d96fabd2462cb42862fd0a117ed42bb98401aa" }
sp-keyring = { git = "https://github.com/paritytech/substrate", rev = "b9d96fabd2462cb42862fd0a117ed42bb98401aa" }
sp-runtime = { git = "https://github.com/paritytech/substrate", rev = "b9d96fabd2462cb42862fd0a117ed42bb98401aa" }
sp-state-machine = { git = "https://github.com/paritytech/substrate", rev = "b9d96fabd2462cb42862fd0a117ed42bb98401aa" }
substrate-test-client = { git = "https://github.com/paritytech/substrate", rev = "b9d96fabd2462cb42862fd0a117ed42bb98401aa" }
[dev-dependencies]
pallet-balances = { git = "https://github.com/paritytech/substrate", rev = "b9d96fabd2462cb42862fd0a117ed42bb98401aa", default-features = false }
serde_json = "1.0"
tokio = { version = "0.2", features = ["macros"] }
// 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 <http://www.gnu.org/licenses/>.
use babe_primitives::AuthorityId as BabeId;
use grandpa::AuthorityId as GrandpaId;
use pallet_staking::Forcing;
use polkadot_primitives::{parachain::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_runtime::Perbill;
const DEFAULT_PROTOCOL_ID: &str = "dot";
/// The `ChainSpec parametrised for polkadot runtime`.
pub type PolkadotChainSpec =
service::GenericChainSpec<polkadot_test_runtime::GenesisConfig, Extensions>;
/// Polkadot 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),
vec![],
None,
Some(DEFAULT_PROTOCOL_ID),
None,
Default::default(),
)
}
/// Polkadot local testnet genesis config (multivalidator Alice + Bob)
pub fn polkadot_local_testnet_genesis(
changes_trie_config: Option<ChangesTrieConfiguration>,
) -> polkadot_test_runtime::GenesisConfig {
polkadot_testnet_genesis(
vec![
get_authority_keys_from_seed("Alice"),
get_authority_keys_from_seed("Bob"),
get_authority_keys_from_seed("Charlie"),
],
get_account_id_from_seed::<sr25519::Public>("Alice"),
None,
changes_trie_config,
)
}
/// Helper function to generate stash, controller and session key from seed
fn get_authority_keys_from_seed(
seed: &str,
) -> (AccountId, AccountId, BabeId, GrandpaId, ValidatorId) {
(
get_account_id_from_seed::<sr25519::Public>(&format!("{}//stash", seed)),
get_account_id_from_seed::<sr25519::Public>(seed),
get_from_seed::<BabeId>(seed),
get_from_seed::<GrandpaId>(seed),
get_from_seed::<ValidatorId>(seed),
)
}
fn testnet_accounts() -> Vec<AccountId> {
vec![
get_account_id_from_seed::<sr25519::Public>("Alice"),
get_account_id_from_seed::<sr25519::Public>("Bob"),
get_account_id_from_seed::<sr25519::Public>("Charlie"),
get_account_id_from_seed::<sr25519::Public>("Dave"),
get_account_id_from_seed::<sr25519::Public>("Eve"),
get_account_id_from_seed::<sr25519::Public>("Ferdie"),
get_account_id_from_seed::<sr25519::Public>("Alice//stash"),
get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
get_account_id_from_seed::<sr25519::Public>("Charlie//stash"),
get_account_id_from_seed::<sr25519::Public>("Dave//stash"),
get_account_id_from_seed::<sr25519::Public>("Eve//stash"),
get_account_id_from_seed::<sr25519::Public>("Ferdie//stash"),
]
}
/// Helper function to create polkadot GenesisConfig for testing
fn polkadot_testnet_genesis(
initial_authorities: Vec<(AccountId, AccountId, BabeId, GrandpaId, ValidatorId)>,
root_key: AccountId,
endowed_accounts: Option<Vec<AccountId>>,
changes_trie_config: Option<ChangesTrieConfiguration>,
) -> polkadot_test_runtime::GenesisConfig {
use polkadot_test_runtime as polkadot;
let endowed_accounts: Vec<AccountId> = endowed_accounts.unwrap_or_else(testnet_accounts);
const ENDOWMENT: u128 = 1_000_000 * DOTS;
const STASH: u128 = 100 * DOTS;
polkadot::GenesisConfig {
system: Some(polkadot::SystemConfig {
code: polkadot::WASM_BINARY.to_vec(),
changes_trie_config,
}),
indices: Some(polkadot::IndicesConfig { indices: vec![] }),
balances: Some(polkadot::BalancesConfig {
balances: endowed_accounts
.iter()
.map(|k| (k.clone(), ENDOWMENT))
.collect(),
}),
session: Some(polkadot::SessionConfig {
keys: initial_authorities
.iter()
.map(|x| {
(
x.0.clone(),
x.0.clone(),
polkadot_test_runtime::SessionKeys {
babe: x.2.clone(),
grandpa: x.3.clone(),
parachain_validator: x.4.clone(),
},
)
})
.collect::<Vec<_>>(),
}),
staking: Some(polkadot::StakingConfig {
minimum_validator_count: 1,
validator_count: 2,
stakers: initial_authorities
.iter()
.map(|x| {
(
x.0.clone(),
x.1.clone(),
STASH,
polkadot::StakerStatus::Validator,
)
})
.collect(),
invulnerables: initial_authorities.iter().map(|x| x.0.clone()).collect(),
force_era: Forcing::NotForcing,
slash_reward_fraction: Perbill::from_percent(10),
..Default::default()
}),
babe: Some(Default::default()),
grandpa: Some(Default::default()),
authority_discovery: Some(polkadot::AuthorityDiscoveryConfig { keys: vec![] }),
parachains: Some(polkadot::ParachainsConfig {
authorities: vec![],
}),
registrar: Some(polkadot::RegistrarConfig {
parachains: vec![],
_phdata: Default::default(),
}),
claims: Some(polkadot::ClaimsConfig {
claims: vec![],
vesting: vec![],
}),
vesting: Some(polkadot::VestingConfig { vesting: vec![] }),
sudo: Some(polkadot::SudoConfig { key: root_key }),
}
}
/// Can be called for a `Configuration` to check if it is a configuration for the `Test` network.
pub trait IdentifyVariant {
/// Returns if this is a configuration for the `Test` network.
fn is_test(&self) -> bool;
}
impl IdentifyVariant for Box<dyn ChainSpec> {
fn is_test(&self) -> bool {
self.id().starts_with("test")
}
}
// 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 <http://www.gnu.org/licenses/>.
//! Polkadot test service only.
#![warn(missing_docs)]
mod chain_spec;
pub use chain_spec::*;
use consensus_common::{block_validation::Chain, SelectChain};
use futures::future::Future;
use grandpa::FinalityProofProvider as GrandpaFinalityProofProvider;
use log::info;
use polkadot_network::{legacy::gossip::Known, protocol as network_protocol};
use polkadot_primitives::{
parachain::{self, CollatorId},
Block, BlockId, Hash,
};
use polkadot_runtime_common::{parachains, registrar, BlockHashCount};
use polkadot_service::{
new_full, new_full_start, FullNodeHandles, PolkadotClient, ServiceComponents,
};
use polkadot_test_runtime::{RestrictFunctionality, Runtime, SignedExtra, SignedPayload, VERSION};
use sc_chain_spec::ChainSpec;
use sc_client_api::{execution_extensions::ExecutionStrategies, BlockchainEvents};
use sc_executor::native_executor_instance;
use sc_informant::OutputFormat;
use sc_network::{
config::{NetworkConfiguration, TransportConfig},
multiaddr, NetworkService,
};
use service::{
config::{DatabaseConfig, KeystoreConfig, MultiaddrWithPeerId, WasmExecutionMethod},
error::Error as ServiceError,
RpcHandlers, TaskExecutor, TaskManager,
};
use service::{BasePath, Configuration, Role, TFullBackend};
use sp_arithmetic::traits::SaturatedConversion;
use sp_blockchain::HeaderBackend;
use sp_keyring::Sr25519Keyring;
use sp_runtime::{codec::Encode, generic};
use sp_state_machine::BasicExternalities;
use std::sync::Arc;
use std::time::Duration;
use substrate_test_client::{BlockchainEventsExt, RpcHandlersExt, RpcTransactionOutput, RpcTransactionError};
native_executor_instance!(
pub PolkadotTestExecutor,
polkadot_test_runtime::api::dispatch,
polkadot_test_runtime::native_version,
frame_benchmarking::benchmarking::HostFunctions,
);
/// Create a new Polkadot test service for a full node.
pub fn polkadot_test_new_full(
config: Configuration,
collating_for: Option<(CollatorId, parachain::Id)>,
max_block_data_size: Option<u64>,
authority_discovery_enabled: bool,
slot_duration: u64,
) -> Result<
(
TaskManager,
Arc<impl PolkadotClient<Block, TFullBackend<Block>, polkadot_test_runtime::RuntimeApi>>,
FullNodeHandles,
Arc<NetworkService<Block, Hash>>,
Arc<RpcHandlers>,
),
ServiceError,
> {
let (task_manager, client, handles, network, rpc_handlers) = new_full!(test
config,
collating_for,
max_block_data_size,
authority_discovery_enabled,
slot_duration,
polkadot_test_runtime::RuntimeApi,
PolkadotTestExecutor,
);
Ok((task_manager, client, handles, network, rpc_handlers))
}
/// Create a Polkadot `Configuration`. By default an in-memory socket will be used, therefore you need to provide boot
/// nodes if you want the future node to be connected to other nodes. The `storage_update_func` can be used to make
/// adjustements to the runtime before the node starts.
pub fn node_config(
storage_update_func: impl Fn(),
task_executor: TaskExecutor,
key: Sr25519Keyring,
boot_nodes: Vec<MultiaddrWithPeerId>,
) -> Configuration {
let base_path = BasePath::new_temp_dir().expect("could not create temporary directory");
let root = base_path.path();
let role = Role::Authority {
sentry_nodes: Vec::new(),
};
let key_seed = key.to_seed();
let mut spec = polkadot_local_testnet_config();
let mut storage = spec
.as_storage_builder()
.build_storage()
.expect("could not build storage");
BasicExternalities::execute_with_storage(&mut storage, storage_update_func);
spec.set_storage(storage);
let mut network_config = NetworkConfiguration::new(
format!("Polkadot Test Node for: {}", key_seed),
"network/test/0.1",
Default::default(),
None,
);
let informant_output_format = OutputFormat {
enable_color: false,
prefix: format!("[{}] ", key_seed),
};
network_config.boot_nodes = boot_nodes;
network_config.allow_non_globals_in_dht = true;
network_config
.listen_addresses
.push(multiaddr::Protocol::Memory(rand::random()).into());
network_config.transport = TransportConfig::MemoryOnly;
Configuration {
impl_name: "polkadot-test-node".to_string(),
impl_version: "0.1".to_string(),
role,
task_executor,
transaction_pool: Default::default(),
network: network_config,
keystore: KeystoreConfig::Path {
path: root.join("key"),
password: None,
},
database: DatabaseConfig::RocksDb {
path: root.join("db"),
cache_size: 128,
},
state_cache_size: 16777216,
state_cache_child_ratio: None,
pruning: Default::default(),
chain_spec: Box::new(spec),
wasm_method: WasmExecutionMethod::Interpreted,
// NOTE: we enforce the use of the native runtime to make the errors more debuggable
execution_strategies: ExecutionStrategies {
syncing: sc_client_api::ExecutionStrategy::NativeWhenPossible,
importing: sc_client_api::ExecutionStrategy::NativeWhenPossible,
block_construction: sc_client_api::ExecutionStrategy::NativeWhenPossible,
offchain_worker: sc_client_api::ExecutionStrategy::NativeWhenPossible,
other: sc_client_api::ExecutionStrategy::NativeWhenPossible,
},
rpc_http: None,
rpc_ws: None,
rpc_ipc: None,
rpc_ws_max_connections: None,
rpc_cors: None,
rpc_methods: Default::default(),
prometheus_config: None,
telemetry_endpoints: None,
telemetry_external_transport: None,
default_heap_pages: None,
offchain_worker: Default::default(),
force_authoring: false,
disable_grandpa: false,
dev_key_seed: Some(key_seed),
tracing_targets: None,
tracing_receiver: Default::default(),
max_runtime_instances: 8,
announce_block: true,
base_path: Some(base_path),
informant_output_format,
}
}
/// Run a Polkadot test node using the Polkadot test runtime. The node will be using an in-memory socket, therefore you
/// need to provide boot nodes if you want it to be connected to other nodes. The `storage_update_func` can be used to
/// make adjustements to the runtime before the node starts.
pub fn run_test_node(
task_executor: TaskExecutor,
key: Sr25519Keyring,
storage_update_func: impl Fn(),
boot_nodes: Vec<MultiaddrWithPeerId>,
) -> PolkadotTestNode<
TaskManager,
impl PolkadotClient<Block, TFullBackend<Block>, polkadot_test_runtime::RuntimeApi>,
> {
let config = node_config(storage_update_func, task_executor, key, boot_nodes);
let multiaddr = config.network.listen_addresses[0].clone();
let authority_discovery_enabled = false;
let (task_manager, client, handles, network, rpc_handlers) =
polkadot_test_new_full(config, None, None, authority_discovery_enabled, 6000)
.expect("could not create Polkadot test service");
let peer_id = network.local_peer_id().clone();
let addr = MultiaddrWithPeerId { multiaddr, peer_id };
PolkadotTestNode {
task_manager,
client,
handles,
addr,
rpc_handlers,
}
}
/// A Polkadot test node instance used for testing.
pub struct PolkadotTestNode<S, C> {
/// TaskManager's instance.
pub task_manager: S,
/// Client's instance.
pub client: Arc<C>,
/// Node's handles.
pub handles: FullNodeHandles,
/// The `MultiaddrWithPeerId` to this node. This is useful if you want to pass it as "boot node" to other nodes.
pub addr: MultiaddrWithPeerId,
/// RPCHandlers to make RPC queries.
pub rpc_handlers: Arc<RpcHandlers>,
}
impl<S, C> PolkadotTestNode<S, C>
where
C: HeaderBackend<Block>,
{
/// Send a transaction through RPCHandlers to call a function.
pub async fn call_function(
&self,
function: polkadot_test_runtime::Call,
caller: Sr25519Keyring,
) -> Result<RpcTransactionOutput, RpcTransactionError> {
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 = (
RestrictFunctionality,
frame_system::CheckSpecVersion::<Runtime>::new(),
frame_system::CheckTxVersion::<Runtime>::new(),
frame_system::CheckGenesis::<Runtime>::new(),
frame_system::CheckEra::<Runtime>::from(generic::Era::mortal(period, current_block)),
frame_system::CheckNonce::<Runtime>::from(nonce),
frame_system::CheckWeight::<Runtime>::new(),
pallet_transaction_payment::ChargeTransactionPayment::<Runtime>::from(tip),
registrar::LimitParathreadCommits::<Runtime>::new(),
parachains::ValidateDoubleVoteReports::<Runtime>::new(),
);
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::Signature::Sr25519(signature.clone()),
extra.clone(),
);
self.rpc_handlers.send_transaction(extrinsic.into()).await
}
}
impl<S, C> PolkadotTestNode<S, C>
where
C: BlockchainEvents<Block>,
{
/// 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<Output = ()> {
self.client.wait_for_blocks(count)
}
}
// 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