From ab51fe9abe30a54554d789637d568df67cfdfefd Mon Sep 17 00:00:00 2001 From: Cecile Tonglet <cecile@parity.io> Date: Mon, 18 May 2020 17:17:34 +0200 Subject: [PATCH] Integration test (#91) --- cumulus/.editorconfig | 7 + cumulus/.gitlab-ci.yml | 2 + cumulus/Cargo.lock | 164 +++++++- cumulus/test/parachain/Cargo.toml | 17 + cumulus/test/parachain/src/cli.rs | 7 + cumulus/test/parachain/src/command.rs | 93 +++-- .../test/parachain/tests/integration_test.rs | 372 ++++++++++++++++++ 7 files changed, 615 insertions(+), 47 deletions(-) create mode 100644 cumulus/test/parachain/tests/integration_test.rs diff --git a/cumulus/.editorconfig b/cumulus/.editorconfig index d44b1ae078b..e8ff2027ca4 100644 --- a/cumulus/.editorconfig +++ b/cumulus/.editorconfig @@ -20,3 +20,10 @@ indent_style=space indent_size=4 tab_width=8 end_of_line=lf + +[*.json] +indent_style=space +indent_size=2 +tab_width=8 +end_of_line=lf + diff --git a/cumulus/.gitlab-ci.yml b/cumulus/.gitlab-ci.yml index 9bc4151ec85..39851191339 100644 --- a/cumulus/.gitlab-ci.yml +++ b/cumulus/.gitlab-ci.yml @@ -63,6 +63,8 @@ test-linux-stable: script: - time cargo test --all --release --locked | tee output.log + - time cargo test --release -- --ignored integration_test | + tee -a output.log - sccache -s after_script: - echo "___Collecting warnings for check_warnings job___" diff --git a/cumulus/Cargo.lock b/cumulus/Cargo.lock index 249e13a9ce6..af133aaa8b5 100644 --- a/cumulus/Cargo.lock +++ b/cumulus/Cargo.lock @@ -59,6 +59,12 @@ dependencies = [ "const-random", ] +[[package]] +name = "ahash" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c251dce3391a07b43218ca070203ecb8f9f520d35ab71312296a59dbceab154" + [[package]] name = "aho-corasick" version = "0.7.10" @@ -190,12 +196,23 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7deb0a829ca7bcfaf5da70b073a8d128619259a7be8216a355e23f00763059e5" +[[package]] +name = "async-attributes" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efd3d156917d94862e779f356c5acae312b08fd3121e792c857d7928c8088423" +dependencies = [ + "quote 1.0.3", + "syn 1.0.18", +] + [[package]] name = "async-std" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "538ecb01eb64eecd772087e5b6f7540cbc917f047727339a472dafed2185b267" dependencies = [ + "async-attributes", "async-task", "broadcaster", "crossbeam-channel", @@ -226,6 +243,18 @@ dependencies = [ "winapi 0.3.8", ] +[[package]] +name = "async-tls" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce6977f57fa68da77ffe5542950d47e9c23d65f5bc7cb0a9f8700996913eec7" +dependencies = [ + "futures 0.3.4", + "rustls 0.16.0", + "webpki", + "webpki-roots 0.17.0", +] + [[package]] name = "async-tls" version = "0.7.0" @@ -233,7 +262,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95fd83426b89b034bf4e9ceb9c533c2f2386b813fd3dcae0a425ec6f1837d78a" dependencies = [ "futures 0.3.4", - "rustls", + "rustls 0.17.0", "webpki", "webpki-roots 0.19.0", ] @@ -289,6 +318,15 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5024ee8015f02155eee35c711107ddd9a9bf3cb689cf2a9089c97e79b6e1ae83" +[[package]] +name = "base64" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" +dependencies = [ + "byteorder", +] + [[package]] name = "base64" version = "0.11.0" @@ -949,7 +987,7 @@ dependencies = [ "cumulus-test-client", "frame-executive", "hash-db", - "hashbrown", + "hashbrown 0.6.3", "memory-db 0.18.1", "parity-scale-codec", "polkadot-parachain", @@ -987,19 +1025,27 @@ name = "cumulus-test-parachain-collator" version = "0.1.0" dependencies = [ "assert_cmd", + "async-std", "cumulus-collator", "cumulus-consensus", "cumulus-test-parachain-runtime", "derive_more 0.15.0", "exit-future 0.1.4", + "frame-system", "futures 0.3.4", + "hex", + "jsonrpsee", "log 0.4.8", "nix 0.17.0", + "pallet-sudo", + "pallet-transaction-payment", "parity-scale-codec", "parking_lot 0.9.0", "polkadot-cli", "polkadot-collator", "polkadot-primitives", + "polkadot-runtime", + "polkadot-runtime-common", "polkadot-service", "sc-basic-authorship", "sc-cli", @@ -1009,6 +1055,8 @@ dependencies = [ "sc-network", "sc-service", "sc-transaction-pool", + "serde_json", + "sp-arithmetic", "sp-consensus", "sp-core", "sp-inherents", @@ -1016,8 +1064,11 @@ dependencies = [ "sp-runtime", "sp-timestamp", "sp-transaction-pool", + "sp-version", "structopt", "substrate-build-script-utils", + "substrate-test-runtime-client", + "tempfile", "trie-root 0.15.2", ] @@ -1952,10 +2003,20 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e6073d0ca812575946eb5f35ff68dbe519907b25c42530389ff946dc84c6ead" dependencies = [ - "ahash", + "ahash 0.2.18", "autocfg 0.1.7", ] +[[package]] +name = "hashbrown" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96282e96bfcd3da0d3aa9938bedf1e50df3269b6db08b4876d2da0bb1a0841cf" +dependencies = [ + "ahash 0.3.4", + "autocfg 1.0.0", +] + [[package]] name = "heck" version = "0.3.1" @@ -2144,7 +2205,7 @@ dependencies = [ "futures-util", "hyper 0.13.5", "log 0.4.8", - "rustls", + "rustls 0.17.0", "rustls-native-certs", "tokio 0.2.20", "tokio-rustls", @@ -2403,6 +2464,51 @@ dependencies = [ "ws", ] +[[package]] +name = "jsonrpsee" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc8a1da5a54b417cfb7edb9f932024d833dc333de50c21c0e1b28d0e8b4f853" +dependencies = [ + "async-std", + "async-tls 0.6.0", + "bs58", + "bytes 0.5.4", + "fnv", + "futures 0.3.4", + "futures-timer 3.0.2", + "globset", + "hashbrown 0.7.2", + "hyper 0.13.5", + "jsonrpsee-proc-macros", + "lazy_static", + "log 0.4.8", + "parking_lot 0.10.2", + "pin-project", + "rand 0.7.3", + "serde", + "serde_json", + "smallvec 1.4.0", + "soketto", + "thiserror", + "tokio 0.2.20", + "unicase", + "url 2.1.1", + "webpki", +] + +[[package]] +name = "jsonrpsee-proc-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1ed1b5f6937dd2c6c79a9ac6e0e3f41bbc64edb5d443840bdc73e606009ed70" +dependencies = [ + "Inflector", + "proc-macro2 1.0.10", + "quote 1.0.3", + "syn 1.0.18", +] + [[package]] name = "keccak" version = "0.1.0" @@ -2866,14 +2972,14 @@ version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6874c9069ce93d899df9dc7b29f129c706b2a0fdc048f11d878935352b580190" dependencies = [ - "async-tls", + "async-tls 0.7.0", "bytes 0.5.4", "either", "futures 0.3.4", "libp2p-core", "log 0.4.8", "quicksink", - "rustls", + "rustls 0.17.0", "rw-stream-sink", "soketto", "url 2.1.1", @@ -3003,7 +3109,7 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0609345ddee5badacf857d4f547e0e5a2e987db77085c24cd887f73573a04237" dependencies = [ - "hashbrown", + "hashbrown 0.6.3", ] [[package]] @@ -3078,9 +3184,9 @@ version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "881736a0f68a6fae1b596bb066c5bd16d7b3ed645a4dd8ffaefd02f585abaf71" dependencies = [ - "ahash", + "ahash 0.2.18", "hash-db", - "hashbrown", + "hashbrown 0.6.3", "parity-util-mem 0.3.0", ] @@ -3090,9 +3196,9 @@ version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be512cb2ccb4ecbdca937fdd4a62ea5f09f8e7195466a85e4632b3d5bcce82e6" dependencies = [ - "ahash", + "ahash 0.2.18", "hash-db", - "hashbrown", + "hashbrown 0.6.3", "parity-util-mem 0.6.1", ] @@ -5244,7 +5350,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2bc8af4bda8e1ff4932523b94d3dd20ee30a87232323eda55903ffd71d2fb017" dependencies = [ - "base64", + "base64 0.11.0", "blake2b_simd", "constant_time_eq", "crossbeam-utils", @@ -5283,13 +5389,26 @@ dependencies = [ "semver", ] +[[package]] +name = "rustls" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b25a18b1bf7387f0145e7f8324e700805aade3842dd3db2e74e4cdeb4677c09e" +dependencies = [ + "base64 0.10.1", + "log 0.4.8", + "ring", + "sct", + "webpki", +] + [[package]] name = "rustls" version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0d4a31f5d68413404705d6982529b0e11a9aacd4839d1d6222ee3b8cb4015e1" dependencies = [ - "base64", + "base64 0.11.0", "log 0.4.8", "ring", "sct", @@ -5303,7 +5422,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75ffeb84a6bd9d014713119542ce415db3a3e4748f0bfce1e1416cd224a23a5" dependencies = [ "openssl-probe", - "rustls", + "rustls 0.17.0", "schannel", "security-framework", ] @@ -6455,7 +6574,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c9dab3f95c9ebdf3a88268c19af668f637a3c5039c2c56ff2d40b1b2d64a25b" dependencies = [ - "base64", + "base64 0.11.0", "bytes 0.5.4", "flate2", "futures 0.3.4", @@ -7746,7 +7865,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4adb8b3e5f86b707f1b54e7c15b6de52617a823608ccda98a15d3a24222f265a" dependencies = [ "futures-core", - "rustls", + "rustls 0.17.0", "tokio 0.2.20", "webpki", ] @@ -7920,7 +8039,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bcc309f34008563989045a4c4dbcc5770467f3a3785ee80a9b5cc0d83362475f" dependencies = [ "hash-db", - "hashbrown", + "hashbrown 0.6.3", "log 0.4.8", "rustc-hex", "smallvec 1.4.0", @@ -8285,7 +8404,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80f3dea0e60c076dd0da27fa10c821323903c9554c617ed32eaab8e7a7e36c89" dependencies = [ "anyhow", - "base64", + "base64 0.11.0", "bincode", "cranelift-codegen", "cranelift-entity", @@ -8361,6 +8480,15 @@ dependencies = [ "untrusted", ] +[[package]] +name = "webpki-roots" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a262ae37dd9d60f60dd473d1158f9fbebf110ba7b6a5051c8160460f6043718b" +dependencies = [ + "webpki", +] + [[package]] name = "webpki-roots" version = "0.18.0" diff --git a/cumulus/test/parachain/Cargo.toml b/cumulus/test/parachain/Cargo.toml index 65523231517..48a0bb70515 100644 --- a/cumulus/test/parachain/Cargo.toml +++ b/cumulus/test/parachain/Cargo.toml @@ -55,3 +55,20 @@ substrate-build-script-utils = { git = "https://github.com/paritytech/substrate" [dev-dependencies] assert_cmd = "0.12" nix = "0.17" +tempfile = "3.1" +jsonrpsee = "0.1" +async-std = { version = "1.2.0", features = [ "attributes" ] } +hex = "0.4" +serde_json = "1.0" + +# Polkadot dependencies +polkadot-runtime-common = { git = "https://github.com/paritytech/polkadot", branch = "cumulus-branch" } +polkadot-runtime = { git = "https://github.com/paritytech/polkadot", branch = "cumulus-branch" } + +# Substrate dependencies +substrate-test-runtime-client = { git = "https://github.com/paritytech/substrate", branch = "cumulus-branch" } +frame-system = { git = "https://github.com/paritytech/substrate", branch = "cumulus-branch" } +pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", branch = "cumulus-branch" } +sp-arithmetic = { git = "https://github.com/paritytech/substrate", branch = "cumulus-branch" } +sp-version = { git = "https://github.com/paritytech/substrate", branch = "cumulus-branch" } +pallet-sudo = { git = "https://github.com/paritytech/substrate", branch = "cumulus-branch" } diff --git a/cumulus/test/parachain/src/cli.rs b/cumulus/test/parachain/src/cli.rs index 8abcff9fc24..2c2450aeb66 100644 --- a/cumulus/test/parachain/src/cli.rs +++ b/cumulus/test/parachain/src/cli.rs @@ -24,9 +24,16 @@ use structopt::StructOpt; pub enum Subcommand { #[structopt(flatten)] Base(sc_cli::Subcommand), + /// Export the genesis state of the parachain. #[structopt(name = "export-genesis-state")] ExportGenesisState(ExportGenesisStateCommand), + + /// Run Polkadot for testing purpose + Polkadot(polkadot_cli::Cli), + + #[structopt(name = "validation-worker", setting = structopt::clap::AppSettings::Hidden)] + PolkadotValidationWorker(polkadot_cli::ValidationWorkerCommand), } /// Command for exporting the genesis state of the parachain diff --git a/cumulus/test/parachain/src/command.rs b/cumulus/test/parachain/src/command.rs index 59955074a82..326a25e4bc1 100644 --- a/cumulus/test/parachain/src/command.rs +++ b/cumulus/test/parachain/src/command.rs @@ -23,6 +23,7 @@ use sc_cli::{ CliConfiguration, Error, ImportParams, KeystoreParams, NetworkParams, Result, SharedParams, SubstrateCli, }; +use sc_executor::NativeExecutionDispatch; use sc_network::config::TransportConfig; use sc_service::config::{NetworkConfiguration, NodeKeyConfig, PrometheusConfig}; use sp_core::hexdisplay::HexDisplay; @@ -111,6 +112,36 @@ impl SubstrateCli for PolkadotCli { } } +fn generate_genesis_state() -> Result<Block> { + let storage = (&chain_spec::get_chain_spec()).build_storage()?; + + let child_roots = storage.children_default.iter().map(|(sk, child_content)| { + let state_root = + <<<Block as BlockT>::Header as HeaderT>::Hashing as HashT>::trie_root( + child_content.data.clone().into_iter().collect(), + ); + (sk.clone(), state_root.encode()) + }); + let state_root = <<<Block as BlockT>::Header as HeaderT>::Hashing as HashT>::trie_root( + storage.top.clone().into_iter().chain(child_roots).collect(), + ); + + let extrinsics_root = <<<Block as BlockT>::Header as HeaderT>::Hashing as HashT>::trie_root( + Vec::new(), + ); + + Ok(Block::new( + <<Block as BlockT>::Header as HeaderT>::new( + Zero::zero(), + extrinsics_root, + state_root, + Default::default(), + Default::default(), + ), + Default::default(), + )) +} + /// Parse command line arguments into service configuration. pub fn run() -> Result<()> { let cli = Cli::from_args(); @@ -124,35 +155,7 @@ pub fn run() -> Result<()> { Some(Subcommand::ExportGenesisState(params)) => { sc_cli::init_logger(""); - let storage = (&chain_spec::get_chain_spec()).build_storage()?; - - let child_roots = storage.children_default.iter().map(|(sk, child_content)| { - let state_root = - <<<Block as BlockT>::Header as HeaderT>::Hashing as HashT>::trie_root( - child_content.data.clone().into_iter().collect(), - ); - (sk.clone(), state_root.encode()) - }); - let state_root = <<<Block as BlockT>::Header as HeaderT>::Hashing as HashT>::trie_root( - storage.top.clone().into_iter().chain(child_roots).collect(), - ); - let block = { - let extrinsics_root = <<<Block as BlockT>::Header as HeaderT>::Hashing as HashT>::trie_root( - Vec::new(), - ); - - Block::new( - <<Block as BlockT>::Header as HeaderT>::new( - Zero::zero(), - extrinsics_root, - state_root, - Default::default(), - Default::default(), - ), - Default::default(), - ) - }; - + let block = generate_genesis_state()?; let header_hex = format!("0x{:?}", HexDisplay::from(&block.header().encode())); if let Some(output) = ¶ms.output { @@ -163,6 +166,38 @@ pub fn run() -> Result<()> { Ok(()) } + Some(Subcommand::Polkadot(polkadot_cli)) => { + let runner = polkadot_cli.create_runner(&polkadot_cli.run.base)?; + let authority_discovery_enabled = polkadot_cli.run.authority_discovery_enabled; + let grandpa_pause = if polkadot_cli.run.grandpa_pause.is_empty() { + None + } else { + Some((polkadot_cli.run.grandpa_pause[0], polkadot_cli.run.grandpa_pause[1])) + }; + + runner.run_node( + |config| { + polkadot_service::polkadot_new_light(config) + }, + |config| { + polkadot_service::polkadot_new_full( + config, + None, + None, + authority_discovery_enabled, + 6000, + grandpa_pause + ).map(|(s, _, _)| s) + }, + polkadot_service::PolkadotExecutor::native_version().runtime_version + ) + }, + Some(Subcommand::PolkadotValidationWorker(cmd)) => { + sc_cli::init_logger(""); + polkadot_service::run_validation_worker(&cmd.mem_id)?; + + Ok(()) + }, None => { let runner = cli.create_runner(&cli.run)?; diff --git a/cumulus/test/parachain/tests/integration_test.rs b/cumulus/test/parachain/tests/integration_test.rs new file mode 100644 index 00000000000..85595c82f22 --- /dev/null +++ b/cumulus/test/parachain/tests/integration_test.rs @@ -0,0 +1,372 @@ +// Copyright 2020 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 <http://www.gnu.org/licenses/>. + +// TODO: this is necessary for the jsonrpsee macro used +#![allow(unused_variables, dead_code)] + +use assert_cmd::cargo::cargo_bin; +use async_std::{net, task::sleep}; +use codec::Encode; +use futures::{future::FutureExt, join, pin_mut, select}; +use polkadot_primitives::parachain::{Info, Scheduling}; +use polkadot_primitives::Hash as PHash; +use polkadot_runtime::{Header, OnlyStakingAndClaims, Runtime, SignedExtra, SignedPayload}; +use polkadot_runtime_common::{parachains, registrar, BlockHashCount}; +use serde_json::Value; +use sp_arithmetic::traits::SaturatedConversion; +use sp_runtime::generic; +use sp_version::RuntimeVersion; +use std::{ + collections::HashSet, + env, fs, + io::Read, + path::PathBuf, + process::{Child, Command, Stdio}, + time::Duration, +}; +use substrate_test_runtime_client::AccountKeyring::Alice; +use tempfile::tempdir; + +static POLKADOT_ARGS: &[&str] = &["polkadot", "--chain=res/polkadot_chainspec.json"]; +static INTEGRATION_TEST_ALLOWED_TIME: Option<&str> = option_env!("INTEGRATION_TEST_ALLOWED_TIME"); + +jsonrpsee::rpc_api! { + Author { + #[rpc(method = "author_submitExtrinsic", positional_params)] + fn submit_extrinsic(extrinsic: String) -> PHash; + } + + Chain { + #[rpc(method = "chain_getFinalizedHead")] + fn current_block_hash() -> PHash; + + #[rpc(method = "chain_getHeader", positional_params)] + fn header(hash: PHash) -> Option<Header>; + + #[rpc(method = "chain_getBlockHash", positional_params)] + fn block_hash(hash: Option<u64>) -> Option<PHash>; + } + + State { + #[rpc(method = "state_getRuntimeVersion")] + fn runtime_version() -> RuntimeVersion; + } + + System { + #[rpc(method = "system_networkState")] + fn network_state() -> Value; + } +} + +// Adapted from +// https://github.com/rust-lang/cargo/blob/485670b3983b52289a2f353d589c57fae2f60f82/tests/testsuite/support/mod.rs#L507 +fn target_dir() -> PathBuf { + env::current_exe() + .ok() + .map(|mut path| { + path.pop(); + if path.ends_with("deps") { + path.pop(); + } + path + }) + .unwrap() +} + +struct ChildHelper<'a> { + name: String, + child: &'a mut Child, +} + +impl<'a> Drop for ChildHelper<'a> { + fn drop(&mut self) { + let name = self.name.clone(); + + self.terminate(); + + let mut stdout = String::new(); + if let Some(reader) = self.child.stdout.as_mut() { + let _ = reader.read_to_string(&mut stdout); + } + eprintln!("process '{}' stdout:\n{}\n", name, stdout,); + + let mut stderr = String::new(); + if let Some(reader) = self.child.stderr.as_mut() { + let _ = reader.read_to_string(&mut stderr); + } + eprintln!("process '{}' stderr:\n{}\n", name, stderr,); + } +} + +impl<'a> ChildHelper<'a> { + fn new(name: &str, child: &'a mut Child) -> ChildHelper<'a> { + ChildHelper { + name: name.to_string(), + child, + } + } + + fn terminate(&mut self) { + match self.child.try_wait() { + Ok(Some(_)) => return, + Ok(None) => {} + Err(err) => { + eprintln!("could not wait for child process to finish: {}", err); + let _ = self.child.kill(); + let _ = self.child.wait(); + return; + } + } + + let _ = self.child.kill(); + + let _ = self.child.wait(); + } +} + +async fn wait_for_tcp<A: net::ToSocketAddrs + std::fmt::Display>(address: A) { + while let Err(err) = net::TcpStream::connect(&address).await { + eprintln!("Waiting for {} to be up ({})...", address, err); + sleep(Duration::from_secs(2)).await; + } +} + +#[async_std::test] +#[ignore] +async fn integration_test() { + assert!( + !net::TcpStream::connect("127.0.0.1:27015").await.is_ok(), + "tcp port is already open 127.0.0.1:27015, this test cannot be run", + ); + assert!( + !net::TcpStream::connect("127.0.0.1:27016").await.is_ok(), + "tcp port is already open 127.0.0.1:27016, this test cannot be run", + ); + + let t1 = sleep(Duration::from_secs( + INTEGRATION_TEST_ALLOWED_TIME + .and_then(|x| x.parse().ok()) + .unwrap_or(600), + )) + .fuse(); + let t2 = async { + // start alice + let polkadot_alice_dir = tempdir().unwrap(); + let mut polkadot_alice = Command::new(cargo_bin("cumulus-test-parachain-collator")) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .args(POLKADOT_ARGS) + .arg("--base-path") + .arg(polkadot_alice_dir.path()) + .arg("--alice") + .arg("--unsafe-rpc-expose") + .arg("--rpc-port=27015") + .arg("--port=27115") + .spawn() + .unwrap(); + let polkadot_alice_helper = ChildHelper::new("alice", &mut polkadot_alice); + + // start bob + let polkadot_bob_dir = tempdir().unwrap(); + let mut polkadot_bob = Command::new(cargo_bin("cumulus-test-parachain-collator")) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .args(POLKADOT_ARGS) + .arg("--base-path") + .arg(polkadot_bob_dir.path()) + .arg("--bob") + .arg("--unsafe-rpc-expose") + .arg("--rpc-port=27016") + .arg("--port=27116") + .spawn() + .unwrap(); + let polkadot_bob_helper = ChildHelper::new("bob", &mut polkadot_bob); + + // wait for both nodes to be up and running + join!( + wait_for_tcp("127.0.0.1:27015"), + wait_for_tcp("127.0.0.1:27016") + ); + + // export genesis state + let cmd = Command::new(cargo_bin("cumulus-test-parachain-collator")) + .arg("export-genesis-state") + .output() + .unwrap(); + assert!(cmd.status.success()); + let output = &cmd.stdout; + let genesis_state = hex::decode(&output[2..output.len() - 1]).unwrap(); + + // connect RPC clients + let transport_client_alice = + jsonrpsee::transport::http::HttpTransportClient::new("http://127.0.0.1:27015"); + let mut client_alice = jsonrpsee::raw::RawClient::new(transport_client_alice); + let transport_client_bob = + jsonrpsee::transport::http::HttpTransportClient::new("http://127.0.0.1:27016"); + let mut client_bob = jsonrpsee::raw::RawClient::new(transport_client_bob); + + // retrieve nodes network id + let polkadot_alice_id = System::network_state(&mut client_alice).await.unwrap()["peerId"] + .as_str() + .unwrap() + .to_string(); + let polkadot_bob_id = System::network_state(&mut client_bob).await.unwrap()["peerId"] + .as_str() + .unwrap() + .to_string(); + + // retrieve runtime version + let runtime_version = State::runtime_version(&mut client_alice).await.unwrap(); + + // get the current block + let current_block_hash = Chain::block_hash(&mut client_alice, None) + .await + .unwrap() + .unwrap(); + let current_block = Chain::header(&mut client_alice, current_block_hash) + .await + .unwrap() + .unwrap() + .number + .saturated_into::<u64>(); + + let genesis_block = Chain::block_hash(&mut client_alice, 0) + .await + .unwrap() + .unwrap(); + + // create and sign transaction + let wasm = fs::read(target_dir().join( + "wbuild/cumulus-test-parachain-runtime/cumulus_test_parachain_runtime.compact.wasm", + )) + .unwrap(); + let call = pallet_sudo::Call::sudo(Box::new( + registrar::Call::<Runtime>::register_para( + 100.into(), + Info { + scheduling: Scheduling::Always, + }, + wasm.into(), + genesis_state.into(), + ) + .into(), + )); + 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 = ( + OnlyStakingAndClaims, + frame_system::CheckVersion::<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( + call.clone().into(), + extra.clone(), + ( + (), + runtime_version.spec_version, + genesis_block, + current_block_hash, + (), + (), + (), + (), + (), + ), + ); + let signature = raw_payload.using_encoded(|e| Alice.sign(e)); + + // register parachain + let ex = polkadot_runtime::UncheckedExtrinsic::new_signed( + call.into(), + Alice.into(), + sp_runtime::MultiSignature::Sr25519(signature), + extra, + ); + let _register_block_hash = + Author::submit_extrinsic(&mut client_alice, format!("0x{}", hex::encode(ex.encode()))) + .await + .unwrap(); + + // run cumulus + let cumulus_dir = tempdir().unwrap(); + let mut cumulus = Command::new(cargo_bin("cumulus-test-parachain-collator")) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .arg("--base-path") + .arg(cumulus_dir.path()) + .arg("--unsafe-rpc-expose") + .arg("--rpc-port=27017") + .arg("--port=27117") + .arg("--") + .arg(format!( + "--bootnodes=/ip4/127.0.0.1/tcp/27115/p2p/{}", + polkadot_alice_id + )) + .arg(format!( + "--bootnodes=/ip4/127.0.0.1/tcp/27116/p2p/{}", + polkadot_bob_id + )) + .spawn() + .unwrap(); + let cumulus_helper = ChildHelper::new("cumulus", &mut cumulus); + wait_for_tcp("127.0.0.1:27017").await; + + // connect rpc client to cumulus + let transport_client_cumulus = + jsonrpsee::transport::http::HttpTransportClient::new("http://127.0.0.1:27017"); + let mut client_cumulus = jsonrpsee::raw::RawClient::new(transport_client_cumulus); + + // wait for parachain blocks to be produced + let number_of_blocks = 4; + let mut previous_blocks = HashSet::with_capacity(number_of_blocks); + loop { + let current_block_hash = Chain::block_hash(&mut client_cumulus, None) + .await + .unwrap() + .unwrap(); + + if previous_blocks.insert(current_block_hash) { + eprintln!("new parachain block: {}", current_block_hash); + + if previous_blocks.len() == number_of_blocks { + break; + } + } + + sleep(Duration::from_secs(2)).await; + } + } + .fuse(); + + pin_mut!(t1, t2); + + select! { + _ = t1 => { + panic!("the test took too long, maybe no parachain blocks have been produced"); + }, + _ = t2 => {}, + } +} -- GitLab