From 4ac95dcbfff341e7d13a76b34623ad5040b49efb Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Tue, 1 Feb 2022 16:11:55 +0100 Subject: [PATCH 01/15] [ci] Fix docker credentials (#4826) --- .gitlab-ci.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 72f258bc13f6..27a83ef8dfd7 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -361,7 +361,6 @@ build-rustdoc: .build-push-image: &build-push-image <<: *kubernetes-env - <<: *vault-secrets image: quay.io/buildah/stable variables: &image-variables GIT_STRATEGY: none @@ -601,10 +600,8 @@ zombienet-test-parachains-upgrade-smoke-test: - job: publish-polkadot-image - job: publish-malus-image - job: publish-adder-collator-image - variables: GH_DIR: 'https://github.com/paritytech/polkadot/tree/${CI_COMMIT_SHORT_SHA}/zombienet_tests/parachains' - before_script: - echo "ZombieNet Tests Config" - echo "docker.io/parity/polkadot:latest" @@ -614,7 +611,6 @@ zombienet-test-parachains-upgrade-smoke-test: - export DEBUG=zombie,zombie::network-node - export ZOMBIENET_INTEGRATION_TEST_IMAGE="docker.io/parity/polkadot:latest" # Use polkadot latest image - export COL_IMAGE="docker.io/parity/polkadot-collator:latest" # Use cumulus lastest image - script: - /home/nonroot/zombie-net/scripts/run-test-env-manager.sh --github-remote-dir="${GH_DIR}" From bd3f56fd7d4f2ee9f36ac91092f33af6376f586a Mon Sep 17 00:00:00 2001 From: Bernhard Schuster Date: Wed, 2 Feb 2022 11:19:57 +0100 Subject: [PATCH 02/15] reduce forwarded number of disputes by one order of magnitude --- node/core/provisioner/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/core/provisioner/src/lib.rs b/node/core/provisioner/src/lib.rs index 66df739f687b..8789098693fe 100644 --- a/node/core/provisioner/src/lib.rs +++ b/node/core/provisioner/src/lib.rs @@ -655,7 +655,7 @@ async fn select_disputes( sender: &mut impl SubsystemSender, metrics: &metrics::Metrics, ) -> Result { - const MAX_DISPUTES_FORWARDED_TO_RUNTIME: usize = 10_000; + const MAX_DISPUTES_FORWARDED_TO_RUNTIME: usize = 1_000; // We use `RecentDisputes` instead of `ActiveDisputes` because redundancy is fine. // It's heavier than `ActiveDisputes` but ensures that everything from the dispute From bf2f830e141b4cccbec6fc055e15d415e7f077f3 Mon Sep 17 00:00:00 2001 From: radupopa2010 Date: Wed, 2 Feb 2022 13:56:41 +0100 Subject: [PATCH 03/15] feat(cicd): expire artifacts after 7 days (#4833) We received several alerts about disk space in gitlab server. Even if we have 1TiB allocated, disk space is consumed very fast. We need to address this problem by expiring artifacts after 7 days. --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 27a83ef8dfd7..ff60e5bdcc0b 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -40,7 +40,7 @@ default: artifacts: name: "${CI_JOB_NAME}_${CI_COMMIT_REF_NAME}" when: on_success - expire_in: 28 days + expire_in: 7 days paths: - ./artifacts/ From 200f873b460541489d929e8849c184d59ce817a6 Mon Sep 17 00:00:00 2001 From: Mara Robin B Date: Wed, 2 Feb 2022 14:33:48 +0100 Subject: [PATCH 04/15] Bump transaction_version for polkadot, kusama, & westend (#4831) * bump transaction_version for kusama * bump transaction_version for polkadot * bump transaction_version for westend --- runtime/kusama/src/lib.rs | 2 +- runtime/polkadot/src/lib.rs | 2 +- runtime/westend/src/lib.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/runtime/kusama/src/lib.rs b/runtime/kusama/src/lib.rs index 39d7d27a008b..abd5ef1dffb3 100644 --- a/runtime/kusama/src/lib.rs +++ b/runtime/kusama/src/lib.rs @@ -121,7 +121,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { apis: RUNTIME_API_VERSIONS, #[cfg(feature = "disable-runtime-api")] apis: version::create_apis_vec![[]], - transaction_version: 8, + transaction_version: 9, state_version: 0, }; diff --git a/runtime/polkadot/src/lib.rs b/runtime/polkadot/src/lib.rs index af86b782614c..9b3d40b358e1 100644 --- a/runtime/polkadot/src/lib.rs +++ b/runtime/polkadot/src/lib.rs @@ -120,7 +120,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { apis: RUNTIME_API_VERSIONS, #[cfg(feature = "disable-runtime-api")] apis: version::create_apis_vec![[]], - transaction_version: 9, + transaction_version: 10, state_version: 0, }; diff --git a/runtime/westend/src/lib.rs b/runtime/westend/src/lib.rs index ed63e14cc8db..ff1e68ef1f67 100644 --- a/runtime/westend/src/lib.rs +++ b/runtime/westend/src/lib.rs @@ -117,7 +117,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { apis: RUNTIME_API_VERSIONS, #[cfg(feature = "disable-runtime-api")] apis: version::create_apis_vec![[]], - transaction_version: 8, + transaction_version: 9, state_version: 0, }; From 92ccbf5593a7fd4529a61cc8c0abccd2251d48a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Wed, 2 Feb 2022 14:45:09 +0100 Subject: [PATCH 05/15] Bump substrate (#4828) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Bump substrate * Update Substrate Co-authored-by: Bastian Köcher --- Cargo.lock | 587 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 359 insertions(+), 228 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 90f7d35f1a4a..33afce31f5ff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -439,7 +439,7 @@ dependencies = [ [[package]] name = "beefy-gadget" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "beefy-primitives", "fnv", @@ -468,7 +468,7 @@ dependencies = [ [[package]] name = "beefy-gadget-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "beefy-gadget", "beefy-primitives", @@ -491,12 +491,12 @@ dependencies = [ [[package]] name = "beefy-merkle-tree" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" [[package]] name = "beefy-primitives" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "parity-scale-codec", "scale-info", @@ -1339,7 +1339,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1a816186fa68d9e426e3cb4ae4dff1fcd8e4a2c34b781bf7a822574a0d0aac8" dependencies = [ - "sct", + "sct 0.6.1", ] [[package]] @@ -1907,7 +1907,7 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "fork-tree" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "parity-scale-codec", ] @@ -1925,7 +1925,7 @@ dependencies = [ [[package]] name = "frame-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "frame-support", "frame-system", @@ -1946,7 +1946,7 @@ dependencies = [ [[package]] name = "frame-benchmarking-cli" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "Inflector", "chrono", @@ -1972,7 +1972,7 @@ dependencies = [ [[package]] name = "frame-election-provider-support" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "frame-support", "frame-system", @@ -1986,7 +1986,7 @@ dependencies = [ [[package]] name = "frame-executive" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "frame-support", "frame-system", @@ -2014,7 +2014,7 @@ dependencies = [ [[package]] name = "frame-support" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "bitflags", "frame-metadata", @@ -2043,7 +2043,7 @@ dependencies = [ [[package]] name = "frame-support-procedural" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "Inflector", "frame-support-procedural-tools", @@ -2055,7 +2055,7 @@ dependencies = [ [[package]] name = "frame-support-procedural-tools" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "frame-support-procedural-tools-derive", "proc-macro-crate 1.1.0", @@ -2067,7 +2067,7 @@ dependencies = [ [[package]] name = "frame-support-procedural-tools-derive" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "proc-macro2", "quote", @@ -2077,7 +2077,7 @@ dependencies = [ [[package]] name = "frame-support-test" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "frame-support", "frame-support-test-pallet", @@ -2100,7 +2100,7 @@ dependencies = [ [[package]] name = "frame-support-test-pallet" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "frame-support", "frame-system", @@ -2111,7 +2111,7 @@ dependencies = [ [[package]] name = "frame-system" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "frame-support", "log", @@ -2128,7 +2128,7 @@ dependencies = [ [[package]] name = "frame-system-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "frame-benchmarking", "frame-support", @@ -2143,7 +2143,7 @@ dependencies = [ [[package]] name = "frame-system-rpc-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "parity-scale-codec", "sp-api", @@ -2152,7 +2152,7 @@ dependencies = [ [[package]] name = "frame-try-runtime" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "frame-support", "sp-api", @@ -2304,8 +2304,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a1387e07917c711fb4ee4f48ea0adb04a3c9739e53ef85bf43ae1edc2937a8b" dependencies = [ "futures-io", - "rustls", - "webpki", + "rustls 0.19.1", + "webpki 0.21.4", ] [[package]] @@ -2348,7 +2348,7 @@ dependencies = [ [[package]] name = "generate-bags" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "chrono", "frame-election-provider-support", @@ -2704,11 +2704,11 @@ dependencies = [ "futures-util", "hyper", "log", - "rustls", - "rustls-native-certs", + "rustls 0.19.1", + "rustls-native-certs 0.5.0", "tokio", - "tokio-rustls", - "webpki", + "tokio-rustls 0.22.0", + "webpki 0.21.4", ] [[package]] @@ -3081,19 +3081,73 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6373a33d987866ccfe1af4bc11b089dce941764313f9fd8b7cf13fcb51b72dc5" dependencies = [ - "jsonrpsee-proc-macros", - "jsonrpsee-types", + "jsonrpsee-types 0.4.1", "jsonrpsee-utils", - "jsonrpsee-ws-client", + "jsonrpsee-ws-client 0.4.1", +] + +[[package]] +name = "jsonrpsee" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05fd8cd6c6b1bbd06881d2cf88f1fc83cc36c98f2219090f839115fb4a956cb9" +dependencies = [ + "jsonrpsee-core", + "jsonrpsee-proc-macros", + "jsonrpsee-types 0.8.0", + "jsonrpsee-ws-client 0.8.0", +] + +[[package]] +name = "jsonrpsee-client-transport" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3303cdf246e6ab76e2866fb3d9acb6c76a068b1b28bd923a1b7a8122257ad7b5" +dependencies = [ + "futures 0.3.19", + "http", + "jsonrpsee-core", + "jsonrpsee-types 0.8.0", + "pin-project 1.0.10", + "rustls-native-certs 0.6.1", + "soketto", + "thiserror", + "tokio", + "tokio-rustls 0.23.2", + "tokio-util", + "tracing", + "webpki-roots 0.22.2", +] + +[[package]] +name = "jsonrpsee-core" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f220b5a238dc7992b90f1144fbf6eaa585872c9376afe6fe6863ffead6191bf3" +dependencies = [ + "anyhow", + "arrayvec 0.7.2", + "async-trait", + "beef", + "futures-channel", + "futures-util", + "hyper", + "jsonrpsee-types 0.8.0", + "rustc-hash", + "serde", + "serde_json", + "soketto", + "thiserror", + "tokio", + "tracing", ] [[package]] name = "jsonrpsee-proc-macros" -version = "0.4.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d802063f7a3c867456955f9d2f15eb3ee0edb5ec9ec2b5526324756759221c0f" +checksum = "4299ebf790ea9de1cb72e73ff2ae44c723ef264299e5e2d5ef46a371eb3ac3d8" dependencies = [ - "log", "proc-macro-crate 1.1.0", "proc-macro2", "quote", @@ -3119,6 +3173,20 @@ dependencies = [ "thiserror", ] +[[package]] +name = "jsonrpsee-types" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1b3f601bbbe45cd63f5407b6f7d7950e08a7d4f82aa699ff41a4a5e9e54df58" +dependencies = [ + "anyhow", + "beef", + "serde", + "serde_json", + "thiserror", + "tracing", +] + [[package]] name = "jsonrpsee-utils" version = "0.4.1" @@ -3127,7 +3195,7 @@ checksum = "0109c4f972058f3b1925b73a17210aff7b63b65967264d0045d15ee88fe84f0c" dependencies = [ "arrayvec 0.7.2", "beef", - "jsonrpsee-types", + "jsonrpsee-types 0.4.1", ] [[package]] @@ -3141,19 +3209,30 @@ dependencies = [ "fnv", "futures 0.3.19", "http", - "jsonrpsee-types", + "jsonrpsee-types 0.4.1", "log", "pin-project 1.0.10", - "rustls-native-certs", + "rustls-native-certs 0.5.0", "serde", "serde_json", "soketto", "thiserror", "tokio", - "tokio-rustls", + "tokio-rustls 0.22.0", "tokio-util", ] +[[package]] +name = "jsonrpsee-ws-client" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aff425cee7c779e33920913bc695447416078ee6d119f443f3060feffa4e86b5" +dependencies = [ + "jsonrpsee-client-transport", + "jsonrpsee-core", + "jsonrpsee-types 0.8.0", +] + [[package]] name = "keccak" version = "0.1.0" @@ -3833,7 +3912,7 @@ dependencies = [ "rw-stream-sink", "soketto", "url 2.2.2", - "webpki-roots", + "webpki-roots 0.21.1", ] [[package]] @@ -4438,7 +4517,7 @@ dependencies = [ [[package]] name = "node-primitives" version = "2.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "frame-system", "parity-scale-codec", @@ -4693,7 +4772,7 @@ checksum = "2386b4ebe91c2f7f51082d4cefa145d030e33a1842a96b12e4885cc3c01f7a55" [[package]] name = "pallet-assets" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "frame-benchmarking", "frame-support", @@ -4707,7 +4786,7 @@ dependencies = [ [[package]] name = "pallet-authority-discovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "frame-support", "frame-system", @@ -4723,7 +4802,7 @@ dependencies = [ [[package]] name = "pallet-authorship" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "frame-support", "frame-system", @@ -4738,7 +4817,7 @@ dependencies = [ [[package]] name = "pallet-babe" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "frame-benchmarking", "frame-support", @@ -4762,7 +4841,7 @@ dependencies = [ [[package]] name = "pallet-bags-list" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -4782,7 +4861,7 @@ dependencies = [ [[package]] name = "pallet-bags-list-remote-tests" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "frame-election-provider-support", "frame-support", @@ -4802,7 +4881,7 @@ dependencies = [ [[package]] name = "pallet-balances" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "frame-benchmarking", "frame-support", @@ -4817,7 +4896,7 @@ dependencies = [ [[package]] name = "pallet-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "beefy-primitives", "frame-support", @@ -4833,7 +4912,7 @@ dependencies = [ [[package]] name = "pallet-beefy-mmr" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "beefy-merkle-tree", "beefy-primitives", @@ -4858,7 +4937,7 @@ dependencies = [ [[package]] name = "pallet-bounties" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "frame-benchmarking", "frame-support", @@ -4942,7 +5021,7 @@ dependencies = [ [[package]] name = "pallet-collective" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "frame-benchmarking", "frame-support", @@ -4959,7 +5038,7 @@ dependencies = [ [[package]] name = "pallet-democracy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "frame-benchmarking", "frame-support", @@ -4975,7 +5054,7 @@ dependencies = [ [[package]] name = "pallet-election-provider-multi-phase" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -4992,14 +5071,13 @@ dependencies = [ "sp-runtime", "sp-std", "static_assertions", - "strum 0.22.0", - "strum_macros 0.23.1", + "strum", ] [[package]] name = "pallet-elections-phragmen" version = "5.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "frame-benchmarking", "frame-support", @@ -5017,7 +5095,7 @@ dependencies = [ [[package]] name = "pallet-gilt" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "frame-benchmarking", "frame-support", @@ -5032,7 +5110,7 @@ dependencies = [ [[package]] name = "pallet-grandpa" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "frame-benchmarking", "frame-support", @@ -5055,7 +5133,7 @@ dependencies = [ [[package]] name = "pallet-identity" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "enumflags2", "frame-benchmarking", @@ -5071,7 +5149,7 @@ dependencies = [ [[package]] name = "pallet-im-online" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "frame-benchmarking", "frame-support", @@ -5091,7 +5169,7 @@ dependencies = [ [[package]] name = "pallet-indices" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "frame-benchmarking", "frame-support", @@ -5108,7 +5186,7 @@ dependencies = [ [[package]] name = "pallet-membership" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "frame-benchmarking", "frame-support", @@ -5125,7 +5203,7 @@ dependencies = [ [[package]] name = "pallet-mmr" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "ckb-merkle-mountain-range", "frame-benchmarking", @@ -5143,7 +5221,7 @@ dependencies = [ [[package]] name = "pallet-mmr-primitives" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "frame-support", "frame-system", @@ -5159,7 +5237,7 @@ dependencies = [ [[package]] name = "pallet-mmr-rpc" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "jsonrpc-core", "jsonrpc-core-client", @@ -5176,7 +5254,7 @@ dependencies = [ [[package]] name = "pallet-multisig" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "frame-benchmarking", "frame-support", @@ -5191,7 +5269,7 @@ dependencies = [ [[package]] name = "pallet-nicks" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "frame-support", "frame-system", @@ -5205,7 +5283,7 @@ dependencies = [ [[package]] name = "pallet-offences" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "frame-support", "frame-system", @@ -5222,7 +5300,7 @@ dependencies = [ [[package]] name = "pallet-offences-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -5245,7 +5323,7 @@ dependencies = [ [[package]] name = "pallet-preimage" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "frame-benchmarking", "frame-support", @@ -5261,7 +5339,7 @@ dependencies = [ [[package]] name = "pallet-proxy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "frame-benchmarking", "frame-support", @@ -5276,7 +5354,7 @@ dependencies = [ [[package]] name = "pallet-recovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "frame-support", "frame-system", @@ -5290,7 +5368,7 @@ dependencies = [ [[package]] name = "pallet-scheduler" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "frame-benchmarking", "frame-support", @@ -5306,7 +5384,7 @@ dependencies = [ [[package]] name = "pallet-session" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "frame-support", "frame-system", @@ -5327,7 +5405,7 @@ dependencies = [ [[package]] name = "pallet-session-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "frame-benchmarking", "frame-support", @@ -5343,7 +5421,7 @@ dependencies = [ [[package]] name = "pallet-society" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "frame-support", "frame-system", @@ -5357,7 +5435,7 @@ dependencies = [ [[package]] name = "pallet-staking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -5380,7 +5458,7 @@ dependencies = [ [[package]] name = "pallet-staking-reward-curve" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "proc-macro-crate 1.1.0", "proc-macro2", @@ -5391,7 +5469,7 @@ dependencies = [ [[package]] name = "pallet-staking-reward-fn" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "log", "sp-arithmetic", @@ -5400,7 +5478,7 @@ dependencies = [ [[package]] name = "pallet-sudo" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "frame-support", "frame-system", @@ -5414,7 +5492,7 @@ dependencies = [ [[package]] name = "pallet-timestamp" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "frame-benchmarking", "frame-support", @@ -5432,7 +5510,7 @@ dependencies = [ [[package]] name = "pallet-tips" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "frame-benchmarking", "frame-support", @@ -5451,7 +5529,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "frame-support", "frame-system", @@ -5468,7 +5546,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "jsonrpc-core", "jsonrpc-core-client", @@ -5485,7 +5563,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "pallet-transaction-payment", "parity-scale-codec", @@ -5496,7 +5574,7 @@ dependencies = [ [[package]] name = "pallet-treasury" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "frame-benchmarking", "frame-support", @@ -5513,7 +5591,7 @@ dependencies = [ [[package]] name = "pallet-utility" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "frame-benchmarking", "frame-support", @@ -5529,7 +5607,7 @@ dependencies = [ [[package]] name = "pallet-vesting" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "frame-benchmarking", "frame-support", @@ -6594,7 +6672,7 @@ dependencies = [ "polkadot-primitives", "sc-authority-discovery", "sc-network", - "strum 0.23.0", + "strum", "thiserror", ] @@ -7922,10 +8000,10 @@ dependencies = [ [[package]] name = "remote-externalities" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "env_logger 0.9.0", - "jsonrpsee", + "jsonrpsee 0.8.0", "log", "parity-scale-codec", "serde", @@ -8185,8 +8263,20 @@ dependencies = [ "base64", "log", "ring", - "sct", - "webpki", + "sct 0.6.1", + "webpki 0.21.4", +] + +[[package]] +name = "rustls" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d37e5e2290f3e040b594b1a9e04377c2c671f1a1cfd9bfdef82106ac1c113f84" +dependencies = [ + "log", + "ring", + "sct 0.7.0", + "webpki 0.22.0", ] [[package]] @@ -8196,11 +8286,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a07b7c1885bd8ed3831c289b7870b13ef46fe0e856d288c30d9cc17d75a2092" dependencies = [ "openssl-probe", - "rustls", + "rustls 0.19.1", "schannel", "security-framework", ] +[[package]] +name = "rustls-native-certs" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca9ebdfa27d3fc180e42879037b5338ab1c040c06affd00d8338598e7800943" +dependencies = [ + "openssl-probe", + "rustls-pemfile", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pemfile" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eebeaeb360c87bfb72e84abdb3447159c0eaececf1bef2aecd65a8be949d1c9" +dependencies = [ + "base64", +] + [[package]] name = "rustversion" version = "1.0.6" @@ -8245,7 +8356,7 @@ dependencies = [ [[package]] name = "sc-allocator" version = "4.1.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "log", "sp-core", @@ -8256,7 +8367,7 @@ dependencies = [ [[package]] name = "sc-authority-discovery" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "async-trait", "futures 0.3.19", @@ -8283,7 +8394,7 @@ dependencies = [ [[package]] name = "sc-basic-authorship" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "futures 0.3.19", "futures-timer", @@ -8306,7 +8417,7 @@ dependencies = [ [[package]] name = "sc-block-builder" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "parity-scale-codec", "sc-client-api", @@ -8322,7 +8433,7 @@ dependencies = [ [[package]] name = "sc-chain-spec" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "impl-trait-for-tuples", "memmap2 0.5.0", @@ -8339,7 +8450,7 @@ dependencies = [ [[package]] name = "sc-chain-spec-derive" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "proc-macro-crate 1.1.0", "proc-macro2", @@ -8350,7 +8461,7 @@ dependencies = [ [[package]] name = "sc-cli" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "chrono", "clap", @@ -8388,7 +8499,7 @@ dependencies = [ [[package]] name = "sc-client-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "fnv", "futures 0.3.19", @@ -8416,7 +8527,7 @@ dependencies = [ [[package]] name = "sc-client-db" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "hash-db", "kvdb", @@ -8441,7 +8552,7 @@ dependencies = [ [[package]] name = "sc-consensus" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "async-trait", "futures 0.3.19", @@ -8465,7 +8576,7 @@ dependencies = [ [[package]] name = "sc-consensus-babe" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "async-trait", "fork-tree", @@ -8508,7 +8619,7 @@ dependencies = [ [[package]] name = "sc-consensus-babe-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "futures 0.3.19", "jsonrpc-core", @@ -8532,7 +8643,7 @@ dependencies = [ [[package]] name = "sc-consensus-epochs" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "fork-tree", "parity-scale-codec", @@ -8545,7 +8656,7 @@ dependencies = [ [[package]] name = "sc-consensus-slots" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "async-trait", "futures 0.3.19", @@ -8570,7 +8681,7 @@ dependencies = [ [[package]] name = "sc-consensus-uncles" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "sc-client-api", "sp-authorship", @@ -8581,7 +8692,7 @@ dependencies = [ [[package]] name = "sc-executor" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "lazy_static", "libsecp256k1", @@ -8609,7 +8720,7 @@ dependencies = [ [[package]] name = "sc-executor-common" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "environmental", "parity-scale-codec", @@ -8626,7 +8737,7 @@ dependencies = [ [[package]] name = "sc-executor-wasmi" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "log", "parity-scale-codec", @@ -8642,7 +8753,7 @@ dependencies = [ [[package]] name = "sc-executor-wasmtime" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "cfg-if 1.0.0", "libc", @@ -8660,7 +8771,7 @@ dependencies = [ [[package]] name = "sc-finality-grandpa" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "async-trait", "dyn-clone", @@ -8698,7 +8809,7 @@ dependencies = [ [[package]] name = "sc-finality-grandpa-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "finality-grandpa", "futures 0.3.19", @@ -8722,7 +8833,7 @@ dependencies = [ [[package]] name = "sc-informant" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "ansi_term", "futures 0.3.19", @@ -8739,7 +8850,7 @@ dependencies = [ [[package]] name = "sc-keystore" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "async-trait", "hex", @@ -8754,7 +8865,7 @@ dependencies = [ [[package]] name = "sc-network" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "async-std", "async-trait", @@ -8804,7 +8915,7 @@ dependencies = [ [[package]] name = "sc-network-gossip" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "futures 0.3.19", "futures-timer", @@ -8820,7 +8931,7 @@ dependencies = [ [[package]] name = "sc-offchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "bytes 1.1.0", "fnv", @@ -8848,7 +8959,7 @@ dependencies = [ [[package]] name = "sc-peerset" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "futures 0.3.19", "libp2p", @@ -8861,7 +8972,7 @@ dependencies = [ [[package]] name = "sc-proposer-metrics" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "log", "substrate-prometheus-endpoint", @@ -8870,7 +8981,7 @@ dependencies = [ [[package]] name = "sc-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "futures 0.3.19", "hash-db", @@ -8901,7 +9012,7 @@ dependencies = [ [[package]] name = "sc-rpc-api" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "futures 0.3.19", "jsonrpc-core", @@ -8926,7 +9037,7 @@ dependencies = [ [[package]] name = "sc-rpc-server" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "futures 0.3.19", "jsonrpc-core", @@ -8943,7 +9054,7 @@ dependencies = [ [[package]] name = "sc-service" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "async-trait", "directories", @@ -9007,7 +9118,7 @@ dependencies = [ [[package]] name = "sc-state-db" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "log", "parity-scale-codec", @@ -9021,7 +9132,7 @@ dependencies = [ [[package]] name = "sc-sync-state-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "jsonrpc-core", "jsonrpc-core-client", @@ -9043,7 +9154,7 @@ dependencies = [ [[package]] name = "sc-telemetry" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "chrono", "futures 0.3.19", @@ -9061,7 +9172,7 @@ dependencies = [ [[package]] name = "sc-tracing" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "ansi_term", "atty", @@ -9092,7 +9203,7 @@ dependencies = [ [[package]] name = "sc-tracing-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "proc-macro-crate 1.1.0", "proc-macro2", @@ -9103,7 +9214,7 @@ dependencies = [ [[package]] name = "sc-transaction-pool" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "futures 0.3.19", "futures-timer", @@ -9130,7 +9241,7 @@ dependencies = [ [[package]] name = "sc-transaction-pool-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "futures 0.3.19", "log", @@ -9143,7 +9254,7 @@ dependencies = [ [[package]] name = "sc-utils" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "futures 0.3.19", "futures-timer", @@ -9228,6 +9339,16 @@ dependencies = [ "untrusted", ] +[[package]] +name = "sct" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "secrecy" version = "0.8.0" @@ -9572,7 +9693,7 @@ dependencies = [ [[package]] name = "sp-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "hash-db", "log", @@ -9589,7 +9710,7 @@ dependencies = [ [[package]] name = "sp-api-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "blake2-rfc", "proc-macro-crate 1.1.0", @@ -9600,8 +9721,8 @@ dependencies = [ [[package]] name = "sp-application-crypto" -version = "4.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +version = "5.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "parity-scale-codec", "scale-info", @@ -9614,7 +9735,7 @@ dependencies = [ [[package]] name = "sp-arithmetic" version = "4.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "integer-sqrt", "num-traits", @@ -9629,7 +9750,7 @@ dependencies = [ [[package]] name = "sp-authority-discovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "parity-scale-codec", "scale-info", @@ -9642,7 +9763,7 @@ dependencies = [ [[package]] name = "sp-authorship" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "async-trait", "parity-scale-codec", @@ -9654,7 +9775,7 @@ dependencies = [ [[package]] name = "sp-block-builder" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "parity-scale-codec", "sp-api", @@ -9666,7 +9787,7 @@ dependencies = [ [[package]] name = "sp-blockchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "futures 0.3.19", "log", @@ -9684,7 +9805,7 @@ dependencies = [ [[package]] name = "sp-consensus" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "async-trait", "futures 0.3.19", @@ -9703,7 +9824,7 @@ dependencies = [ [[package]] name = "sp-consensus-babe" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "async-trait", "merlin", @@ -9726,7 +9847,7 @@ dependencies = [ [[package]] name = "sp-consensus-slots" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "parity-scale-codec", "scale-info", @@ -9738,7 +9859,7 @@ dependencies = [ [[package]] name = "sp-consensus-vrf" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "parity-scale-codec", "schnorrkel", @@ -9749,8 +9870,8 @@ dependencies = [ [[package]] name = "sp-core" -version = "4.1.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +version = "5.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "base58", "bitflags", @@ -9798,7 +9919,7 @@ dependencies = [ [[package]] name = "sp-core-hashing" version = "4.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "blake2-rfc", "byteorder", @@ -9811,7 +9932,7 @@ dependencies = [ [[package]] name = "sp-core-hashing-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "proc-macro2", "quote", @@ -9822,7 +9943,7 @@ dependencies = [ [[package]] name = "sp-database" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "kvdb", "parking_lot", @@ -9831,7 +9952,7 @@ dependencies = [ [[package]] name = "sp-debug-derive" version = "4.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "proc-macro2", "quote", @@ -9840,8 +9961,8 @@ dependencies = [ [[package]] name = "sp-externalities" -version = "0.10.0" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +version = "0.11.0" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "environmental", "parity-scale-codec", @@ -9852,7 +9973,7 @@ dependencies = [ [[package]] name = "sp-finality-grandpa" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "finality-grandpa", "log", @@ -9870,7 +9991,7 @@ dependencies = [ [[package]] name = "sp-inherents" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "async-trait", "impl-trait-for-tuples", @@ -9883,8 +10004,8 @@ dependencies = [ [[package]] name = "sp-io" -version = "4.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +version = "5.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "futures 0.3.19", "hash-db", @@ -9908,18 +10029,18 @@ dependencies = [ [[package]] name = "sp-keyring" version = "4.1.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "lazy_static", "sp-core", "sp-runtime", - "strum 0.22.0", + "strum", ] [[package]] name = "sp-keystore" -version = "0.10.0" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +version = "0.11.0" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "async-trait", "futures 0.3.19", @@ -9936,7 +10057,7 @@ dependencies = [ [[package]] name = "sp-maybe-compressed-blob" version = "4.1.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "zstd", ] @@ -9944,7 +10065,7 @@ dependencies = [ [[package]] name = "sp-npos-elections" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "parity-scale-codec", "scale-info", @@ -9959,7 +10080,7 @@ dependencies = [ [[package]] name = "sp-npos-elections-solution-type" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "proc-macro-crate 1.1.0", "proc-macro2", @@ -9970,7 +10091,7 @@ dependencies = [ [[package]] name = "sp-offchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "sp-api", "sp-core", @@ -9980,7 +10101,7 @@ dependencies = [ [[package]] name = "sp-panic-handler" version = "4.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "backtrace", "lazy_static", @@ -9989,8 +10110,8 @@ dependencies = [ [[package]] name = "sp-rpc" -version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +version = "5.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "rustc-hash", "serde", @@ -9999,8 +10120,8 @@ dependencies = [ [[package]] name = "sp-runtime" -version = "4.1.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +version = "5.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "either", "hash256-std-hasher", @@ -10021,8 +10142,8 @@ dependencies = [ [[package]] name = "sp-runtime-interface" -version = "4.1.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +version = "5.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "impl-trait-for-tuples", "parity-scale-codec", @@ -10039,7 +10160,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface-proc-macro" version = "4.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "Inflector", "proc-macro-crate 1.1.0", @@ -10051,7 +10172,7 @@ dependencies = [ [[package]] name = "sp-serializer" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "serde", "serde_json", @@ -10060,7 +10181,7 @@ dependencies = [ [[package]] name = "sp-session" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "parity-scale-codec", "scale-info", @@ -10074,7 +10195,7 @@ dependencies = [ [[package]] name = "sp-staking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "parity-scale-codec", "scale-info", @@ -10084,8 +10205,8 @@ dependencies = [ [[package]] name = "sp-state-machine" -version = "0.10.0" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +version = "0.11.0" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "hash-db", "log", @@ -10108,12 +10229,12 @@ dependencies = [ [[package]] name = "sp-std" version = "4.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" [[package]] name = "sp-storage" -version = "4.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +version = "5.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "impl-serde", "parity-scale-codec", @@ -10126,7 +10247,7 @@ dependencies = [ [[package]] name = "sp-tasks" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "log", "sp-core", @@ -10139,7 +10260,7 @@ dependencies = [ [[package]] name = "sp-timestamp" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "async-trait", "futures-timer", @@ -10155,7 +10276,7 @@ dependencies = [ [[package]] name = "sp-tracing" version = "4.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "parity-scale-codec", "sp-std", @@ -10167,7 +10288,7 @@ dependencies = [ [[package]] name = "sp-transaction-pool" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "sp-api", "sp-runtime", @@ -10176,7 +10297,7 @@ dependencies = [ [[package]] name = "sp-transaction-storage-proof" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "async-trait", "log", @@ -10191,8 +10312,8 @@ dependencies = [ [[package]] name = "sp-trie" -version = "4.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +version = "5.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "hash-db", "memory-db", @@ -10207,7 +10328,7 @@ dependencies = [ [[package]] name = "sp-version" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "impl-serde", "parity-scale-codec", @@ -10224,7 +10345,7 @@ dependencies = [ [[package]] name = "sp-version-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "parity-scale-codec", "proc-macro2", @@ -10234,8 +10355,8 @@ dependencies = [ [[package]] name = "sp-wasm-interface" -version = "4.1.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +version = "5.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "impl-trait-for-tuples", "log", @@ -10280,7 +10401,7 @@ dependencies = [ "frame-election-provider-support", "frame-support", "frame-system", - "jsonrpsee", + "jsonrpsee 0.4.1", "kusama-runtime", "log", "pallet-balances", @@ -10357,34 +10478,13 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" -[[package]] -name = "strum" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7ac893c7d471c8a21f31cfe213ec4f6d9afeed25537c772e08ef3f005f8729e" -dependencies = [ - "strum_macros 0.22.0", -] - [[package]] name = "strum" version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cae14b91c7d11c9a851d3fbc80a963198998c2a64eec840477fa92d8ce9b70bb" dependencies = [ - "strum_macros 0.23.1", -] - -[[package]] -name = "strum_macros" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "339f799d8b549e3744c7ac7feb216383e4005d94bdb22561b3ab8f3b808ae9fb" -dependencies = [ - "heck 0.3.3", - "proc-macro2", - "quote", - "syn", + "strum_macros", ] [[package]] @@ -10424,7 +10524,7 @@ dependencies = [ [[package]] name = "substrate-build-script-utils" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "platforms", ] @@ -10432,7 +10532,7 @@ dependencies = [ [[package]] name = "substrate-frame-rpc-system" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "frame-system-rpc-runtime-api", "futures 0.3.19", @@ -10454,7 +10554,7 @@ dependencies = [ [[package]] name = "substrate-prometheus-endpoint" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "async-std", "futures-util", @@ -10468,7 +10568,7 @@ dependencies = [ [[package]] name = "substrate-test-client" version = "2.0.1" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "async-trait", "futures 0.3.19", @@ -10494,7 +10594,7 @@ dependencies = [ [[package]] name = "substrate-test-utils" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "futures 0.3.19", "substrate-test-utils-derive", @@ -10504,7 +10604,7 @@ dependencies = [ [[package]] name = "substrate-test-utils-derive" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "proc-macro-crate 1.1.0", "proc-macro2", @@ -10515,12 +10615,13 @@ dependencies = [ [[package]] name = "substrate-wasm-builder" version = "5.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "ansi_term", "build-helper", "cargo_metadata", "sp-maybe-compressed-blob", + "strum", "tempfile", "toml", "walkdir", @@ -10859,9 +10960,20 @@ version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc6844de72e57df1980054b38be3a9f4702aba4858be64dd700181a8a6d0e1b6" dependencies = [ - "rustls", + "rustls 0.19.1", + "tokio", + "webpki 0.21.4", +] + +[[package]] +name = "tokio-rustls" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a27d5f2b839802bd8267fa19b0530f5a08b9c08cd417976be2a65d130fe1c11b" +dependencies = [ + "rustls 0.20.2", "tokio", - "webpki", + "webpki 0.22.0", ] [[package]] @@ -11078,10 +11190,10 @@ checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" [[package]] name = "try-runtime-cli" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#da534d7f945c72b373f157826a95786543a6ec9c" +source = "git+https://github.com/paritytech/substrate?branch=master#529c2fd27d3d584951f73ba05bdea357117eadec" dependencies = [ "clap", - "jsonrpsee", + "jsonrpsee 0.4.1", "log", "parity-scale-codec", "remote-externalities", @@ -11667,13 +11779,32 @@ dependencies = [ "untrusted", ] +[[package]] +name = "webpki" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "webpki-roots" version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aabe153544e473b775453675851ecc86863d2a81d786d741f6b76778f2a48940" dependencies = [ - "webpki", + "webpki 0.21.4", +] + +[[package]] +name = "webpki-roots" +version = "0.22.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "552ceb903e957524388c4d3475725ff2c8b7960922063af6ce53c9a43da07449" +dependencies = [ + "webpki 0.22.0", ] [[package]] From 50521332a200a9f7498f26e034b535fcfde4fa40 Mon Sep 17 00:00:00 2001 From: Chevdor Date: Wed, 2 Feb 2022 15:22:32 +0100 Subject: [PATCH 06/15] Version bumps to v0.9.16 and 9160 (#4767) * Bump spec_version * Bump version to 0.9.16 --- Cargo.lock | 162 +++++++++--------- Cargo.toml | 2 +- cli/Cargo.toml | 2 +- core-primitives/Cargo.toml | 2 +- erasure-coding/Cargo.toml | 2 +- erasure-coding/fuzzer/Cargo.toml | 2 +- node/client/Cargo.toml | 2 +- node/collation-generation/Cargo.toml | 2 +- node/core/approval-voting/Cargo.toml | 2 +- node/core/av-store/Cargo.toml | 2 +- node/core/backing/Cargo.toml | 2 +- node/core/bitfield-signing/Cargo.toml | 2 +- node/core/candidate-validation/Cargo.toml | 2 +- node/core/chain-api/Cargo.toml | 2 +- node/core/chain-selection/Cargo.toml | 2 +- node/core/dispute-coordinator/Cargo.toml | 2 +- node/core/parachains-inherent/Cargo.toml | 2 +- node/core/provisioner/Cargo.toml | 2 +- node/core/pvf-checker/Cargo.toml | 2 +- node/core/pvf/Cargo.toml | 2 +- node/core/runtime-api/Cargo.toml | 2 +- node/jaeger/Cargo.toml | 2 +- node/malus/Cargo.toml | 2 +- node/metered-channel/Cargo.toml | 2 +- node/metrics/Cargo.toml | 2 +- node/network/approval-distribution/Cargo.toml | 2 +- .../availability-distribution/Cargo.toml | 2 +- node/network/availability-recovery/Cargo.toml | 2 +- node/network/bitfield-distribution/Cargo.toml | 2 +- node/network/bridge/Cargo.toml | 2 +- node/network/collator-protocol/Cargo.toml | 2 +- node/network/dispute-distribution/Cargo.toml | 2 +- node/network/gossip-support/Cargo.toml | 2 +- node/network/protocol/Cargo.toml | 2 +- .../network/statement-distribution/Cargo.toml | 2 +- node/overseer/Cargo.toml | 2 +- node/overseer/overseer-gen/Cargo.toml | 2 +- .../overseer-gen/proc-macro/Cargo.toml | 2 +- node/primitives/Cargo.toml | 2 +- node/service/Cargo.toml | 2 +- node/subsystem-test-helpers/Cargo.toml | 2 +- node/subsystem-types/Cargo.toml | 2 +- node/subsystem-util/Cargo.toml | 2 +- node/subsystem/Cargo.toml | 2 +- node/test/client/Cargo.toml | 2 +- node/test/performance-test/Cargo.toml | 2 +- node/test/service/Cargo.toml | 2 +- node/zombienet-backchannel/Cargo.toml | 2 +- parachain/Cargo.toml | 2 +- parachain/test-parachains/Cargo.toml | 2 +- parachain/test-parachains/adder/Cargo.toml | 2 +- .../test-parachains/adder/collator/Cargo.toml | 2 +- parachain/test-parachains/halt/Cargo.toml | 2 +- primitives/Cargo.toml | 2 +- primitives/test-helpers/Cargo.toml | 2 +- rpc/Cargo.toml | 2 +- runtime/common/Cargo.toml | 2 +- runtime/common/slot_range_helper/Cargo.toml | 2 +- runtime/kusama/Cargo.toml | 2 +- runtime/kusama/constants/Cargo.toml | 2 +- runtime/kusama/src/lib.rs | 2 +- runtime/metrics/Cargo.toml | 2 +- runtime/parachains/Cargo.toml | 2 +- runtime/polkadot/Cargo.toml | 2 +- runtime/polkadot/constants/Cargo.toml | 2 +- runtime/polkadot/src/lib.rs | 2 +- runtime/rococo/Cargo.toml | 2 +- runtime/rococo/constants/Cargo.toml | 2 +- runtime/test-runtime/Cargo.toml | 2 +- runtime/test-runtime/constants/Cargo.toml | 2 +- runtime/westend/Cargo.toml | 2 +- runtime/westend/constants/Cargo.toml | 2 +- runtime/westend/src/lib.rs | 2 +- statement-table/Cargo.toml | 2 +- utils/generate-bags/Cargo.toml | 2 +- utils/remote-ext-tests/bags-list/Cargo.toml | 14 +- utils/staking-miner/Cargo.toml | 2 +- xcm/Cargo.toml | 2 +- xcm/pallet-xcm-benchmarks/Cargo.toml | 2 +- xcm/pallet-xcm/Cargo.toml | 2 +- xcm/xcm-builder/Cargo.toml | 2 +- xcm/xcm-executor/Cargo.toml | 2 +- xcm/xcm-executor/integration-tests/Cargo.toml | 2 +- xcm/xcm-simulator/Cargo.toml | 2 +- xcm/xcm-simulator/example/Cargo.toml | 2 +- xcm/xcm-simulator/fuzzer/Cargo.toml | 2 +- 86 files changed, 172 insertions(+), 172 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 33afce31f5ff..311a648fd0a1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3251,7 +3251,7 @@ dependencies = [ [[package]] name = "kusama-runtime" -version = "0.9.13" +version = "0.9.16" dependencies = [ "beefy-primitives", "bitvec", @@ -3343,7 +3343,7 @@ dependencies = [ [[package]] name = "kusama-runtime-constants" -version = "0.9.13" +version = "0.9.16" dependencies = [ "frame-support", "polkadot-primitives", @@ -4225,7 +4225,7 @@ dependencies = [ [[package]] name = "metered-channel" -version = "0.9.13" +version = "0.9.16" dependencies = [ "assert_matches", "derive_more", @@ -5621,7 +5621,7 @@ dependencies = [ [[package]] name = "pallet-xcm" -version = "0.9.13" +version = "0.9.16" dependencies = [ "frame-support", "frame-system", @@ -5643,7 +5643,7 @@ dependencies = [ [[package]] name = "pallet-xcm-benchmarks" -version = "0.9.8" +version = "0.9.16" dependencies = [ "frame-benchmarking", "frame-support", @@ -5993,7 +5993,7 @@ checksum = "e8d0eef3571242013a0d5dc84861c3ae4a652e56e12adf8bdc26ff5f8cb34c94" [[package]] name = "polkadot" -version = "0.9.13" +version = "0.9.16" dependencies = [ "assert_cmd", "color-eyre", @@ -6008,7 +6008,7 @@ dependencies = [ [[package]] name = "polkadot-approval-distribution" -version = "0.9.13" +version = "0.9.16" dependencies = [ "assert_matches", "env_logger 0.9.0", @@ -6028,7 +6028,7 @@ dependencies = [ [[package]] name = "polkadot-availability-bitfield-distribution" -version = "0.9.13" +version = "0.9.16" dependencies = [ "assert_matches", "bitvec", @@ -6049,7 +6049,7 @@ dependencies = [ [[package]] name = "polkadot-availability-distribution" -version = "0.9.13" +version = "0.9.16" dependencies = [ "assert_matches", "derive_more", @@ -6077,7 +6077,7 @@ dependencies = [ [[package]] name = "polkadot-availability-recovery" -version = "0.9.13" +version = "0.9.16" dependencies = [ "assert_matches", "env_logger 0.9.0", @@ -6105,7 +6105,7 @@ dependencies = [ [[package]] name = "polkadot-cli" -version = "0.9.13" +version = "0.9.16" dependencies = [ "clap", "frame-benchmarking-cli", @@ -6127,7 +6127,7 @@ dependencies = [ [[package]] name = "polkadot-client" -version = "0.9.13" +version = "0.9.16" dependencies = [ "beefy-primitives", "frame-benchmarking", @@ -6159,7 +6159,7 @@ dependencies = [ [[package]] name = "polkadot-collator-protocol" -version = "0.9.13" +version = "0.9.16" dependencies = [ "always-assert", "assert_matches", @@ -6187,7 +6187,7 @@ dependencies = [ [[package]] name = "polkadot-core-primitives" -version = "0.9.13" +version = "0.9.16" dependencies = [ "parity-scale-codec", "parity-util-mem", @@ -6199,7 +6199,7 @@ dependencies = [ [[package]] name = "polkadot-dispute-distribution" -version = "0.9.13" +version = "0.9.16" dependencies = [ "assert_matches", "async-trait", @@ -6229,7 +6229,7 @@ dependencies = [ [[package]] name = "polkadot-erasure-coding" -version = "0.9.13" +version = "0.9.16" dependencies = [ "parity-scale-codec", "polkadot-node-primitives", @@ -6242,7 +6242,7 @@ dependencies = [ [[package]] name = "polkadot-gossip-support" -version = "0.9.13" +version = "0.9.16" dependencies = [ "assert_matches", "async-trait", @@ -6268,7 +6268,7 @@ dependencies = [ [[package]] name = "polkadot-network-bridge" -version = "0.9.13" +version = "0.9.16" dependencies = [ "assert_matches", "async-trait", @@ -6292,7 +6292,7 @@ dependencies = [ [[package]] name = "polkadot-node-collation-generation" -version = "0.9.13" +version = "0.9.16" dependencies = [ "futures 0.3.19", "parity-scale-codec", @@ -6311,7 +6311,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-approval-voting" -version = "0.9.13" +version = "0.9.16" dependencies = [ "assert_matches", "bitvec", @@ -6348,7 +6348,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-av-store" -version = "0.9.13" +version = "0.9.16" dependencies = [ "assert_matches", "bitvec", @@ -6376,7 +6376,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-backing" -version = "0.9.13" +version = "0.9.16" dependencies = [ "assert_matches", "bitvec", @@ -6401,7 +6401,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-bitfield-signing" -version = "0.9.13" +version = "0.9.16" dependencies = [ "futures 0.3.19", "polkadot-node-subsystem", @@ -6417,7 +6417,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-candidate-validation" -version = "0.9.13" +version = "0.9.16" dependencies = [ "assert_matches", "async-trait", @@ -6439,7 +6439,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-chain-api" -version = "0.9.13" +version = "0.9.16" dependencies = [ "futures 0.3.19", "maplit", @@ -6458,7 +6458,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-chain-selection" -version = "0.9.13" +version = "0.9.16" dependencies = [ "assert_matches", "futures 0.3.19", @@ -6479,7 +6479,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-dispute-coordinator" -version = "0.9.13" +version = "0.9.16" dependencies = [ "assert_matches", "futures 0.3.19", @@ -6503,7 +6503,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-parachains-inherent" -version = "0.9.13" +version = "0.9.16" dependencies = [ "async-trait", "futures 0.3.19", @@ -6519,7 +6519,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-provisioner" -version = "0.9.13" +version = "0.9.16" dependencies = [ "bitvec", "futures 0.3.19", @@ -6539,7 +6539,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-pvf" -version = "0.9.13" +version = "0.9.16" dependencies = [ "always-assert", "assert_matches", @@ -6572,7 +6572,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-pvf-checker" -version = "0.9.13" +version = "0.9.16" dependencies = [ "futures 0.3.19", "futures-timer", @@ -6595,7 +6595,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-runtime-api" -version = "0.9.13" +version = "0.9.16" dependencies = [ "futures 0.3.19", "memory-lru", @@ -6616,7 +6616,7 @@ dependencies = [ [[package]] name = "polkadot-node-jaeger" -version = "0.9.13" +version = "0.9.16" dependencies = [ "async-std", "lazy_static", @@ -6633,7 +6633,7 @@ dependencies = [ [[package]] name = "polkadot-node-metrics" -version = "0.9.13" +version = "0.9.16" dependencies = [ "assert_cmd", "bs58", @@ -6661,7 +6661,7 @@ dependencies = [ [[package]] name = "polkadot-node-network-protocol" -version = "0.9.13" +version = "0.9.16" dependencies = [ "async-trait", "derive_more", @@ -6678,7 +6678,7 @@ dependencies = [ [[package]] name = "polkadot-node-primitives" -version = "0.9.13" +version = "0.9.16" dependencies = [ "bounded-vec", "futures 0.3.19", @@ -6700,7 +6700,7 @@ dependencies = [ [[package]] name = "polkadot-node-subsystem" -version = "0.9.13" +version = "0.9.16" dependencies = [ "polkadot-node-jaeger", "polkadot-node-subsystem-types", @@ -6709,7 +6709,7 @@ dependencies = [ [[package]] name = "polkadot-node-subsystem-test-helpers" -version = "0.9.13" +version = "0.9.16" dependencies = [ "async-trait", "futures 0.3.19", @@ -6727,7 +6727,7 @@ dependencies = [ [[package]] name = "polkadot-node-subsystem-types" -version = "0.9.13" +version = "0.9.16" dependencies = [ "derive_more", "futures 0.3.19", @@ -6745,7 +6745,7 @@ dependencies = [ [[package]] name = "polkadot-node-subsystem-util" -version = "0.9.13" +version = "0.9.16" dependencies = [ "assert_matches", "async-trait", @@ -6778,7 +6778,7 @@ dependencies = [ [[package]] name = "polkadot-overseer" -version = "0.9.13" +version = "0.9.16" dependencies = [ "assert_matches", "femme", @@ -6803,7 +6803,7 @@ dependencies = [ [[package]] name = "polkadot-overseer-gen" -version = "0.9.13" +version = "0.9.16" dependencies = [ "async-trait", "futures 0.3.19", @@ -6820,7 +6820,7 @@ dependencies = [ [[package]] name = "polkadot-overseer-gen-proc-macro" -version = "0.9.13" +version = "0.9.16" dependencies = [ "assert_matches", "proc-macro-crate 1.1.0", @@ -6831,7 +6831,7 @@ dependencies = [ [[package]] name = "polkadot-parachain" -version = "0.9.13" +version = "0.9.16" dependencies = [ "derive_more", "frame-support", @@ -6847,7 +6847,7 @@ dependencies = [ [[package]] name = "polkadot-performance-test" -version = "0.9.13" +version = "0.9.16" dependencies = [ "env_logger 0.9.0", "kusama-runtime", @@ -6861,7 +6861,7 @@ dependencies = [ [[package]] name = "polkadot-primitives" -version = "0.9.13" +version = "0.9.16" dependencies = [ "bitvec", "frame-system", @@ -6890,7 +6890,7 @@ dependencies = [ [[package]] name = "polkadot-primitives-test-helpers" -version = "0.9.13" +version = "0.9.16" dependencies = [ "polkadot-primitives", "sp-application-crypto", @@ -6900,7 +6900,7 @@ dependencies = [ [[package]] name = "polkadot-rpc" -version = "0.9.13" +version = "0.9.16" dependencies = [ "beefy-gadget", "beefy-gadget-rpc", @@ -6930,7 +6930,7 @@ dependencies = [ [[package]] name = "polkadot-runtime" -version = "0.9.13" +version = "0.9.16" dependencies = [ "beefy-primitives", "bitvec", @@ -7019,7 +7019,7 @@ dependencies = [ [[package]] name = "polkadot-runtime-common" -version = "0.9.13" +version = "0.9.16" dependencies = [ "beefy-primitives", "bitvec", @@ -7071,7 +7071,7 @@ dependencies = [ [[package]] name = "polkadot-runtime-constants" -version = "0.9.13" +version = "0.9.16" dependencies = [ "frame-support", "polkadot-primitives", @@ -7082,7 +7082,7 @@ dependencies = [ [[package]] name = "polkadot-runtime-metrics" -version = "0.9.13" +version = "0.9.16" dependencies = [ "bs58", "parity-scale-codec", @@ -7093,7 +7093,7 @@ dependencies = [ [[package]] name = "polkadot-runtime-parachains" -version = "0.9.13" +version = "0.9.16" dependencies = [ "assert_matches", "bitflags", @@ -7143,7 +7143,7 @@ dependencies = [ [[package]] name = "polkadot-service" -version = "0.9.13" +version = "0.9.16" dependencies = [ "assert_matches", "async-trait", @@ -7250,7 +7250,7 @@ dependencies = [ [[package]] name = "polkadot-statement-distribution" -version = "0.9.13" +version = "0.9.16" dependencies = [ "arrayvec 0.5.2", "assert_matches", @@ -7280,7 +7280,7 @@ dependencies = [ [[package]] name = "polkadot-statement-table" -version = "0.9.13" +version = "0.9.16" dependencies = [ "parity-scale-codec", "polkadot-primitives", @@ -7289,7 +7289,7 @@ dependencies = [ [[package]] name = "polkadot-test-client" -version = "0.9.13" +version = "0.9.16" dependencies = [ "futures 0.3.19", "parity-scale-codec", @@ -7315,7 +7315,7 @@ dependencies = [ [[package]] name = "polkadot-test-malus" -version = "0.9.13" +version = "0.9.16" dependencies = [ "assert_matches", "async-trait", @@ -7342,7 +7342,7 @@ dependencies = [ [[package]] name = "polkadot-test-runtime" -version = "0.9.13" +version = "0.9.16" dependencies = [ "beefy-primitives", "bitvec", @@ -7408,7 +7408,7 @@ dependencies = [ [[package]] name = "polkadot-test-service" -version = "0.9.13" +version = "0.9.16" dependencies = [ "frame-benchmarking", "frame-system", @@ -7463,7 +7463,7 @@ dependencies = [ [[package]] name = "polkadot-voter-bags" -version = "0.9.0" +version = "0.9.16" dependencies = [ "clap", "generate-bags", @@ -7980,7 +7980,7 @@ dependencies = [ [[package]] name = "remote-ext-tests-bags-list" -version = "0.9.13" +version = "0.9.16" dependencies = [ "clap", "frame-system", @@ -8111,7 +8111,7 @@ dependencies = [ [[package]] name = "rococo-runtime" -version = "0.9.13" +version = "0.9.16" dependencies = [ "beefy-primitives", "bp-messages", @@ -8185,7 +8185,7 @@ dependencies = [ [[package]] name = "rococo-runtime-constants" -version = "0.9.13" +version = "0.9.16" dependencies = [ "frame-support", "polkadot-primitives", @@ -9605,7 +9605,7 @@ checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" [[package]] name = "slot-range-helper" -version = "0.9.13" +version = "0.9.16" dependencies = [ "enumn", "parity-scale-codec", @@ -10394,7 +10394,7 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "staking-miner" -version = "0.9.13" +version = "0.9.16" dependencies = [ "clap", "env_logger 0.9.0", @@ -10700,7 +10700,7 @@ checksum = "13a4ec180a2de59b57434704ccfad967f789b12737738798fa08798cd5824c16" [[package]] name = "test-parachain-adder" -version = "0.9.13" +version = "0.9.16" dependencies = [ "dlmalloc", "parity-scale-codec", @@ -10713,7 +10713,7 @@ dependencies = [ [[package]] name = "test-parachain-adder-collator" -version = "0.9.13" +version = "0.9.16" dependencies = [ "clap", "futures 0.3.19", @@ -10739,14 +10739,14 @@ dependencies = [ [[package]] name = "test-parachain-halt" -version = "0.9.13" +version = "0.9.16" dependencies = [ "substrate-wasm-builder", ] [[package]] name = "test-parachains" -version = "0.9.13" +version = "0.9.16" dependencies = [ "parity-scale-codec", "sp-core", @@ -10757,7 +10757,7 @@ dependencies = [ [[package]] name = "test-runtime-constants" -version = "0.9.13" +version = "0.9.16" dependencies = [ "frame-support", "polkadot-primitives", @@ -11818,7 +11818,7 @@ dependencies = [ [[package]] name = "westend-runtime" -version = "0.9.13" +version = "0.9.16" dependencies = [ "beefy-primitives", "bitvec", @@ -11907,7 +11907,7 @@ dependencies = [ [[package]] name = "westend-runtime-constants" -version = "0.9.13" +version = "0.9.16" dependencies = [ "frame-support", "polkadot-primitives", @@ -12023,7 +12023,7 @@ dependencies = [ [[package]] name = "xcm" -version = "0.9.13" +version = "0.9.16" dependencies = [ "derivative", "impl-trait-for-tuples", @@ -12035,7 +12035,7 @@ dependencies = [ [[package]] name = "xcm-builder" -version = "0.9.13" +version = "0.9.16" dependencies = [ "frame-support", "frame-system", @@ -12058,7 +12058,7 @@ dependencies = [ [[package]] name = "xcm-executor" -version = "0.9.13" +version = "0.9.16" dependencies = [ "frame-benchmarking", "frame-support", @@ -12075,7 +12075,7 @@ dependencies = [ [[package]] name = "xcm-executor-integration-tests" -version = "0.9.13" +version = "0.9.16" dependencies = [ "frame-support", "frame-system", @@ -12105,7 +12105,7 @@ dependencies = [ [[package]] name = "xcm-simulator" -version = "0.9.13" +version = "0.9.16" dependencies = [ "frame-support", "parity-scale-codec", @@ -12121,7 +12121,7 @@ dependencies = [ [[package]] name = "xcm-simulator-example" -version = "0.9.13" +version = "0.9.16" dependencies = [ "frame-support", "frame-system", @@ -12144,7 +12144,7 @@ dependencies = [ [[package]] name = "xcm-simulator-fuzzer" -version = "0.9.9" +version = "0.9.16" dependencies = [ "frame-support", "frame-system", @@ -12203,7 +12203,7 @@ dependencies = [ [[package]] name = "zombienet-backchannel" -version = "0.9.13" +version = "0.9.16" dependencies = [ "futures-util", "lazy_static", diff --git a/Cargo.toml b/Cargo.toml index 5648a82a635a..da63014e59fa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ path = "src/main.rs" name = "polkadot" description = "Implementation of a `https://polkadot.network` node in Rust based on the Substrate framework." license = "GPL-3.0-only" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2018" rust-version = "1.57.0" # custom profiles diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 903e89dc9076..228b5264f9bd 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-cli" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] description = "Polkadot Relay-chain Client Node" edition = "2018" diff --git a/core-primitives/Cargo.toml b/core-primitives/Cargo.toml index 641a9f066440..8b683c321c60 100644 --- a/core-primitives/Cargo.toml +++ b/core-primitives/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-core-primitives" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2018" diff --git a/erasure-coding/Cargo.toml b/erasure-coding/Cargo.toml index 89329429cc1b..f0a725105a40 100644 --- a/erasure-coding/Cargo.toml +++ b/erasure-coding/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-erasure-coding" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2018" diff --git a/erasure-coding/fuzzer/Cargo.toml b/erasure-coding/fuzzer/Cargo.toml index fe8c6fcdf63f..580080d2d73e 100644 --- a/erasure-coding/fuzzer/Cargo.toml +++ b/erasure-coding/fuzzer/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "erasure_coding_fuzzer" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2018" diff --git a/node/client/Cargo.toml b/node/client/Cargo.toml index 265a0a81c030..0e382e8b59f3 100644 --- a/node/client/Cargo.toml +++ b/node/client/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-client" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2018" diff --git a/node/collation-generation/Cargo.toml b/node/collation-generation/Cargo.toml index f02650d511c6..c0fb7340e67c 100644 --- a/node/collation-generation/Cargo.toml +++ b/node/collation-generation/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-node-collation-generation" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2018" diff --git a/node/core/approval-voting/Cargo.toml b/node/core/approval-voting/Cargo.toml index 25e8c5901823..562c094b113d 100644 --- a/node/core/approval-voting/Cargo.toml +++ b/node/core/approval-voting/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-node-core-approval-voting" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2018" diff --git a/node/core/av-store/Cargo.toml b/node/core/av-store/Cargo.toml index ede37569913b..4c46a79d35af 100644 --- a/node/core/av-store/Cargo.toml +++ b/node/core/av-store/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-node-core-av-store" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2018" diff --git a/node/core/backing/Cargo.toml b/node/core/backing/Cargo.toml index 6444853555eb..d23ead6bf442 100644 --- a/node/core/backing/Cargo.toml +++ b/node/core/backing/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-node-core-backing" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2018" diff --git a/node/core/bitfield-signing/Cargo.toml b/node/core/bitfield-signing/Cargo.toml index 3e56b903ecff..ec9e8c940478 100644 --- a/node/core/bitfield-signing/Cargo.toml +++ b/node/core/bitfield-signing/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-node-core-bitfield-signing" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2018" diff --git a/node/core/candidate-validation/Cargo.toml b/node/core/candidate-validation/Cargo.toml index ea6ee3edbf62..6f4ea9adac15 100644 --- a/node/core/candidate-validation/Cargo.toml +++ b/node/core/candidate-validation/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-node-core-candidate-validation" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2018" diff --git a/node/core/chain-api/Cargo.toml b/node/core/chain-api/Cargo.toml index 4fd20e920fd1..3c851f69411c 100644 --- a/node/core/chain-api/Cargo.toml +++ b/node/core/chain-api/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-node-core-chain-api" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2018" diff --git a/node/core/chain-selection/Cargo.toml b/node/core/chain-selection/Cargo.toml index 814f732dae61..0b05ea1a15f6 100644 --- a/node/core/chain-selection/Cargo.toml +++ b/node/core/chain-selection/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "polkadot-node-core-chain-selection" description = "Chain Selection Subsystem" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2018" diff --git a/node/core/dispute-coordinator/Cargo.toml b/node/core/dispute-coordinator/Cargo.toml index a53e0437f5f5..96b9cbffb7f8 100644 --- a/node/core/dispute-coordinator/Cargo.toml +++ b/node/core/dispute-coordinator/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-node-core-dispute-coordinator" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2018" diff --git a/node/core/parachains-inherent/Cargo.toml b/node/core/parachains-inherent/Cargo.toml index 2bd49fb701a4..6f277fffc306 100644 --- a/node/core/parachains-inherent/Cargo.toml +++ b/node/core/parachains-inherent/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-node-core-parachains-inherent" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2018" diff --git a/node/core/provisioner/Cargo.toml b/node/core/provisioner/Cargo.toml index 1b88b9d201f5..9c31f2352fec 100644 --- a/node/core/provisioner/Cargo.toml +++ b/node/core/provisioner/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-node-core-provisioner" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2018" diff --git a/node/core/pvf-checker/Cargo.toml b/node/core/pvf-checker/Cargo.toml index 6e2cf4a94461..9be6db0ecc0b 100644 --- a/node/core/pvf-checker/Cargo.toml +++ b/node/core/pvf-checker/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-node-core-pvf-checker" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2018" diff --git a/node/core/pvf/Cargo.toml b/node/core/pvf/Cargo.toml index 4c685f19c4ec..b45aae492a0d 100644 --- a/node/core/pvf/Cargo.toml +++ b/node/core/pvf/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-node-core-pvf" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2018" diff --git a/node/core/runtime-api/Cargo.toml b/node/core/runtime-api/Cargo.toml index 434be9ba63ef..aba1807f2414 100644 --- a/node/core/runtime-api/Cargo.toml +++ b/node/core/runtime-api/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-node-core-runtime-api" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2018" diff --git a/node/jaeger/Cargo.toml b/node/jaeger/Cargo.toml index 3a8f5e27cbec..722078e80a35 100644 --- a/node/jaeger/Cargo.toml +++ b/node/jaeger/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-node-jaeger" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2018" description = "Polkadot Jaeger primitives" diff --git a/node/malus/Cargo.toml b/node/malus/Cargo.toml index 6e70902fc5c7..b0c410c9e2b0 100644 --- a/node/malus/Cargo.toml +++ b/node/malus/Cargo.toml @@ -2,7 +2,7 @@ name = "polkadot-test-malus" description = "Misbehaving nodes for local testnets, system and Simnet tests." license = "GPL-3.0-only" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2018" readme = "README.md" diff --git a/node/metered-channel/Cargo.toml b/node/metered-channel/Cargo.toml index 17babb593a92..ac657812d83c 100644 --- a/node/metered-channel/Cargo.toml +++ b/node/metered-channel/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "metered-channel" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2018" description = "Channels with attached Meters" diff --git a/node/metrics/Cargo.toml b/node/metrics/Cargo.toml index 4055fff1bc9a..0c6ebbb65a42 100644 --- a/node/metrics/Cargo.toml +++ b/node/metrics/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-node-metrics" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2018" description = "Subsystem metric helpers" diff --git a/node/network/approval-distribution/Cargo.toml b/node/network/approval-distribution/Cargo.toml index fdad3c8cbfb2..f5b249218197 100644 --- a/node/network/approval-distribution/Cargo.toml +++ b/node/network/approval-distribution/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-approval-distribution" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2018" diff --git a/node/network/availability-distribution/Cargo.toml b/node/network/availability-distribution/Cargo.toml index e7ff04bd0dd0..c33513b2285a 100644 --- a/node/network/availability-distribution/Cargo.toml +++ b/node/network/availability-distribution/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-availability-distribution" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2018" diff --git a/node/network/availability-recovery/Cargo.toml b/node/network/availability-recovery/Cargo.toml index c0def1af5177..e3cc654c5270 100644 --- a/node/network/availability-recovery/Cargo.toml +++ b/node/network/availability-recovery/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-availability-recovery" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2018" diff --git a/node/network/bitfield-distribution/Cargo.toml b/node/network/bitfield-distribution/Cargo.toml index 13fddb322973..4e7a309d0d87 100644 --- a/node/network/bitfield-distribution/Cargo.toml +++ b/node/network/bitfield-distribution/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-availability-bitfield-distribution" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2018" diff --git a/node/network/bridge/Cargo.toml b/node/network/bridge/Cargo.toml index 7d587a8f588c..9d2d714ee44c 100644 --- a/node/network/bridge/Cargo.toml +++ b/node/network/bridge/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-network-bridge" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2018" diff --git a/node/network/collator-protocol/Cargo.toml b/node/network/collator-protocol/Cargo.toml index bd448ecbaa9c..16ee69e637b5 100644 --- a/node/network/collator-protocol/Cargo.toml +++ b/node/network/collator-protocol/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-collator-protocol" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2018" diff --git a/node/network/dispute-distribution/Cargo.toml b/node/network/dispute-distribution/Cargo.toml index d346450e47ba..65517287ff34 100644 --- a/node/network/dispute-distribution/Cargo.toml +++ b/node/network/dispute-distribution/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-dispute-distribution" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2018" diff --git a/node/network/gossip-support/Cargo.toml b/node/network/gossip-support/Cargo.toml index e9f41edca58b..7f524e26002d 100644 --- a/node/network/gossip-support/Cargo.toml +++ b/node/network/gossip-support/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-gossip-support" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2018" diff --git a/node/network/protocol/Cargo.toml b/node/network/protocol/Cargo.toml index d2d11212de8e..e29fe0de98a3 100644 --- a/node/network/protocol/Cargo.toml +++ b/node/network/protocol/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-node-network-protocol" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2018" description = "Primitives types for the Node-side" diff --git a/node/network/statement-distribution/Cargo.toml b/node/network/statement-distribution/Cargo.toml index add65e923cf4..bf2c3644bac0 100644 --- a/node/network/statement-distribution/Cargo.toml +++ b/node/network/statement-distribution/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-statement-distribution" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] description = "Statement Distribution Subsystem" edition = "2018" diff --git a/node/overseer/Cargo.toml b/node/overseer/Cargo.toml index 1a6c8f5247ac..2b2ce13bfdc7 100644 --- a/node/overseer/Cargo.toml +++ b/node/overseer/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-overseer" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2018" diff --git a/node/overseer/overseer-gen/Cargo.toml b/node/overseer/overseer-gen/Cargo.toml index 1a53359638c6..543e984fea18 100644 --- a/node/overseer/overseer-gen/Cargo.toml +++ b/node/overseer/overseer-gen/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-overseer-gen" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2018" description = "Generate an overseer including builder pattern and message wrapper from a single struct." diff --git a/node/overseer/overseer-gen/proc-macro/Cargo.toml b/node/overseer/overseer-gen/proc-macro/Cargo.toml index f0c3cc9d12a0..9df040bf059a 100644 --- a/node/overseer/overseer-gen/proc-macro/Cargo.toml +++ b/node/overseer/overseer-gen/proc-macro/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-overseer-gen-proc-macro" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2018" description = "Generate an overseer including builder pattern and message wrapper from a single annotated struct definition." diff --git a/node/primitives/Cargo.toml b/node/primitives/Cargo.toml index 7a216e6e55de..97e872fe7494 100644 --- a/node/primitives/Cargo.toml +++ b/node/primitives/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-node-primitives" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2018" description = "Primitives types for the Node-side" diff --git a/node/service/Cargo.toml b/node/service/Cargo.toml index 056287e53107..ce3de4e8b49b 100644 --- a/node/service/Cargo.toml +++ b/node/service/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-service" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2018" diff --git a/node/subsystem-test-helpers/Cargo.toml b/node/subsystem-test-helpers/Cargo.toml index 339bc4b5b09b..1d1dda5fbaa0 100644 --- a/node/subsystem-test-helpers/Cargo.toml +++ b/node/subsystem-test-helpers/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-node-subsystem-test-helpers" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2018" description = "Subsystem traits and message definitions" diff --git a/node/subsystem-types/Cargo.toml b/node/subsystem-types/Cargo.toml index 7040f7819a9b..0bb521178f22 100644 --- a/node/subsystem-types/Cargo.toml +++ b/node/subsystem-types/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-node-subsystem-types" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2018" description = "Subsystem traits and message definitions" diff --git a/node/subsystem-util/Cargo.toml b/node/subsystem-util/Cargo.toml index 54fdd548ba23..cf22f7916132 100644 --- a/node/subsystem-util/Cargo.toml +++ b/node/subsystem-util/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-node-subsystem-util" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2018" description = "Subsystem traits and message definitions" diff --git a/node/subsystem/Cargo.toml b/node/subsystem/Cargo.toml index abc10136de23..5fb2ba14e64b 100644 --- a/node/subsystem/Cargo.toml +++ b/node/subsystem/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-node-subsystem" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2018" description = "Subsystem traits and message definitions and the generated overseer" diff --git a/node/test/client/Cargo.toml b/node/test/client/Cargo.toml index 1c4eaff63ccc..536dd854c933 100644 --- a/node/test/client/Cargo.toml +++ b/node/test/client/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-test-client" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2018" diff --git a/node/test/performance-test/Cargo.toml b/node/test/performance-test/Cargo.toml index 69790d53f0f2..8a4f52089c62 100644 --- a/node/test/performance-test/Cargo.toml +++ b/node/test/performance-test/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-performance-test" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2018" diff --git a/node/test/service/Cargo.toml b/node/test/service/Cargo.toml index b8b1a89eb554..6e8afce0ccac 100644 --- a/node/test/service/Cargo.toml +++ b/node/test/service/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-test-service" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2018" diff --git a/node/zombienet-backchannel/Cargo.toml b/node/zombienet-backchannel/Cargo.toml index eeff7b4e9835..437734852237 100644 --- a/node/zombienet-backchannel/Cargo.toml +++ b/node/zombienet-backchannel/Cargo.toml @@ -2,7 +2,7 @@ name = "zombienet-backchannel" description = "Zombienet backchannel to notify test runner and coordinate with malus actors." license = "GPL-3.0-only" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2021" readme = "README.md" diff --git a/parachain/Cargo.toml b/parachain/Cargo.toml index dbbf06a947bf..933f949623d4 100644 --- a/parachain/Cargo.toml +++ b/parachain/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-parachain" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] description = "Types and utilities for creating and working with parachains" edition = "2018" diff --git a/parachain/test-parachains/Cargo.toml b/parachain/test-parachains/Cargo.toml index f1c7dd46090f..36a9236796bf 100644 --- a/parachain/test-parachains/Cargo.toml +++ b/parachain/test-parachains/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "test-parachains" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] description = "Integration tests using the test-parachains" edition = "2018" diff --git a/parachain/test-parachains/adder/Cargo.toml b/parachain/test-parachains/adder/Cargo.toml index 4271a7fe4528..872a8c6dd582 100644 --- a/parachain/test-parachains/adder/Cargo.toml +++ b/parachain/test-parachains/adder/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "test-parachain-adder" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] description = "Test parachain which adds to a number as its state transition" edition = "2018" diff --git a/parachain/test-parachains/adder/collator/Cargo.toml b/parachain/test-parachains/adder/collator/Cargo.toml index bc038bedde53..564c2d590115 100644 --- a/parachain/test-parachains/adder/collator/Cargo.toml +++ b/parachain/test-parachains/adder/collator/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "test-parachain-adder-collator" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] description = "Collator for the adder test parachain" edition = "2018" diff --git a/parachain/test-parachains/halt/Cargo.toml b/parachain/test-parachains/halt/Cargo.toml index 6430279f5111..80db7b78de95 100644 --- a/parachain/test-parachains/halt/Cargo.toml +++ b/parachain/test-parachains/halt/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "test-parachain-halt" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] description = "Test parachain which executes forever" edition = "2018" diff --git a/primitives/Cargo.toml b/primitives/Cargo.toml index a58b58ed4708..6a9c84a3b801 100644 --- a/primitives/Cargo.toml +++ b/primitives/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-primitives" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2018" diff --git a/primitives/test-helpers/Cargo.toml b/primitives/test-helpers/Cargo.toml index 6cd01d404388..27eb8eb8b05f 100644 --- a/primitives/test-helpers/Cargo.toml +++ b/primitives/test-helpers/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-primitives-test-helpers" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2021" diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index a1850ec091bd..5496ee8126bd 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-rpc" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2018" diff --git a/runtime/common/Cargo.toml b/runtime/common/Cargo.toml index 69b2debdb64a..faef96cac3cc 100644 --- a/runtime/common/Cargo.toml +++ b/runtime/common/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-runtime-common" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2018" diff --git a/runtime/common/slot_range_helper/Cargo.toml b/runtime/common/slot_range_helper/Cargo.toml index a0a4513a6425..e36cb78fe25a 100644 --- a/runtime/common/slot_range_helper/Cargo.toml +++ b/runtime/common/slot_range_helper/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "slot-range-helper" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2018" diff --git a/runtime/kusama/Cargo.toml b/runtime/kusama/Cargo.toml index e74a7e4c5a53..9a74f361cfac 100644 --- a/runtime/kusama/Cargo.toml +++ b/runtime/kusama/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "kusama-runtime" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2018" build = "build.rs" diff --git a/runtime/kusama/constants/Cargo.toml b/runtime/kusama/constants/Cargo.toml index 1ef07a005945..f0a6023ebf7b 100644 --- a/runtime/kusama/constants/Cargo.toml +++ b/runtime/kusama/constants/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "kusama-runtime-constants" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2021" diff --git a/runtime/kusama/src/lib.rs b/runtime/kusama/src/lib.rs index abd5ef1dffb3..249b43f778fb 100644 --- a/runtime/kusama/src/lib.rs +++ b/runtime/kusama/src/lib.rs @@ -115,7 +115,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("kusama"), impl_name: create_runtime_str!("parity-kusama"), authoring_version: 2, - spec_version: 9140, + spec_version: 9160, impl_version: 0, #[cfg(not(feature = "disable-runtime-api"))] apis: RUNTIME_API_VERSIONS, diff --git a/runtime/metrics/Cargo.toml b/runtime/metrics/Cargo.toml index 9c7431d779ba..97bf343aff67 100644 --- a/runtime/metrics/Cargo.toml +++ b/runtime/metrics/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-runtime-metrics" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2018" diff --git a/runtime/parachains/Cargo.toml b/runtime/parachains/Cargo.toml index 6ac657530b38..b6fa2d3206b9 100644 --- a/runtime/parachains/Cargo.toml +++ b/runtime/parachains/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-runtime-parachains" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2018" diff --git a/runtime/polkadot/Cargo.toml b/runtime/polkadot/Cargo.toml index ee58079f0ca9..129ec20089dd 100644 --- a/runtime/polkadot/Cargo.toml +++ b/runtime/polkadot/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-runtime" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2018" build = "build.rs" diff --git a/runtime/polkadot/constants/Cargo.toml b/runtime/polkadot/constants/Cargo.toml index 42f4ebe95edb..f63232a3565f 100644 --- a/runtime/polkadot/constants/Cargo.toml +++ b/runtime/polkadot/constants/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-runtime-constants" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2021" diff --git a/runtime/polkadot/src/lib.rs b/runtime/polkadot/src/lib.rs index 9b3d40b358e1..09d74520ed28 100644 --- a/runtime/polkadot/src/lib.rs +++ b/runtime/polkadot/src/lib.rs @@ -114,7 +114,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("polkadot"), impl_name: create_runtime_str!("parity-polkadot"), authoring_version: 0, - spec_version: 9140, + spec_version: 9160, impl_version: 0, #[cfg(not(feature = "disable-runtime-api"))] apis: RUNTIME_API_VERSIONS, diff --git a/runtime/rococo/Cargo.toml b/runtime/rococo/Cargo.toml index 2c40ff64710b..917f0c114d64 100644 --- a/runtime/rococo/Cargo.toml +++ b/runtime/rococo/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rococo-runtime" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2018" build = "build.rs" diff --git a/runtime/rococo/constants/Cargo.toml b/runtime/rococo/constants/Cargo.toml index 553c67b694d7..3851b6d6c8e8 100644 --- a/runtime/rococo/constants/Cargo.toml +++ b/runtime/rococo/constants/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rococo-runtime-constants" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2021" diff --git a/runtime/test-runtime/Cargo.toml b/runtime/test-runtime/Cargo.toml index 91d0b1322752..9a4dcea58c9d 100644 --- a/runtime/test-runtime/Cargo.toml +++ b/runtime/test-runtime/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-test-runtime" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2018" build = "build.rs" diff --git a/runtime/test-runtime/constants/Cargo.toml b/runtime/test-runtime/constants/Cargo.toml index 88df1f86cc1b..5bfac0d79fef 100644 --- a/runtime/test-runtime/constants/Cargo.toml +++ b/runtime/test-runtime/constants/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "test-runtime-constants" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2021" diff --git a/runtime/westend/Cargo.toml b/runtime/westend/Cargo.toml index 75301f054b2b..716520c91aba 100644 --- a/runtime/westend/Cargo.toml +++ b/runtime/westend/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "westend-runtime" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2018" build = "build.rs" diff --git a/runtime/westend/constants/Cargo.toml b/runtime/westend/constants/Cargo.toml index ead62809a00a..e401f22a3611 100644 --- a/runtime/westend/constants/Cargo.toml +++ b/runtime/westend/constants/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "westend-runtime-constants" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2021" diff --git a/runtime/westend/src/lib.rs b/runtime/westend/src/lib.rs index ff1e68ef1f67..eb5af15c4af5 100644 --- a/runtime/westend/src/lib.rs +++ b/runtime/westend/src/lib.rs @@ -111,7 +111,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("westend"), impl_name: create_runtime_str!("parity-westend"), authoring_version: 2, - spec_version: 9140, + spec_version: 9160, impl_version: 0, #[cfg(not(feature = "disable-runtime-api"))] apis: RUNTIME_API_VERSIONS, diff --git a/statement-table/Cargo.toml b/statement-table/Cargo.toml index db48cca6f093..8892e4a2fbf6 100644 --- a/statement-table/Cargo.toml +++ b/statement-table/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-statement-table" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2018" diff --git a/utils/generate-bags/Cargo.toml b/utils/generate-bags/Cargo.toml index 4b3a35b6ecaf..3561712340a2 100644 --- a/utils/generate-bags/Cargo.toml +++ b/utils/generate-bags/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-voter-bags" -version = "0.9.0" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2018" diff --git a/utils/remote-ext-tests/bags-list/Cargo.toml b/utils/remote-ext-tests/bags-list/Cargo.toml index aca6b3efaab7..fbc42a30c74e 100644 --- a/utils/remote-ext-tests/bags-list/Cargo.toml +++ b/utils/remote-ext-tests/bags-list/Cargo.toml @@ -1,16 +1,16 @@ [package] name = "remote-ext-tests-bags-list" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2018" [dependencies] -polkadot-runtime = { version = "0.9.13", path = "../../../runtime/polkadot" } -kusama-runtime = { version = "0.9.13", path = "../../../runtime/kusama" } -westend-runtime = { version = "0.9.13", path = "../../../runtime/westend" } -polkadot-runtime-constants = { version = "0.9.13", path = "../../../runtime/polkadot/constants" } -kusama-runtime-constants = { version = "0.9.13", path = "../../../runtime/kusama/constants" } -westend-runtime-constants = { version = "0.9.13", path = "../../../runtime/westend/constants" } +polkadot-runtime = { version = "0.9.16", path = "../../../runtime/polkadot" } +kusama-runtime = { version = "0.9.16", path = "../../../runtime/kusama" } +westend-runtime = { version = "0.9.16", path = "../../../runtime/westend" } +polkadot-runtime-constants = { version = "0.9.16", path = "../../../runtime/polkadot/constants" } +kusama-runtime-constants = { version = "0.9.16", path = "../../../runtime/kusama/constants" } +westend-runtime-constants = { version = "0.9.16", path = "../../../runtime/westend/constants" } pallet-bags-list-remote-tests = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-tracing = { git = "https://github.com/paritytech/substrate", branch = "master" } diff --git a/utils/staking-miner/Cargo.toml b/utils/staking-miner/Cargo.toml index ac0fe6f43997..21e08f84ba7a 100644 --- a/utils/staking-miner/Cargo.toml +++ b/utils/staking-miner/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "staking-miner" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] edition = "2018" diff --git a/xcm/Cargo.toml b/xcm/Cargo.toml index 74fba460bdd9..0b268e1304e5 100644 --- a/xcm/Cargo.toml +++ b/xcm/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "xcm" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] description = "The basic XCM datastructures." edition = "2018" diff --git a/xcm/pallet-xcm-benchmarks/Cargo.toml b/xcm/pallet-xcm-benchmarks/Cargo.toml index 6406b2482072..d59714aad06c 100644 --- a/xcm/pallet-xcm-benchmarks/Cargo.toml +++ b/xcm/pallet-xcm-benchmarks/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-xcm-benchmarks" authors = ["Parity Technologies "] edition = "2018" -version = "0.9.8" +version = "0.9.16" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/xcm/pallet-xcm/Cargo.toml b/xcm/pallet-xcm/Cargo.toml index b72fba007be9..ca553fe30796 100644 --- a/xcm/pallet-xcm/Cargo.toml +++ b/xcm/pallet-xcm/Cargo.toml @@ -2,7 +2,7 @@ authors = ["Parity Technologies "] edition = "2018" name = "pallet-xcm" -version = "0.9.13" +version = "0.9.16" [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } diff --git a/xcm/xcm-builder/Cargo.toml b/xcm/xcm-builder/Cargo.toml index bf776f73b7fa..9cda2e4b0f64 100644 --- a/xcm/xcm-builder/Cargo.toml +++ b/xcm/xcm-builder/Cargo.toml @@ -3,7 +3,7 @@ authors = ["Parity Technologies "] edition = "2018" name = "xcm-builder" description = "Tools & types for building with XCM and its executor." -version = "0.9.13" +version = "0.9.16" [dependencies] parity-scale-codec = { version = "2.3.1", default-features = false, features = ["derive"] } diff --git a/xcm/xcm-executor/Cargo.toml b/xcm/xcm-executor/Cargo.toml index 04006ce65afb..39bdb88ae4c0 100644 --- a/xcm/xcm-executor/Cargo.toml +++ b/xcm/xcm-executor/Cargo.toml @@ -3,7 +3,7 @@ authors = ["Parity Technologies "] edition = "2018" name = "xcm-executor" description = "An abstract and configurable XCM message executor." -version = "0.9.13" +version = "0.9.16" [dependencies] impl-trait-for-tuples = "0.2.0" diff --git a/xcm/xcm-executor/integration-tests/Cargo.toml b/xcm/xcm-executor/integration-tests/Cargo.toml index 3f25cc18eebf..ba20f1e910e0 100644 --- a/xcm/xcm-executor/integration-tests/Cargo.toml +++ b/xcm/xcm-executor/integration-tests/Cargo.toml @@ -3,7 +3,7 @@ authors = ["Parity Technologies "] edition = "2018" name = "xcm-executor-integration-tests" description = "Integration tests for the XCM Executor" -version = "0.9.13" +version = "0.9.16" [dependencies] frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } diff --git a/xcm/xcm-simulator/Cargo.toml b/xcm/xcm-simulator/Cargo.toml index f5320e6ab8d0..deb3ea641784 100644 --- a/xcm/xcm-simulator/Cargo.toml +++ b/xcm/xcm-simulator/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "xcm-simulator" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] description = "Test kit to simulate cross-chain message passing and XCM execution" edition = "2018" diff --git a/xcm/xcm-simulator/example/Cargo.toml b/xcm/xcm-simulator/example/Cargo.toml index 8b25dd6b9344..64a156849a9b 100644 --- a/xcm/xcm-simulator/example/Cargo.toml +++ b/xcm/xcm-simulator/example/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "xcm-simulator-example" -version = "0.9.13" +version = "0.9.16" authors = ["Parity Technologies "] description = "Examples of xcm-simulator usage." edition = "2018" diff --git a/xcm/xcm-simulator/fuzzer/Cargo.toml b/xcm/xcm-simulator/fuzzer/Cargo.toml index 9fada9b71d55..59962ca67897 100644 --- a/xcm/xcm-simulator/fuzzer/Cargo.toml +++ b/xcm/xcm-simulator/fuzzer/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "xcm-simulator-fuzzer" -version = "0.9.9" +version = "0.9.16" authors = ["Parity Technologies "] description = "Examples of xcm-simulator usage." edition = "2018" From 498a7976d588553e1ed27ff0b1b7728e062e334b Mon Sep 17 00:00:00 2001 From: Lldenaurois Date: Wed, 2 Feb 2022 18:40:21 +0100 Subject: [PATCH 07/15] Add tests to ensure session is set correctly in `OnChainScrapingVotes` (#4821) Co-authored-by: Bernhard Schuster --- runtime/parachains/src/disputes.rs | 6 +- .../parachains/src/paras_inherent/tests.rs | 151 +++++++++++++++++- 2 files changed, 150 insertions(+), 7 deletions(-) diff --git a/runtime/parachains/src/disputes.rs b/runtime/parachains/src/disputes.rs index 884e3b47c0fc..2b8662ea41fd 100644 --- a/runtime/parachains/src/disputes.rs +++ b/runtime/parachains/src/disputes.rs @@ -1313,6 +1313,10 @@ fn check_signature( } } +#[cfg(test)] +#[allow(unused_imports)] +pub(crate) use self::tests::run_to_block; + #[cfg(test)] mod tests { use super::*; @@ -1363,7 +1367,7 @@ mod tests { // Run to specific block, while calling disputes pallet hooks manually, because disputes is not // integrated in initializer yet. - fn run_to_block<'a>( + pub(crate) fn run_to_block<'a>( to: BlockNumber, new_session: impl Fn(BlockNumber) -> Option>, ) { diff --git a/runtime/parachains/src/paras_inherent/tests.rs b/runtime/parachains/src/paras_inherent/tests.rs index b00599379b5f..e8ff10b5ed99 100644 --- a/runtime/parachains/src/paras_inherent/tests.rs +++ b/runtime/parachains/src/paras_inherent/tests.rs @@ -127,6 +127,115 @@ mod enter { Pallet::::on_chain_votes().unwrap().backing_validators_per_candidate.len(), 2 ); + + assert_eq!( + // The session of the on chain votes should equal the current session, which is 2 + Pallet::::on_chain_votes().unwrap().session, + 2 + ); + }); + } + + #[test] + fn test_session_is_tracked_in_on_chain_scraping() { + use crate::disputes::run_to_block; + use primitives::v1::{ + DisputeStatement, DisputeStatementSet, ExplicitDisputeStatement, + InvalidDisputeStatementKind, ValidDisputeStatementKind, + }; + use sp_core::{crypto::CryptoType, Pair}; + + new_test_ext(Default::default()).execute_with(|| { + let v0 = ::Pair::generate().0; + let v1 = ::Pair::generate().0; + + run_to_block(6, |b| { + // a new session at each block + Some(( + true, + b, + vec![(&0, v0.public()), (&1, v1.public())], + Some(vec![(&0, v0.public()), (&1, v1.public())]), + )) + }); + + let generate_votes = |session: u32, candidate_hash: CandidateHash| { + // v0 votes for 3 + vec![DisputeStatementSet { + candidate_hash: candidate_hash.clone(), + session, + statements: vec![ + ( + DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), + ValidatorIndex(0), + v0.sign( + &ExplicitDisputeStatement { + valid: false, + candidate_hash: candidate_hash.clone(), + session, + } + .signing_payload(), + ), + ), + ( + DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), + ValidatorIndex(1), + v1.sign( + &ExplicitDisputeStatement { + valid: false, + candidate_hash: candidate_hash.clone(), + session, + } + .signing_payload(), + ), + ), + ( + DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), + ValidatorIndex(1), + v1.sign( + &ExplicitDisputeStatement { + valid: true, + candidate_hash: candidate_hash.clone(), + session, + } + .signing_payload(), + ), + ), + ], + }] + .into_iter() + .map(CheckedDisputeStatementSet::unchecked_from_unchecked) + .collect::>() + }; + + let candidate_hash = CandidateHash(sp_core::H256::repeat_byte(1)); + let statements = generate_votes(3, candidate_hash.clone()); + set_scrapable_on_chain_disputes::(3, statements); + assert_matches!(pallet::Pallet::::on_chain_votes(), Some(ScrapedOnChainVotes { + session, + .. + } ) => { + assert_eq!(session, 3); + }); + run_to_block(7, |b| { + // a new session at each block + Some(( + true, + b, + vec![(&0, v0.public()), (&1, v1.public())], + Some(vec![(&0, v0.public()), (&1, v1.public())]), + )) + }); + + let candidate_hash = CandidateHash(sp_core::H256::repeat_byte(2)); + let statements = generate_votes(7, candidate_hash.clone()); + set_scrapable_on_chain_disputes::(7, statements); + assert_matches!(pallet::Pallet::::on_chain_votes(), Some(ScrapedOnChainVotes { + session, + .. + } ) => { + assert_eq!(session, 7); + }); }); } @@ -194,6 +303,12 @@ mod enter { Pallet::::on_chain_votes().unwrap().backing_validators_per_candidate.len(), 0 ); + + assert_eq!( + // The session of the on chain votes should equal the current session, which is 2 + Pallet::::on_chain_votes().unwrap().session, + 2 + ); }); } @@ -258,6 +373,12 @@ mod enter { Pallet::::on_chain_votes().unwrap().backing_validators_per_candidate.len(), 0 ); + + assert_eq!( + // The session of the on chain votes should equal the current session, which is 2 + Pallet::::on_chain_votes().unwrap().session, + 2 + ); }); } @@ -300,6 +421,9 @@ mod enter { frame_system::RawOrigin::None.into(), expected_para_inherent_data, ), Err(e) => { dbg!(e) }); + + // The block was not included, as such, `on_chain_votes` _must_ return `None`. + assert_eq!(Pallet::::on_chain_votes(), None,); }); } @@ -377,6 +501,12 @@ mod enter { Pallet::::on_chain_votes().unwrap().backing_validators_per_candidate.len(), 0, ); + + assert_eq!( + // The session of the on chain votes should equal the current session, which is 2 + Pallet::::on_chain_votes().unwrap().session, + 2 + ); }); } @@ -425,12 +555,8 @@ mod enter { dbg!(e) }); - assert_eq!( - // The length of this vec is equal to the number of candidates, so we know - // all of our candidates got filtered out - Pallet::::on_chain_votes(), - None, - ); + // The block was not included, as such, `on_chain_votes` _must_ return `None`. + assert_eq!(Pallet::::on_chain_votes(), None,); }); } @@ -514,6 +640,12 @@ mod enter { Pallet::::on_chain_votes().unwrap().backing_validators_per_candidate.len(), 0, ); + + assert_eq!( + // The session of the on chain votes should equal the current session, which is 2 + Pallet::::on_chain_votes().unwrap().session, + 2 + ); }); } @@ -674,6 +806,12 @@ mod enter { Pallet::::on_chain_votes().unwrap().backing_validators_per_candidate.len(), 1 ); + + assert_eq!( + // The session of the on chain votes should equal the current session, which is 2 + Pallet::::on_chain_votes().unwrap().session, + 2 + ); }); } @@ -717,6 +855,7 @@ mod enter { expected_para_inherent_data, ), Err(e) => { dbg!(e) }); + // The block was not included, as such, `on_chain_votes` _must_ return `None`. assert_matches!(Pallet::::on_chain_votes(), None); }); } From 8a5f2620bd8b6acbfd738eaa7975fd6d3340c204 Mon Sep 17 00:00:00 2001 From: Bernhard Schuster Date: Thu, 3 Feb 2022 09:12:41 +0100 Subject: [PATCH 08/15] [chore] runtime split tests (#4834) --- runtime/parachains/src/configuration.rs | 565 +--- runtime/parachains/src/configuration/tests.rs | 553 ++++ runtime/parachains/src/disputes.rs | 2481 +---------------- runtime/parachains/src/disputes/tests.rs | 2453 ++++++++++++++++ runtime/parachains/src/dmp.rs | 197 +- runtime/parachains/src/dmp/tests.rs | 203 ++ runtime/parachains/src/hrmp.rs | 594 +--- runtime/parachains/src/hrmp/tests.rs | 601 ++++ runtime/parachains/src/initializer.rs | 138 +- runtime/parachains/src/initializer/tests.rs | 131 + runtime/parachains/src/scheduler.rs | 1459 +--------- runtime/parachains/src/scheduler/tests.rs | 1451 ++++++++++ runtime/parachains/src/session_info.rs | 205 +- runtime/parachains/src/session_info/tests.rs | 214 ++ runtime/parachains/src/shared.rs | 93 +- runtime/parachains/src/shared/tests.rs | 99 + runtime/parachains/src/ump.rs | 342 +-- runtime/parachains/src/ump/tests.rs | 350 +++ 18 files changed, 6086 insertions(+), 6043 deletions(-) create mode 100644 runtime/parachains/src/configuration/tests.rs create mode 100644 runtime/parachains/src/disputes/tests.rs create mode 100644 runtime/parachains/src/dmp/tests.rs create mode 100644 runtime/parachains/src/hrmp/tests.rs create mode 100644 runtime/parachains/src/initializer/tests.rs create mode 100644 runtime/parachains/src/scheduler/tests.rs create mode 100644 runtime/parachains/src/session_info/tests.rs create mode 100644 runtime/parachains/src/shared/tests.rs create mode 100644 runtime/parachains/src/ump/tests.rs diff --git a/runtime/parachains/src/configuration.rs b/runtime/parachains/src/configuration.rs index 32a71975789d..8337be8c2958 100644 --- a/runtime/parachains/src/configuration.rs +++ b/runtime/parachains/src/configuration.rs @@ -26,6 +26,9 @@ use primitives::v1::{Balance, SessionIndex, MAX_CODE_SIZE, MAX_HEAD_DATA_SIZE, M use sp_runtime::traits::Zero; use sp_std::prelude::*; +#[cfg(test)] +mod tests; + #[cfg(feature = "runtime-benchmarks")] mod benchmarking; @@ -1301,565 +1304,3 @@ impl Pallet { Ok(()) } } - -#[cfg(test)] -mod tests { - use super::*; - use crate::mock::{new_test_ext, Configuration, Origin, ParasShared, Test}; - use frame_support::{assert_err, assert_ok}; - - fn on_new_session( - session_index: SessionIndex, - ) -> (HostConfiguration, HostConfiguration) { - ParasShared::set_session_index(session_index); - let SessionChangeOutcome { prev_config, new_config } = - Configuration::initializer_on_new_session(&session_index); - let new_config = new_config.unwrap_or_else(|| prev_config.clone()); - (prev_config, new_config) - } - - #[test] - fn default_is_consistent() { - new_test_ext(Default::default()).execute_with(|| { - Configuration::config().panic_if_not_consistent(); - }); - } - - #[test] - fn scheduled_session_is_two_sessions_from_now() { - new_test_ext(Default::default()).execute_with(|| { - // The logic here is really tested only with scheduled_session = 2. It should work - // with other values, but that should receive a more rigorious testing. - on_new_session(1); - assert_eq!(Configuration::scheduled_session(), 3); - }); - } - - #[test] - fn initializer_on_new_session() { - new_test_ext(Default::default()).execute_with(|| { - let (prev_config, new_config) = on_new_session(1); - assert_eq!(prev_config, new_config); - assert_ok!(Configuration::set_validation_upgrade_delay(Origin::root(), 100)); - - let (prev_config, new_config) = on_new_session(2); - assert_eq!(prev_config, new_config); - - let (prev_config, new_config) = on_new_session(3); - assert_eq!(prev_config, HostConfiguration::default()); - assert_eq!( - new_config, - HostConfiguration { validation_upgrade_delay: 100, ..prev_config } - ); - }); - } - - #[test] - fn config_changes_after_2_session_boundary() { - new_test_ext(Default::default()).execute_with(|| { - let old_config = Configuration::config(); - let mut config = old_config.clone(); - config.validation_upgrade_delay = 100; - assert!(old_config != config); - - assert_ok!(Configuration::set_validation_upgrade_delay(Origin::root(), 100)); - - // Verify that the current configuration has not changed and that there is a scheduled - // change for the SESSION_DELAY sessions in advance. - assert_eq!(Configuration::config(), old_config); - assert_eq!(::PendingConfigs::get(), vec![(2, config.clone())]); - - on_new_session(1); - - // One session has passed, we should be still waiting for the pending configuration. - assert_eq!(Configuration::config(), old_config); - assert_eq!(::PendingConfigs::get(), vec![(2, config.clone())]); - - on_new_session(2); - - assert_eq!(Configuration::config(), config); - assert_eq!(::PendingConfigs::get(), vec![]); - }) - } - - #[test] - fn consecutive_changes_within_one_session() { - new_test_ext(Default::default()).execute_with(|| { - let old_config = Configuration::config(); - let mut config = old_config.clone(); - config.validation_upgrade_delay = 100; - config.validation_upgrade_cooldown = 100; - assert!(old_config != config); - - assert_ok!(Configuration::set_validation_upgrade_delay(Origin::root(), 100)); - assert_ok!(Configuration::set_validation_upgrade_cooldown(Origin::root(), 100)); - assert_eq!(Configuration::config(), old_config); - assert_eq!(::PendingConfigs::get(), vec![(2, config.clone())]); - - on_new_session(1); - - assert_eq!(Configuration::config(), old_config); - assert_eq!(::PendingConfigs::get(), vec![(2, config.clone())]); - - on_new_session(2); - - assert_eq!(Configuration::config(), config); - assert_eq!(::PendingConfigs::get(), vec![]); - }); - } - - #[test] - fn pending_next_session_but_we_upgrade_once_more() { - new_test_ext(Default::default()).execute_with(|| { - let initial_config = Configuration::config(); - let intermediate_config = - HostConfiguration { validation_upgrade_delay: 100, ..initial_config.clone() }; - let final_config = HostConfiguration { - validation_upgrade_delay: 100, - validation_upgrade_cooldown: 99, - ..initial_config.clone() - }; - - assert_ok!(Configuration::set_validation_upgrade_delay(Origin::root(), 100)); - assert_eq!(Configuration::config(), initial_config); - assert_eq!( - ::PendingConfigs::get(), - vec![(2, intermediate_config.clone())] - ); - - on_new_session(1); - - // We are still waiting until the pending configuration is applied and we add another - // update. - assert_ok!(Configuration::set_validation_upgrade_cooldown(Origin::root(), 99)); - - // This should result in yet another configiguration change scheduled. - assert_eq!(Configuration::config(), initial_config); - assert_eq!( - ::PendingConfigs::get(), - vec![(2, intermediate_config.clone()), (3, final_config.clone())] - ); - - on_new_session(2); - - assert_eq!(Configuration::config(), intermediate_config); - assert_eq!( - ::PendingConfigs::get(), - vec![(3, final_config.clone())] - ); - - on_new_session(3); - - assert_eq!(Configuration::config(), final_config); - assert_eq!(::PendingConfigs::get(), vec![]); - }); - } - - #[test] - fn scheduled_session_config_update_while_next_session_pending() { - new_test_ext(Default::default()).execute_with(|| { - let initial_config = Configuration::config(); - let intermediate_config = - HostConfiguration { validation_upgrade_delay: 100, ..initial_config.clone() }; - let final_config = HostConfiguration { - validation_upgrade_delay: 100, - validation_upgrade_cooldown: 99, - code_retention_period: 98, - ..initial_config.clone() - }; - - assert_ok!(Configuration::set_validation_upgrade_delay(Origin::root(), 100)); - assert_eq!(Configuration::config(), initial_config); - assert_eq!( - ::PendingConfigs::get(), - vec![(2, intermediate_config.clone())] - ); - - on_new_session(1); - - // The second call should fall into the case where we already have a pending config - // update for the scheduled_session, but we want to update it once more. - assert_ok!(Configuration::set_validation_upgrade_cooldown(Origin::root(), 99)); - assert_ok!(Configuration::set_code_retention_period(Origin::root(), 98)); - - // This should result in yet another configiguration change scheduled. - assert_eq!(Configuration::config(), initial_config); - assert_eq!( - ::PendingConfigs::get(), - vec![(2, intermediate_config.clone()), (3, final_config.clone())] - ); - - on_new_session(2); - - assert_eq!(Configuration::config(), intermediate_config); - assert_eq!( - ::PendingConfigs::get(), - vec![(3, final_config.clone())] - ); - - on_new_session(3); - - assert_eq!(Configuration::config(), final_config); - assert_eq!(::PendingConfigs::get(), vec![]); - }); - } - - #[test] - fn invariants() { - new_test_ext(Default::default()).execute_with(|| { - assert_err!( - Configuration::set_max_code_size(Origin::root(), MAX_CODE_SIZE + 1), - Error::::InvalidNewValue - ); - - assert_err!( - Configuration::set_max_pov_size(Origin::root(), MAX_POV_SIZE + 1), - Error::::InvalidNewValue - ); - - assert_err!( - Configuration::set_max_head_data_size(Origin::root(), MAX_HEAD_DATA_SIZE + 1), - Error::::InvalidNewValue - ); - - assert_err!( - Configuration::set_chain_availability_period(Origin::root(), 0), - Error::::InvalidNewValue - ); - assert_err!( - Configuration::set_thread_availability_period(Origin::root(), 0), - Error::::InvalidNewValue - ); - assert_err!( - Configuration::set_no_show_slots(Origin::root(), 0), - Error::::InvalidNewValue - ); - - ::ActiveConfig::put(HostConfiguration { - chain_availability_period: 10, - thread_availability_period: 8, - minimum_validation_upgrade_delay: 11, - ..Default::default() - }); - assert_err!( - Configuration::set_chain_availability_period(Origin::root(), 12), - Error::::InvalidNewValue - ); - assert_err!( - Configuration::set_thread_availability_period(Origin::root(), 12), - Error::::InvalidNewValue - ); - assert_err!( - Configuration::set_minimum_validation_upgrade_delay(Origin::root(), 9), - Error::::InvalidNewValue - ); - - assert_err!( - Configuration::set_validation_upgrade_delay(Origin::root(), 0), - Error::::InvalidNewValue - ); - }); - } - - #[test] - fn consistency_bypass_works() { - new_test_ext(Default::default()).execute_with(|| { - assert_err!( - Configuration::set_max_code_size(Origin::root(), MAX_CODE_SIZE + 1), - Error::::InvalidNewValue - ); - - assert_ok!(Configuration::set_bypass_consistency_check(Origin::root(), true)); - assert_ok!(Configuration::set_max_code_size(Origin::root(), MAX_CODE_SIZE + 1)); - - assert_eq!( - Configuration::config().max_code_size, - HostConfiguration::::default().max_code_size - ); - - on_new_session(1); - on_new_session(2); - - assert_eq!(Configuration::config().max_code_size, MAX_CODE_SIZE + 1); - }); - } - - #[test] - fn setting_pending_config_members() { - new_test_ext(Default::default()).execute_with(|| { - let new_config = HostConfiguration { - validation_upgrade_cooldown: 100, - validation_upgrade_delay: 10, - code_retention_period: 5, - max_code_size: 100_000, - max_pov_size: 1024, - max_head_data_size: 1_000, - parathread_cores: 2, - parathread_retries: 5, - group_rotation_frequency: 20, - chain_availability_period: 10, - thread_availability_period: 8, - scheduling_lookahead: 3, - max_validators_per_core: None, - max_validators: None, - dispute_period: 239, - dispute_post_conclusion_acceptance_period: 10, - dispute_max_spam_slots: 2, - dispute_conclusion_by_time_out_period: 512, - no_show_slots: 240, - n_delay_tranches: 241, - zeroth_delay_tranche_width: 242, - needed_approvals: 242, - relay_vrf_modulo_samples: 243, - max_upward_queue_count: 1337, - max_upward_queue_size: 228, - max_downward_message_size: 2048, - ump_service_total_weight: 20000, - max_upward_message_size: 448, - max_upward_message_num_per_candidate: 5, - hrmp_sender_deposit: 22, - hrmp_recipient_deposit: 4905, - hrmp_channel_max_capacity: 3921, - hrmp_channel_max_total_size: 7687, - hrmp_max_parachain_inbound_channels: 37, - hrmp_max_parathread_inbound_channels: 19, - hrmp_channel_max_message_size: 8192, - hrmp_max_parachain_outbound_channels: 10, - hrmp_max_parathread_outbound_channels: 20, - hrmp_max_message_num_per_candidate: 20, - ump_max_individual_weight: 909, - pvf_checking_enabled: true, - pvf_voting_ttl: 3, - minimum_validation_upgrade_delay: 20, - }; - - assert!(::PendingConfig::get(shared::SESSION_DELAY).is_none()); - - Configuration::set_validation_upgrade_cooldown( - Origin::root(), - new_config.validation_upgrade_cooldown, - ) - .unwrap(); - Configuration::set_validation_upgrade_delay( - Origin::root(), - new_config.validation_upgrade_delay, - ) - .unwrap(); - Configuration::set_code_retention_period( - Origin::root(), - new_config.code_retention_period, - ) - .unwrap(); - Configuration::set_max_code_size(Origin::root(), new_config.max_code_size).unwrap(); - Configuration::set_max_pov_size(Origin::root(), new_config.max_pov_size).unwrap(); - Configuration::set_max_head_data_size(Origin::root(), new_config.max_head_data_size) - .unwrap(); - Configuration::set_parathread_cores(Origin::root(), new_config.parathread_cores) - .unwrap(); - Configuration::set_parathread_retries(Origin::root(), new_config.parathread_retries) - .unwrap(); - Configuration::set_group_rotation_frequency( - Origin::root(), - new_config.group_rotation_frequency, - ) - .unwrap(); - // This comes out of order to satisfy the validity criteria for the chain and thread - // availability periods. - Configuration::set_minimum_validation_upgrade_delay( - Origin::root(), - new_config.minimum_validation_upgrade_delay, - ) - .unwrap(); - Configuration::set_chain_availability_period( - Origin::root(), - new_config.chain_availability_period, - ) - .unwrap(); - Configuration::set_thread_availability_period( - Origin::root(), - new_config.thread_availability_period, - ) - .unwrap(); - Configuration::set_scheduling_lookahead( - Origin::root(), - new_config.scheduling_lookahead, - ) - .unwrap(); - Configuration::set_max_validators_per_core( - Origin::root(), - new_config.max_validators_per_core, - ) - .unwrap(); - Configuration::set_max_validators(Origin::root(), new_config.max_validators).unwrap(); - Configuration::set_dispute_period(Origin::root(), new_config.dispute_period).unwrap(); - Configuration::set_dispute_post_conclusion_acceptance_period( - Origin::root(), - new_config.dispute_post_conclusion_acceptance_period, - ) - .unwrap(); - Configuration::set_dispute_max_spam_slots( - Origin::root(), - new_config.dispute_max_spam_slots, - ) - .unwrap(); - Configuration::set_dispute_conclusion_by_time_out_period( - Origin::root(), - new_config.dispute_conclusion_by_time_out_period, - ) - .unwrap(); - Configuration::set_no_show_slots(Origin::root(), new_config.no_show_slots).unwrap(); - Configuration::set_n_delay_tranches(Origin::root(), new_config.n_delay_tranches) - .unwrap(); - Configuration::set_zeroth_delay_tranche_width( - Origin::root(), - new_config.zeroth_delay_tranche_width, - ) - .unwrap(); - Configuration::set_needed_approvals(Origin::root(), new_config.needed_approvals) - .unwrap(); - Configuration::set_relay_vrf_modulo_samples( - Origin::root(), - new_config.relay_vrf_modulo_samples, - ) - .unwrap(); - Configuration::set_max_upward_queue_count( - Origin::root(), - new_config.max_upward_queue_count, - ) - .unwrap(); - Configuration::set_max_upward_queue_size( - Origin::root(), - new_config.max_upward_queue_size, - ) - .unwrap(); - Configuration::set_max_downward_message_size( - Origin::root(), - new_config.max_downward_message_size, - ) - .unwrap(); - Configuration::set_ump_service_total_weight( - Origin::root(), - new_config.ump_service_total_weight, - ) - .unwrap(); - Configuration::set_max_upward_message_size( - Origin::root(), - new_config.max_upward_message_size, - ) - .unwrap(); - Configuration::set_max_upward_message_num_per_candidate( - Origin::root(), - new_config.max_upward_message_num_per_candidate, - ) - .unwrap(); - Configuration::set_hrmp_sender_deposit(Origin::root(), new_config.hrmp_sender_deposit) - .unwrap(); - Configuration::set_hrmp_recipient_deposit( - Origin::root(), - new_config.hrmp_recipient_deposit, - ) - .unwrap(); - Configuration::set_hrmp_channel_max_capacity( - Origin::root(), - new_config.hrmp_channel_max_capacity, - ) - .unwrap(); - Configuration::set_hrmp_channel_max_total_size( - Origin::root(), - new_config.hrmp_channel_max_total_size, - ) - .unwrap(); - Configuration::set_hrmp_max_parachain_inbound_channels( - Origin::root(), - new_config.hrmp_max_parachain_inbound_channels, - ) - .unwrap(); - Configuration::set_hrmp_max_parathread_inbound_channels( - Origin::root(), - new_config.hrmp_max_parathread_inbound_channels, - ) - .unwrap(); - Configuration::set_hrmp_channel_max_message_size( - Origin::root(), - new_config.hrmp_channel_max_message_size, - ) - .unwrap(); - Configuration::set_hrmp_max_parachain_outbound_channels( - Origin::root(), - new_config.hrmp_max_parachain_outbound_channels, - ) - .unwrap(); - Configuration::set_hrmp_max_parathread_outbound_channels( - Origin::root(), - new_config.hrmp_max_parathread_outbound_channels, - ) - .unwrap(); - Configuration::set_hrmp_max_message_num_per_candidate( - Origin::root(), - new_config.hrmp_max_message_num_per_candidate, - ) - .unwrap(); - Configuration::set_ump_max_individual_weight( - Origin::root(), - new_config.ump_max_individual_weight, - ) - .unwrap(); - Configuration::set_pvf_checking_enabled( - Origin::root(), - new_config.pvf_checking_enabled, - ) - .unwrap(); - Configuration::set_pvf_voting_ttl(Origin::root(), new_config.pvf_voting_ttl).unwrap(); - - assert_eq!( - ::PendingConfigs::get(), - vec![(shared::SESSION_DELAY, new_config)], - ); - }) - } - - #[test] - fn non_root_cannot_set_config() { - new_test_ext(Default::default()).execute_with(|| { - assert!(Configuration::set_validation_upgrade_delay(Origin::signed(1), 100).is_err()); - }); - } - - #[test] - fn verify_externally_accessible() { - // This test verifies that the value can be accessed through the well known keys and the - // host configuration decodes into the abridged version. - - use primitives::v1::{well_known_keys, AbridgedHostConfiguration}; - - new_test_ext(Default::default()).execute_with(|| { - let ground_truth = HostConfiguration::default(); - - // Make sure that the configuration is stored in the storage. - ::ActiveConfig::put(ground_truth.clone()); - - // Extract the active config via the well known key. - let raw_active_config = sp_io::storage::get(well_known_keys::ACTIVE_CONFIG) - .expect("config must be present in storage under ACTIVE_CONFIG"); - let abridged_config = AbridgedHostConfiguration::decode(&mut &raw_active_config[..]) - .expect("HostConfiguration must be decodable into AbridgedHostConfiguration"); - - assert_eq!( - abridged_config, - AbridgedHostConfiguration { - max_code_size: ground_truth.max_code_size, - max_head_data_size: ground_truth.max_head_data_size, - max_upward_queue_count: ground_truth.max_upward_queue_count, - max_upward_queue_size: ground_truth.max_upward_queue_size, - max_upward_message_size: ground_truth.max_upward_message_size, - max_upward_message_num_per_candidate: ground_truth - .max_upward_message_num_per_candidate, - hrmp_max_message_num_per_candidate: ground_truth - .hrmp_max_message_num_per_candidate, - validation_upgrade_cooldown: ground_truth.validation_upgrade_cooldown, - validation_upgrade_delay: ground_truth.validation_upgrade_delay, - }, - ); - }); - } -} diff --git a/runtime/parachains/src/configuration/tests.rs b/runtime/parachains/src/configuration/tests.rs new file mode 100644 index 000000000000..8750560e4a99 --- /dev/null +++ b/runtime/parachains/src/configuration/tests.rs @@ -0,0 +1,553 @@ +// 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 super::*; +use crate::mock::{new_test_ext, Configuration, Origin, ParasShared, Test}; +use frame_support::{assert_err, assert_ok}; + +fn on_new_session(session_index: SessionIndex) -> (HostConfiguration, HostConfiguration) { + ParasShared::set_session_index(session_index); + let SessionChangeOutcome { prev_config, new_config } = + Configuration::initializer_on_new_session(&session_index); + let new_config = new_config.unwrap_or_else(|| prev_config.clone()); + (prev_config, new_config) +} + +#[test] +fn default_is_consistent() { + new_test_ext(Default::default()).execute_with(|| { + Configuration::config().panic_if_not_consistent(); + }); +} + +#[test] +fn scheduled_session_is_two_sessions_from_now() { + new_test_ext(Default::default()).execute_with(|| { + // The logic here is really tested only with scheduled_session = 2. It should work + // with other values, but that should receive a more rigorious testing. + on_new_session(1); + assert_eq!(Configuration::scheduled_session(), 3); + }); +} + +#[test] +fn initializer_on_new_session() { + new_test_ext(Default::default()).execute_with(|| { + let (prev_config, new_config) = on_new_session(1); + assert_eq!(prev_config, new_config); + assert_ok!(Configuration::set_validation_upgrade_delay(Origin::root(), 100)); + + let (prev_config, new_config) = on_new_session(2); + assert_eq!(prev_config, new_config); + + let (prev_config, new_config) = on_new_session(3); + assert_eq!(prev_config, HostConfiguration::default()); + assert_eq!(new_config, HostConfiguration { validation_upgrade_delay: 100, ..prev_config }); + }); +} + +#[test] +fn config_changes_after_2_session_boundary() { + new_test_ext(Default::default()).execute_with(|| { + let old_config = Configuration::config(); + let mut config = old_config.clone(); + config.validation_upgrade_delay = 100; + assert!(old_config != config); + + assert_ok!(Configuration::set_validation_upgrade_delay(Origin::root(), 100)); + + // Verify that the current configuration has not changed and that there is a scheduled + // change for the SESSION_DELAY sessions in advance. + assert_eq!(Configuration::config(), old_config); + assert_eq!(::PendingConfigs::get(), vec![(2, config.clone())]); + + on_new_session(1); + + // One session has passed, we should be still waiting for the pending configuration. + assert_eq!(Configuration::config(), old_config); + assert_eq!(::PendingConfigs::get(), vec![(2, config.clone())]); + + on_new_session(2); + + assert_eq!(Configuration::config(), config); + assert_eq!(::PendingConfigs::get(), vec![]); + }) +} + +#[test] +fn consecutive_changes_within_one_session() { + new_test_ext(Default::default()).execute_with(|| { + let old_config = Configuration::config(); + let mut config = old_config.clone(); + config.validation_upgrade_delay = 100; + config.validation_upgrade_cooldown = 100; + assert!(old_config != config); + + assert_ok!(Configuration::set_validation_upgrade_delay(Origin::root(), 100)); + assert_ok!(Configuration::set_validation_upgrade_cooldown(Origin::root(), 100)); + assert_eq!(Configuration::config(), old_config); + assert_eq!(::PendingConfigs::get(), vec![(2, config.clone())]); + + on_new_session(1); + + assert_eq!(Configuration::config(), old_config); + assert_eq!(::PendingConfigs::get(), vec![(2, config.clone())]); + + on_new_session(2); + + assert_eq!(Configuration::config(), config); + assert_eq!(::PendingConfigs::get(), vec![]); + }); +} + +#[test] +fn pending_next_session_but_we_upgrade_once_more() { + new_test_ext(Default::default()).execute_with(|| { + let initial_config = Configuration::config(); + let intermediate_config = + HostConfiguration { validation_upgrade_delay: 100, ..initial_config.clone() }; + let final_config = HostConfiguration { + validation_upgrade_delay: 100, + validation_upgrade_cooldown: 99, + ..initial_config.clone() + }; + + assert_ok!(Configuration::set_validation_upgrade_delay(Origin::root(), 100)); + assert_eq!(Configuration::config(), initial_config); + assert_eq!( + ::PendingConfigs::get(), + vec![(2, intermediate_config.clone())] + ); + + on_new_session(1); + + // We are still waiting until the pending configuration is applied and we add another + // update. + assert_ok!(Configuration::set_validation_upgrade_cooldown(Origin::root(), 99)); + + // This should result in yet another configiguration change scheduled. + assert_eq!(Configuration::config(), initial_config); + assert_eq!( + ::PendingConfigs::get(), + vec![(2, intermediate_config.clone()), (3, final_config.clone())] + ); + + on_new_session(2); + + assert_eq!(Configuration::config(), intermediate_config); + assert_eq!( + ::PendingConfigs::get(), + vec![(3, final_config.clone())] + ); + + on_new_session(3); + + assert_eq!(Configuration::config(), final_config); + assert_eq!(::PendingConfigs::get(), vec![]); + }); +} + +#[test] +fn scheduled_session_config_update_while_next_session_pending() { + new_test_ext(Default::default()).execute_with(|| { + let initial_config = Configuration::config(); + let intermediate_config = + HostConfiguration { validation_upgrade_delay: 100, ..initial_config.clone() }; + let final_config = HostConfiguration { + validation_upgrade_delay: 100, + validation_upgrade_cooldown: 99, + code_retention_period: 98, + ..initial_config.clone() + }; + + assert_ok!(Configuration::set_validation_upgrade_delay(Origin::root(), 100)); + assert_eq!(Configuration::config(), initial_config); + assert_eq!( + ::PendingConfigs::get(), + vec![(2, intermediate_config.clone())] + ); + + on_new_session(1); + + // The second call should fall into the case where we already have a pending config + // update for the scheduled_session, but we want to update it once more. + assert_ok!(Configuration::set_validation_upgrade_cooldown(Origin::root(), 99)); + assert_ok!(Configuration::set_code_retention_period(Origin::root(), 98)); + + // This should result in yet another configiguration change scheduled. + assert_eq!(Configuration::config(), initial_config); + assert_eq!( + ::PendingConfigs::get(), + vec![(2, intermediate_config.clone()), (3, final_config.clone())] + ); + + on_new_session(2); + + assert_eq!(Configuration::config(), intermediate_config); + assert_eq!( + ::PendingConfigs::get(), + vec![(3, final_config.clone())] + ); + + on_new_session(3); + + assert_eq!(Configuration::config(), final_config); + assert_eq!(::PendingConfigs::get(), vec![]); + }); +} + +#[test] +fn invariants() { + new_test_ext(Default::default()).execute_with(|| { + assert_err!( + Configuration::set_max_code_size(Origin::root(), MAX_CODE_SIZE + 1), + Error::::InvalidNewValue + ); + + assert_err!( + Configuration::set_max_pov_size(Origin::root(), MAX_POV_SIZE + 1), + Error::::InvalidNewValue + ); + + assert_err!( + Configuration::set_max_head_data_size(Origin::root(), MAX_HEAD_DATA_SIZE + 1), + Error::::InvalidNewValue + ); + + assert_err!( + Configuration::set_chain_availability_period(Origin::root(), 0), + Error::::InvalidNewValue + ); + assert_err!( + Configuration::set_thread_availability_period(Origin::root(), 0), + Error::::InvalidNewValue + ); + assert_err!( + Configuration::set_no_show_slots(Origin::root(), 0), + Error::::InvalidNewValue + ); + + ::ActiveConfig::put(HostConfiguration { + chain_availability_period: 10, + thread_availability_period: 8, + minimum_validation_upgrade_delay: 11, + ..Default::default() + }); + assert_err!( + Configuration::set_chain_availability_period(Origin::root(), 12), + Error::::InvalidNewValue + ); + assert_err!( + Configuration::set_thread_availability_period(Origin::root(), 12), + Error::::InvalidNewValue + ); + assert_err!( + Configuration::set_minimum_validation_upgrade_delay(Origin::root(), 9), + Error::::InvalidNewValue + ); + + assert_err!( + Configuration::set_validation_upgrade_delay(Origin::root(), 0), + Error::::InvalidNewValue + ); + }); +} + +#[test] +fn consistency_bypass_works() { + new_test_ext(Default::default()).execute_with(|| { + assert_err!( + Configuration::set_max_code_size(Origin::root(), MAX_CODE_SIZE + 1), + Error::::InvalidNewValue + ); + + assert_ok!(Configuration::set_bypass_consistency_check(Origin::root(), true)); + assert_ok!(Configuration::set_max_code_size(Origin::root(), MAX_CODE_SIZE + 1)); + + assert_eq!( + Configuration::config().max_code_size, + HostConfiguration::::default().max_code_size + ); + + on_new_session(1); + on_new_session(2); + + assert_eq!(Configuration::config().max_code_size, MAX_CODE_SIZE + 1); + }); +} + +#[test] +fn setting_pending_config_members() { + new_test_ext(Default::default()).execute_with(|| { + let new_config = HostConfiguration { + validation_upgrade_cooldown: 100, + validation_upgrade_delay: 10, + code_retention_period: 5, + max_code_size: 100_000, + max_pov_size: 1024, + max_head_data_size: 1_000, + parathread_cores: 2, + parathread_retries: 5, + group_rotation_frequency: 20, + chain_availability_period: 10, + thread_availability_period: 8, + scheduling_lookahead: 3, + max_validators_per_core: None, + max_validators: None, + dispute_period: 239, + dispute_post_conclusion_acceptance_period: 10, + dispute_max_spam_slots: 2, + dispute_conclusion_by_time_out_period: 512, + no_show_slots: 240, + n_delay_tranches: 241, + zeroth_delay_tranche_width: 242, + needed_approvals: 242, + relay_vrf_modulo_samples: 243, + max_upward_queue_count: 1337, + max_upward_queue_size: 228, + max_downward_message_size: 2048, + ump_service_total_weight: 20000, + max_upward_message_size: 448, + max_upward_message_num_per_candidate: 5, + hrmp_sender_deposit: 22, + hrmp_recipient_deposit: 4905, + hrmp_channel_max_capacity: 3921, + hrmp_channel_max_total_size: 7687, + hrmp_max_parachain_inbound_channels: 37, + hrmp_max_parathread_inbound_channels: 19, + hrmp_channel_max_message_size: 8192, + hrmp_max_parachain_outbound_channels: 10, + hrmp_max_parathread_outbound_channels: 20, + hrmp_max_message_num_per_candidate: 20, + ump_max_individual_weight: 909, + pvf_checking_enabled: true, + pvf_voting_ttl: 3, + minimum_validation_upgrade_delay: 20, + }; + + assert!(::PendingConfig::get(shared::SESSION_DELAY).is_none()); + + Configuration::set_validation_upgrade_cooldown( + Origin::root(), + new_config.validation_upgrade_cooldown, + ) + .unwrap(); + Configuration::set_validation_upgrade_delay( + Origin::root(), + new_config.validation_upgrade_delay, + ) + .unwrap(); + Configuration::set_code_retention_period(Origin::root(), new_config.code_retention_period) + .unwrap(); + Configuration::set_max_code_size(Origin::root(), new_config.max_code_size).unwrap(); + Configuration::set_max_pov_size(Origin::root(), new_config.max_pov_size).unwrap(); + Configuration::set_max_head_data_size(Origin::root(), new_config.max_head_data_size) + .unwrap(); + Configuration::set_parathread_cores(Origin::root(), new_config.parathread_cores).unwrap(); + Configuration::set_parathread_retries(Origin::root(), new_config.parathread_retries) + .unwrap(); + Configuration::set_group_rotation_frequency( + Origin::root(), + new_config.group_rotation_frequency, + ) + .unwrap(); + // This comes out of order to satisfy the validity criteria for the chain and thread + // availability periods. + Configuration::set_minimum_validation_upgrade_delay( + Origin::root(), + new_config.minimum_validation_upgrade_delay, + ) + .unwrap(); + Configuration::set_chain_availability_period( + Origin::root(), + new_config.chain_availability_period, + ) + .unwrap(); + Configuration::set_thread_availability_period( + Origin::root(), + new_config.thread_availability_period, + ) + .unwrap(); + Configuration::set_scheduling_lookahead(Origin::root(), new_config.scheduling_lookahead) + .unwrap(); + Configuration::set_max_validators_per_core( + Origin::root(), + new_config.max_validators_per_core, + ) + .unwrap(); + Configuration::set_max_validators(Origin::root(), new_config.max_validators).unwrap(); + Configuration::set_dispute_period(Origin::root(), new_config.dispute_period).unwrap(); + Configuration::set_dispute_post_conclusion_acceptance_period( + Origin::root(), + new_config.dispute_post_conclusion_acceptance_period, + ) + .unwrap(); + Configuration::set_dispute_max_spam_slots( + Origin::root(), + new_config.dispute_max_spam_slots, + ) + .unwrap(); + Configuration::set_dispute_conclusion_by_time_out_period( + Origin::root(), + new_config.dispute_conclusion_by_time_out_period, + ) + .unwrap(); + Configuration::set_no_show_slots(Origin::root(), new_config.no_show_slots).unwrap(); + Configuration::set_n_delay_tranches(Origin::root(), new_config.n_delay_tranches).unwrap(); + Configuration::set_zeroth_delay_tranche_width( + Origin::root(), + new_config.zeroth_delay_tranche_width, + ) + .unwrap(); + Configuration::set_needed_approvals(Origin::root(), new_config.needed_approvals).unwrap(); + Configuration::set_relay_vrf_modulo_samples( + Origin::root(), + new_config.relay_vrf_modulo_samples, + ) + .unwrap(); + Configuration::set_max_upward_queue_count( + Origin::root(), + new_config.max_upward_queue_count, + ) + .unwrap(); + Configuration::set_max_upward_queue_size(Origin::root(), new_config.max_upward_queue_size) + .unwrap(); + Configuration::set_max_downward_message_size( + Origin::root(), + new_config.max_downward_message_size, + ) + .unwrap(); + Configuration::set_ump_service_total_weight( + Origin::root(), + new_config.ump_service_total_weight, + ) + .unwrap(); + Configuration::set_max_upward_message_size( + Origin::root(), + new_config.max_upward_message_size, + ) + .unwrap(); + Configuration::set_max_upward_message_num_per_candidate( + Origin::root(), + new_config.max_upward_message_num_per_candidate, + ) + .unwrap(); + Configuration::set_hrmp_sender_deposit(Origin::root(), new_config.hrmp_sender_deposit) + .unwrap(); + Configuration::set_hrmp_recipient_deposit( + Origin::root(), + new_config.hrmp_recipient_deposit, + ) + .unwrap(); + Configuration::set_hrmp_channel_max_capacity( + Origin::root(), + new_config.hrmp_channel_max_capacity, + ) + .unwrap(); + Configuration::set_hrmp_channel_max_total_size( + Origin::root(), + new_config.hrmp_channel_max_total_size, + ) + .unwrap(); + Configuration::set_hrmp_max_parachain_inbound_channels( + Origin::root(), + new_config.hrmp_max_parachain_inbound_channels, + ) + .unwrap(); + Configuration::set_hrmp_max_parathread_inbound_channels( + Origin::root(), + new_config.hrmp_max_parathread_inbound_channels, + ) + .unwrap(); + Configuration::set_hrmp_channel_max_message_size( + Origin::root(), + new_config.hrmp_channel_max_message_size, + ) + .unwrap(); + Configuration::set_hrmp_max_parachain_outbound_channels( + Origin::root(), + new_config.hrmp_max_parachain_outbound_channels, + ) + .unwrap(); + Configuration::set_hrmp_max_parathread_outbound_channels( + Origin::root(), + new_config.hrmp_max_parathread_outbound_channels, + ) + .unwrap(); + Configuration::set_hrmp_max_message_num_per_candidate( + Origin::root(), + new_config.hrmp_max_message_num_per_candidate, + ) + .unwrap(); + Configuration::set_ump_max_individual_weight( + Origin::root(), + new_config.ump_max_individual_weight, + ) + .unwrap(); + Configuration::set_pvf_checking_enabled(Origin::root(), new_config.pvf_checking_enabled) + .unwrap(); + Configuration::set_pvf_voting_ttl(Origin::root(), new_config.pvf_voting_ttl).unwrap(); + + assert_eq!( + ::PendingConfigs::get(), + vec![(shared::SESSION_DELAY, new_config)], + ); + }) +} + +#[test] +fn non_root_cannot_set_config() { + new_test_ext(Default::default()).execute_with(|| { + assert!(Configuration::set_validation_upgrade_delay(Origin::signed(1), 100).is_err()); + }); +} + +#[test] +fn verify_externally_accessible() { + // This test verifies that the value can be accessed through the well known keys and the + // host configuration decodes into the abridged version. + + use primitives::v1::{well_known_keys, AbridgedHostConfiguration}; + + new_test_ext(Default::default()).execute_with(|| { + let ground_truth = HostConfiguration::default(); + + // Make sure that the configuration is stored in the storage. + ::ActiveConfig::put(ground_truth.clone()); + + // Extract the active config via the well known key. + let raw_active_config = sp_io::storage::get(well_known_keys::ACTIVE_CONFIG) + .expect("config must be present in storage under ACTIVE_CONFIG"); + let abridged_config = AbridgedHostConfiguration::decode(&mut &raw_active_config[..]) + .expect("HostConfiguration must be decodable into AbridgedHostConfiguration"); + + assert_eq!( + abridged_config, + AbridgedHostConfiguration { + max_code_size: ground_truth.max_code_size, + max_head_data_size: ground_truth.max_head_data_size, + max_upward_queue_count: ground_truth.max_upward_queue_count, + max_upward_queue_size: ground_truth.max_upward_queue_size, + max_upward_message_size: ground_truth.max_upward_message_size, + max_upward_message_num_per_candidate: ground_truth + .max_upward_message_num_per_candidate, + hrmp_max_message_num_per_candidate: ground_truth.hrmp_max_message_num_per_candidate, + validation_upgrade_cooldown: ground_truth.validation_upgrade_cooldown, + validation_upgrade_delay: ground_truth.validation_upgrade_delay, + }, + ); + }); +} diff --git a/runtime/parachains/src/disputes.rs b/runtime/parachains/src/disputes.rs index 2b8662ea41fd..b723d4a4ab13 100644 --- a/runtime/parachains/src/disputes.rs +++ b/runtime/parachains/src/disputes.rs @@ -35,6 +35,13 @@ use sp_runtime::{ }; use sp_std::{cmp::Ordering, prelude::*}; +#[cfg(test)] +#[allow(unused_imports)] +pub(crate) use self::tests::run_to_block; + +#[cfg(test)] +mod tests; + #[cfg(feature = "runtime-benchmarks")] mod benchmarking; @@ -1312,2477 +1319,3 @@ fn check_signature( Err(()) } } - -#[cfg(test)] -#[allow(unused_imports)] -pub(crate) use self::tests::run_to_block; - -#[cfg(test)] -mod tests { - use super::*; - use crate::{ - configuration::HostConfiguration, - disputes::DisputesHandler, - mock::{ - new_test_ext, AccountId, AllPalletsWithSystem, Initializer, MockGenesisConfig, System, - Test, PUNISH_VALIDATORS_AGAINST, PUNISH_VALIDATORS_FOR, PUNISH_VALIDATORS_INCONCLUSIVE, - REWARD_VALIDATORS, - }, - }; - use frame_support::{ - assert_err, assert_noop, assert_ok, - traits::{OnFinalize, OnInitialize}, - }; - use primitives::v1::BlockNumber; - use sp_core::{crypto::CryptoType, Pair}; - - /// Filtering updates the spam slots, as such update them. - fn update_spam_slots(stmts: MultiDisputeStatementSet) -> CheckedMultiDisputeStatementSet { - let config = >::config(); - let max_spam_slots = config.dispute_max_spam_slots; - let post_conclusion_acceptance_period = config.dispute_post_conclusion_acceptance_period; - - stmts - .into_iter() - .filter_map(|set| { - // updates spam slots implicitly - let filter = Pallet::::filter_dispute_data( - &set, - post_conclusion_acceptance_period, - max_spam_slots, - VerifyDisputeSignatures::Skip, - ); - filter.filter_statement_set(set) - }) - .collect::>() - } - - // All arguments for `initializer::on_new_session` - type NewSession<'a> = ( - bool, - SessionIndex, - Vec<(&'a AccountId, ValidatorId)>, - Option>, - ); - - // Run to specific block, while calling disputes pallet hooks manually, because disputes is not - // integrated in initializer yet. - pub(crate) fn run_to_block<'a>( - to: BlockNumber, - new_session: impl Fn(BlockNumber) -> Option>, - ) { - while System::block_number() < to { - let b = System::block_number(); - if b != 0 { - // circumvent requirement to have bitfields and headers in block for testing purposes - crate::paras_inherent::Included::::set(Some(())); - - AllPalletsWithSystem::on_finalize(b); - System::finalize(); - } - - System::reset_events(); - System::initialize(&(b + 1), &Default::default(), &Default::default()); - AllPalletsWithSystem::on_initialize(b + 1); - - if let Some(new_session) = new_session(b + 1) { - Initializer::test_trigger_on_new_session( - new_session.0, - new_session.1, - new_session.2.into_iter(), - new_session.3.map(|q| q.into_iter()), - ); - } - } - } - - #[test] - fn test_contains_duplicates_in_sorted_iter() { - // We here use the implicit ascending sorting and builtin equality of integers - let v = vec![1, 2, 3, 5, 5, 8]; - assert_eq!(true, contains_duplicates_in_sorted_iter(&v, |a, b| a == b)); - - let v = vec![1, 2, 3, 4]; - assert_eq!(false, contains_duplicates_in_sorted_iter(&v, |a, b| a == b)); - } - - #[test] - fn test_dispute_state_flag_from_state() { - assert_eq!( - DisputeStateFlags::from_state(&DisputeState { - validators_for: bitvec![BitOrderLsb0, u8; 0, 0, 0, 0, 0, 0, 0, 0], - validators_against: bitvec![BitOrderLsb0, u8; 0, 0, 0, 0, 0, 0, 0, 0], - start: 0, - concluded_at: None, - }), - DisputeStateFlags::default(), - ); - - assert_eq!( - DisputeStateFlags::from_state(&DisputeState { - validators_for: bitvec![BitOrderLsb0, u8; 1, 1, 1, 1, 1, 0, 0], - validators_against: bitvec![BitOrderLsb0, u8; 0, 0, 0, 0, 0, 0, 0], - start: 0, - concluded_at: None, - }), - DisputeStateFlags::FOR_SUPERMAJORITY | DisputeStateFlags::CONFIRMED, - ); - - assert_eq!( - DisputeStateFlags::from_state(&DisputeState { - validators_for: bitvec![BitOrderLsb0, u8; 0, 0, 0, 0, 0, 0, 0], - validators_against: bitvec![BitOrderLsb0, u8; 1, 1, 1, 1, 1, 0, 0], - start: 0, - concluded_at: None, - }), - DisputeStateFlags::AGAINST_SUPERMAJORITY | DisputeStateFlags::CONFIRMED, - ); - } - - #[test] - fn test_import_new_participant_spam_inc() { - let mut importer = DisputeStateImporter::new( - DisputeState { - validators_for: bitvec![BitOrderLsb0, u8; 1, 0, 0, 0, 0, 0, 0, 0], - validators_against: bitvec![BitOrderLsb0, u8; 0, 0, 0, 0, 0, 0, 0, 0], - start: 0, - concluded_at: None, - }, - 0, - ); - - assert_err!( - importer.import(ValidatorIndex(9), true), - VoteImportError::ValidatorIndexOutOfBounds, - ); - - assert_err!(importer.import(ValidatorIndex(0), true), VoteImportError::DuplicateStatement); - assert_ok!(importer.import(ValidatorIndex(0), false)); - - assert_ok!(importer.import(ValidatorIndex(2), true)); - assert_err!(importer.import(ValidatorIndex(2), true), VoteImportError::DuplicateStatement); - - assert_ok!(importer.import(ValidatorIndex(2), false)); - assert_err!(importer.import(ValidatorIndex(2), false), VoteImportError::DuplicateStatement); - - let summary = importer.finish(); - assert_eq!(summary.new_flags, DisputeStateFlags::default()); - assert_eq!( - summary.state, - DisputeState { - validators_for: bitvec![BitOrderLsb0, u8; 1, 0, 1, 0, 0, 0, 0, 0], - validators_against: bitvec![BitOrderLsb0, u8; 1, 0, 1, 0, 0, 0, 0, 0], - start: 0, - concluded_at: None, - }, - ); - assert_eq!(summary.spam_slot_changes, vec![(ValidatorIndex(2), SpamSlotChange::Inc)]); - assert!(summary.slash_for.is_empty()); - assert!(summary.slash_against.is_empty()); - assert_eq!(summary.new_participants, bitvec![BitOrderLsb0, u8; 0, 0, 1, 0, 0, 0, 0, 0]); - } - - #[test] - fn test_import_prev_participant_spam_dec_confirmed() { - let mut importer = DisputeStateImporter::new( - DisputeState { - validators_for: bitvec![BitOrderLsb0, u8; 1, 0, 0, 0, 0, 0, 0, 0], - validators_against: bitvec![BitOrderLsb0, u8; 0, 1, 0, 0, 0, 0, 0, 0], - start: 0, - concluded_at: None, - }, - 0, - ); - - assert_ok!(importer.import(ValidatorIndex(2), true)); - - let summary = importer.finish(); - assert_eq!( - summary.state, - DisputeState { - validators_for: bitvec![BitOrderLsb0, u8; 1, 0, 1, 0, 0, 0, 0, 0], - validators_against: bitvec![BitOrderLsb0, u8; 0, 1, 0, 0, 0, 0, 0, 0], - start: 0, - concluded_at: None, - }, - ); - assert_eq!( - summary.spam_slot_changes, - vec![ - (ValidatorIndex(0), SpamSlotChange::Dec), - (ValidatorIndex(1), SpamSlotChange::Dec), - ], - ); - assert!(summary.slash_for.is_empty()); - assert!(summary.slash_against.is_empty()); - assert_eq!(summary.new_participants, bitvec![BitOrderLsb0, u8; 0, 0, 1, 0, 0, 0, 0, 0]); - assert_eq!(summary.new_flags, DisputeStateFlags::CONFIRMED); - } - - #[test] - fn test_import_prev_participant_spam_dec_confirmed_slash_for() { - let mut importer = DisputeStateImporter::new( - DisputeState { - validators_for: bitvec![BitOrderLsb0, u8; 1, 0, 0, 0, 0, 0, 0, 0], - validators_against: bitvec![BitOrderLsb0, u8; 0, 1, 0, 0, 0, 0, 0, 0], - start: 0, - concluded_at: None, - }, - 0, - ); - - assert_ok!(importer.import(ValidatorIndex(2), true)); - assert_ok!(importer.import(ValidatorIndex(2), false)); - assert_ok!(importer.import(ValidatorIndex(3), false)); - assert_ok!(importer.import(ValidatorIndex(4), false)); - assert_ok!(importer.import(ValidatorIndex(5), false)); - assert_ok!(importer.import(ValidatorIndex(6), false)); - - let summary = importer.finish(); - assert_eq!( - summary.state, - DisputeState { - validators_for: bitvec![BitOrderLsb0, u8; 1, 0, 1, 0, 0, 0, 0, 0], - validators_against: bitvec![BitOrderLsb0, u8; 0, 1, 1, 1, 1, 1, 1, 0], - start: 0, - concluded_at: Some(0), - }, - ); - assert_eq!( - summary.spam_slot_changes, - vec![ - (ValidatorIndex(0), SpamSlotChange::Dec), - (ValidatorIndex(1), SpamSlotChange::Dec), - ], - ); - assert_eq!(summary.slash_for, vec![ValidatorIndex(0), ValidatorIndex(2)]); - assert!(summary.slash_against.is_empty()); - assert_eq!(summary.new_participants, bitvec![BitOrderLsb0, u8; 0, 0, 1, 1, 1, 1, 1, 0]); - assert_eq!( - summary.new_flags, - DisputeStateFlags::CONFIRMED | DisputeStateFlags::AGAINST_SUPERMAJORITY, - ); - } - - #[test] - fn test_import_slash_against() { - let mut importer = DisputeStateImporter::new( - DisputeState { - validators_for: bitvec![BitOrderLsb0, u8; 1, 0, 1, 0, 0, 0, 0, 0], - validators_against: bitvec![BitOrderLsb0, u8; 0, 1, 0, 0, 0, 0, 0, 0], - start: 0, - concluded_at: None, - }, - 0, - ); - - assert_ok!(importer.import(ValidatorIndex(3), true)); - assert_ok!(importer.import(ValidatorIndex(4), true)); - assert_ok!(importer.import(ValidatorIndex(5), false)); - assert_ok!(importer.import(ValidatorIndex(6), true)); - assert_ok!(importer.import(ValidatorIndex(7), true)); - - let summary = importer.finish(); - assert_eq!( - summary.state, - DisputeState { - validators_for: bitvec![BitOrderLsb0, u8; 1, 0, 1, 1, 1, 0, 1, 1], - validators_against: bitvec![BitOrderLsb0, u8; 0, 1, 0, 0, 0, 1, 0, 0], - start: 0, - concluded_at: Some(0), - }, - ); - assert!(summary.spam_slot_changes.is_empty()); - assert!(summary.slash_for.is_empty()); - assert_eq!(summary.slash_against, vec![ValidatorIndex(1), ValidatorIndex(5)]); - assert_eq!(summary.new_participants, bitvec![BitOrderLsb0, u8; 0, 0, 0, 1, 1, 1, 1, 1]); - assert_eq!(summary.new_flags, DisputeStateFlags::FOR_SUPERMAJORITY); - } - - // Test that punish_inconclusive is correctly called. - #[test] - fn test_initializer_initialize() { - let dispute_conclusion_by_time_out_period = 3; - let start = 10; - - let mock_genesis_config = MockGenesisConfig { - configuration: crate::configuration::GenesisConfig { - config: HostConfiguration { - dispute_conclusion_by_time_out_period, - ..Default::default() - }, - ..Default::default() - }, - ..Default::default() - }; - - new_test_ext(mock_genesis_config).execute_with(|| { - // We need 6 validators for the byzantine threshold to be 2 - let v0 = ::Pair::generate().0; - let v1 = ::Pair::generate().0; - let v2 = ::Pair::generate().0; - let v3 = ::Pair::generate().0; - let v4 = ::Pair::generate().0; - let v5 = ::Pair::generate().0; - let v6 = ::Pair::generate().0; - - run_to_block(start, |b| { - // a new session at each block - Some(( - true, - b, - vec![ - (&0, v0.public()), - (&1, v1.public()), - (&2, v2.public()), - (&3, v3.public()), - (&4, v4.public()), - (&5, v5.public()), - (&6, v6.public()), - ], - Some(vec![ - (&0, v0.public()), - (&1, v1.public()), - (&2, v2.public()), - (&3, v3.public()), - (&4, v4.public()), - (&5, v5.public()), - (&6, v6.public()), - ]), - )) - }); - - let candidate_hash = CandidateHash(sp_core::H256::repeat_byte(1)); - - // v0 votes for 3, v6 against. - let stmts = vec![DisputeStatementSet { - candidate_hash: candidate_hash.clone(), - session: start - 1, - statements: vec![ - ( - DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), - ValidatorIndex(0), - v0.sign( - &ExplicitDisputeStatement { - valid: true, - candidate_hash: candidate_hash.clone(), - session: start - 1, - } - .signing_payload(), - ), - ), - ( - DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), - ValidatorIndex(6), - v2.sign( - &ExplicitDisputeStatement { - valid: false, - candidate_hash: candidate_hash.clone(), - session: start - 1, - } - .signing_payload(), - ), - ), - ], - }]; - - let stmts = update_spam_slots(stmts); - assert_eq!(SpamSlots::::get(start - 1), Some(vec![1, 0, 0, 0, 0, 0, 1])); - - assert_ok!( - Pallet::::process_checked_multi_dispute_data(stmts), - vec![(9, candidate_hash.clone())], - ); - - // Run to timeout period - run_to_block(start + dispute_conclusion_by_time_out_period, |_| None); - assert_eq!(SpamSlots::::get(start - 1), Some(vec![1, 0, 0, 0, 0, 0, 1])); - - // Run to timeout + 1 in order to executive on_finalize(timeout) - run_to_block(start + dispute_conclusion_by_time_out_period + 1, |_| None); - assert_eq!(SpamSlots::::get(start - 1), Some(vec![0, 0, 0, 0, 0, 0, 0])); - assert_eq!( - PUNISH_VALIDATORS_INCONCLUSIVE.with(|r| r.borrow()[0].clone()), - (9, vec![ValidatorIndex(0), ValidatorIndex(6)]), - ); - }); - } - - // Test pruning works - #[test] - fn test_initializer_on_new_session() { - let dispute_period = 3; - - let mock_genesis_config = MockGenesisConfig { - configuration: crate::configuration::GenesisConfig { - config: HostConfiguration { dispute_period, ..Default::default() }, - ..Default::default() - }, - ..Default::default() - }; - - new_test_ext(mock_genesis_config).execute_with(|| { - let v0 = ::Pair::generate().0; - - let candidate_hash = CandidateHash(sp_core::H256::repeat_byte(1)); - Pallet::::note_included(0, candidate_hash.clone(), 0); - Pallet::::note_included(1, candidate_hash.clone(), 1); - Pallet::::note_included(2, candidate_hash.clone(), 2); - Pallet::::note_included(3, candidate_hash.clone(), 3); - Pallet::::note_included(4, candidate_hash.clone(), 4); - Pallet::::note_included(5, candidate_hash.clone(), 5); - Pallet::::note_included(6, candidate_hash.clone(), 5); - - run_to_block(7, |b| { - // a new session at each block - Some((true, b, vec![(&0, v0.public())], Some(vec![(&0, v0.public())]))) - }); - - // current session is 7, - // we keep for dispute_period + 1 session and we remove in on_finalize - // thus we keep info for session 3, 4, 5, 6, 7. - assert_eq!(Included::::iter_prefix(0).count(), 0); - assert_eq!(Included::::iter_prefix(1).count(), 0); - assert_eq!(Included::::iter_prefix(2).count(), 0); - assert_eq!(Included::::iter_prefix(3).count(), 1); - assert_eq!(Included::::iter_prefix(4).count(), 1); - assert_eq!(Included::::iter_prefix(5).count(), 1); - assert_eq!(Included::::iter_prefix(6).count(), 1); - }); - } - - #[test] - fn test_provide_data_duplicate_error() { - new_test_ext(Default::default()).execute_with(|| { - let candidate_hash_1 = CandidateHash(sp_core::H256::repeat_byte(1)); - let candidate_hash_2 = CandidateHash(sp_core::H256::repeat_byte(2)); - - let mut stmts = vec![ - DisputeStatementSet { - candidate_hash: candidate_hash_2, - session: 2, - statements: vec![], - }, - DisputeStatementSet { - candidate_hash: candidate_hash_1, - session: 1, - statements: vec![], - }, - DisputeStatementSet { - candidate_hash: candidate_hash_2, - session: 2, - statements: vec![], - }, - ]; - - assert!(Pallet::::deduplicate_and_sort_dispute_data(&mut stmts).is_err()); - assert_eq!(stmts.len(), 2); - }) - } - - #[test] - fn test_provide_multi_dispute_is_providing() { - new_test_ext(Default::default()).execute_with(|| { - let v0 = ::Pair::generate().0; - let v1 = ::Pair::generate().0; - - run_to_block(3, |b| { - // a new session at each block - if b == 1 { - Some(( - true, - b, - vec![(&0, v0.public()), (&1, v1.public())], - Some(vec![(&0, v0.public()), (&1, v1.public())]), - )) - } else { - Some((true, b, vec![(&1, v1.public())], Some(vec![(&1, v1.public())]))) - } - }); - - let candidate_hash = CandidateHash(sp_core::H256::repeat_byte(1)); - let stmts = vec![DisputeStatementSet { - candidate_hash: candidate_hash.clone(), - session: 1, - statements: vec![ - ( - DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), - ValidatorIndex(0), - v0.sign( - &ExplicitDisputeStatement { - valid: true, - candidate_hash: candidate_hash.clone(), - session: 1, - } - .signing_payload(), - ), - ), - ( - DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), - ValidatorIndex(1), - v1.sign( - &ExplicitDisputeStatement { - valid: false, - candidate_hash: candidate_hash.clone(), - session: 1, - } - .signing_payload(), - ), - ), - ], - }]; - - assert_ok!( - Pallet::::process_checked_multi_dispute_data( - stmts - .into_iter() - .map(CheckedDisputeStatementSet::unchecked_from_unchecked) - .collect() - ), - vec![(1, candidate_hash.clone())], - ); - }) - } - - #[test] - fn test_freeze_on_note_included() { - new_test_ext(Default::default()).execute_with(|| { - let v0 = ::Pair::generate().0; - let v1 = ::Pair::generate().0; - - run_to_block(6, |b| { - // a new session at each block - Some(( - true, - b, - vec![(&0, v0.public()), (&1, v1.public())], - Some(vec![(&0, v0.public()), (&1, v1.public())]), - )) - }); - - let candidate_hash = CandidateHash(sp_core::H256::repeat_byte(1)); - - // v0 votes for 3 - let stmts = vec![DisputeStatementSet { - candidate_hash: candidate_hash.clone(), - session: 3, - statements: vec![ - ( - DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), - ValidatorIndex(0), - v0.sign( - &ExplicitDisputeStatement { - valid: false, - candidate_hash: candidate_hash.clone(), - session: 3, - } - .signing_payload(), - ), - ), - ( - DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), - ValidatorIndex(1), - v1.sign( - &ExplicitDisputeStatement { - valid: false, - candidate_hash: candidate_hash.clone(), - session: 3, - } - .signing_payload(), - ), - ), - ( - DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), - ValidatorIndex(1), - v1.sign( - &ExplicitDisputeStatement { - valid: true, - candidate_hash: candidate_hash.clone(), - session: 3, - } - .signing_payload(), - ), - ), - ], - }]; - assert!(Pallet::::process_checked_multi_dispute_data( - stmts - .into_iter() - .map(CheckedDisputeStatementSet::unchecked_from_unchecked) - .collect() - ) - .is_ok()); - - Pallet::::note_included(3, candidate_hash.clone(), 3); - assert_eq!(Frozen::::get(), Some(2)); - }); - } - - #[test] - fn test_freeze_provided_against_supermajority_for_included() { - new_test_ext(Default::default()).execute_with(|| { - let v0 = ::Pair::generate().0; - let v1 = ::Pair::generate().0; - - run_to_block(6, |b| { - // a new session at each block - Some(( - true, - b, - vec![(&0, v0.public()), (&1, v1.public())], - Some(vec![(&0, v0.public()), (&1, v1.public())]), - )) - }); - - let candidate_hash = CandidateHash(sp_core::H256::repeat_byte(1)); - - // v0 votes for 3 - let stmts = vec![DisputeStatementSet { - candidate_hash: candidate_hash.clone(), - session: 3, - statements: vec![ - ( - DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), - ValidatorIndex(0), - v0.sign( - &ExplicitDisputeStatement { - valid: false, - candidate_hash: candidate_hash.clone(), - session: 3, - } - .signing_payload(), - ), - ), - ( - DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), - ValidatorIndex(1), - v1.sign( - &ExplicitDisputeStatement { - valid: false, - candidate_hash: candidate_hash.clone(), - session: 3, - } - .signing_payload(), - ), - ), - ( - DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), - ValidatorIndex(1), - v1.sign( - &ExplicitDisputeStatement { - valid: true, - candidate_hash: candidate_hash.clone(), - session: 3, - } - .signing_payload(), - ), - ), - ], - }]; - - Pallet::::note_included(3, candidate_hash.clone(), 3); - assert!(Pallet::::process_checked_multi_dispute_data( - stmts - .into_iter() - .map(CheckedDisputeStatementSet::unchecked_from_unchecked) - .collect() - ) - .is_ok()); - assert_eq!(Frozen::::get(), Some(2)); - }); - } - - // tests for: - // * provide_multi_dispute: with success scenario - // * disputes: correctness of datas - // * could_be_invalid: correctness of datas - // * note_included: decrement spam correctly - // * spam slots: correctly incremented and decremented - // * ensure rewards and punishment are correctly called. - #[test] - fn test_provide_multi_dispute_success_and_other() { - new_test_ext(Default::default()).execute_with(|| { - // 7 validators needed for byzantine threshold of 2. - let v0 = ::Pair::generate().0; - let v1 = ::Pair::generate().0; - let v2 = ::Pair::generate().0; - let v3 = ::Pair::generate().0; - let v4 = ::Pair::generate().0; - let v5 = ::Pair::generate().0; - let v6 = ::Pair::generate().0; - - // v0 -> 0 - // v1 -> 3 - // v2 -> 6 - // v3 -> 5 - // v4 -> 1 - // v5 -> 4 - // v6 -> 2 - - run_to_block(6, |b| { - // a new session at each block - Some(( - true, - b, - vec![ - (&0, v0.public()), - (&1, v1.public()), - (&2, v2.public()), - (&3, v3.public()), - (&4, v4.public()), - (&5, v5.public()), - (&6, v6.public()), - ], - Some(vec![ - (&0, v0.public()), - (&1, v1.public()), - (&2, v2.public()), - (&3, v3.public()), - (&4, v4.public()), - (&5, v5.public()), - (&6, v6.public()), - ]), - )) - }); - - let candidate_hash = CandidateHash(sp_core::H256::repeat_byte(1)); - - // v0 votes for 3, v6 votes against - let stmts = vec![DisputeStatementSet { - candidate_hash: candidate_hash.clone(), - session: 3, - statements: vec![ - ( - DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), - ValidatorIndex(0), - v0.sign( - &ExplicitDisputeStatement { - valid: true, - candidate_hash: candidate_hash.clone(), - session: 3, - } - .signing_payload(), - ), - ), - ( - DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), - ValidatorIndex(2), - v6.sign( - &ExplicitDisputeStatement { - valid: false, - candidate_hash: candidate_hash.clone(), - session: 3, - } - .signing_payload(), - ), - ), - ], - }]; - - let stmts = update_spam_slots(stmts); - assert_eq!(SpamSlots::::get(3), Some(vec![1, 0, 1, 0, 0, 0, 0])); - - assert_ok!( - Pallet::::process_checked_multi_dispute_data(stmts), - vec![(3, candidate_hash.clone())], - ); - - // v1 votes for 4 and for 3, v6 votes against 4. - let stmts = vec![ - DisputeStatementSet { - candidate_hash: candidate_hash.clone(), - session: 4, - statements: vec![ - ( - DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), - ValidatorIndex(3), - v1.sign( - &ExplicitDisputeStatement { - valid: true, - candidate_hash: candidate_hash.clone(), - session: 4, - } - .signing_payload(), - ), - ), - ( - DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), - ValidatorIndex(2), - v6.sign( - &ExplicitDisputeStatement { - valid: false, - candidate_hash: candidate_hash.clone(), - session: 4, - } - .signing_payload(), - ), - ), - ], - }, - DisputeStatementSet { - candidate_hash: candidate_hash.clone(), - session: 3, - statements: vec![( - DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), - ValidatorIndex(3), - v1.sign( - &ExplicitDisputeStatement { - valid: true, - candidate_hash: candidate_hash.clone(), - session: 3, - } - .signing_payload(), - ), - )], - }, - ]; - - let stmts = update_spam_slots(stmts); - - assert_ok!( - Pallet::::process_checked_multi_dispute_data(stmts), - vec![(4, candidate_hash.clone())], - ); - assert_eq!(SpamSlots::::get(3), Some(vec![0, 0, 0, 0, 0, 0, 0])); // Confirmed as no longer spam - assert_eq!(SpamSlots::::get(4), Some(vec![0, 0, 1, 1, 0, 0, 0])); - - // v3 votes against 3 and for 5, v6 votes against 5. - let stmts = vec![ - DisputeStatementSet { - candidate_hash: candidate_hash.clone(), - session: 3, - statements: vec![( - DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), - ValidatorIndex(5), - v3.sign( - &ExplicitDisputeStatement { - valid: false, - candidate_hash: candidate_hash.clone(), - session: 3, - } - .signing_payload(), - ), - )], - }, - DisputeStatementSet { - candidate_hash: candidate_hash.clone(), - session: 5, - statements: vec![ - ( - DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), - ValidatorIndex(5), - v3.sign( - &ExplicitDisputeStatement { - valid: true, - candidate_hash: candidate_hash.clone(), - session: 5, - } - .signing_payload(), - ), - ), - ( - DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), - ValidatorIndex(2), - v6.sign( - &ExplicitDisputeStatement { - valid: false, - candidate_hash: candidate_hash.clone(), - session: 5, - } - .signing_payload(), - ), - ), - ], - }, - ]; - - let stmts = update_spam_slots(stmts); - assert_ok!( - Pallet::::process_checked_multi_dispute_data(stmts), - vec![(5, candidate_hash.clone())], - ); - assert_eq!(SpamSlots::::get(3), Some(vec![0, 0, 0, 0, 0, 0, 0])); - assert_eq!(SpamSlots::::get(4), Some(vec![0, 0, 1, 1, 0, 0, 0])); - assert_eq!(SpamSlots::::get(5), Some(vec![0, 0, 1, 0, 0, 1, 0])); - - // v2 votes for 3 and against 5 - let stmts = vec![ - DisputeStatementSet { - candidate_hash: candidate_hash.clone(), - session: 3, - statements: vec![( - DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), - ValidatorIndex(6), - v2.sign( - &ExplicitDisputeStatement { - valid: true, - candidate_hash: candidate_hash.clone(), - session: 3, - } - .signing_payload(), - ), - )], - }, - DisputeStatementSet { - candidate_hash: candidate_hash.clone(), - session: 5, - statements: vec![( - DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), - ValidatorIndex(6), - v2.sign( - &ExplicitDisputeStatement { - valid: false, - candidate_hash: candidate_hash.clone(), - session: 5, - } - .signing_payload(), - ), - )], - }, - ]; - let stmts = update_spam_slots(stmts); - assert_ok!(Pallet::::process_checked_multi_dispute_data(stmts), vec![]); - assert_eq!(SpamSlots::::get(3), Some(vec![0, 0, 0, 0, 0, 0, 0])); - assert_eq!(SpamSlots::::get(4), Some(vec![0, 0, 1, 1, 0, 0, 0])); - assert_eq!(SpamSlots::::get(5), Some(vec![0, 0, 0, 0, 0, 0, 0])); - - let stmts = vec![ - // 0, 4, and 5 vote against 5 - DisputeStatementSet { - candidate_hash: candidate_hash.clone(), - session: 5, - statements: vec![ - ( - DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), - ValidatorIndex(0), - v0.sign( - &ExplicitDisputeStatement { - valid: false, - candidate_hash: candidate_hash.clone(), - session: 5, - } - .signing_payload(), - ), - ), - ( - DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), - ValidatorIndex(1), - v4.sign( - &ExplicitDisputeStatement { - valid: false, - candidate_hash: candidate_hash.clone(), - session: 5, - } - .signing_payload(), - ), - ), - ( - DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), - ValidatorIndex(4), - v5.sign( - &ExplicitDisputeStatement { - valid: false, - candidate_hash: candidate_hash.clone(), - session: 5, - } - .signing_payload(), - ), - ), - ], - }, - // 4 and 5 vote for 3 - DisputeStatementSet { - candidate_hash: candidate_hash.clone(), - session: 3, - statements: vec![ - ( - DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), - ValidatorIndex(1), - v4.sign( - &ExplicitDisputeStatement { - valid: true, - candidate_hash: candidate_hash.clone(), - session: 3, - } - .signing_payload(), - ), - ), - ( - DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), - ValidatorIndex(4), - v5.sign( - &ExplicitDisputeStatement { - valid: true, - candidate_hash: candidate_hash.clone(), - session: 3, - } - .signing_payload(), - ), - ), - ], - }, - ]; - let stmts = update_spam_slots(stmts); - assert_ok!(Pallet::::process_checked_multi_dispute_data(stmts), vec![]); - - assert_eq!( - Pallet::::disputes(), - vec![ - ( - 5, - candidate_hash.clone(), - DisputeState { - validators_for: bitvec![BitOrderLsb0, u8; 0, 0, 0, 0, 0, 1, 0], - validators_against: bitvec![BitOrderLsb0, u8; 1, 1, 1, 0, 1, 0, 1], - start: 6, - concluded_at: Some(6), // 5 vote against - } - ), - ( - 3, - candidate_hash.clone(), - DisputeState { - validators_for: bitvec![BitOrderLsb0, u8; 1, 1, 0, 1, 1, 0, 1], - validators_against: bitvec![BitOrderLsb0, u8; 0, 0, 1, 0, 0, 1, 0], - start: 6, - concluded_at: Some(6), // 5 vote for - } - ), - ( - 4, - candidate_hash.clone(), - DisputeState { - validators_for: bitvec![BitOrderLsb0, u8; 0, 0, 0, 1, 0, 0, 0], - validators_against: bitvec![BitOrderLsb0, u8; 0, 0, 1, 0, 0, 0, 0], - start: 6, - concluded_at: None, - } - ), - ] - ); - - assert!(!Pallet::::concluded_invalid(3, candidate_hash.clone())); - assert!(!Pallet::::concluded_invalid(4, candidate_hash.clone())); - assert!(Pallet::::concluded_invalid(5, candidate_hash.clone())); - - // Ensure inclusion removes spam slots - assert_eq!(SpamSlots::::get(4), Some(vec![0, 0, 1, 1, 0, 0, 0])); - Pallet::::note_included(4, candidate_hash.clone(), 4); - assert_eq!(SpamSlots::::get(4), Some(vec![0, 0, 0, 0, 0, 0, 0])); - - // Ensure the `reward_validator` function was correctly called - assert_eq!( - REWARD_VALIDATORS.with(|r| r.borrow().clone()), - vec![ - (3, vec![ValidatorIndex(0), ValidatorIndex(2)]), - (4, vec![ValidatorIndex(2), ValidatorIndex(3)]), - (3, vec![ValidatorIndex(3)]), - (3, vec![ValidatorIndex(5)]), - (5, vec![ValidatorIndex(2), ValidatorIndex(5)]), - (3, vec![ValidatorIndex(6)]), - (5, vec![ValidatorIndex(6)]), - (5, vec![ValidatorIndex(0), ValidatorIndex(1), ValidatorIndex(4)]), - (3, vec![ValidatorIndex(1), ValidatorIndex(4)]), - ], - ); - - // Ensure punishment against is called - assert_eq!( - PUNISH_VALIDATORS_AGAINST.with(|r| r.borrow().clone()), - vec![ - (3, vec![]), - (4, vec![]), - (3, vec![]), - (3, vec![]), - (5, vec![]), - (3, vec![]), - (5, vec![]), - (5, vec![]), - (3, vec![ValidatorIndex(2), ValidatorIndex(5)]), - ], - ); - - // Ensure punishment for is called - assert_eq!( - PUNISH_VALIDATORS_FOR.with(|r| r.borrow().clone()), - vec![ - (3, vec![]), - (4, vec![]), - (3, vec![]), - (3, vec![]), - (5, vec![]), - (3, vec![]), - (5, vec![]), - (5, vec![ValidatorIndex(5)]), - (3, vec![]), - ], - ); - }) - } - - #[test] - fn test_revert_and_freeze() { - new_test_ext(Default::default()).execute_with(|| { - // events are ignored for genesis block - System::set_block_number(1); - - Frozen::::put(Some(0)); - assert_noop!( - { - Pallet::::revert_and_freeze(0); - Result::<(), ()>::Err(()) // Just a small trick in order to use `assert_noop`. - }, - (), - ); - - Frozen::::kill(); - Pallet::::revert_and_freeze(0); - - assert_eq!(Frozen::::get(), Some(0)); - assert_eq!(System::digest().logs[0], ConsensusLog::Revert(1).into()); - System::assert_has_event(Event::Revert(1).into()); - }) - } - - #[test] - fn test_revert_and_freeze_merges() { - new_test_ext(Default::default()).execute_with(|| { - Frozen::::put(Some(10)); - assert_noop!( - { - Pallet::::revert_and_freeze(10); - Result::<(), ()>::Err(()) // Just a small trick in order to use `assert_noop`. - }, - (), - ); - - Pallet::::revert_and_freeze(8); - assert_eq!(Frozen::::get(), Some(8)); - }) - } - - #[test] - fn test_has_supermajority_against() { - assert_eq!( - has_supermajority_against(&DisputeState { - validators_for: bitvec![BitOrderLsb0, u8; 1, 1, 0, 0, 0, 0, 0, 0], - validators_against: bitvec![BitOrderLsb0, u8; 1, 1, 1, 1, 1, 0, 0, 0], - start: 0, - concluded_at: None, - }), - false, - ); - - assert_eq!( - has_supermajority_against(&DisputeState { - validators_for: bitvec![BitOrderLsb0, u8; 1, 1, 0, 0, 0, 0, 0, 0], - validators_against: bitvec![BitOrderLsb0, u8; 1, 1, 1, 1, 1, 1, 0, 0], - start: 0, - concluded_at: None, - }), - true, - ); - } - - #[test] - fn test_decrement_spam() { - let original_spam_slots = vec![0, 1, 2, 3, 4, 5, 6, 7]; - - // Test confirm is no-op - let mut spam_slots = original_spam_slots.clone(); - let dispute_state_confirm = DisputeState { - validators_for: bitvec![BitOrderLsb0, u8; 1, 1, 0, 0, 0, 0, 0, 0], - validators_against: bitvec![BitOrderLsb0, u8; 1, 0, 1, 0, 0, 0, 0, 0], - start: 0, - concluded_at: None, - }; - assert_eq!( - DisputeStateFlags::from_state(&dispute_state_confirm), - DisputeStateFlags::CONFIRMED - ); - assert_eq!( - decrement_spam(spam_slots.as_mut(), &dispute_state_confirm), - bitvec![BitOrderLsb0, u8; 1, 1, 1, 0, 0, 0, 0, 0], - ); - assert_eq!(spam_slots, original_spam_slots); - - // Test not confirm is decreasing spam - let mut spam_slots = original_spam_slots.clone(); - let dispute_state_no_confirm = DisputeState { - validators_for: bitvec![BitOrderLsb0, u8; 1, 0, 0, 0, 0, 0, 0, 0], - validators_against: bitvec![BitOrderLsb0, u8; 1, 0, 1, 0, 0, 0, 0, 0], - start: 0, - concluded_at: None, - }; - assert_eq!( - DisputeStateFlags::from_state(&dispute_state_no_confirm), - DisputeStateFlags::default() - ); - assert_eq!( - decrement_spam(spam_slots.as_mut(), &dispute_state_no_confirm), - bitvec![BitOrderLsb0, u8; 1, 0, 1, 0, 0, 0, 0, 0], - ); - assert_eq!(spam_slots, vec![0, 1, 1, 3, 4, 5, 6, 7]); - } - - #[test] - fn test_check_signature() { - let validator_id = ::Pair::generate().0; - let wrong_validator_id = ::Pair::generate().0; - - let session = 0; - let wrong_session = 1; - let candidate_hash = CandidateHash(sp_core::H256::repeat_byte(1)); - let wrong_candidate_hash = CandidateHash(sp_core::H256::repeat_byte(2)); - let inclusion_parent = sp_core::H256::repeat_byte(3); - let wrong_inclusion_parent = sp_core::H256::repeat_byte(4); - - let statement_1 = DisputeStatement::Valid(ValidDisputeStatementKind::Explicit); - let statement_2 = DisputeStatement::Valid(ValidDisputeStatementKind::BackingSeconded( - inclusion_parent.clone(), - )); - let wrong_statement_2 = DisputeStatement::Valid( - ValidDisputeStatementKind::BackingSeconded(wrong_inclusion_parent.clone()), - ); - let statement_3 = DisputeStatement::Valid(ValidDisputeStatementKind::BackingValid( - inclusion_parent.clone(), - )); - let wrong_statement_3 = DisputeStatement::Valid(ValidDisputeStatementKind::BackingValid( - wrong_inclusion_parent.clone(), - )); - let statement_4 = DisputeStatement::Valid(ValidDisputeStatementKind::ApprovalChecking); - let statement_5 = DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit); - - let signed_1 = validator_id.sign( - &ExplicitDisputeStatement { - valid: true, - candidate_hash: candidate_hash.clone(), - session, - } - .signing_payload(), - ); - let signed_2 = - validator_id.sign(&CompactStatement::Seconded(candidate_hash.clone()).signing_payload( - &SigningContext { session_index: session, parent_hash: inclusion_parent.clone() }, - )); - let signed_3 = - validator_id.sign(&CompactStatement::Valid(candidate_hash.clone()).signing_payload( - &SigningContext { session_index: session, parent_hash: inclusion_parent.clone() }, - )); - let signed_4 = - validator_id.sign(&ApprovalVote(candidate_hash.clone()).signing_payload(session)); - let signed_5 = validator_id.sign( - &ExplicitDisputeStatement { - valid: false, - candidate_hash: candidate_hash.clone(), - session, - } - .signing_payload(), - ); - - assert!(check_signature( - &validator_id.public(), - candidate_hash, - session, - &statement_1, - &signed_1 - ) - .is_ok()); - assert!(check_signature( - &wrong_validator_id.public(), - candidate_hash, - session, - &statement_1, - &signed_1 - ) - .is_err()); - assert!(check_signature( - &validator_id.public(), - wrong_candidate_hash, - session, - &statement_1, - &signed_1 - ) - .is_err()); - assert!(check_signature( - &validator_id.public(), - candidate_hash, - wrong_session, - &statement_1, - &signed_1 - ) - .is_err()); - assert!(check_signature( - &validator_id.public(), - candidate_hash, - session, - &statement_2, - &signed_1 - ) - .is_err()); - assert!(check_signature( - &validator_id.public(), - candidate_hash, - session, - &statement_3, - &signed_1 - ) - .is_err()); - assert!(check_signature( - &validator_id.public(), - candidate_hash, - session, - &statement_4, - &signed_1 - ) - .is_err()); - assert!(check_signature( - &validator_id.public(), - candidate_hash, - session, - &statement_5, - &signed_1 - ) - .is_err()); - - assert!(check_signature( - &validator_id.public(), - candidate_hash, - session, - &statement_2, - &signed_2 - ) - .is_ok()); - assert!(check_signature( - &wrong_validator_id.public(), - candidate_hash, - session, - &statement_2, - &signed_2 - ) - .is_err()); - assert!(check_signature( - &validator_id.public(), - wrong_candidate_hash, - session, - &statement_2, - &signed_2 - ) - .is_err()); - assert!(check_signature( - &validator_id.public(), - candidate_hash, - wrong_session, - &statement_2, - &signed_2 - ) - .is_err()); - assert!(check_signature( - &validator_id.public(), - candidate_hash, - session, - &wrong_statement_2, - &signed_2 - ) - .is_err()); - assert!(check_signature( - &validator_id.public(), - candidate_hash, - session, - &statement_1, - &signed_2 - ) - .is_err()); - assert!(check_signature( - &validator_id.public(), - candidate_hash, - session, - &statement_3, - &signed_2 - ) - .is_err()); - assert!(check_signature( - &validator_id.public(), - candidate_hash, - session, - &statement_4, - &signed_2 - ) - .is_err()); - assert!(check_signature( - &validator_id.public(), - candidate_hash, - session, - &statement_5, - &signed_2 - ) - .is_err()); - - assert!(check_signature( - &validator_id.public(), - candidate_hash, - session, - &statement_3, - &signed_3 - ) - .is_ok()); - assert!(check_signature( - &wrong_validator_id.public(), - candidate_hash, - session, - &statement_3, - &signed_3 - ) - .is_err()); - assert!(check_signature( - &validator_id.public(), - wrong_candidate_hash, - session, - &statement_3, - &signed_3 - ) - .is_err()); - assert!(check_signature( - &validator_id.public(), - candidate_hash, - wrong_session, - &statement_3, - &signed_3 - ) - .is_err()); - assert!(check_signature( - &validator_id.public(), - candidate_hash, - session, - &wrong_statement_3, - &signed_3 - ) - .is_err()); - assert!(check_signature( - &validator_id.public(), - candidate_hash, - session, - &statement_1, - &signed_3 - ) - .is_err()); - assert!(check_signature( - &validator_id.public(), - candidate_hash, - session, - &statement_2, - &signed_3 - ) - .is_err()); - assert!(check_signature( - &validator_id.public(), - candidate_hash, - session, - &statement_4, - &signed_3 - ) - .is_err()); - assert!(check_signature( - &validator_id.public(), - candidate_hash, - session, - &statement_5, - &signed_3 - ) - .is_err()); - - assert!(check_signature( - &validator_id.public(), - candidate_hash, - session, - &statement_4, - &signed_4 - ) - .is_ok()); - assert!(check_signature( - &wrong_validator_id.public(), - candidate_hash, - session, - &statement_4, - &signed_4 - ) - .is_err()); - assert!(check_signature( - &validator_id.public(), - wrong_candidate_hash, - session, - &statement_4, - &signed_4 - ) - .is_err()); - assert!(check_signature( - &validator_id.public(), - candidate_hash, - wrong_session, - &statement_4, - &signed_4 - ) - .is_err()); - assert!(check_signature( - &validator_id.public(), - candidate_hash, - session, - &statement_1, - &signed_4 - ) - .is_err()); - assert!(check_signature( - &validator_id.public(), - candidate_hash, - session, - &statement_2, - &signed_4 - ) - .is_err()); - assert!(check_signature( - &validator_id.public(), - candidate_hash, - session, - &statement_3, - &signed_4 - ) - .is_err()); - assert!(check_signature( - &validator_id.public(), - candidate_hash, - session, - &statement_5, - &signed_4 - ) - .is_err()); - - assert!(check_signature( - &validator_id.public(), - candidate_hash, - session, - &statement_5, - &signed_5 - ) - .is_ok()); - assert!(check_signature( - &wrong_validator_id.public(), - candidate_hash, - session, - &statement_5, - &signed_5 - ) - .is_err()); - assert!(check_signature( - &validator_id.public(), - wrong_candidate_hash, - session, - &statement_5, - &signed_5 - ) - .is_err()); - assert!(check_signature( - &validator_id.public(), - candidate_hash, - wrong_session, - &statement_5, - &signed_5 - ) - .is_err()); - assert!(check_signature( - &validator_id.public(), - candidate_hash, - session, - &statement_1, - &signed_5 - ) - .is_err()); - assert!(check_signature( - &validator_id.public(), - candidate_hash, - session, - &statement_2, - &signed_5 - ) - .is_err()); - assert!(check_signature( - &validator_id.public(), - candidate_hash, - session, - &statement_3, - &signed_5 - ) - .is_err()); - assert!(check_signature( - &validator_id.public(), - candidate_hash, - session, - &statement_4, - &signed_5 - ) - .is_err()); - } - - #[test] - fn deduplication_and_sorting_works() { - new_test_ext(Default::default()).execute_with(|| { - let v0 = ::Pair::generate().0; - let v1 = ::Pair::generate().0; - let v2 = ::Pair::generate().0; - let v3 = ::Pair::generate().0; - - run_to_block(3, |b| { - // a new session at each block - Some(( - true, - b, - vec![ - (&0, v0.public()), - (&1, v1.public()), - (&2, v2.public()), - (&3, v3.public()), - ], - Some(vec![ - (&0, v0.public()), - (&1, v1.public()), - (&2, v2.public()), - (&3, v3.public()), - ]), - )) - }); - - let candidate_hash_a = CandidateHash(sp_core::H256::repeat_byte(1)); - let candidate_hash_b = CandidateHash(sp_core::H256::repeat_byte(2)); - let candidate_hash_c = CandidateHash(sp_core::H256::repeat_byte(3)); - - let create_explicit_statement = |vidx: ValidatorIndex, - validator: &::Pair, - c_hash: &CandidateHash, - valid, - session| { - let payload = - ExplicitDisputeStatement { valid, candidate_hash: c_hash.clone(), session } - .signing_payload(); - let sig = validator.sign(&payload); - (DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), vidx, sig.clone()) - }; - - let explicit_triple_a = - create_explicit_statement(ValidatorIndex(0), &v0, &candidate_hash_a, true, 1); - let explicit_triple_a_bad = - create_explicit_statement(ValidatorIndex(1), &v1, &candidate_hash_a, false, 1); - - let explicit_triple_b = - create_explicit_statement(ValidatorIndex(0), &v0, &candidate_hash_b, true, 2); - let explicit_triple_b_bad = - create_explicit_statement(ValidatorIndex(1), &v1, &candidate_hash_b, false, 2); - - let explicit_triple_c = - create_explicit_statement(ValidatorIndex(0), &v0, &candidate_hash_c, true, 2); - let explicit_triple_c_bad = - create_explicit_statement(ValidatorIndex(1), &v1, &candidate_hash_c, false, 2); - - let mut disputes = vec![ - DisputeStatementSet { - candidate_hash: candidate_hash_b.clone(), - session: 2, - statements: vec![explicit_triple_b.clone(), explicit_triple_b_bad.clone()], - }, - // same session as above - DisputeStatementSet { - candidate_hash: candidate_hash_c.clone(), - session: 2, - statements: vec![explicit_triple_c, explicit_triple_c_bad], - }, - // the duplicate set - DisputeStatementSet { - candidate_hash: candidate_hash_b.clone(), - session: 2, - statements: vec![explicit_triple_b.clone(), explicit_triple_b_bad.clone()], - }, - DisputeStatementSet { - candidate_hash: candidate_hash_a.clone(), - session: 1, - statements: vec![explicit_triple_a, explicit_triple_a_bad], - }, - ]; - - let disputes_orig = disputes.clone(); - - as DisputesHandler< - ::BlockNumber, - >>::deduplicate_and_sort_dispute_data(&mut disputes).unwrap_err(); - - // assert ordering of local only disputes, and at the same time, and being free of duplicates - assert_eq!(disputes_orig.len(), disputes.len() + 1); - - let are_these_equal = |a: &DisputeStatementSet, b: &DisputeStatementSet| { - use core::cmp::Ordering; - // we only have local disputes here, so sorting of those adheres to the - // simplified sorting logic - let cmp = - a.session.cmp(&b.session).then_with(|| a.candidate_hash.cmp(&b.candidate_hash)); - assert_ne!(cmp, Ordering::Greater); - cmp == Ordering::Equal - }; - - assert_eq!(false, contains_duplicates_in_sorted_iter(&disputes, are_these_equal)); - }) - } - - fn apply_filter_all>( - sets: I, - ) -> Vec { - let config = >::config(); - let max_spam_slots = config.dispute_max_spam_slots; - let post_conclusion_acceptance_period = config.dispute_post_conclusion_acceptance_period; - - let mut acc = Vec::::new(); - for dispute_statement in sets { - if let Some(checked) = - as DisputesHandler<::BlockNumber>>::filter_dispute_data( - dispute_statement, - max_spam_slots, - post_conclusion_acceptance_period, - VerifyDisputeSignatures::Yes, - ) { - acc.push(checked); - } - } - acc - } - - #[test] - fn filter_removes_duplicates_within_set() { - new_test_ext(Default::default()).execute_with(|| { - let v0 = ::Pair::generate().0; - let v1 = ::Pair::generate().0; - - run_to_block(3, |b| { - // a new session at each block - Some(( - true, - b, - vec![(&0, v0.public()), (&1, v1.public())], - Some(vec![(&0, v0.public()), (&1, v1.public())]), - )) - }); - - let candidate_hash = CandidateHash(sp_core::H256::repeat_byte(1)); - - let payload = ExplicitDisputeStatement { - valid: true, - candidate_hash: candidate_hash.clone(), - session: 1, - } - .signing_payload(); - - let payload_against = ExplicitDisputeStatement { - valid: false, - candidate_hash: candidate_hash.clone(), - session: 1, - } - .signing_payload(); - - let sig_a = v0.sign(&payload); - let sig_b = v0.sign(&payload); - let sig_c = v0.sign(&payload); - let sig_d = v1.sign(&payload_against); - - let statements = DisputeStatementSet { - candidate_hash: candidate_hash.clone(), - session: 1, - statements: vec![ - ( - DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), - ValidatorIndex(0), - sig_a.clone(), - ), - ( - DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), - ValidatorIndex(0), - sig_b, - ), - ( - DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), - ValidatorIndex(0), - sig_c, - ), - ( - DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), - ValidatorIndex(1), - sig_d.clone(), - ), - ], - }; - - let max_spam_slots = 10; - let post_conclusion_acceptance_period = 10; - let statements = as DisputesHandler< - ::BlockNumber, - >>::filter_dispute_data( - statements, - max_spam_slots, - post_conclusion_acceptance_period, - VerifyDisputeSignatures::Yes, - ); - - assert_eq!( - statements, - Some(CheckedDisputeStatementSet::unchecked_from_unchecked(DisputeStatementSet { - candidate_hash: candidate_hash.clone(), - session: 1, - statements: vec![ - ( - DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), - ValidatorIndex(0), - sig_a, - ), - ( - DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), - ValidatorIndex(1), - sig_d, - ), - ] - })) - ); - }) - } - - #[test] - fn filter_bad_signatures_correctly_detects_single_sided() { - new_test_ext(Default::default()).execute_with(|| { - let v0 = ::Pair::generate().0; - let v1 = ::Pair::generate().0; - let v2 = ::Pair::generate().0; - let v3 = ::Pair::generate().0; - - run_to_block(3, |b| { - // a new session at each block - Some(( - true, - b, - vec![ - (&0, v0.public()), - (&1, v1.public()), - (&2, v2.public()), - (&3, v3.public()), - ], - Some(vec![ - (&0, v0.public()), - (&1, v1.public()), - (&2, v2.public()), - (&3, v3.public()), - ]), - )) - }); - - let candidate_hash_a = CandidateHash(sp_core::H256::repeat_byte(1)); - - let payload = |c_hash: &CandidateHash, valid| { - ExplicitDisputeStatement { valid, candidate_hash: c_hash.clone(), session: 1 } - .signing_payload() - }; - - let payload_a = payload(&candidate_hash_a, true); - let payload_a_bad = payload(&candidate_hash_a, false); - - let sig_0 = v0.sign(&payload_a); - let sig_1 = v1.sign(&payload_a_bad); - - let statements = vec![DisputeStatementSet { - candidate_hash: candidate_hash_a.clone(), - session: 1, - statements: vec![ - ( - DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), - ValidatorIndex(0), - sig_0.clone(), - ), - ( - DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), - ValidatorIndex(2), - sig_1.clone(), - ), - ], - }]; - - let statements = apply_filter_all::(statements); - - assert!(statements.is_empty()); - }) - } - - #[test] - fn filter_correctly_accounts_spam_slots() { - let dispute_max_spam_slots = 2; - - let mock_genesis_config = MockGenesisConfig { - configuration: crate::configuration::GenesisConfig { - config: HostConfiguration { dispute_max_spam_slots, ..Default::default() }, - ..Default::default() - }, - ..Default::default() - }; - - new_test_ext(mock_genesis_config).execute_with(|| { - // We need 7 validators for the byzantine threshold to be 2 - let v0 = ::Pair::generate().0; - let v1 = ::Pair::generate().0; - let v2 = ::Pair::generate().0; - let v3 = ::Pair::generate().0; - let v4 = ::Pair::generate().0; - let v5 = ::Pair::generate().0; - let v6 = ::Pair::generate().0; - - run_to_block(3, |b| { - // a new session at each block - Some(( - true, - b, - vec![ - (&0, v0.public()), - (&1, v1.public()), - (&2, v2.public()), - (&3, v3.public()), - (&4, v4.public()), - (&5, v5.public()), - (&6, v6.public()), - ], - Some(vec![ - (&0, v0.public()), - (&1, v1.public()), - (&2, v2.public()), - (&3, v3.public()), - (&4, v4.public()), - (&5, v5.public()), - (&6, v6.public()), - ]), - )) - }); - - let candidate_hash_a = CandidateHash(sp_core::H256::repeat_byte(1)); - let candidate_hash_b = CandidateHash(sp_core::H256::repeat_byte(2)); - let candidate_hash_c = CandidateHash(sp_core::H256::repeat_byte(3)); - - let payload = |c_hash: &CandidateHash, valid| { - ExplicitDisputeStatement { valid, candidate_hash: c_hash.clone(), session: 1 } - .signing_payload() - }; - - let payload_a = payload(&candidate_hash_a, true); - let payload_b = payload(&candidate_hash_b, true); - let payload_c = payload(&candidate_hash_c, true); - - let payload_a_bad = payload(&candidate_hash_a, false); - let payload_b_bad = payload(&candidate_hash_b, false); - let payload_c_bad = payload(&candidate_hash_c, false); - - let sig_0a = v0.sign(&payload_a); - let sig_0b = v0.sign(&payload_b); - let sig_0c = v0.sign(&payload_c); - - let sig_1b = v1.sign(&payload_b); - - let sig_2a = v2.sign(&payload_a_bad); - let sig_2b = v2.sign(&payload_b_bad); - let sig_2c = v2.sign(&payload_c_bad); - - let statements = vec![ - // validators 0 and 2 get 1 spam slot from this. - DisputeStatementSet { - candidate_hash: candidate_hash_a.clone(), - session: 1, - statements: vec![ - ( - DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), - ValidatorIndex(0), - sig_0a.clone(), - ), - ( - DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), - ValidatorIndex(6), - sig_2a.clone(), - ), - ], - }, - // Validators 0, 2, and 3 get no spam slots for this - DisputeStatementSet { - candidate_hash: candidate_hash_b.clone(), - session: 1, - statements: vec![ - ( - DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), - ValidatorIndex(0), - sig_0b.clone(), - ), - ( - DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), - ValidatorIndex(3), - sig_1b.clone(), - ), - ( - DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), - ValidatorIndex(6), - sig_2b.clone(), - ), - ], - }, - // Validators 0 and 2 get an extra spam slot for this. - DisputeStatementSet { - candidate_hash: candidate_hash_c.clone(), - session: 1, - statements: vec![ - ( - DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), - ValidatorIndex(0), - sig_0c.clone(), - ), - ( - DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), - ValidatorIndex(6), - sig_2c.clone(), - ), - ], - }, - ]; - - let old_statements = statements - .clone() - .into_iter() - .map(CheckedDisputeStatementSet::unchecked_from_unchecked) - .collect::>(); - let statements = apply_filter_all::(statements); - - assert_eq!(statements, old_statements); - }) - } - - #[test] - fn filter_removes_session_out_of_bounds() { - new_test_ext(Default::default()).execute_with(|| { - let v0 = ::Pair::generate().0; - - run_to_block(3, |b| { - // a new session at each block - Some((true, b, vec![(&0, v0.public())], Some(vec![(&0, v0.public())]))) - }); - - let candidate_hash = CandidateHash(sp_core::H256::repeat_byte(1)); - - let payload = ExplicitDisputeStatement { - valid: true, - candidate_hash: candidate_hash.clone(), - session: 1, - } - .signing_payload(); - - let sig_a = v0.sign(&payload); - - let statements = vec![DisputeStatementSet { - candidate_hash: candidate_hash.clone(), - session: 100, - statements: vec![( - DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), - ValidatorIndex(0), - sig_a, - )], - }]; - - let statements = apply_filter_all::(statements); - - assert!(statements.is_empty()); - }) - } - - #[test] - fn filter_removes_concluded_ancient() { - let dispute_post_conclusion_acceptance_period = 2; - - let mock_genesis_config = MockGenesisConfig { - configuration: crate::configuration::GenesisConfig { - config: HostConfiguration { - dispute_post_conclusion_acceptance_period, - ..Default::default() - }, - ..Default::default() - }, - ..Default::default() - }; - - new_test_ext(mock_genesis_config).execute_with(|| { - let v0 = ::Pair::generate().0; - - run_to_block(3, |b| { - // a new session at each block - Some((true, b, vec![(&0, v0.public())], Some(vec![(&0, v0.public())]))) - }); - - let candidate_hash_a = CandidateHash(sp_core::H256::repeat_byte(1)); - let candidate_hash_b = CandidateHash(sp_core::H256::repeat_byte(2)); - - >::insert( - &1, - &candidate_hash_a, - DisputeState { - validators_for: bitvec![BitOrderLsb0, u8; 0; 4], - validators_against: bitvec![BitOrderLsb0, u8; 1; 4], - start: 0, - concluded_at: Some(0), - }, - ); - - >::insert( - &1, - &candidate_hash_b, - DisputeState { - validators_for: bitvec![BitOrderLsb0, u8; 0; 4], - validators_against: bitvec![BitOrderLsb0, u8; 1; 4], - start: 0, - concluded_at: Some(1), - }, - ); - - let payload_a = ExplicitDisputeStatement { - valid: true, - candidate_hash: candidate_hash_a.clone(), - session: 1, - } - .signing_payload(); - - let payload_b = ExplicitDisputeStatement { - valid: true, - candidate_hash: candidate_hash_b.clone(), - session: 1, - } - .signing_payload(); - - let sig_a = v0.sign(&payload_a); - let sig_b = v0.sign(&payload_b); - - let statements = vec![ - DisputeStatementSet { - candidate_hash: candidate_hash_a.clone(), - session: 1, - statements: vec![( - DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), - ValidatorIndex(0), - sig_a, - )], - }, - DisputeStatementSet { - candidate_hash: candidate_hash_b.clone(), - session: 1, - statements: vec![( - DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), - ValidatorIndex(0), - sig_b.clone(), - )], - }, - ]; - - let statements = apply_filter_all::(statements); - - assert_eq!( - statements, - vec![CheckedDisputeStatementSet::unchecked_from_unchecked(DisputeStatementSet { - candidate_hash: candidate_hash_b.clone(), - session: 1, - statements: vec![( - DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), - ValidatorIndex(0), - sig_b, - ),] - })] - ); - }) - } - - #[test] - fn filter_removes_duplicate_statements_sets() { - new_test_ext(Default::default()).execute_with(|| { - let v0 = ::Pair::generate().0; - let v1 = ::Pair::generate().0; - - run_to_block(3, |b| { - // a new session at each block - Some(( - true, - b, - vec![(&0, v0.public()), (&1, v1.public())], - Some(vec![(&0, v0.public()), (&1, v1.public())]), - )) - }); - - let candidate_hash_a = CandidateHash(sp_core::H256::repeat_byte(1)); - - let payload = ExplicitDisputeStatement { - valid: true, - candidate_hash: candidate_hash_a.clone(), - session: 1, - } - .signing_payload(); - - let payload_against = ExplicitDisputeStatement { - valid: false, - candidate_hash: candidate_hash_a.clone(), - session: 1, - } - .signing_payload(); - - let sig_a = v0.sign(&payload); - let sig_a_against = v1.sign(&payload_against); - - let statements = vec![ - ( - DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), - ValidatorIndex(0), - sig_a.clone(), - ), - ( - DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), - ValidatorIndex(1), - sig_a_against.clone(), - ), - ]; - - let mut sets = vec![ - DisputeStatementSet { - candidate_hash: candidate_hash_a.clone(), - session: 1, - statements: statements.clone(), - }, - DisputeStatementSet { - candidate_hash: candidate_hash_a.clone(), - session: 1, - statements: statements.clone(), - }, - ]; - - // `Err(())` indicates presence of duplicates - assert!( as DisputesHandler< - ::BlockNumber, - >>::deduplicate_and_sort_dispute_data(&mut sets) - .is_err()); - - assert_eq!( - sets, - vec![DisputeStatementSet { - candidate_hash: candidate_hash_a.clone(), - session: 1, - statements, - }] - ); - }) - } - - #[test] - fn assure_no_duplicate_statements_sets_are_fine() { - new_test_ext(Default::default()).execute_with(|| { - let v0 = ::Pair::generate().0; - let v1 = ::Pair::generate().0; - - run_to_block(3, |b| { - // a new session at each block - Some(( - true, - b, - vec![(&0, v0.public()), (&1, v1.public())], - Some(vec![(&0, v0.public()), (&1, v1.public())]), - )) - }); - - let candidate_hash_a = CandidateHash(sp_core::H256::repeat_byte(1)); - - let payload = ExplicitDisputeStatement { - valid: true, - candidate_hash: candidate_hash_a.clone(), - session: 1, - } - .signing_payload(); - - let payload_against = ExplicitDisputeStatement { - valid: false, - candidate_hash: candidate_hash_a.clone(), - session: 1, - } - .signing_payload(); - - let sig_a = v0.sign(&payload); - let sig_a_against = v1.sign(&payload_against); - - let statements = vec![ - ( - DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), - ValidatorIndex(0), - sig_a.clone(), - ), - ( - DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), - ValidatorIndex(1), - sig_a_against.clone(), - ), - ]; - - let sets = vec![ - DisputeStatementSet { - candidate_hash: candidate_hash_a.clone(), - session: 1, - statements: statements.clone(), - }, - DisputeStatementSet { - candidate_hash: candidate_hash_a.clone(), - session: 2, - statements: statements.clone(), - }, - ]; - - // `Err(())` indicates presence of duplicates - assert!( as DisputesHandler< - ::BlockNumber, - >>::assure_deduplicated_and_sorted(&sets) - .is_ok()); - }) - } - - #[test] - fn assure_detects_duplicate_statements_sets() { - new_test_ext(Default::default()).execute_with(|| { - let v0 = ::Pair::generate().0; - let v1 = ::Pair::generate().0; - - run_to_block(3, |b| { - // a new session at each block - Some(( - true, - b, - vec![(&0, v0.public()), (&1, v1.public())], - Some(vec![(&0, v0.public()), (&1, v1.public())]), - )) - }); - - let candidate_hash_a = CandidateHash(sp_core::H256::repeat_byte(1)); - - let payload = ExplicitDisputeStatement { - valid: true, - candidate_hash: candidate_hash_a.clone(), - session: 1, - } - .signing_payload(); - - let payload_against = ExplicitDisputeStatement { - valid: false, - candidate_hash: candidate_hash_a.clone(), - session: 1, - } - .signing_payload(); - - let sig_a = v0.sign(&payload); - let sig_a_against = v1.sign(&payload_against); - - let statements = vec![ - ( - DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), - ValidatorIndex(0), - sig_a.clone(), - ), - ( - DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), - ValidatorIndex(1), - sig_a_against.clone(), - ), - ]; - - let sets = vec![ - DisputeStatementSet { - candidate_hash: candidate_hash_a.clone(), - session: 1, - statements: statements.clone(), - }, - DisputeStatementSet { - candidate_hash: candidate_hash_a.clone(), - session: 1, - statements: statements.clone(), - }, - ]; - - // `Err(())` indicates presence of duplicates - assert!( as DisputesHandler< - ::BlockNumber, - >>::assure_deduplicated_and_sorted(&sets) - .is_err()); - }) - } - - #[test] - fn filter_ignores_single_sided() { - new_test_ext(Default::default()).execute_with(|| { - let v0 = ::Pair::generate().0; - - run_to_block(3, |b| { - // a new session at each block - Some((true, b, vec![(&0, v0.public())], Some(vec![(&0, v0.public())]))) - }); - - let candidate_hash_a = CandidateHash(sp_core::H256::repeat_byte(1)); - - let payload = ExplicitDisputeStatement { - valid: true, - candidate_hash: candidate_hash_a.clone(), - session: 1, - } - .signing_payload(); - - let sig_a = v0.sign(&payload); - - let statements = vec![DisputeStatementSet { - candidate_hash: candidate_hash_a.clone(), - session: 1, - statements: vec![( - DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), - ValidatorIndex(0), - sig_a.clone(), - )], - }]; - - let statements = apply_filter_all::(statements); - - assert!(statements.is_empty()); - }) - } - - #[test] - fn import_ignores_single_sided() { - new_test_ext(Default::default()).execute_with(|| { - let v0 = ::Pair::generate().0; - - run_to_block(3, |b| { - // a new session at each block - Some((true, b, vec![(&0, v0.public())], Some(vec![(&0, v0.public())]))) - }); - - let candidate_hash_a = CandidateHash(sp_core::H256::repeat_byte(1)); - - let payload = ExplicitDisputeStatement { - valid: true, - candidate_hash: candidate_hash_a.clone(), - session: 1, - } - .signing_payload(); - - let sig_a = v0.sign(&payload); - - let statements = vec![DisputeStatementSet { - candidate_hash: candidate_hash_a.clone(), - session: 1, - statements: vec![( - DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), - ValidatorIndex(0), - sig_a.clone(), - )], - }]; - - let statements = apply_filter_all::(statements); - assert!(statements.is_empty()); - }) - } -} diff --git a/runtime/parachains/src/disputes/tests.rs b/runtime/parachains/src/disputes/tests.rs new file mode 100644 index 000000000000..5a00cfa8f4bc --- /dev/null +++ b/runtime/parachains/src/disputes/tests.rs @@ -0,0 +1,2453 @@ +// 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 super::*; +use crate::{ + configuration::HostConfiguration, + disputes::DisputesHandler, + mock::{ + new_test_ext, AccountId, AllPalletsWithSystem, Initializer, MockGenesisConfig, System, + Test, PUNISH_VALIDATORS_AGAINST, PUNISH_VALIDATORS_FOR, PUNISH_VALIDATORS_INCONCLUSIVE, + REWARD_VALIDATORS, + }, +}; +use frame_support::{ + assert_err, assert_noop, assert_ok, + traits::{OnFinalize, OnInitialize}, +}; +use primitives::v1::BlockNumber; +use sp_core::{crypto::CryptoType, Pair}; + +/// Filtering updates the spam slots, as such update them. +fn update_spam_slots(stmts: MultiDisputeStatementSet) -> CheckedMultiDisputeStatementSet { + let config = >::config(); + let max_spam_slots = config.dispute_max_spam_slots; + let post_conclusion_acceptance_period = config.dispute_post_conclusion_acceptance_period; + + stmts + .into_iter() + .filter_map(|set| { + // updates spam slots implicitly + let filter = Pallet::::filter_dispute_data( + &set, + post_conclusion_acceptance_period, + max_spam_slots, + VerifyDisputeSignatures::Skip, + ); + filter.filter_statement_set(set) + }) + .collect::>() +} + +// All arguments for `initializer::on_new_session` +type NewSession<'a> = ( + bool, + SessionIndex, + Vec<(&'a AccountId, ValidatorId)>, + Option>, +); + +// Run to specific block, while calling disputes pallet hooks manually, because disputes is not +// integrated in initializer yet. +pub(crate) fn run_to_block<'a>( + to: BlockNumber, + new_session: impl Fn(BlockNumber) -> Option>, +) { + while System::block_number() < to { + let b = System::block_number(); + if b != 0 { + // circumvent requirement to have bitfields and headers in block for testing purposes + crate::paras_inherent::Included::::set(Some(())); + + AllPalletsWithSystem::on_finalize(b); + System::finalize(); + } + + System::reset_events(); + System::initialize(&(b + 1), &Default::default(), &Default::default()); + AllPalletsWithSystem::on_initialize(b + 1); + + if let Some(new_session) = new_session(b + 1) { + Initializer::test_trigger_on_new_session( + new_session.0, + new_session.1, + new_session.2.into_iter(), + new_session.3.map(|q| q.into_iter()), + ); + } + } +} + +#[test] +fn test_contains_duplicates_in_sorted_iter() { + // We here use the implicit ascending sorting and builtin equality of integers + let v = vec![1, 2, 3, 5, 5, 8]; + assert_eq!(true, contains_duplicates_in_sorted_iter(&v, |a, b| a == b)); + + let v = vec![1, 2, 3, 4]; + assert_eq!(false, contains_duplicates_in_sorted_iter(&v, |a, b| a == b)); +} + +#[test] +fn test_dispute_state_flag_from_state() { + assert_eq!( + DisputeStateFlags::from_state(&DisputeState { + validators_for: bitvec![BitOrderLsb0, u8; 0, 0, 0, 0, 0, 0, 0, 0], + validators_against: bitvec![BitOrderLsb0, u8; 0, 0, 0, 0, 0, 0, 0, 0], + start: 0, + concluded_at: None, + }), + DisputeStateFlags::default(), + ); + + assert_eq!( + DisputeStateFlags::from_state(&DisputeState { + validators_for: bitvec![BitOrderLsb0, u8; 1, 1, 1, 1, 1, 0, 0], + validators_against: bitvec![BitOrderLsb0, u8; 0, 0, 0, 0, 0, 0, 0], + start: 0, + concluded_at: None, + }), + DisputeStateFlags::FOR_SUPERMAJORITY | DisputeStateFlags::CONFIRMED, + ); + + assert_eq!( + DisputeStateFlags::from_state(&DisputeState { + validators_for: bitvec![BitOrderLsb0, u8; 0, 0, 0, 0, 0, 0, 0], + validators_against: bitvec![BitOrderLsb0, u8; 1, 1, 1, 1, 1, 0, 0], + start: 0, + concluded_at: None, + }), + DisputeStateFlags::AGAINST_SUPERMAJORITY | DisputeStateFlags::CONFIRMED, + ); +} + +#[test] +fn test_import_new_participant_spam_inc() { + let mut importer = DisputeStateImporter::new( + DisputeState { + validators_for: bitvec![BitOrderLsb0, u8; 1, 0, 0, 0, 0, 0, 0, 0], + validators_against: bitvec![BitOrderLsb0, u8; 0, 0, 0, 0, 0, 0, 0, 0], + start: 0, + concluded_at: None, + }, + 0, + ); + + assert_err!( + importer.import(ValidatorIndex(9), true), + VoteImportError::ValidatorIndexOutOfBounds, + ); + + assert_err!(importer.import(ValidatorIndex(0), true), VoteImportError::DuplicateStatement); + assert_ok!(importer.import(ValidatorIndex(0), false)); + + assert_ok!(importer.import(ValidatorIndex(2), true)); + assert_err!(importer.import(ValidatorIndex(2), true), VoteImportError::DuplicateStatement); + + assert_ok!(importer.import(ValidatorIndex(2), false)); + assert_err!(importer.import(ValidatorIndex(2), false), VoteImportError::DuplicateStatement); + + let summary = importer.finish(); + assert_eq!(summary.new_flags, DisputeStateFlags::default()); + assert_eq!( + summary.state, + DisputeState { + validators_for: bitvec![BitOrderLsb0, u8; 1, 0, 1, 0, 0, 0, 0, 0], + validators_against: bitvec![BitOrderLsb0, u8; 1, 0, 1, 0, 0, 0, 0, 0], + start: 0, + concluded_at: None, + }, + ); + assert_eq!(summary.spam_slot_changes, vec![(ValidatorIndex(2), SpamSlotChange::Inc)]); + assert!(summary.slash_for.is_empty()); + assert!(summary.slash_against.is_empty()); + assert_eq!(summary.new_participants, bitvec![BitOrderLsb0, u8; 0, 0, 1, 0, 0, 0, 0, 0]); +} + +#[test] +fn test_import_prev_participant_spam_dec_confirmed() { + let mut importer = DisputeStateImporter::new( + DisputeState { + validators_for: bitvec![BitOrderLsb0, u8; 1, 0, 0, 0, 0, 0, 0, 0], + validators_against: bitvec![BitOrderLsb0, u8; 0, 1, 0, 0, 0, 0, 0, 0], + start: 0, + concluded_at: None, + }, + 0, + ); + + assert_ok!(importer.import(ValidatorIndex(2), true)); + + let summary = importer.finish(); + assert_eq!( + summary.state, + DisputeState { + validators_for: bitvec![BitOrderLsb0, u8; 1, 0, 1, 0, 0, 0, 0, 0], + validators_against: bitvec![BitOrderLsb0, u8; 0, 1, 0, 0, 0, 0, 0, 0], + start: 0, + concluded_at: None, + }, + ); + assert_eq!( + summary.spam_slot_changes, + vec![(ValidatorIndex(0), SpamSlotChange::Dec), (ValidatorIndex(1), SpamSlotChange::Dec),], + ); + assert!(summary.slash_for.is_empty()); + assert!(summary.slash_against.is_empty()); + assert_eq!(summary.new_participants, bitvec![BitOrderLsb0, u8; 0, 0, 1, 0, 0, 0, 0, 0]); + assert_eq!(summary.new_flags, DisputeStateFlags::CONFIRMED); +} + +#[test] +fn test_import_prev_participant_spam_dec_confirmed_slash_for() { + let mut importer = DisputeStateImporter::new( + DisputeState { + validators_for: bitvec![BitOrderLsb0, u8; 1, 0, 0, 0, 0, 0, 0, 0], + validators_against: bitvec![BitOrderLsb0, u8; 0, 1, 0, 0, 0, 0, 0, 0], + start: 0, + concluded_at: None, + }, + 0, + ); + + assert_ok!(importer.import(ValidatorIndex(2), true)); + assert_ok!(importer.import(ValidatorIndex(2), false)); + assert_ok!(importer.import(ValidatorIndex(3), false)); + assert_ok!(importer.import(ValidatorIndex(4), false)); + assert_ok!(importer.import(ValidatorIndex(5), false)); + assert_ok!(importer.import(ValidatorIndex(6), false)); + + let summary = importer.finish(); + assert_eq!( + summary.state, + DisputeState { + validators_for: bitvec![BitOrderLsb0, u8; 1, 0, 1, 0, 0, 0, 0, 0], + validators_against: bitvec![BitOrderLsb0, u8; 0, 1, 1, 1, 1, 1, 1, 0], + start: 0, + concluded_at: Some(0), + }, + ); + assert_eq!( + summary.spam_slot_changes, + vec![(ValidatorIndex(0), SpamSlotChange::Dec), (ValidatorIndex(1), SpamSlotChange::Dec),], + ); + assert_eq!(summary.slash_for, vec![ValidatorIndex(0), ValidatorIndex(2)]); + assert!(summary.slash_against.is_empty()); + assert_eq!(summary.new_participants, bitvec![BitOrderLsb0, u8; 0, 0, 1, 1, 1, 1, 1, 0]); + assert_eq!( + summary.new_flags, + DisputeStateFlags::CONFIRMED | DisputeStateFlags::AGAINST_SUPERMAJORITY, + ); +} + +#[test] +fn test_import_slash_against() { + let mut importer = DisputeStateImporter::new( + DisputeState { + validators_for: bitvec![BitOrderLsb0, u8; 1, 0, 1, 0, 0, 0, 0, 0], + validators_against: bitvec![BitOrderLsb0, u8; 0, 1, 0, 0, 0, 0, 0, 0], + start: 0, + concluded_at: None, + }, + 0, + ); + + assert_ok!(importer.import(ValidatorIndex(3), true)); + assert_ok!(importer.import(ValidatorIndex(4), true)); + assert_ok!(importer.import(ValidatorIndex(5), false)); + assert_ok!(importer.import(ValidatorIndex(6), true)); + assert_ok!(importer.import(ValidatorIndex(7), true)); + + let summary = importer.finish(); + assert_eq!( + summary.state, + DisputeState { + validators_for: bitvec![BitOrderLsb0, u8; 1, 0, 1, 1, 1, 0, 1, 1], + validators_against: bitvec![BitOrderLsb0, u8; 0, 1, 0, 0, 0, 1, 0, 0], + start: 0, + concluded_at: Some(0), + }, + ); + assert!(summary.spam_slot_changes.is_empty()); + assert!(summary.slash_for.is_empty()); + assert_eq!(summary.slash_against, vec![ValidatorIndex(1), ValidatorIndex(5)]); + assert_eq!(summary.new_participants, bitvec![BitOrderLsb0, u8; 0, 0, 0, 1, 1, 1, 1, 1]); + assert_eq!(summary.new_flags, DisputeStateFlags::FOR_SUPERMAJORITY); +} + +// Test that punish_inconclusive is correctly called. +#[test] +fn test_initializer_initialize() { + let dispute_conclusion_by_time_out_period = 3; + let start = 10; + + let mock_genesis_config = MockGenesisConfig { + configuration: crate::configuration::GenesisConfig { + config: HostConfiguration { + dispute_conclusion_by_time_out_period, + ..Default::default() + }, + ..Default::default() + }, + ..Default::default() + }; + + new_test_ext(mock_genesis_config).execute_with(|| { + // We need 6 validators for the byzantine threshold to be 2 + let v0 = ::Pair::generate().0; + let v1 = ::Pair::generate().0; + let v2 = ::Pair::generate().0; + let v3 = ::Pair::generate().0; + let v4 = ::Pair::generate().0; + let v5 = ::Pair::generate().0; + let v6 = ::Pair::generate().0; + + run_to_block(start, |b| { + // a new session at each block + Some(( + true, + b, + vec![ + (&0, v0.public()), + (&1, v1.public()), + (&2, v2.public()), + (&3, v3.public()), + (&4, v4.public()), + (&5, v5.public()), + (&6, v6.public()), + ], + Some(vec![ + (&0, v0.public()), + (&1, v1.public()), + (&2, v2.public()), + (&3, v3.public()), + (&4, v4.public()), + (&5, v5.public()), + (&6, v6.public()), + ]), + )) + }); + + let candidate_hash = CandidateHash(sp_core::H256::repeat_byte(1)); + + // v0 votes for 3, v6 against. + let stmts = vec![DisputeStatementSet { + candidate_hash: candidate_hash.clone(), + session: start - 1, + statements: vec![ + ( + DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), + ValidatorIndex(0), + v0.sign( + &ExplicitDisputeStatement { + valid: true, + candidate_hash: candidate_hash.clone(), + session: start - 1, + } + .signing_payload(), + ), + ), + ( + DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), + ValidatorIndex(6), + v2.sign( + &ExplicitDisputeStatement { + valid: false, + candidate_hash: candidate_hash.clone(), + session: start - 1, + } + .signing_payload(), + ), + ), + ], + }]; + + let stmts = update_spam_slots(stmts); + assert_eq!(SpamSlots::::get(start - 1), Some(vec![1, 0, 0, 0, 0, 0, 1])); + + assert_ok!( + Pallet::::process_checked_multi_dispute_data(stmts), + vec![(9, candidate_hash.clone())], + ); + + // Run to timeout period + run_to_block(start + dispute_conclusion_by_time_out_period, |_| None); + assert_eq!(SpamSlots::::get(start - 1), Some(vec![1, 0, 0, 0, 0, 0, 1])); + + // Run to timeout + 1 in order to executive on_finalize(timeout) + run_to_block(start + dispute_conclusion_by_time_out_period + 1, |_| None); + assert_eq!(SpamSlots::::get(start - 1), Some(vec![0, 0, 0, 0, 0, 0, 0])); + assert_eq!( + PUNISH_VALIDATORS_INCONCLUSIVE.with(|r| r.borrow()[0].clone()), + (9, vec![ValidatorIndex(0), ValidatorIndex(6)]), + ); + }); +} + +// Test pruning works +#[test] +fn test_initializer_on_new_session() { + let dispute_period = 3; + + let mock_genesis_config = MockGenesisConfig { + configuration: crate::configuration::GenesisConfig { + config: HostConfiguration { dispute_period, ..Default::default() }, + ..Default::default() + }, + ..Default::default() + }; + + new_test_ext(mock_genesis_config).execute_with(|| { + let v0 = ::Pair::generate().0; + + let candidate_hash = CandidateHash(sp_core::H256::repeat_byte(1)); + Pallet::::note_included(0, candidate_hash.clone(), 0); + Pallet::::note_included(1, candidate_hash.clone(), 1); + Pallet::::note_included(2, candidate_hash.clone(), 2); + Pallet::::note_included(3, candidate_hash.clone(), 3); + Pallet::::note_included(4, candidate_hash.clone(), 4); + Pallet::::note_included(5, candidate_hash.clone(), 5); + Pallet::::note_included(6, candidate_hash.clone(), 5); + + run_to_block(7, |b| { + // a new session at each block + Some((true, b, vec![(&0, v0.public())], Some(vec![(&0, v0.public())]))) + }); + + // current session is 7, + // we keep for dispute_period + 1 session and we remove in on_finalize + // thus we keep info for session 3, 4, 5, 6, 7. + assert_eq!(Included::::iter_prefix(0).count(), 0); + assert_eq!(Included::::iter_prefix(1).count(), 0); + assert_eq!(Included::::iter_prefix(2).count(), 0); + assert_eq!(Included::::iter_prefix(3).count(), 1); + assert_eq!(Included::::iter_prefix(4).count(), 1); + assert_eq!(Included::::iter_prefix(5).count(), 1); + assert_eq!(Included::::iter_prefix(6).count(), 1); + }); +} + +#[test] +fn test_provide_data_duplicate_error() { + new_test_ext(Default::default()).execute_with(|| { + let candidate_hash_1 = CandidateHash(sp_core::H256::repeat_byte(1)); + let candidate_hash_2 = CandidateHash(sp_core::H256::repeat_byte(2)); + + let mut stmts = vec![ + DisputeStatementSet { + candidate_hash: candidate_hash_2, + session: 2, + statements: vec![], + }, + DisputeStatementSet { + candidate_hash: candidate_hash_1, + session: 1, + statements: vec![], + }, + DisputeStatementSet { + candidate_hash: candidate_hash_2, + session: 2, + statements: vec![], + }, + ]; + + assert!(Pallet::::deduplicate_and_sort_dispute_data(&mut stmts).is_err()); + assert_eq!(stmts.len(), 2); + }) +} + +#[test] +fn test_provide_multi_dispute_is_providing() { + new_test_ext(Default::default()).execute_with(|| { + let v0 = ::Pair::generate().0; + let v1 = ::Pair::generate().0; + + run_to_block(3, |b| { + // a new session at each block + if b == 1 { + Some(( + true, + b, + vec![(&0, v0.public()), (&1, v1.public())], + Some(vec![(&0, v0.public()), (&1, v1.public())]), + )) + } else { + Some((true, b, vec![(&1, v1.public())], Some(vec![(&1, v1.public())]))) + } + }); + + let candidate_hash = CandidateHash(sp_core::H256::repeat_byte(1)); + let stmts = vec![DisputeStatementSet { + candidate_hash: candidate_hash.clone(), + session: 1, + statements: vec![ + ( + DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), + ValidatorIndex(0), + v0.sign( + &ExplicitDisputeStatement { + valid: true, + candidate_hash: candidate_hash.clone(), + session: 1, + } + .signing_payload(), + ), + ), + ( + DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), + ValidatorIndex(1), + v1.sign( + &ExplicitDisputeStatement { + valid: false, + candidate_hash: candidate_hash.clone(), + session: 1, + } + .signing_payload(), + ), + ), + ], + }]; + + assert_ok!( + Pallet::::process_checked_multi_dispute_data( + stmts + .into_iter() + .map(CheckedDisputeStatementSet::unchecked_from_unchecked) + .collect() + ), + vec![(1, candidate_hash.clone())], + ); + }) +} + +#[test] +fn test_freeze_on_note_included() { + new_test_ext(Default::default()).execute_with(|| { + let v0 = ::Pair::generate().0; + let v1 = ::Pair::generate().0; + + run_to_block(6, |b| { + // a new session at each block + Some(( + true, + b, + vec![(&0, v0.public()), (&1, v1.public())], + Some(vec![(&0, v0.public()), (&1, v1.public())]), + )) + }); + + let candidate_hash = CandidateHash(sp_core::H256::repeat_byte(1)); + + // v0 votes for 3 + let stmts = vec![DisputeStatementSet { + candidate_hash: candidate_hash.clone(), + session: 3, + statements: vec![ + ( + DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), + ValidatorIndex(0), + v0.sign( + &ExplicitDisputeStatement { + valid: false, + candidate_hash: candidate_hash.clone(), + session: 3, + } + .signing_payload(), + ), + ), + ( + DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), + ValidatorIndex(1), + v1.sign( + &ExplicitDisputeStatement { + valid: false, + candidate_hash: candidate_hash.clone(), + session: 3, + } + .signing_payload(), + ), + ), + ( + DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), + ValidatorIndex(1), + v1.sign( + &ExplicitDisputeStatement { + valid: true, + candidate_hash: candidate_hash.clone(), + session: 3, + } + .signing_payload(), + ), + ), + ], + }]; + assert!(Pallet::::process_checked_multi_dispute_data( + stmts + .into_iter() + .map(CheckedDisputeStatementSet::unchecked_from_unchecked) + .collect() + ) + .is_ok()); + + Pallet::::note_included(3, candidate_hash.clone(), 3); + assert_eq!(Frozen::::get(), Some(2)); + }); +} + +#[test] +fn test_freeze_provided_against_supermajority_for_included() { + new_test_ext(Default::default()).execute_with(|| { + let v0 = ::Pair::generate().0; + let v1 = ::Pair::generate().0; + + run_to_block(6, |b| { + // a new session at each block + Some(( + true, + b, + vec![(&0, v0.public()), (&1, v1.public())], + Some(vec![(&0, v0.public()), (&1, v1.public())]), + )) + }); + + let candidate_hash = CandidateHash(sp_core::H256::repeat_byte(1)); + + // v0 votes for 3 + let stmts = vec![DisputeStatementSet { + candidate_hash: candidate_hash.clone(), + session: 3, + statements: vec![ + ( + DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), + ValidatorIndex(0), + v0.sign( + &ExplicitDisputeStatement { + valid: false, + candidate_hash: candidate_hash.clone(), + session: 3, + } + .signing_payload(), + ), + ), + ( + DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), + ValidatorIndex(1), + v1.sign( + &ExplicitDisputeStatement { + valid: false, + candidate_hash: candidate_hash.clone(), + session: 3, + } + .signing_payload(), + ), + ), + ( + DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), + ValidatorIndex(1), + v1.sign( + &ExplicitDisputeStatement { + valid: true, + candidate_hash: candidate_hash.clone(), + session: 3, + } + .signing_payload(), + ), + ), + ], + }]; + + Pallet::::note_included(3, candidate_hash.clone(), 3); + assert!(Pallet::::process_checked_multi_dispute_data( + stmts + .into_iter() + .map(CheckedDisputeStatementSet::unchecked_from_unchecked) + .collect() + ) + .is_ok()); + assert_eq!(Frozen::::get(), Some(2)); + }); +} + +// tests for: +// * provide_multi_dispute: with success scenario +// * disputes: correctness of datas +// * could_be_invalid: correctness of datas +// * note_included: decrement spam correctly +// * spam slots: correctly incremented and decremented +// * ensure rewards and punishment are correctly called. +#[test] +fn test_provide_multi_dispute_success_and_other() { + new_test_ext(Default::default()).execute_with(|| { + // 7 validators needed for byzantine threshold of 2. + let v0 = ::Pair::generate().0; + let v1 = ::Pair::generate().0; + let v2 = ::Pair::generate().0; + let v3 = ::Pair::generate().0; + let v4 = ::Pair::generate().0; + let v5 = ::Pair::generate().0; + let v6 = ::Pair::generate().0; + + // v0 -> 0 + // v1 -> 3 + // v2 -> 6 + // v3 -> 5 + // v4 -> 1 + // v5 -> 4 + // v6 -> 2 + + run_to_block(6, |b| { + // a new session at each block + Some(( + true, + b, + vec![ + (&0, v0.public()), + (&1, v1.public()), + (&2, v2.public()), + (&3, v3.public()), + (&4, v4.public()), + (&5, v5.public()), + (&6, v6.public()), + ], + Some(vec![ + (&0, v0.public()), + (&1, v1.public()), + (&2, v2.public()), + (&3, v3.public()), + (&4, v4.public()), + (&5, v5.public()), + (&6, v6.public()), + ]), + )) + }); + + let candidate_hash = CandidateHash(sp_core::H256::repeat_byte(1)); + + // v0 votes for 3, v6 votes against + let stmts = vec![DisputeStatementSet { + candidate_hash: candidate_hash.clone(), + session: 3, + statements: vec![ + ( + DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), + ValidatorIndex(0), + v0.sign( + &ExplicitDisputeStatement { + valid: true, + candidate_hash: candidate_hash.clone(), + session: 3, + } + .signing_payload(), + ), + ), + ( + DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), + ValidatorIndex(2), + v6.sign( + &ExplicitDisputeStatement { + valid: false, + candidate_hash: candidate_hash.clone(), + session: 3, + } + .signing_payload(), + ), + ), + ], + }]; + + let stmts = update_spam_slots(stmts); + assert_eq!(SpamSlots::::get(3), Some(vec![1, 0, 1, 0, 0, 0, 0])); + + assert_ok!( + Pallet::::process_checked_multi_dispute_data(stmts), + vec![(3, candidate_hash.clone())], + ); + + // v1 votes for 4 and for 3, v6 votes against 4. + let stmts = vec![ + DisputeStatementSet { + candidate_hash: candidate_hash.clone(), + session: 4, + statements: vec![ + ( + DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), + ValidatorIndex(3), + v1.sign( + &ExplicitDisputeStatement { + valid: true, + candidate_hash: candidate_hash.clone(), + session: 4, + } + .signing_payload(), + ), + ), + ( + DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), + ValidatorIndex(2), + v6.sign( + &ExplicitDisputeStatement { + valid: false, + candidate_hash: candidate_hash.clone(), + session: 4, + } + .signing_payload(), + ), + ), + ], + }, + DisputeStatementSet { + candidate_hash: candidate_hash.clone(), + session: 3, + statements: vec![( + DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), + ValidatorIndex(3), + v1.sign( + &ExplicitDisputeStatement { + valid: true, + candidate_hash: candidate_hash.clone(), + session: 3, + } + .signing_payload(), + ), + )], + }, + ]; + + let stmts = update_spam_slots(stmts); + + assert_ok!( + Pallet::::process_checked_multi_dispute_data(stmts), + vec![(4, candidate_hash.clone())], + ); + assert_eq!(SpamSlots::::get(3), Some(vec![0, 0, 0, 0, 0, 0, 0])); // Confirmed as no longer spam + assert_eq!(SpamSlots::::get(4), Some(vec![0, 0, 1, 1, 0, 0, 0])); + + // v3 votes against 3 and for 5, v6 votes against 5. + let stmts = vec![ + DisputeStatementSet { + candidate_hash: candidate_hash.clone(), + session: 3, + statements: vec![( + DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), + ValidatorIndex(5), + v3.sign( + &ExplicitDisputeStatement { + valid: false, + candidate_hash: candidate_hash.clone(), + session: 3, + } + .signing_payload(), + ), + )], + }, + DisputeStatementSet { + candidate_hash: candidate_hash.clone(), + session: 5, + statements: vec![ + ( + DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), + ValidatorIndex(5), + v3.sign( + &ExplicitDisputeStatement { + valid: true, + candidate_hash: candidate_hash.clone(), + session: 5, + } + .signing_payload(), + ), + ), + ( + DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), + ValidatorIndex(2), + v6.sign( + &ExplicitDisputeStatement { + valid: false, + candidate_hash: candidate_hash.clone(), + session: 5, + } + .signing_payload(), + ), + ), + ], + }, + ]; + + let stmts = update_spam_slots(stmts); + assert_ok!( + Pallet::::process_checked_multi_dispute_data(stmts), + vec![(5, candidate_hash.clone())], + ); + assert_eq!(SpamSlots::::get(3), Some(vec![0, 0, 0, 0, 0, 0, 0])); + assert_eq!(SpamSlots::::get(4), Some(vec![0, 0, 1, 1, 0, 0, 0])); + assert_eq!(SpamSlots::::get(5), Some(vec![0, 0, 1, 0, 0, 1, 0])); + + // v2 votes for 3 and against 5 + let stmts = vec![ + DisputeStatementSet { + candidate_hash: candidate_hash.clone(), + session: 3, + statements: vec![( + DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), + ValidatorIndex(6), + v2.sign( + &ExplicitDisputeStatement { + valid: true, + candidate_hash: candidate_hash.clone(), + session: 3, + } + .signing_payload(), + ), + )], + }, + DisputeStatementSet { + candidate_hash: candidate_hash.clone(), + session: 5, + statements: vec![( + DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), + ValidatorIndex(6), + v2.sign( + &ExplicitDisputeStatement { + valid: false, + candidate_hash: candidate_hash.clone(), + session: 5, + } + .signing_payload(), + ), + )], + }, + ]; + let stmts = update_spam_slots(stmts); + assert_ok!(Pallet::::process_checked_multi_dispute_data(stmts), vec![]); + assert_eq!(SpamSlots::::get(3), Some(vec![0, 0, 0, 0, 0, 0, 0])); + assert_eq!(SpamSlots::::get(4), Some(vec![0, 0, 1, 1, 0, 0, 0])); + assert_eq!(SpamSlots::::get(5), Some(vec![0, 0, 0, 0, 0, 0, 0])); + + let stmts = vec![ + // 0, 4, and 5 vote against 5 + DisputeStatementSet { + candidate_hash: candidate_hash.clone(), + session: 5, + statements: vec![ + ( + DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), + ValidatorIndex(0), + v0.sign( + &ExplicitDisputeStatement { + valid: false, + candidate_hash: candidate_hash.clone(), + session: 5, + } + .signing_payload(), + ), + ), + ( + DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), + ValidatorIndex(1), + v4.sign( + &ExplicitDisputeStatement { + valid: false, + candidate_hash: candidate_hash.clone(), + session: 5, + } + .signing_payload(), + ), + ), + ( + DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), + ValidatorIndex(4), + v5.sign( + &ExplicitDisputeStatement { + valid: false, + candidate_hash: candidate_hash.clone(), + session: 5, + } + .signing_payload(), + ), + ), + ], + }, + // 4 and 5 vote for 3 + DisputeStatementSet { + candidate_hash: candidate_hash.clone(), + session: 3, + statements: vec![ + ( + DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), + ValidatorIndex(1), + v4.sign( + &ExplicitDisputeStatement { + valid: true, + candidate_hash: candidate_hash.clone(), + session: 3, + } + .signing_payload(), + ), + ), + ( + DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), + ValidatorIndex(4), + v5.sign( + &ExplicitDisputeStatement { + valid: true, + candidate_hash: candidate_hash.clone(), + session: 3, + } + .signing_payload(), + ), + ), + ], + }, + ]; + let stmts = update_spam_slots(stmts); + assert_ok!(Pallet::::process_checked_multi_dispute_data(stmts), vec![]); + + assert_eq!( + Pallet::::disputes(), + vec![ + ( + 5, + candidate_hash.clone(), + DisputeState { + validators_for: bitvec![BitOrderLsb0, u8; 0, 0, 0, 0, 0, 1, 0], + validators_against: bitvec![BitOrderLsb0, u8; 1, 1, 1, 0, 1, 0, 1], + start: 6, + concluded_at: Some(6), // 5 vote against + } + ), + ( + 3, + candidate_hash.clone(), + DisputeState { + validators_for: bitvec![BitOrderLsb0, u8; 1, 1, 0, 1, 1, 0, 1], + validators_against: bitvec![BitOrderLsb0, u8; 0, 0, 1, 0, 0, 1, 0], + start: 6, + concluded_at: Some(6), // 5 vote for + } + ), + ( + 4, + candidate_hash.clone(), + DisputeState { + validators_for: bitvec![BitOrderLsb0, u8; 0, 0, 0, 1, 0, 0, 0], + validators_against: bitvec![BitOrderLsb0, u8; 0, 0, 1, 0, 0, 0, 0], + start: 6, + concluded_at: None, + } + ), + ] + ); + + assert!(!Pallet::::concluded_invalid(3, candidate_hash.clone())); + assert!(!Pallet::::concluded_invalid(4, candidate_hash.clone())); + assert!(Pallet::::concluded_invalid(5, candidate_hash.clone())); + + // Ensure inclusion removes spam slots + assert_eq!(SpamSlots::::get(4), Some(vec![0, 0, 1, 1, 0, 0, 0])); + Pallet::::note_included(4, candidate_hash.clone(), 4); + assert_eq!(SpamSlots::::get(4), Some(vec![0, 0, 0, 0, 0, 0, 0])); + + // Ensure the `reward_validator` function was correctly called + assert_eq!( + REWARD_VALIDATORS.with(|r| r.borrow().clone()), + vec![ + (3, vec![ValidatorIndex(0), ValidatorIndex(2)]), + (4, vec![ValidatorIndex(2), ValidatorIndex(3)]), + (3, vec![ValidatorIndex(3)]), + (3, vec![ValidatorIndex(5)]), + (5, vec![ValidatorIndex(2), ValidatorIndex(5)]), + (3, vec![ValidatorIndex(6)]), + (5, vec![ValidatorIndex(6)]), + (5, vec![ValidatorIndex(0), ValidatorIndex(1), ValidatorIndex(4)]), + (3, vec![ValidatorIndex(1), ValidatorIndex(4)]), + ], + ); + + // Ensure punishment against is called + assert_eq!( + PUNISH_VALIDATORS_AGAINST.with(|r| r.borrow().clone()), + vec![ + (3, vec![]), + (4, vec![]), + (3, vec![]), + (3, vec![]), + (5, vec![]), + (3, vec![]), + (5, vec![]), + (5, vec![]), + (3, vec![ValidatorIndex(2), ValidatorIndex(5)]), + ], + ); + + // Ensure punishment for is called + assert_eq!( + PUNISH_VALIDATORS_FOR.with(|r| r.borrow().clone()), + vec![ + (3, vec![]), + (4, vec![]), + (3, vec![]), + (3, vec![]), + (5, vec![]), + (3, vec![]), + (5, vec![]), + (5, vec![ValidatorIndex(5)]), + (3, vec![]), + ], + ); + }) +} + +#[test] +fn test_revert_and_freeze() { + new_test_ext(Default::default()).execute_with(|| { + // events are ignored for genesis block + System::set_block_number(1); + + Frozen::::put(Some(0)); + assert_noop!( + { + Pallet::::revert_and_freeze(0); + Result::<(), ()>::Err(()) // Just a small trick in order to use `assert_noop`. + }, + (), + ); + + Frozen::::kill(); + Pallet::::revert_and_freeze(0); + + assert_eq!(Frozen::::get(), Some(0)); + assert_eq!(System::digest().logs[0], ConsensusLog::Revert(1).into()); + System::assert_has_event(Event::Revert(1).into()); + }) +} + +#[test] +fn test_revert_and_freeze_merges() { + new_test_ext(Default::default()).execute_with(|| { + Frozen::::put(Some(10)); + assert_noop!( + { + Pallet::::revert_and_freeze(10); + Result::<(), ()>::Err(()) // Just a small trick in order to use `assert_noop`. + }, + (), + ); + + Pallet::::revert_and_freeze(8); + assert_eq!(Frozen::::get(), Some(8)); + }) +} + +#[test] +fn test_has_supermajority_against() { + assert_eq!( + has_supermajority_against(&DisputeState { + validators_for: bitvec![BitOrderLsb0, u8; 1, 1, 0, 0, 0, 0, 0, 0], + validators_against: bitvec![BitOrderLsb0, u8; 1, 1, 1, 1, 1, 0, 0, 0], + start: 0, + concluded_at: None, + }), + false, + ); + + assert_eq!( + has_supermajority_against(&DisputeState { + validators_for: bitvec![BitOrderLsb0, u8; 1, 1, 0, 0, 0, 0, 0, 0], + validators_against: bitvec![BitOrderLsb0, u8; 1, 1, 1, 1, 1, 1, 0, 0], + start: 0, + concluded_at: None, + }), + true, + ); +} + +#[test] +fn test_decrement_spam() { + let original_spam_slots = vec![0, 1, 2, 3, 4, 5, 6, 7]; + + // Test confirm is no-op + let mut spam_slots = original_spam_slots.clone(); + let dispute_state_confirm = DisputeState { + validators_for: bitvec![BitOrderLsb0, u8; 1, 1, 0, 0, 0, 0, 0, 0], + validators_against: bitvec![BitOrderLsb0, u8; 1, 0, 1, 0, 0, 0, 0, 0], + start: 0, + concluded_at: None, + }; + assert_eq!(DisputeStateFlags::from_state(&dispute_state_confirm), DisputeStateFlags::CONFIRMED); + assert_eq!( + decrement_spam(spam_slots.as_mut(), &dispute_state_confirm), + bitvec![BitOrderLsb0, u8; 1, 1, 1, 0, 0, 0, 0, 0], + ); + assert_eq!(spam_slots, original_spam_slots); + + // Test not confirm is decreasing spam + let mut spam_slots = original_spam_slots.clone(); + let dispute_state_no_confirm = DisputeState { + validators_for: bitvec![BitOrderLsb0, u8; 1, 0, 0, 0, 0, 0, 0, 0], + validators_against: bitvec![BitOrderLsb0, u8; 1, 0, 1, 0, 0, 0, 0, 0], + start: 0, + concluded_at: None, + }; + assert_eq!( + DisputeStateFlags::from_state(&dispute_state_no_confirm), + DisputeStateFlags::default() + ); + assert_eq!( + decrement_spam(spam_slots.as_mut(), &dispute_state_no_confirm), + bitvec![BitOrderLsb0, u8; 1, 0, 1, 0, 0, 0, 0, 0], + ); + assert_eq!(spam_slots, vec![0, 1, 1, 3, 4, 5, 6, 7]); +} + +#[test] +fn test_check_signature() { + let validator_id = ::Pair::generate().0; + let wrong_validator_id = ::Pair::generate().0; + + let session = 0; + let wrong_session = 1; + let candidate_hash = CandidateHash(sp_core::H256::repeat_byte(1)); + let wrong_candidate_hash = CandidateHash(sp_core::H256::repeat_byte(2)); + let inclusion_parent = sp_core::H256::repeat_byte(3); + let wrong_inclusion_parent = sp_core::H256::repeat_byte(4); + + let statement_1 = DisputeStatement::Valid(ValidDisputeStatementKind::Explicit); + let statement_2 = DisputeStatement::Valid(ValidDisputeStatementKind::BackingSeconded( + inclusion_parent.clone(), + )); + let wrong_statement_2 = DisputeStatement::Valid(ValidDisputeStatementKind::BackingSeconded( + wrong_inclusion_parent.clone(), + )); + let statement_3 = + DisputeStatement::Valid(ValidDisputeStatementKind::BackingValid(inclusion_parent.clone())); + let wrong_statement_3 = DisputeStatement::Valid(ValidDisputeStatementKind::BackingValid( + wrong_inclusion_parent.clone(), + )); + let statement_4 = DisputeStatement::Valid(ValidDisputeStatementKind::ApprovalChecking); + let statement_5 = DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit); + + let signed_1 = validator_id.sign( + &ExplicitDisputeStatement { valid: true, candidate_hash: candidate_hash.clone(), session } + .signing_payload(), + ); + let signed_2 = + validator_id.sign(&CompactStatement::Seconded(candidate_hash.clone()).signing_payload( + &SigningContext { session_index: session, parent_hash: inclusion_parent.clone() }, + )); + let signed_3 = + validator_id.sign(&CompactStatement::Valid(candidate_hash.clone()).signing_payload( + &SigningContext { session_index: session, parent_hash: inclusion_parent.clone() }, + )); + let signed_4 = + validator_id.sign(&ApprovalVote(candidate_hash.clone()).signing_payload(session)); + let signed_5 = validator_id.sign( + &ExplicitDisputeStatement { valid: false, candidate_hash: candidate_hash.clone(), session } + .signing_payload(), + ); + + assert!(check_signature( + &validator_id.public(), + candidate_hash, + session, + &statement_1, + &signed_1 + ) + .is_ok()); + assert!(check_signature( + &wrong_validator_id.public(), + candidate_hash, + session, + &statement_1, + &signed_1 + ) + .is_err()); + assert!(check_signature( + &validator_id.public(), + wrong_candidate_hash, + session, + &statement_1, + &signed_1 + ) + .is_err()); + assert!(check_signature( + &validator_id.public(), + candidate_hash, + wrong_session, + &statement_1, + &signed_1 + ) + .is_err()); + assert!(check_signature( + &validator_id.public(), + candidate_hash, + session, + &statement_2, + &signed_1 + ) + .is_err()); + assert!(check_signature( + &validator_id.public(), + candidate_hash, + session, + &statement_3, + &signed_1 + ) + .is_err()); + assert!(check_signature( + &validator_id.public(), + candidate_hash, + session, + &statement_4, + &signed_1 + ) + .is_err()); + assert!(check_signature( + &validator_id.public(), + candidate_hash, + session, + &statement_5, + &signed_1 + ) + .is_err()); + + assert!(check_signature( + &validator_id.public(), + candidate_hash, + session, + &statement_2, + &signed_2 + ) + .is_ok()); + assert!(check_signature( + &wrong_validator_id.public(), + candidate_hash, + session, + &statement_2, + &signed_2 + ) + .is_err()); + assert!(check_signature( + &validator_id.public(), + wrong_candidate_hash, + session, + &statement_2, + &signed_2 + ) + .is_err()); + assert!(check_signature( + &validator_id.public(), + candidate_hash, + wrong_session, + &statement_2, + &signed_2 + ) + .is_err()); + assert!(check_signature( + &validator_id.public(), + candidate_hash, + session, + &wrong_statement_2, + &signed_2 + ) + .is_err()); + assert!(check_signature( + &validator_id.public(), + candidate_hash, + session, + &statement_1, + &signed_2 + ) + .is_err()); + assert!(check_signature( + &validator_id.public(), + candidate_hash, + session, + &statement_3, + &signed_2 + ) + .is_err()); + assert!(check_signature( + &validator_id.public(), + candidate_hash, + session, + &statement_4, + &signed_2 + ) + .is_err()); + assert!(check_signature( + &validator_id.public(), + candidate_hash, + session, + &statement_5, + &signed_2 + ) + .is_err()); + + assert!(check_signature( + &validator_id.public(), + candidate_hash, + session, + &statement_3, + &signed_3 + ) + .is_ok()); + assert!(check_signature( + &wrong_validator_id.public(), + candidate_hash, + session, + &statement_3, + &signed_3 + ) + .is_err()); + assert!(check_signature( + &validator_id.public(), + wrong_candidate_hash, + session, + &statement_3, + &signed_3 + ) + .is_err()); + assert!(check_signature( + &validator_id.public(), + candidate_hash, + wrong_session, + &statement_3, + &signed_3 + ) + .is_err()); + assert!(check_signature( + &validator_id.public(), + candidate_hash, + session, + &wrong_statement_3, + &signed_3 + ) + .is_err()); + assert!(check_signature( + &validator_id.public(), + candidate_hash, + session, + &statement_1, + &signed_3 + ) + .is_err()); + assert!(check_signature( + &validator_id.public(), + candidate_hash, + session, + &statement_2, + &signed_3 + ) + .is_err()); + assert!(check_signature( + &validator_id.public(), + candidate_hash, + session, + &statement_4, + &signed_3 + ) + .is_err()); + assert!(check_signature( + &validator_id.public(), + candidate_hash, + session, + &statement_5, + &signed_3 + ) + .is_err()); + + assert!(check_signature( + &validator_id.public(), + candidate_hash, + session, + &statement_4, + &signed_4 + ) + .is_ok()); + assert!(check_signature( + &wrong_validator_id.public(), + candidate_hash, + session, + &statement_4, + &signed_4 + ) + .is_err()); + assert!(check_signature( + &validator_id.public(), + wrong_candidate_hash, + session, + &statement_4, + &signed_4 + ) + .is_err()); + assert!(check_signature( + &validator_id.public(), + candidate_hash, + wrong_session, + &statement_4, + &signed_4 + ) + .is_err()); + assert!(check_signature( + &validator_id.public(), + candidate_hash, + session, + &statement_1, + &signed_4 + ) + .is_err()); + assert!(check_signature( + &validator_id.public(), + candidate_hash, + session, + &statement_2, + &signed_4 + ) + .is_err()); + assert!(check_signature( + &validator_id.public(), + candidate_hash, + session, + &statement_3, + &signed_4 + ) + .is_err()); + assert!(check_signature( + &validator_id.public(), + candidate_hash, + session, + &statement_5, + &signed_4 + ) + .is_err()); + + assert!(check_signature( + &validator_id.public(), + candidate_hash, + session, + &statement_5, + &signed_5 + ) + .is_ok()); + assert!(check_signature( + &wrong_validator_id.public(), + candidate_hash, + session, + &statement_5, + &signed_5 + ) + .is_err()); + assert!(check_signature( + &validator_id.public(), + wrong_candidate_hash, + session, + &statement_5, + &signed_5 + ) + .is_err()); + assert!(check_signature( + &validator_id.public(), + candidate_hash, + wrong_session, + &statement_5, + &signed_5 + ) + .is_err()); + assert!(check_signature( + &validator_id.public(), + candidate_hash, + session, + &statement_1, + &signed_5 + ) + .is_err()); + assert!(check_signature( + &validator_id.public(), + candidate_hash, + session, + &statement_2, + &signed_5 + ) + .is_err()); + assert!(check_signature( + &validator_id.public(), + candidate_hash, + session, + &statement_3, + &signed_5 + ) + .is_err()); + assert!(check_signature( + &validator_id.public(), + candidate_hash, + session, + &statement_4, + &signed_5 + ) + .is_err()); +} + +#[test] +fn deduplication_and_sorting_works() { + new_test_ext(Default::default()).execute_with(|| { + let v0 = ::Pair::generate().0; + let v1 = ::Pair::generate().0; + let v2 = ::Pair::generate().0; + let v3 = ::Pair::generate().0; + + run_to_block(3, |b| { + // a new session at each block + Some(( + true, + b, + vec![(&0, v0.public()), (&1, v1.public()), (&2, v2.public()), (&3, v3.public())], + Some(vec![ + (&0, v0.public()), + (&1, v1.public()), + (&2, v2.public()), + (&3, v3.public()), + ]), + )) + }); + + let candidate_hash_a = CandidateHash(sp_core::H256::repeat_byte(1)); + let candidate_hash_b = CandidateHash(sp_core::H256::repeat_byte(2)); + let candidate_hash_c = CandidateHash(sp_core::H256::repeat_byte(3)); + + let create_explicit_statement = |vidx: ValidatorIndex, + validator: &::Pair, + c_hash: &CandidateHash, + valid, + session| { + let payload = + ExplicitDisputeStatement { valid, candidate_hash: c_hash.clone(), session } + .signing_payload(); + let sig = validator.sign(&payload); + (DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), vidx, sig.clone()) + }; + + let explicit_triple_a = + create_explicit_statement(ValidatorIndex(0), &v0, &candidate_hash_a, true, 1); + let explicit_triple_a_bad = + create_explicit_statement(ValidatorIndex(1), &v1, &candidate_hash_a, false, 1); + + let explicit_triple_b = + create_explicit_statement(ValidatorIndex(0), &v0, &candidate_hash_b, true, 2); + let explicit_triple_b_bad = + create_explicit_statement(ValidatorIndex(1), &v1, &candidate_hash_b, false, 2); + + let explicit_triple_c = + create_explicit_statement(ValidatorIndex(0), &v0, &candidate_hash_c, true, 2); + let explicit_triple_c_bad = + create_explicit_statement(ValidatorIndex(1), &v1, &candidate_hash_c, false, 2); + + let mut disputes = vec![ + DisputeStatementSet { + candidate_hash: candidate_hash_b.clone(), + session: 2, + statements: vec![explicit_triple_b.clone(), explicit_triple_b_bad.clone()], + }, + // same session as above + DisputeStatementSet { + candidate_hash: candidate_hash_c.clone(), + session: 2, + statements: vec![explicit_triple_c, explicit_triple_c_bad], + }, + // the duplicate set + DisputeStatementSet { + candidate_hash: candidate_hash_b.clone(), + session: 2, + statements: vec![explicit_triple_b.clone(), explicit_triple_b_bad.clone()], + }, + DisputeStatementSet { + candidate_hash: candidate_hash_a.clone(), + session: 1, + statements: vec![explicit_triple_a, explicit_triple_a_bad], + }, + ]; + + let disputes_orig = disputes.clone(); + + as DisputesHandler< + ::BlockNumber, + >>::deduplicate_and_sort_dispute_data(&mut disputes).unwrap_err(); + + // assert ordering of local only disputes, and at the same time, and being free of duplicates + assert_eq!(disputes_orig.len(), disputes.len() + 1); + + let are_these_equal = |a: &DisputeStatementSet, b: &DisputeStatementSet| { + use core::cmp::Ordering; + // we only have local disputes here, so sorting of those adheres to the + // simplified sorting logic + let cmp = + a.session.cmp(&b.session).then_with(|| a.candidate_hash.cmp(&b.candidate_hash)); + assert_ne!(cmp, Ordering::Greater); + cmp == Ordering::Equal + }; + + assert_eq!(false, contains_duplicates_in_sorted_iter(&disputes, are_these_equal)); + }) +} + +fn apply_filter_all>( + sets: I, +) -> Vec { + let config = >::config(); + let max_spam_slots = config.dispute_max_spam_slots; + let post_conclusion_acceptance_period = config.dispute_post_conclusion_acceptance_period; + + let mut acc = Vec::::new(); + for dispute_statement in sets { + if let Some(checked) = as DisputesHandler<::BlockNumber>>::filter_dispute_data( + dispute_statement, + max_spam_slots, + post_conclusion_acceptance_period, + VerifyDisputeSignatures::Yes, + ) { + acc.push(checked); + } + } + acc +} + +#[test] +fn filter_removes_duplicates_within_set() { + new_test_ext(Default::default()).execute_with(|| { + let v0 = ::Pair::generate().0; + let v1 = ::Pair::generate().0; + + run_to_block(3, |b| { + // a new session at each block + Some(( + true, + b, + vec![(&0, v0.public()), (&1, v1.public())], + Some(vec![(&0, v0.public()), (&1, v1.public())]), + )) + }); + + let candidate_hash = CandidateHash(sp_core::H256::repeat_byte(1)); + + let payload = ExplicitDisputeStatement { + valid: true, + candidate_hash: candidate_hash.clone(), + session: 1, + } + .signing_payload(); + + let payload_against = ExplicitDisputeStatement { + valid: false, + candidate_hash: candidate_hash.clone(), + session: 1, + } + .signing_payload(); + + let sig_a = v0.sign(&payload); + let sig_b = v0.sign(&payload); + let sig_c = v0.sign(&payload); + let sig_d = v1.sign(&payload_against); + + let statements = DisputeStatementSet { + candidate_hash: candidate_hash.clone(), + session: 1, + statements: vec![ + ( + DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), + ValidatorIndex(0), + sig_a.clone(), + ), + ( + DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), + ValidatorIndex(0), + sig_b, + ), + ( + DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), + ValidatorIndex(0), + sig_c, + ), + ( + DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), + ValidatorIndex(1), + sig_d.clone(), + ), + ], + }; + + let max_spam_slots = 10; + let post_conclusion_acceptance_period = 10; + let statements = as DisputesHandler< + ::BlockNumber, + >>::filter_dispute_data( + statements, + max_spam_slots, + post_conclusion_acceptance_period, + VerifyDisputeSignatures::Yes, + ); + + assert_eq!( + statements, + Some(CheckedDisputeStatementSet::unchecked_from_unchecked(DisputeStatementSet { + candidate_hash: candidate_hash.clone(), + session: 1, + statements: vec![ + ( + DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), + ValidatorIndex(0), + sig_a, + ), + ( + DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), + ValidatorIndex(1), + sig_d, + ), + ] + })) + ); + }) +} + +#[test] +fn filter_bad_signatures_correctly_detects_single_sided() { + new_test_ext(Default::default()).execute_with(|| { + let v0 = ::Pair::generate().0; + let v1 = ::Pair::generate().0; + let v2 = ::Pair::generate().0; + let v3 = ::Pair::generate().0; + + run_to_block(3, |b| { + // a new session at each block + Some(( + true, + b, + vec![(&0, v0.public()), (&1, v1.public()), (&2, v2.public()), (&3, v3.public())], + Some(vec![ + (&0, v0.public()), + (&1, v1.public()), + (&2, v2.public()), + (&3, v3.public()), + ]), + )) + }); + + let candidate_hash_a = CandidateHash(sp_core::H256::repeat_byte(1)); + + let payload = |c_hash: &CandidateHash, valid| { + ExplicitDisputeStatement { valid, candidate_hash: c_hash.clone(), session: 1 } + .signing_payload() + }; + + let payload_a = payload(&candidate_hash_a, true); + let payload_a_bad = payload(&candidate_hash_a, false); + + let sig_0 = v0.sign(&payload_a); + let sig_1 = v1.sign(&payload_a_bad); + + let statements = vec![DisputeStatementSet { + candidate_hash: candidate_hash_a.clone(), + session: 1, + statements: vec![ + ( + DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), + ValidatorIndex(0), + sig_0.clone(), + ), + ( + DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), + ValidatorIndex(2), + sig_1.clone(), + ), + ], + }]; + + let statements = apply_filter_all::(statements); + + assert!(statements.is_empty()); + }) +} + +#[test] +fn filter_correctly_accounts_spam_slots() { + let dispute_max_spam_slots = 2; + + let mock_genesis_config = MockGenesisConfig { + configuration: crate::configuration::GenesisConfig { + config: HostConfiguration { dispute_max_spam_slots, ..Default::default() }, + ..Default::default() + }, + ..Default::default() + }; + + new_test_ext(mock_genesis_config).execute_with(|| { + // We need 7 validators for the byzantine threshold to be 2 + let v0 = ::Pair::generate().0; + let v1 = ::Pair::generate().0; + let v2 = ::Pair::generate().0; + let v3 = ::Pair::generate().0; + let v4 = ::Pair::generate().0; + let v5 = ::Pair::generate().0; + let v6 = ::Pair::generate().0; + + run_to_block(3, |b| { + // a new session at each block + Some(( + true, + b, + vec![ + (&0, v0.public()), + (&1, v1.public()), + (&2, v2.public()), + (&3, v3.public()), + (&4, v4.public()), + (&5, v5.public()), + (&6, v6.public()), + ], + Some(vec![ + (&0, v0.public()), + (&1, v1.public()), + (&2, v2.public()), + (&3, v3.public()), + (&4, v4.public()), + (&5, v5.public()), + (&6, v6.public()), + ]), + )) + }); + + let candidate_hash_a = CandidateHash(sp_core::H256::repeat_byte(1)); + let candidate_hash_b = CandidateHash(sp_core::H256::repeat_byte(2)); + let candidate_hash_c = CandidateHash(sp_core::H256::repeat_byte(3)); + + let payload = |c_hash: &CandidateHash, valid| { + ExplicitDisputeStatement { valid, candidate_hash: c_hash.clone(), session: 1 } + .signing_payload() + }; + + let payload_a = payload(&candidate_hash_a, true); + let payload_b = payload(&candidate_hash_b, true); + let payload_c = payload(&candidate_hash_c, true); + + let payload_a_bad = payload(&candidate_hash_a, false); + let payload_b_bad = payload(&candidate_hash_b, false); + let payload_c_bad = payload(&candidate_hash_c, false); + + let sig_0a = v0.sign(&payload_a); + let sig_0b = v0.sign(&payload_b); + let sig_0c = v0.sign(&payload_c); + + let sig_1b = v1.sign(&payload_b); + + let sig_2a = v2.sign(&payload_a_bad); + let sig_2b = v2.sign(&payload_b_bad); + let sig_2c = v2.sign(&payload_c_bad); + + let statements = vec![ + // validators 0 and 2 get 1 spam slot from this. + DisputeStatementSet { + candidate_hash: candidate_hash_a.clone(), + session: 1, + statements: vec![ + ( + DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), + ValidatorIndex(0), + sig_0a.clone(), + ), + ( + DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), + ValidatorIndex(6), + sig_2a.clone(), + ), + ], + }, + // Validators 0, 2, and 3 get no spam slots for this + DisputeStatementSet { + candidate_hash: candidate_hash_b.clone(), + session: 1, + statements: vec![ + ( + DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), + ValidatorIndex(0), + sig_0b.clone(), + ), + ( + DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), + ValidatorIndex(3), + sig_1b.clone(), + ), + ( + DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), + ValidatorIndex(6), + sig_2b.clone(), + ), + ], + }, + // Validators 0 and 2 get an extra spam slot for this. + DisputeStatementSet { + candidate_hash: candidate_hash_c.clone(), + session: 1, + statements: vec![ + ( + DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), + ValidatorIndex(0), + sig_0c.clone(), + ), + ( + DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), + ValidatorIndex(6), + sig_2c.clone(), + ), + ], + }, + ]; + + let old_statements = statements + .clone() + .into_iter() + .map(CheckedDisputeStatementSet::unchecked_from_unchecked) + .collect::>(); + let statements = apply_filter_all::(statements); + + assert_eq!(statements, old_statements); + }) +} + +#[test] +fn filter_removes_session_out_of_bounds() { + new_test_ext(Default::default()).execute_with(|| { + let v0 = ::Pair::generate().0; + + run_to_block(3, |b| { + // a new session at each block + Some((true, b, vec![(&0, v0.public())], Some(vec![(&0, v0.public())]))) + }); + + let candidate_hash = CandidateHash(sp_core::H256::repeat_byte(1)); + + let payload = ExplicitDisputeStatement { + valid: true, + candidate_hash: candidate_hash.clone(), + session: 1, + } + .signing_payload(); + + let sig_a = v0.sign(&payload); + + let statements = vec![DisputeStatementSet { + candidate_hash: candidate_hash.clone(), + session: 100, + statements: vec![( + DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), + ValidatorIndex(0), + sig_a, + )], + }]; + + let statements = apply_filter_all::(statements); + + assert!(statements.is_empty()); + }) +} + +#[test] +fn filter_removes_concluded_ancient() { + let dispute_post_conclusion_acceptance_period = 2; + + let mock_genesis_config = MockGenesisConfig { + configuration: crate::configuration::GenesisConfig { + config: HostConfiguration { + dispute_post_conclusion_acceptance_period, + ..Default::default() + }, + ..Default::default() + }, + ..Default::default() + }; + + new_test_ext(mock_genesis_config).execute_with(|| { + let v0 = ::Pair::generate().0; + + run_to_block(3, |b| { + // a new session at each block + Some((true, b, vec![(&0, v0.public())], Some(vec![(&0, v0.public())]))) + }); + + let candidate_hash_a = CandidateHash(sp_core::H256::repeat_byte(1)); + let candidate_hash_b = CandidateHash(sp_core::H256::repeat_byte(2)); + + >::insert( + &1, + &candidate_hash_a, + DisputeState { + validators_for: bitvec![BitOrderLsb0, u8; 0; 4], + validators_against: bitvec![BitOrderLsb0, u8; 1; 4], + start: 0, + concluded_at: Some(0), + }, + ); + + >::insert( + &1, + &candidate_hash_b, + DisputeState { + validators_for: bitvec![BitOrderLsb0, u8; 0; 4], + validators_against: bitvec![BitOrderLsb0, u8; 1; 4], + start: 0, + concluded_at: Some(1), + }, + ); + + let payload_a = ExplicitDisputeStatement { + valid: true, + candidate_hash: candidate_hash_a.clone(), + session: 1, + } + .signing_payload(); + + let payload_b = ExplicitDisputeStatement { + valid: true, + candidate_hash: candidate_hash_b.clone(), + session: 1, + } + .signing_payload(); + + let sig_a = v0.sign(&payload_a); + let sig_b = v0.sign(&payload_b); + + let statements = vec![ + DisputeStatementSet { + candidate_hash: candidate_hash_a.clone(), + session: 1, + statements: vec![( + DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), + ValidatorIndex(0), + sig_a, + )], + }, + DisputeStatementSet { + candidate_hash: candidate_hash_b.clone(), + session: 1, + statements: vec![( + DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), + ValidatorIndex(0), + sig_b.clone(), + )], + }, + ]; + + let statements = apply_filter_all::(statements); + + assert_eq!( + statements, + vec![CheckedDisputeStatementSet::unchecked_from_unchecked(DisputeStatementSet { + candidate_hash: candidate_hash_b.clone(), + session: 1, + statements: vec![( + DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), + ValidatorIndex(0), + sig_b, + ),] + })] + ); + }) +} + +#[test] +fn filter_removes_duplicate_statements_sets() { + new_test_ext(Default::default()).execute_with(|| { + let v0 = ::Pair::generate().0; + let v1 = ::Pair::generate().0; + + run_to_block(3, |b| { + // a new session at each block + Some(( + true, + b, + vec![(&0, v0.public()), (&1, v1.public())], + Some(vec![(&0, v0.public()), (&1, v1.public())]), + )) + }); + + let candidate_hash_a = CandidateHash(sp_core::H256::repeat_byte(1)); + + let payload = ExplicitDisputeStatement { + valid: true, + candidate_hash: candidate_hash_a.clone(), + session: 1, + } + .signing_payload(); + + let payload_against = ExplicitDisputeStatement { + valid: false, + candidate_hash: candidate_hash_a.clone(), + session: 1, + } + .signing_payload(); + + let sig_a = v0.sign(&payload); + let sig_a_against = v1.sign(&payload_against); + + let statements = vec![ + ( + DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), + ValidatorIndex(0), + sig_a.clone(), + ), + ( + DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), + ValidatorIndex(1), + sig_a_against.clone(), + ), + ]; + + let mut sets = vec![ + DisputeStatementSet { + candidate_hash: candidate_hash_a.clone(), + session: 1, + statements: statements.clone(), + }, + DisputeStatementSet { + candidate_hash: candidate_hash_a.clone(), + session: 1, + statements: statements.clone(), + }, + ]; + + // `Err(())` indicates presence of duplicates + assert!( as DisputesHandler< + ::BlockNumber, + >>::deduplicate_and_sort_dispute_data(&mut sets) + .is_err()); + + assert_eq!( + sets, + vec![DisputeStatementSet { + candidate_hash: candidate_hash_a.clone(), + session: 1, + statements, + }] + ); + }) +} + +#[test] +fn assure_no_duplicate_statements_sets_are_fine() { + new_test_ext(Default::default()).execute_with(|| { + let v0 = ::Pair::generate().0; + let v1 = ::Pair::generate().0; + + run_to_block(3, |b| { + // a new session at each block + Some(( + true, + b, + vec![(&0, v0.public()), (&1, v1.public())], + Some(vec![(&0, v0.public()), (&1, v1.public())]), + )) + }); + + let candidate_hash_a = CandidateHash(sp_core::H256::repeat_byte(1)); + + let payload = ExplicitDisputeStatement { + valid: true, + candidate_hash: candidate_hash_a.clone(), + session: 1, + } + .signing_payload(); + + let payload_against = ExplicitDisputeStatement { + valid: false, + candidate_hash: candidate_hash_a.clone(), + session: 1, + } + .signing_payload(); + + let sig_a = v0.sign(&payload); + let sig_a_against = v1.sign(&payload_against); + + let statements = vec![ + ( + DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), + ValidatorIndex(0), + sig_a.clone(), + ), + ( + DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), + ValidatorIndex(1), + sig_a_against.clone(), + ), + ]; + + let sets = vec![ + DisputeStatementSet { + candidate_hash: candidate_hash_a.clone(), + session: 1, + statements: statements.clone(), + }, + DisputeStatementSet { + candidate_hash: candidate_hash_a.clone(), + session: 2, + statements: statements.clone(), + }, + ]; + + // `Err(())` indicates presence of duplicates + assert!( as DisputesHandler< + ::BlockNumber, + >>::assure_deduplicated_and_sorted(&sets) + .is_ok()); + }) +} + +#[test] +fn assure_detects_duplicate_statements_sets() { + new_test_ext(Default::default()).execute_with(|| { + let v0 = ::Pair::generate().0; + let v1 = ::Pair::generate().0; + + run_to_block(3, |b| { + // a new session at each block + Some(( + true, + b, + vec![(&0, v0.public()), (&1, v1.public())], + Some(vec![(&0, v0.public()), (&1, v1.public())]), + )) + }); + + let candidate_hash_a = CandidateHash(sp_core::H256::repeat_byte(1)); + + let payload = ExplicitDisputeStatement { + valid: true, + candidate_hash: candidate_hash_a.clone(), + session: 1, + } + .signing_payload(); + + let payload_against = ExplicitDisputeStatement { + valid: false, + candidate_hash: candidate_hash_a.clone(), + session: 1, + } + .signing_payload(); + + let sig_a = v0.sign(&payload); + let sig_a_against = v1.sign(&payload_against); + + let statements = vec![ + ( + DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), + ValidatorIndex(0), + sig_a.clone(), + ), + ( + DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit), + ValidatorIndex(1), + sig_a_against.clone(), + ), + ]; + + let sets = vec![ + DisputeStatementSet { + candidate_hash: candidate_hash_a.clone(), + session: 1, + statements: statements.clone(), + }, + DisputeStatementSet { + candidate_hash: candidate_hash_a.clone(), + session: 1, + statements: statements.clone(), + }, + ]; + + // `Err(())` indicates presence of duplicates + assert!( as DisputesHandler< + ::BlockNumber, + >>::assure_deduplicated_and_sorted(&sets) + .is_err()); + }) +} + +#[test] +fn filter_ignores_single_sided() { + new_test_ext(Default::default()).execute_with(|| { + let v0 = ::Pair::generate().0; + + run_to_block(3, |b| { + // a new session at each block + Some((true, b, vec![(&0, v0.public())], Some(vec![(&0, v0.public())]))) + }); + + let candidate_hash_a = CandidateHash(sp_core::H256::repeat_byte(1)); + + let payload = ExplicitDisputeStatement { + valid: true, + candidate_hash: candidate_hash_a.clone(), + session: 1, + } + .signing_payload(); + + let sig_a = v0.sign(&payload); + + let statements = vec![DisputeStatementSet { + candidate_hash: candidate_hash_a.clone(), + session: 1, + statements: vec![( + DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), + ValidatorIndex(0), + sig_a.clone(), + )], + }]; + + let statements = apply_filter_all::(statements); + + assert!(statements.is_empty()); + }) +} + +#[test] +fn import_ignores_single_sided() { + new_test_ext(Default::default()).execute_with(|| { + let v0 = ::Pair::generate().0; + + run_to_block(3, |b| { + // a new session at each block + Some((true, b, vec![(&0, v0.public())], Some(vec![(&0, v0.public())]))) + }); + + let candidate_hash_a = CandidateHash(sp_core::H256::repeat_byte(1)); + + let payload = ExplicitDisputeStatement { + valid: true, + candidate_hash: candidate_hash_a.clone(), + session: 1, + } + .signing_payload(); + + let sig_a = v0.sign(&payload); + + let statements = vec![DisputeStatementSet { + candidate_hash: candidate_hash_a.clone(), + session: 1, + statements: vec![( + DisputeStatement::Valid(ValidDisputeStatementKind::Explicit), + ValidatorIndex(0), + sig_a.clone(), + )], + }]; + + let statements = apply_filter_all::(statements); + assert!(statements.is_empty()); + }) +} diff --git a/runtime/parachains/src/dmp.rs b/runtime/parachains/src/dmp.rs index c55a07b9f9ec..4a11796af0ce 100644 --- a/runtime/parachains/src/dmp.rs +++ b/runtime/parachains/src/dmp.rs @@ -26,6 +26,9 @@ use xcm::latest::SendError; pub use pallet::*; +#[cfg(test)] +mod tests; + /// An error sending a downward message. #[cfg_attr(test, derive(Debug))] pub enum QueueDownwardMessageError { @@ -227,197 +230,3 @@ impl Pallet { ::DownwardMessageQueues::get(&recipient) } } - -#[cfg(test)] -mod tests { - use super::*; - use crate::mock::{new_test_ext, Configuration, Dmp, MockGenesisConfig, Paras, System}; - use hex_literal::hex; - use parity_scale_codec::Encode; - use primitives::v1::BlockNumber; - - pub(crate) fn run_to_block(to: BlockNumber, new_session: Option>) { - while System::block_number() < to { - let b = System::block_number(); - Paras::initializer_finalize(b); - Dmp::initializer_finalize(); - if new_session.as_ref().map_or(false, |v| v.contains(&(b + 1))) { - Dmp::initializer_on_new_session(&Default::default(), &Vec::new()); - } - System::on_finalize(b); - - System::on_initialize(b + 1); - System::set_block_number(b + 1); - - Paras::initializer_finalize(b + 1); - Dmp::initializer_initialize(b + 1); - } - } - - fn default_genesis_config() -> MockGenesisConfig { - MockGenesisConfig { - configuration: crate::configuration::GenesisConfig { - config: crate::configuration::HostConfiguration { - max_downward_message_size: 1024, - ..Default::default() - }, - }, - ..Default::default() - } - } - - fn queue_downward_message( - para_id: ParaId, - msg: DownwardMessage, - ) -> Result<(), QueueDownwardMessageError> { - Dmp::queue_downward_message(&Configuration::config(), para_id, msg) - } - - #[test] - fn clean_dmp_works() { - let a = ParaId::from(1312); - let b = ParaId::from(228); - let c = ParaId::from(123); - - new_test_ext(default_genesis_config()).execute_with(|| { - // enqueue downward messages to A, B and C. - queue_downward_message(a, vec![1, 2, 3]).unwrap(); - queue_downward_message(b, vec![4, 5, 6]).unwrap(); - queue_downward_message(c, vec![7, 8, 9]).unwrap(); - - let notification = crate::initializer::SessionChangeNotification::default(); - let outgoing_paras = vec![a, b]; - Dmp::initializer_on_new_session(¬ification, &outgoing_paras); - - assert!(::DownwardMessageQueues::get(&a).is_empty()); - assert!(::DownwardMessageQueues::get(&b).is_empty()); - assert!(!::DownwardMessageQueues::get(&c).is_empty()); - }); - } - - #[test] - fn dmq_length_and_head_updated_properly() { - let a = ParaId::from(1312); - let b = ParaId::from(228); - - new_test_ext(default_genesis_config()).execute_with(|| { - assert_eq!(Dmp::dmq_length(a), 0); - assert_eq!(Dmp::dmq_length(b), 0); - - queue_downward_message(a, vec![1, 2, 3]).unwrap(); - - assert_eq!(Dmp::dmq_length(a), 1); - assert_eq!(Dmp::dmq_length(b), 0); - assert!(!Dmp::dmq_mqc_head(a).is_zero()); - assert!(Dmp::dmq_mqc_head(b).is_zero()); - }); - } - - #[test] - fn dmp_mqc_head_fixture() { - let a = ParaId::from(2000); - - new_test_ext(default_genesis_config()).execute_with(|| { - run_to_block(2, None); - assert!(Dmp::dmq_mqc_head(a).is_zero()); - queue_downward_message(a, vec![1, 2, 3]).unwrap(); - - run_to_block(3, None); - queue_downward_message(a, vec![4, 5, 6]).unwrap(); - - assert_eq!( - Dmp::dmq_mqc_head(a), - hex!["88dc00db8cc9d22aa62b87807705831f164387dfa49f80a8600ed1cbe1704b6b"].into(), - ); - }); - } - - #[test] - fn check_processed_downward_messages() { - let a = ParaId::from(1312); - - new_test_ext(default_genesis_config()).execute_with(|| { - // processed_downward_messages=0 is allowed when the DMQ is empty. - assert!(Dmp::check_processed_downward_messages(a, 0).is_ok()); - - queue_downward_message(a, vec![1, 2, 3]).unwrap(); - queue_downward_message(a, vec![4, 5, 6]).unwrap(); - queue_downward_message(a, vec![7, 8, 9]).unwrap(); - - // 0 doesn't pass if the DMQ has msgs. - assert!(!Dmp::check_processed_downward_messages(a, 0).is_ok()); - // a candidate can consume up to 3 messages - assert!(Dmp::check_processed_downward_messages(a, 1).is_ok()); - assert!(Dmp::check_processed_downward_messages(a, 2).is_ok()); - assert!(Dmp::check_processed_downward_messages(a, 3).is_ok()); - // there is no 4 messages in the queue - assert!(!Dmp::check_processed_downward_messages(a, 4).is_ok()); - }); - } - - #[test] - fn dmq_pruning() { - let a = ParaId::from(1312); - - new_test_ext(default_genesis_config()).execute_with(|| { - assert_eq!(Dmp::dmq_length(a), 0); - - queue_downward_message(a, vec![1, 2, 3]).unwrap(); - queue_downward_message(a, vec![4, 5, 6]).unwrap(); - queue_downward_message(a, vec![7, 8, 9]).unwrap(); - assert_eq!(Dmp::dmq_length(a), 3); - - // pruning 0 elements shouldn't change anything. - Dmp::prune_dmq(a, 0); - assert_eq!(Dmp::dmq_length(a), 3); - - Dmp::prune_dmq(a, 2); - assert_eq!(Dmp::dmq_length(a), 1); - }); - } - - #[test] - fn queue_downward_message_critical() { - let a = ParaId::from(1312); - - let mut genesis = default_genesis_config(); - genesis.configuration.config.max_downward_message_size = 7; - - new_test_ext(genesis).execute_with(|| { - let smol = [0; 3].to_vec(); - let big = [0; 8].to_vec(); - - // still within limits - assert_eq!(smol.encode().len(), 4); - assert!(queue_downward_message(a, smol).is_ok()); - - // that's too big - assert_eq!(big.encode().len(), 9); - assert!(queue_downward_message(a, big).is_err()); - }); - } - - #[test] - fn verify_dmq_mqc_head_is_externally_accessible() { - use hex_literal::hex; - use primitives::v1::well_known_keys; - - let a = ParaId::from(2020); - - new_test_ext(default_genesis_config()).execute_with(|| { - let head = sp_io::storage::get(&well_known_keys::dmq_mqc_head(a)); - assert_eq!(head, None); - - queue_downward_message(a, vec![1, 2, 3]).unwrap(); - - let head = sp_io::storage::get(&well_known_keys::dmq_mqc_head(a)); - assert_eq!( - head, - Some( - hex!["434f8579a2297dfea851bf6be33093c83a78b655a53ae141a7894494c0010589"] - .to_vec() - ) - ); - }); - } -} diff --git a/runtime/parachains/src/dmp/tests.rs b/runtime/parachains/src/dmp/tests.rs new file mode 100644 index 000000000000..46c497dde904 --- /dev/null +++ b/runtime/parachains/src/dmp/tests.rs @@ -0,0 +1,203 @@ +// 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 super::*; +use crate::mock::{new_test_ext, Configuration, Dmp, MockGenesisConfig, Paras, System}; +use hex_literal::hex; +use parity_scale_codec::Encode; +use primitives::v1::BlockNumber; + +pub(crate) fn run_to_block(to: BlockNumber, new_session: Option>) { + while System::block_number() < to { + let b = System::block_number(); + Paras::initializer_finalize(b); + Dmp::initializer_finalize(); + if new_session.as_ref().map_or(false, |v| v.contains(&(b + 1))) { + Dmp::initializer_on_new_session(&Default::default(), &Vec::new()); + } + System::on_finalize(b); + + System::on_initialize(b + 1); + System::set_block_number(b + 1); + + Paras::initializer_finalize(b + 1); + Dmp::initializer_initialize(b + 1); + } +} + +fn default_genesis_config() -> MockGenesisConfig { + MockGenesisConfig { + configuration: crate::configuration::GenesisConfig { + config: crate::configuration::HostConfiguration { + max_downward_message_size: 1024, + ..Default::default() + }, + }, + ..Default::default() + } +} + +fn queue_downward_message( + para_id: ParaId, + msg: DownwardMessage, +) -> Result<(), QueueDownwardMessageError> { + Dmp::queue_downward_message(&Configuration::config(), para_id, msg) +} + +#[test] +fn clean_dmp_works() { + let a = ParaId::from(1312); + let b = ParaId::from(228); + let c = ParaId::from(123); + + new_test_ext(default_genesis_config()).execute_with(|| { + // enqueue downward messages to A, B and C. + queue_downward_message(a, vec![1, 2, 3]).unwrap(); + queue_downward_message(b, vec![4, 5, 6]).unwrap(); + queue_downward_message(c, vec![7, 8, 9]).unwrap(); + + let notification = crate::initializer::SessionChangeNotification::default(); + let outgoing_paras = vec![a, b]; + Dmp::initializer_on_new_session(¬ification, &outgoing_paras); + + assert!(::DownwardMessageQueues::get(&a).is_empty()); + assert!(::DownwardMessageQueues::get(&b).is_empty()); + assert!(!::DownwardMessageQueues::get(&c).is_empty()); + }); +} + +#[test] +fn dmq_length_and_head_updated_properly() { + let a = ParaId::from(1312); + let b = ParaId::from(228); + + new_test_ext(default_genesis_config()).execute_with(|| { + assert_eq!(Dmp::dmq_length(a), 0); + assert_eq!(Dmp::dmq_length(b), 0); + + queue_downward_message(a, vec![1, 2, 3]).unwrap(); + + assert_eq!(Dmp::dmq_length(a), 1); + assert_eq!(Dmp::dmq_length(b), 0); + assert!(!Dmp::dmq_mqc_head(a).is_zero()); + assert!(Dmp::dmq_mqc_head(b).is_zero()); + }); +} + +#[test] +fn dmp_mqc_head_fixture() { + let a = ParaId::from(2000); + + new_test_ext(default_genesis_config()).execute_with(|| { + run_to_block(2, None); + assert!(Dmp::dmq_mqc_head(a).is_zero()); + queue_downward_message(a, vec![1, 2, 3]).unwrap(); + + run_to_block(3, None); + queue_downward_message(a, vec![4, 5, 6]).unwrap(); + + assert_eq!( + Dmp::dmq_mqc_head(a), + hex!["88dc00db8cc9d22aa62b87807705831f164387dfa49f80a8600ed1cbe1704b6b"].into(), + ); + }); +} + +#[test] +fn check_processed_downward_messages() { + let a = ParaId::from(1312); + + new_test_ext(default_genesis_config()).execute_with(|| { + // processed_downward_messages=0 is allowed when the DMQ is empty. + assert!(Dmp::check_processed_downward_messages(a, 0).is_ok()); + + queue_downward_message(a, vec![1, 2, 3]).unwrap(); + queue_downward_message(a, vec![4, 5, 6]).unwrap(); + queue_downward_message(a, vec![7, 8, 9]).unwrap(); + + // 0 doesn't pass if the DMQ has msgs. + assert!(!Dmp::check_processed_downward_messages(a, 0).is_ok()); + // a candidate can consume up to 3 messages + assert!(Dmp::check_processed_downward_messages(a, 1).is_ok()); + assert!(Dmp::check_processed_downward_messages(a, 2).is_ok()); + assert!(Dmp::check_processed_downward_messages(a, 3).is_ok()); + // there is no 4 messages in the queue + assert!(!Dmp::check_processed_downward_messages(a, 4).is_ok()); + }); +} + +#[test] +fn dmq_pruning() { + let a = ParaId::from(1312); + + new_test_ext(default_genesis_config()).execute_with(|| { + assert_eq!(Dmp::dmq_length(a), 0); + + queue_downward_message(a, vec![1, 2, 3]).unwrap(); + queue_downward_message(a, vec![4, 5, 6]).unwrap(); + queue_downward_message(a, vec![7, 8, 9]).unwrap(); + assert_eq!(Dmp::dmq_length(a), 3); + + // pruning 0 elements shouldn't change anything. + Dmp::prune_dmq(a, 0); + assert_eq!(Dmp::dmq_length(a), 3); + + Dmp::prune_dmq(a, 2); + assert_eq!(Dmp::dmq_length(a), 1); + }); +} + +#[test] +fn queue_downward_message_critical() { + let a = ParaId::from(1312); + + let mut genesis = default_genesis_config(); + genesis.configuration.config.max_downward_message_size = 7; + + new_test_ext(genesis).execute_with(|| { + let smol = [0; 3].to_vec(); + let big = [0; 8].to_vec(); + + // still within limits + assert_eq!(smol.encode().len(), 4); + assert!(queue_downward_message(a, smol).is_ok()); + + // that's too big + assert_eq!(big.encode().len(), 9); + assert!(queue_downward_message(a, big).is_err()); + }); +} + +#[test] +fn verify_dmq_mqc_head_is_externally_accessible() { + use hex_literal::hex; + use primitives::v1::well_known_keys; + + let a = ParaId::from(2020); + + new_test_ext(default_genesis_config()).execute_with(|| { + let head = sp_io::storage::get(&well_known_keys::dmq_mqc_head(a)); + assert_eq!(head, None); + + queue_downward_message(a, vec![1, 2, 3]).unwrap(); + + let head = sp_io::storage::get(&well_known_keys::dmq_mqc_head(a)); + assert_eq!( + head, + Some(hex!["434f8579a2297dfea851bf6be33093c83a78b655a53ae141a7894494c0010589"].to_vec()) + ); + }); +} diff --git a/runtime/parachains/src/hrmp.rs b/runtime/parachains/src/hrmp.rs index bba182d4c466..025addbc9184 100644 --- a/runtime/parachains/src/hrmp.rs +++ b/runtime/parachains/src/hrmp.rs @@ -43,6 +43,9 @@ pub const HRMP_MAX_INBOUND_CHANNELS_BOUND: u32 = 128; /// Same as [`HRMP_MAX_INBOUND_CHANNELS_BOUND`], but for outbound channels. pub const HRMP_MAX_OUTBOUND_CHANNELS_BOUND: u32 = 128; +#[cfg(test)] +pub(crate) mod tests; + #[cfg(feature = "runtime-benchmarks")] mod benchmarking; @@ -1543,594 +1546,3 @@ impl Pallet { } } } - -#[cfg(test)] -pub(crate) mod tests { - use super::*; - use crate::mock::{ - new_test_ext, Configuration, Event as MockEvent, Hrmp, MockGenesisConfig, Paras, - ParasShared, System, Test, - }; - use frame_support::{assert_noop, assert_ok, traits::Currency as _}; - use primitives::v1::BlockNumber; - use std::collections::BTreeMap; - - fn run_to_block(to: BlockNumber, new_session: Option>) { - let config = Configuration::config(); - while System::block_number() < to { - let b = System::block_number(); - - // NOTE: this is in reverse initialization order. - Hrmp::initializer_finalize(); - Paras::initializer_finalize(b); - ParasShared::initializer_finalize(); - - if new_session.as_ref().map_or(false, |v| v.contains(&(b + 1))) { - let notification = crate::initializer::SessionChangeNotification { - prev_config: config.clone(), - new_config: config.clone(), - session_index: ParasShared::session_index() + 1, - ..Default::default() - }; - - // NOTE: this is in initialization order. - ParasShared::initializer_on_new_session( - notification.session_index, - notification.random_seed, - ¬ification.new_config, - notification.validators.clone(), - ); - let outgoing_paras = Paras::initializer_on_new_session(¬ification); - Hrmp::initializer_on_new_session(¬ification, &outgoing_paras); - } - - System::on_finalize(b); - - System::on_initialize(b + 1); - System::set_block_number(b + 1); - - // NOTE: this is in initialization order. - ParasShared::initializer_initialize(b + 1); - Paras::initializer_initialize(b + 1); - Hrmp::initializer_initialize(b + 1); - } - } - - #[derive(Debug)] - pub(super) struct GenesisConfigBuilder { - hrmp_channel_max_capacity: u32, - hrmp_channel_max_message_size: u32, - hrmp_max_parathread_outbound_channels: u32, - hrmp_max_parachain_outbound_channels: u32, - hrmp_max_parathread_inbound_channels: u32, - hrmp_max_parachain_inbound_channels: u32, - hrmp_max_message_num_per_candidate: u32, - hrmp_channel_max_total_size: u32, - hrmp_sender_deposit: Balance, - hrmp_recipient_deposit: Balance, - } - - impl Default for GenesisConfigBuilder { - fn default() -> Self { - Self { - hrmp_channel_max_capacity: 2, - hrmp_channel_max_message_size: 8, - hrmp_max_parathread_outbound_channels: 1, - hrmp_max_parachain_outbound_channels: 2, - hrmp_max_parathread_inbound_channels: 1, - hrmp_max_parachain_inbound_channels: 2, - hrmp_max_message_num_per_candidate: 2, - hrmp_channel_max_total_size: 16, - hrmp_sender_deposit: 100, - hrmp_recipient_deposit: 100, - } - } - } - - impl GenesisConfigBuilder { - pub(super) fn build(self) -> crate::mock::MockGenesisConfig { - let mut genesis = default_genesis_config(); - let config = &mut genesis.configuration.config; - config.hrmp_channel_max_capacity = self.hrmp_channel_max_capacity; - config.hrmp_channel_max_message_size = self.hrmp_channel_max_message_size; - config.hrmp_max_parathread_outbound_channels = - self.hrmp_max_parathread_outbound_channels; - config.hrmp_max_parachain_outbound_channels = self.hrmp_max_parachain_outbound_channels; - config.hrmp_max_parathread_inbound_channels = self.hrmp_max_parathread_inbound_channels; - config.hrmp_max_parachain_inbound_channels = self.hrmp_max_parachain_inbound_channels; - config.hrmp_max_message_num_per_candidate = self.hrmp_max_message_num_per_candidate; - config.hrmp_channel_max_total_size = self.hrmp_channel_max_total_size; - config.hrmp_sender_deposit = self.hrmp_sender_deposit; - config.hrmp_recipient_deposit = self.hrmp_recipient_deposit; - genesis - } - } - - fn default_genesis_config() -> MockGenesisConfig { - MockGenesisConfig { - configuration: crate::configuration::GenesisConfig { - config: crate::configuration::HostConfiguration { - max_downward_message_size: 1024, - pvf_checking_enabled: false, - ..Default::default() - }, - }, - ..Default::default() - } - } - - fn register_parachain_with_balance(id: ParaId, balance: Balance) { - assert_ok!(Paras::schedule_para_initialize( - id, - crate::paras::ParaGenesisArgs { - parachain: true, - genesis_head: vec![1].into(), - validation_code: vec![1].into(), - }, - )); - ::Currency::make_free_balance_be(&id.into_account(), balance); - } - - fn register_parachain(id: ParaId) { - register_parachain_with_balance(id, 1000); - } - - fn deregister_parachain(id: ParaId) { - assert_ok!(Paras::schedule_para_cleanup(id)); - } - - fn channel_exists(sender: ParaId, recipient: ParaId) -> bool { - ::HrmpChannels::get(&HrmpChannelId { sender, recipient }).is_some() - } - - #[test] - fn empty_state_consistent_state() { - new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| { - Hrmp::assert_storage_consistency_exhaustive(); - }); - } - - #[test] - fn open_channel_works() { - let para_a = 1.into(); - let para_a_origin: crate::Origin = 1.into(); - let para_b = 3.into(); - let para_b_origin: crate::Origin = 3.into(); - - new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| { - // We need both A & B to be registered and alive parachains. - register_parachain(para_a); - register_parachain(para_b); - - run_to_block(5, Some(vec![4, 5])); - Hrmp::hrmp_init_open_channel(para_a_origin.into(), para_b, 2, 8).unwrap(); - Hrmp::assert_storage_consistency_exhaustive(); - assert!(System::events().iter().any(|record| record.event == - MockEvent::Hrmp(Event::OpenChannelRequested(para_a, para_b, 2, 8)))); - - Hrmp::hrmp_accept_open_channel(para_b_origin.into(), para_a).unwrap(); - Hrmp::assert_storage_consistency_exhaustive(); - assert!(System::events().iter().any(|record| record.event == - MockEvent::Hrmp(Event::OpenChannelAccepted(para_a, para_b)))); - - // Advance to a block 6, but without session change. That means that the channel has - // not been created yet. - run_to_block(6, None); - assert!(!channel_exists(para_a, para_b)); - Hrmp::assert_storage_consistency_exhaustive(); - - // Now let the session change happen and thus open the channel. - run_to_block(8, Some(vec![8])); - assert!(channel_exists(para_a, para_b)); - }); - } - - #[test] - fn close_channel_works() { - let para_a = 5.into(); - let para_b = 2.into(); - let para_b_origin: crate::Origin = 2.into(); - - new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| { - register_parachain(para_a); - register_parachain(para_b); - - run_to_block(5, Some(vec![4, 5])); - Hrmp::init_open_channel(para_a, para_b, 2, 8).unwrap(); - Hrmp::accept_open_channel(para_b, para_a).unwrap(); - - run_to_block(6, Some(vec![6])); - assert!(channel_exists(para_a, para_b)); - - // Close the channel. The effect is not immediate, but rather deferred to the next - // session change. - let channel_id = HrmpChannelId { sender: para_a, recipient: para_b }; - Hrmp::hrmp_close_channel(para_b_origin.into(), channel_id.clone()).unwrap(); - assert!(channel_exists(para_a, para_b)); - Hrmp::assert_storage_consistency_exhaustive(); - - // After the session change the channel should be closed. - run_to_block(8, Some(vec![8])); - assert!(!channel_exists(para_a, para_b)); - Hrmp::assert_storage_consistency_exhaustive(); - assert!(System::events().iter().any(|record| record.event == - MockEvent::Hrmp(Event::ChannelClosed(para_b, channel_id.clone())))); - }); - } - - #[test] - fn send_recv_messages() { - let para_a = 32.into(); - let para_b = 64.into(); - - let mut genesis = GenesisConfigBuilder::default(); - genesis.hrmp_channel_max_message_size = 20; - genesis.hrmp_channel_max_total_size = 20; - new_test_ext(genesis.build()).execute_with(|| { - register_parachain(para_a); - register_parachain(para_b); - - run_to_block(5, Some(vec![4, 5])); - Hrmp::init_open_channel(para_a, para_b, 2, 20).unwrap(); - Hrmp::accept_open_channel(para_b, para_a).unwrap(); - - // On Block 6: - // A sends a message to B - run_to_block(6, Some(vec![6])); - assert!(channel_exists(para_a, para_b)); - let msgs = vec![OutboundHrmpMessage { - recipient: para_b, - data: b"this is an emergency".to_vec(), - }]; - let config = Configuration::config(); - assert!(Hrmp::check_outbound_hrmp(&config, para_a, &msgs).is_ok()); - let _ = Hrmp::queue_outbound_hrmp(para_a, msgs); - Hrmp::assert_storage_consistency_exhaustive(); - - // On Block 7: - // B receives the message sent by A. B sets the watermark to 6. - run_to_block(7, None); - assert!(Hrmp::check_hrmp_watermark(para_b, 7, 6).is_ok()); - let _ = Hrmp::prune_hrmp(para_b, 6); - Hrmp::assert_storage_consistency_exhaustive(); - }); - } - - #[test] - fn hrmp_mqc_head_fixture() { - let para_a = 2000.into(); - let para_b = 2024.into(); - - let mut genesis = GenesisConfigBuilder::default(); - genesis.hrmp_channel_max_message_size = 20; - genesis.hrmp_channel_max_total_size = 20; - new_test_ext(genesis.build()).execute_with(|| { - register_parachain(para_a); - register_parachain(para_b); - - run_to_block(2, Some(vec![1, 2])); - Hrmp::init_open_channel(para_a, para_b, 2, 20).unwrap(); - Hrmp::accept_open_channel(para_b, para_a).unwrap(); - - run_to_block(3, Some(vec![3])); - let _ = Hrmp::queue_outbound_hrmp( - para_a, - vec![OutboundHrmpMessage { recipient: para_b, data: vec![1, 2, 3] }], - ); - - run_to_block(4, None); - let _ = Hrmp::queue_outbound_hrmp( - para_a, - vec![OutboundHrmpMessage { recipient: para_b, data: vec![4, 5, 6] }], - ); - - assert_eq!( - Hrmp::hrmp_mqc_heads(para_b), - vec![( - para_a, - hex_literal::hex![ - "a964fd3b4f3d3ce92a0e25e576b87590d92bb5cb7031909c7f29050e1f04a375" - ] - .into() - ),], - ); - }); - } - - #[test] - fn accept_incoming_request_and_offboard() { - let para_a = 32.into(); - let para_b = 64.into(); - - new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| { - register_parachain(para_a); - register_parachain(para_b); - - run_to_block(5, Some(vec![4, 5])); - Hrmp::init_open_channel(para_a, para_b, 2, 8).unwrap(); - Hrmp::accept_open_channel(para_b, para_a).unwrap(); - deregister_parachain(para_a); - - // On Block 7: 2x session change. The channel should not be created. - run_to_block(7, Some(vec![6, 7])); - assert!(!Paras::is_valid_para(para_a)); - assert!(!channel_exists(para_a, para_b)); - Hrmp::assert_storage_consistency_exhaustive(); - }); - } - - #[test] - fn check_sent_messages() { - let para_a = 32.into(); - let para_b = 64.into(); - let para_c = 97.into(); - - new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| { - register_parachain(para_a); - register_parachain(para_b); - register_parachain(para_c); - - run_to_block(5, Some(vec![4, 5])); - - // Open two channels to the same receiver, b: - // a -> b, c -> b - Hrmp::init_open_channel(para_a, para_b, 2, 8).unwrap(); - Hrmp::accept_open_channel(para_b, para_a).unwrap(); - Hrmp::init_open_channel(para_c, para_b, 2, 8).unwrap(); - Hrmp::accept_open_channel(para_b, para_c).unwrap(); - - // On Block 6: session change. - run_to_block(6, Some(vec![6])); - assert!(Paras::is_valid_para(para_a)); - - let msgs = vec![OutboundHrmpMessage { recipient: para_b, data: b"knock".to_vec() }]; - let config = Configuration::config(); - assert!(Hrmp::check_outbound_hrmp(&config, para_a, &msgs).is_ok()); - let _ = Hrmp::queue_outbound_hrmp(para_a, msgs.clone()); - - // Verify that the sent messages are there and that also the empty channels are present. - let mqc_heads = Hrmp::hrmp_mqc_heads(para_b); - let contents = Hrmp::inbound_hrmp_channels_contents(para_b); - assert_eq!( - contents, - vec![ - (para_a, vec![InboundHrmpMessage { sent_at: 6, data: b"knock".to_vec() }]), - (para_c, vec![]) - ] - .into_iter() - .collect::>(), - ); - assert_eq!( - mqc_heads, - vec![ - ( - para_a, - hex_literal::hex!( - "3bba6404e59c91f51deb2ae78f1273ebe75896850713e13f8c0eba4b0996c483" - ) - .into() - ), - (para_c, Default::default()) - ], - ); - - Hrmp::assert_storage_consistency_exhaustive(); - }); - } - - #[test] - fn verify_externally_accessible() { - use primitives::v1::{well_known_keys, AbridgedHrmpChannel}; - - let para_a = 20.into(); - let para_b = 21.into(); - - new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| { - // Register two parachains, wait until a session change, then initiate channel open - // request and accept that, and finally wait until the next session. - register_parachain(para_a); - register_parachain(para_b); - run_to_block(5, Some(vec![4, 5])); - Hrmp::init_open_channel(para_a, para_b, 2, 8).unwrap(); - Hrmp::accept_open_channel(para_b, para_a).unwrap(); - run_to_block(8, Some(vec![8])); - - // Here we have a channel a->b opened. - // - // Try to obtain this channel from the storage and - // decode it into the abridged version. - assert!(channel_exists(para_a, para_b)); - let raw_hrmp_channel = - sp_io::storage::get(&well_known_keys::hrmp_channels(HrmpChannelId { - sender: para_a, - recipient: para_b, - })) - .expect("the channel exists and we must be able to get it through well known keys"); - let abridged_hrmp_channel = AbridgedHrmpChannel::decode(&mut &raw_hrmp_channel[..]) - .expect("HrmpChannel should be decodable as AbridgedHrmpChannel"); - - assert_eq!( - abridged_hrmp_channel, - AbridgedHrmpChannel { - max_capacity: 2, - max_total_size: 16, - max_message_size: 8, - msg_count: 0, - total_size: 0, - mqc_head: None, - }, - ); - - let raw_ingress_index = - sp_io::storage::get(&well_known_keys::hrmp_ingress_channel_index(para_b)) - .expect("the ingress index must be present for para_b"); - let ingress_index = >::decode(&mut &raw_ingress_index[..]) - .expect("ingress indexx should be decodable as a list of para ids"); - assert_eq!(ingress_index, vec![para_a]); - - // Now, verify that we can access and decode the egress index. - let raw_egress_index = - sp_io::storage::get(&well_known_keys::hrmp_egress_channel_index(para_a)) - .expect("the egress index must be present for para_a"); - let egress_index = >::decode(&mut &raw_egress_index[..]) - .expect("egress index should be decodable as a list of para ids"); - assert_eq!(egress_index, vec![para_b]); - }); - } - - #[test] - fn charging_deposits() { - let para_a = 32.into(); - let para_b = 64.into(); - - new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| { - register_parachain_with_balance(para_a, 0); - register_parachain(para_b); - run_to_block(5, Some(vec![4, 5])); - - assert_noop!( - Hrmp::init_open_channel(para_a, para_b, 2, 8), - pallet_balances::Error::::InsufficientBalance - ); - }); - - new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| { - register_parachain(para_a); - register_parachain_with_balance(para_b, 0); - run_to_block(5, Some(vec![4, 5])); - - Hrmp::init_open_channel(para_a, para_b, 2, 8).unwrap(); - - assert_noop!( - Hrmp::accept_open_channel(para_b, para_a), - pallet_balances::Error::::InsufficientBalance - ); - }); - } - - #[test] - fn refund_deposit_on_normal_closure() { - let para_a = 32.into(); - let para_b = 64.into(); - - let mut genesis = GenesisConfigBuilder::default(); - genesis.hrmp_sender_deposit = 20; - genesis.hrmp_recipient_deposit = 15; - new_test_ext(genesis.build()).execute_with(|| { - // Register two parachains funded with different amounts of funds and arrange a channel. - register_parachain_with_balance(para_a, 100); - register_parachain_with_balance(para_b, 110); - run_to_block(5, Some(vec![4, 5])); - Hrmp::init_open_channel(para_a, para_b, 2, 8).unwrap(); - Hrmp::accept_open_channel(para_b, para_a).unwrap(); - assert_eq!(::Currency::free_balance(¶_a.into_account()), 80); - assert_eq!(::Currency::free_balance(¶_b.into_account()), 95); - run_to_block(8, Some(vec![8])); - - // Now, we close the channel and wait until the next session. - Hrmp::close_channel(para_b, HrmpChannelId { sender: para_a, recipient: para_b }) - .unwrap(); - run_to_block(10, Some(vec![10])); - assert_eq!(::Currency::free_balance(¶_a.into_account()), 100); - assert_eq!(::Currency::free_balance(¶_b.into_account()), 110); - }); - } - - #[test] - fn refund_deposit_on_offboarding() { - let para_a = 32.into(); - let para_b = 64.into(); - - let mut genesis = GenesisConfigBuilder::default(); - genesis.hrmp_sender_deposit = 20; - genesis.hrmp_recipient_deposit = 15; - new_test_ext(genesis.build()).execute_with(|| { - // Register two parachains and open a channel between them. - register_parachain_with_balance(para_a, 100); - register_parachain_with_balance(para_b, 110); - run_to_block(5, Some(vec![4, 5])); - Hrmp::init_open_channel(para_a, para_b, 2, 8).unwrap(); - Hrmp::accept_open_channel(para_b, para_a).unwrap(); - assert_eq!(::Currency::free_balance(¶_a.into_account()), 80); - assert_eq!(::Currency::free_balance(¶_b.into_account()), 95); - run_to_block(8, Some(vec![8])); - assert!(channel_exists(para_a, para_b)); - - // Then deregister one parachain. - deregister_parachain(para_a); - run_to_block(10, Some(vec![9, 10])); - - // The channel should be removed. - assert!(!Paras::is_valid_para(para_a)); - assert!(!channel_exists(para_a, para_b)); - Hrmp::assert_storage_consistency_exhaustive(); - - assert_eq!(::Currency::free_balance(¶_a.into_account()), 100); - assert_eq!(::Currency::free_balance(¶_b.into_account()), 110); - }); - } - - #[test] - fn no_dangling_open_requests() { - let para_a = 32.into(); - let para_b = 64.into(); - - let mut genesis = GenesisConfigBuilder::default(); - genesis.hrmp_sender_deposit = 20; - genesis.hrmp_recipient_deposit = 15; - new_test_ext(genesis.build()).execute_with(|| { - // Register two parachains and open a channel between them. - register_parachain_with_balance(para_a, 100); - register_parachain_with_balance(para_b, 110); - run_to_block(5, Some(vec![4, 5])); - - // Start opening a channel a->b - Hrmp::init_open_channel(para_a, para_b, 2, 8).unwrap(); - assert_eq!(::Currency::free_balance(¶_a.into_account()), 80); - - // Then deregister one parachain, but don't wait two sessions until it takes effect. - // Instead, `para_b` will confirm the request, which will take place the same time - // the offboarding should happen. - deregister_parachain(para_a); - run_to_block(9, Some(vec![9])); - Hrmp::accept_open_channel(para_b, para_a).unwrap(); - assert_eq!(::Currency::free_balance(¶_b.into_account()), 95); - assert!(!channel_exists(para_a, para_b)); - run_to_block(10, Some(vec![10])); - - // The outcome we expect is `para_b` should receive the refund. - assert_eq!(::Currency::free_balance(¶_b.into_account()), 110); - assert!(!channel_exists(para_a, para_b)); - Hrmp::assert_storage_consistency_exhaustive(); - }); - } - - #[test] - fn cancel_pending_open_channel_request() { - let para_a = 32.into(); - let para_b = 64.into(); - - let mut genesis = GenesisConfigBuilder::default(); - genesis.hrmp_sender_deposit = 20; - genesis.hrmp_recipient_deposit = 15; - new_test_ext(genesis.build()).execute_with(|| { - // Register two parachains and open a channel between them. - register_parachain_with_balance(para_a, 100); - register_parachain_with_balance(para_b, 110); - run_to_block(5, Some(vec![4, 5])); - - // Start opening a channel a->b - Hrmp::init_open_channel(para_a, para_b, 2, 8).unwrap(); - assert_eq!(::Currency::free_balance(¶_a.into_account()), 80); - - // Cancel opening the channel - Hrmp::cancel_open_request(para_a, HrmpChannelId { sender: para_a, recipient: para_b }) - .unwrap(); - assert_eq!(::Currency::free_balance(¶_a.into_account()), 100); - - run_to_block(10, Some(vec![10])); - assert!(!channel_exists(para_a, para_b)); - Hrmp::assert_storage_consistency_exhaustive(); - }); - } -} diff --git a/runtime/parachains/src/hrmp/tests.rs b/runtime/parachains/src/hrmp/tests.rs new file mode 100644 index 000000000000..35dd006a4481 --- /dev/null +++ b/runtime/parachains/src/hrmp/tests.rs @@ -0,0 +1,601 @@ +// 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 super::*; +use crate::mock::{ + new_test_ext, Configuration, Event as MockEvent, Hrmp, MockGenesisConfig, Paras, ParasShared, + System, Test, +}; +use frame_support::{assert_noop, assert_ok, traits::Currency as _}; +use primitives::v1::BlockNumber; +use std::collections::BTreeMap; + +fn run_to_block(to: BlockNumber, new_session: Option>) { + let config = Configuration::config(); + while System::block_number() < to { + let b = System::block_number(); + + // NOTE: this is in reverse initialization order. + Hrmp::initializer_finalize(); + Paras::initializer_finalize(b); + ParasShared::initializer_finalize(); + + if new_session.as_ref().map_or(false, |v| v.contains(&(b + 1))) { + let notification = crate::initializer::SessionChangeNotification { + prev_config: config.clone(), + new_config: config.clone(), + session_index: ParasShared::session_index() + 1, + ..Default::default() + }; + + // NOTE: this is in initialization order. + ParasShared::initializer_on_new_session( + notification.session_index, + notification.random_seed, + ¬ification.new_config, + notification.validators.clone(), + ); + let outgoing_paras = Paras::initializer_on_new_session(¬ification); + Hrmp::initializer_on_new_session(¬ification, &outgoing_paras); + } + + System::on_finalize(b); + + System::on_initialize(b + 1); + System::set_block_number(b + 1); + + // NOTE: this is in initialization order. + ParasShared::initializer_initialize(b + 1); + Paras::initializer_initialize(b + 1); + Hrmp::initializer_initialize(b + 1); + } +} + +#[derive(Debug)] +pub(super) struct GenesisConfigBuilder { + hrmp_channel_max_capacity: u32, + hrmp_channel_max_message_size: u32, + hrmp_max_parathread_outbound_channels: u32, + hrmp_max_parachain_outbound_channels: u32, + hrmp_max_parathread_inbound_channels: u32, + hrmp_max_parachain_inbound_channels: u32, + hrmp_max_message_num_per_candidate: u32, + hrmp_channel_max_total_size: u32, + hrmp_sender_deposit: Balance, + hrmp_recipient_deposit: Balance, +} + +impl Default for GenesisConfigBuilder { + fn default() -> Self { + Self { + hrmp_channel_max_capacity: 2, + hrmp_channel_max_message_size: 8, + hrmp_max_parathread_outbound_channels: 1, + hrmp_max_parachain_outbound_channels: 2, + hrmp_max_parathread_inbound_channels: 1, + hrmp_max_parachain_inbound_channels: 2, + hrmp_max_message_num_per_candidate: 2, + hrmp_channel_max_total_size: 16, + hrmp_sender_deposit: 100, + hrmp_recipient_deposit: 100, + } + } +} + +impl GenesisConfigBuilder { + pub(super) fn build(self) -> crate::mock::MockGenesisConfig { + let mut genesis = default_genesis_config(); + let config = &mut genesis.configuration.config; + config.hrmp_channel_max_capacity = self.hrmp_channel_max_capacity; + config.hrmp_channel_max_message_size = self.hrmp_channel_max_message_size; + config.hrmp_max_parathread_outbound_channels = self.hrmp_max_parathread_outbound_channels; + config.hrmp_max_parachain_outbound_channels = self.hrmp_max_parachain_outbound_channels; + config.hrmp_max_parathread_inbound_channels = self.hrmp_max_parathread_inbound_channels; + config.hrmp_max_parachain_inbound_channels = self.hrmp_max_parachain_inbound_channels; + config.hrmp_max_message_num_per_candidate = self.hrmp_max_message_num_per_candidate; + config.hrmp_channel_max_total_size = self.hrmp_channel_max_total_size; + config.hrmp_sender_deposit = self.hrmp_sender_deposit; + config.hrmp_recipient_deposit = self.hrmp_recipient_deposit; + genesis + } +} + +fn default_genesis_config() -> MockGenesisConfig { + MockGenesisConfig { + configuration: crate::configuration::GenesisConfig { + config: crate::configuration::HostConfiguration { + max_downward_message_size: 1024, + pvf_checking_enabled: false, + ..Default::default() + }, + }, + ..Default::default() + } +} + +fn register_parachain_with_balance(id: ParaId, balance: Balance) { + assert_ok!(Paras::schedule_para_initialize( + id, + crate::paras::ParaGenesisArgs { + parachain: true, + genesis_head: vec![1].into(), + validation_code: vec![1].into(), + }, + )); + ::Currency::make_free_balance_be(&id.into_account(), balance); +} + +fn register_parachain(id: ParaId) { + register_parachain_with_balance(id, 1000); +} + +fn deregister_parachain(id: ParaId) { + assert_ok!(Paras::schedule_para_cleanup(id)); +} + +fn channel_exists(sender: ParaId, recipient: ParaId) -> bool { + ::HrmpChannels::get(&HrmpChannelId { sender, recipient }).is_some() +} + +#[test] +fn empty_state_consistent_state() { + new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| { + Hrmp::assert_storage_consistency_exhaustive(); + }); +} + +#[test] +fn open_channel_works() { + let para_a = 1.into(); + let para_a_origin: crate::Origin = 1.into(); + let para_b = 3.into(); + let para_b_origin: crate::Origin = 3.into(); + + new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| { + // We need both A & B to be registered and alive parachains. + register_parachain(para_a); + register_parachain(para_b); + + run_to_block(5, Some(vec![4, 5])); + Hrmp::hrmp_init_open_channel(para_a_origin.into(), para_b, 2, 8).unwrap(); + Hrmp::assert_storage_consistency_exhaustive(); + assert!(System::events().iter().any(|record| record.event == + MockEvent::Hrmp(Event::OpenChannelRequested(para_a, para_b, 2, 8)))); + + Hrmp::hrmp_accept_open_channel(para_b_origin.into(), para_a).unwrap(); + Hrmp::assert_storage_consistency_exhaustive(); + assert!(System::events() + .iter() + .any(|record| record.event == + MockEvent::Hrmp(Event::OpenChannelAccepted(para_a, para_b)))); + + // Advance to a block 6, but without session change. That means that the channel has + // not been created yet. + run_to_block(6, None); + assert!(!channel_exists(para_a, para_b)); + Hrmp::assert_storage_consistency_exhaustive(); + + // Now let the session change happen and thus open the channel. + run_to_block(8, Some(vec![8])); + assert!(channel_exists(para_a, para_b)); + }); +} + +#[test] +fn close_channel_works() { + let para_a = 5.into(); + let para_b = 2.into(); + let para_b_origin: crate::Origin = 2.into(); + + new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| { + register_parachain(para_a); + register_parachain(para_b); + + run_to_block(5, Some(vec![4, 5])); + Hrmp::init_open_channel(para_a, para_b, 2, 8).unwrap(); + Hrmp::accept_open_channel(para_b, para_a).unwrap(); + + run_to_block(6, Some(vec![6])); + assert!(channel_exists(para_a, para_b)); + + // Close the channel. The effect is not immediate, but rather deferred to the next + // session change. + let channel_id = HrmpChannelId { sender: para_a, recipient: para_b }; + Hrmp::hrmp_close_channel(para_b_origin.into(), channel_id.clone()).unwrap(); + assert!(channel_exists(para_a, para_b)); + Hrmp::assert_storage_consistency_exhaustive(); + + // After the session change the channel should be closed. + run_to_block(8, Some(vec![8])); + assert!(!channel_exists(para_a, para_b)); + Hrmp::assert_storage_consistency_exhaustive(); + assert!(System::events().iter().any(|record| record.event == + MockEvent::Hrmp(Event::ChannelClosed(para_b, channel_id.clone())))); + }); +} + +#[test] +fn send_recv_messages() { + let para_a = 32.into(); + let para_b = 64.into(); + + let mut genesis = GenesisConfigBuilder::default(); + genesis.hrmp_channel_max_message_size = 20; + genesis.hrmp_channel_max_total_size = 20; + new_test_ext(genesis.build()).execute_with(|| { + register_parachain(para_a); + register_parachain(para_b); + + run_to_block(5, Some(vec![4, 5])); + Hrmp::init_open_channel(para_a, para_b, 2, 20).unwrap(); + Hrmp::accept_open_channel(para_b, para_a).unwrap(); + + // On Block 6: + // A sends a message to B + run_to_block(6, Some(vec![6])); + assert!(channel_exists(para_a, para_b)); + let msgs = + vec![OutboundHrmpMessage { recipient: para_b, data: b"this is an emergency".to_vec() }]; + let config = Configuration::config(); + assert!(Hrmp::check_outbound_hrmp(&config, para_a, &msgs).is_ok()); + let _ = Hrmp::queue_outbound_hrmp(para_a, msgs); + Hrmp::assert_storage_consistency_exhaustive(); + + // On Block 7: + // B receives the message sent by A. B sets the watermark to 6. + run_to_block(7, None); + assert!(Hrmp::check_hrmp_watermark(para_b, 7, 6).is_ok()); + let _ = Hrmp::prune_hrmp(para_b, 6); + Hrmp::assert_storage_consistency_exhaustive(); + }); +} + +#[test] +fn hrmp_mqc_head_fixture() { + let para_a = 2000.into(); + let para_b = 2024.into(); + + let mut genesis = GenesisConfigBuilder::default(); + genesis.hrmp_channel_max_message_size = 20; + genesis.hrmp_channel_max_total_size = 20; + new_test_ext(genesis.build()).execute_with(|| { + register_parachain(para_a); + register_parachain(para_b); + + run_to_block(2, Some(vec![1, 2])); + Hrmp::init_open_channel(para_a, para_b, 2, 20).unwrap(); + Hrmp::accept_open_channel(para_b, para_a).unwrap(); + + run_to_block(3, Some(vec![3])); + let _ = Hrmp::queue_outbound_hrmp( + para_a, + vec![OutboundHrmpMessage { recipient: para_b, data: vec![1, 2, 3] }], + ); + + run_to_block(4, None); + let _ = Hrmp::queue_outbound_hrmp( + para_a, + vec![OutboundHrmpMessage { recipient: para_b, data: vec![4, 5, 6] }], + ); + + assert_eq!( + Hrmp::hrmp_mqc_heads(para_b), + vec![( + para_a, + hex_literal::hex![ + "a964fd3b4f3d3ce92a0e25e576b87590d92bb5cb7031909c7f29050e1f04a375" + ] + .into() + ),], + ); + }); +} + +#[test] +fn accept_incoming_request_and_offboard() { + let para_a = 32.into(); + let para_b = 64.into(); + + new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| { + register_parachain(para_a); + register_parachain(para_b); + + run_to_block(5, Some(vec![4, 5])); + Hrmp::init_open_channel(para_a, para_b, 2, 8).unwrap(); + Hrmp::accept_open_channel(para_b, para_a).unwrap(); + deregister_parachain(para_a); + + // On Block 7: 2x session change. The channel should not be created. + run_to_block(7, Some(vec![6, 7])); + assert!(!Paras::is_valid_para(para_a)); + assert!(!channel_exists(para_a, para_b)); + Hrmp::assert_storage_consistency_exhaustive(); + }); +} + +#[test] +fn check_sent_messages() { + let para_a = 32.into(); + let para_b = 64.into(); + let para_c = 97.into(); + + new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| { + register_parachain(para_a); + register_parachain(para_b); + register_parachain(para_c); + + run_to_block(5, Some(vec![4, 5])); + + // Open two channels to the same receiver, b: + // a -> b, c -> b + Hrmp::init_open_channel(para_a, para_b, 2, 8).unwrap(); + Hrmp::accept_open_channel(para_b, para_a).unwrap(); + Hrmp::init_open_channel(para_c, para_b, 2, 8).unwrap(); + Hrmp::accept_open_channel(para_b, para_c).unwrap(); + + // On Block 6: session change. + run_to_block(6, Some(vec![6])); + assert!(Paras::is_valid_para(para_a)); + + let msgs = vec![OutboundHrmpMessage { recipient: para_b, data: b"knock".to_vec() }]; + let config = Configuration::config(); + assert!(Hrmp::check_outbound_hrmp(&config, para_a, &msgs).is_ok()); + let _ = Hrmp::queue_outbound_hrmp(para_a, msgs.clone()); + + // Verify that the sent messages are there and that also the empty channels are present. + let mqc_heads = Hrmp::hrmp_mqc_heads(para_b); + let contents = Hrmp::inbound_hrmp_channels_contents(para_b); + assert_eq!( + contents, + vec![ + (para_a, vec![InboundHrmpMessage { sent_at: 6, data: b"knock".to_vec() }]), + (para_c, vec![]) + ] + .into_iter() + .collect::>(), + ); + assert_eq!( + mqc_heads, + vec![ + ( + para_a, + hex_literal::hex!( + "3bba6404e59c91f51deb2ae78f1273ebe75896850713e13f8c0eba4b0996c483" + ) + .into() + ), + (para_c, Default::default()) + ], + ); + + Hrmp::assert_storage_consistency_exhaustive(); + }); +} + +#[test] +fn verify_externally_accessible() { + use primitives::v1::{well_known_keys, AbridgedHrmpChannel}; + + let para_a = 20.into(); + let para_b = 21.into(); + + new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| { + // Register two parachains, wait until a session change, then initiate channel open + // request and accept that, and finally wait until the next session. + register_parachain(para_a); + register_parachain(para_b); + run_to_block(5, Some(vec![4, 5])); + Hrmp::init_open_channel(para_a, para_b, 2, 8).unwrap(); + Hrmp::accept_open_channel(para_b, para_a).unwrap(); + run_to_block(8, Some(vec![8])); + + // Here we have a channel a->b opened. + // + // Try to obtain this channel from the storage and + // decode it into the abridged version. + assert!(channel_exists(para_a, para_b)); + let raw_hrmp_channel = + sp_io::storage::get(&well_known_keys::hrmp_channels(HrmpChannelId { + sender: para_a, + recipient: para_b, + })) + .expect("the channel exists and we must be able to get it through well known keys"); + let abridged_hrmp_channel = AbridgedHrmpChannel::decode(&mut &raw_hrmp_channel[..]) + .expect("HrmpChannel should be decodable as AbridgedHrmpChannel"); + + assert_eq!( + abridged_hrmp_channel, + AbridgedHrmpChannel { + max_capacity: 2, + max_total_size: 16, + max_message_size: 8, + msg_count: 0, + total_size: 0, + mqc_head: None, + }, + ); + + let raw_ingress_index = + sp_io::storage::get(&well_known_keys::hrmp_ingress_channel_index(para_b)) + .expect("the ingress index must be present for para_b"); + let ingress_index = >::decode(&mut &raw_ingress_index[..]) + .expect("ingress indexx should be decodable as a list of para ids"); + assert_eq!(ingress_index, vec![para_a]); + + // Now, verify that we can access and decode the egress index. + let raw_egress_index = + sp_io::storage::get(&well_known_keys::hrmp_egress_channel_index(para_a)) + .expect("the egress index must be present for para_a"); + let egress_index = >::decode(&mut &raw_egress_index[..]) + .expect("egress index should be decodable as a list of para ids"); + assert_eq!(egress_index, vec![para_b]); + }); +} + +#[test] +fn charging_deposits() { + let para_a = 32.into(); + let para_b = 64.into(); + + new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| { + register_parachain_with_balance(para_a, 0); + register_parachain(para_b); + run_to_block(5, Some(vec![4, 5])); + + assert_noop!( + Hrmp::init_open_channel(para_a, para_b, 2, 8), + pallet_balances::Error::::InsufficientBalance + ); + }); + + new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| { + register_parachain(para_a); + register_parachain_with_balance(para_b, 0); + run_to_block(5, Some(vec![4, 5])); + + Hrmp::init_open_channel(para_a, para_b, 2, 8).unwrap(); + + assert_noop!( + Hrmp::accept_open_channel(para_b, para_a), + pallet_balances::Error::::InsufficientBalance + ); + }); +} + +#[test] +fn refund_deposit_on_normal_closure() { + let para_a = 32.into(); + let para_b = 64.into(); + + let mut genesis = GenesisConfigBuilder::default(); + genesis.hrmp_sender_deposit = 20; + genesis.hrmp_recipient_deposit = 15; + new_test_ext(genesis.build()).execute_with(|| { + // Register two parachains funded with different amounts of funds and arrange a channel. + register_parachain_with_balance(para_a, 100); + register_parachain_with_balance(para_b, 110); + run_to_block(5, Some(vec![4, 5])); + Hrmp::init_open_channel(para_a, para_b, 2, 8).unwrap(); + Hrmp::accept_open_channel(para_b, para_a).unwrap(); + assert_eq!(::Currency::free_balance(¶_a.into_account()), 80); + assert_eq!(::Currency::free_balance(¶_b.into_account()), 95); + run_to_block(8, Some(vec![8])); + + // Now, we close the channel and wait until the next session. + Hrmp::close_channel(para_b, HrmpChannelId { sender: para_a, recipient: para_b }).unwrap(); + run_to_block(10, Some(vec![10])); + assert_eq!(::Currency::free_balance(¶_a.into_account()), 100); + assert_eq!(::Currency::free_balance(¶_b.into_account()), 110); + }); +} + +#[test] +fn refund_deposit_on_offboarding() { + let para_a = 32.into(); + let para_b = 64.into(); + + let mut genesis = GenesisConfigBuilder::default(); + genesis.hrmp_sender_deposit = 20; + genesis.hrmp_recipient_deposit = 15; + new_test_ext(genesis.build()).execute_with(|| { + // Register two parachains and open a channel between them. + register_parachain_with_balance(para_a, 100); + register_parachain_with_balance(para_b, 110); + run_to_block(5, Some(vec![4, 5])); + Hrmp::init_open_channel(para_a, para_b, 2, 8).unwrap(); + Hrmp::accept_open_channel(para_b, para_a).unwrap(); + assert_eq!(::Currency::free_balance(¶_a.into_account()), 80); + assert_eq!(::Currency::free_balance(¶_b.into_account()), 95); + run_to_block(8, Some(vec![8])); + assert!(channel_exists(para_a, para_b)); + + // Then deregister one parachain. + deregister_parachain(para_a); + run_to_block(10, Some(vec![9, 10])); + + // The channel should be removed. + assert!(!Paras::is_valid_para(para_a)); + assert!(!channel_exists(para_a, para_b)); + Hrmp::assert_storage_consistency_exhaustive(); + + assert_eq!(::Currency::free_balance(¶_a.into_account()), 100); + assert_eq!(::Currency::free_balance(¶_b.into_account()), 110); + }); +} + +#[test] +fn no_dangling_open_requests() { + let para_a = 32.into(); + let para_b = 64.into(); + + let mut genesis = GenesisConfigBuilder::default(); + genesis.hrmp_sender_deposit = 20; + genesis.hrmp_recipient_deposit = 15; + new_test_ext(genesis.build()).execute_with(|| { + // Register two parachains and open a channel between them. + register_parachain_with_balance(para_a, 100); + register_parachain_with_balance(para_b, 110); + run_to_block(5, Some(vec![4, 5])); + + // Start opening a channel a->b + Hrmp::init_open_channel(para_a, para_b, 2, 8).unwrap(); + assert_eq!(::Currency::free_balance(¶_a.into_account()), 80); + + // Then deregister one parachain, but don't wait two sessions until it takes effect. + // Instead, `para_b` will confirm the request, which will take place the same time + // the offboarding should happen. + deregister_parachain(para_a); + run_to_block(9, Some(vec![9])); + Hrmp::accept_open_channel(para_b, para_a).unwrap(); + assert_eq!(::Currency::free_balance(¶_b.into_account()), 95); + assert!(!channel_exists(para_a, para_b)); + run_to_block(10, Some(vec![10])); + + // The outcome we expect is `para_b` should receive the refund. + assert_eq!(::Currency::free_balance(¶_b.into_account()), 110); + assert!(!channel_exists(para_a, para_b)); + Hrmp::assert_storage_consistency_exhaustive(); + }); +} + +#[test] +fn cancel_pending_open_channel_request() { + let para_a = 32.into(); + let para_b = 64.into(); + + let mut genesis = GenesisConfigBuilder::default(); + genesis.hrmp_sender_deposit = 20; + genesis.hrmp_recipient_deposit = 15; + new_test_ext(genesis.build()).execute_with(|| { + // Register two parachains and open a channel between them. + register_parachain_with_balance(para_a, 100); + register_parachain_with_balance(para_b, 110); + run_to_block(5, Some(vec![4, 5])); + + // Start opening a channel a->b + Hrmp::init_open_channel(para_a, para_b, 2, 8).unwrap(); + assert_eq!(::Currency::free_balance(¶_a.into_account()), 80); + + // Cancel opening the channel + Hrmp::cancel_open_request(para_a, HrmpChannelId { sender: para_a, recipient: para_b }) + .unwrap(); + assert_eq!(::Currency::free_balance(¶_a.into_account()), 100); + + run_to_block(10, Some(vec![10])); + assert!(!channel_exists(para_a, para_b)); + Hrmp::assert_storage_consistency_exhaustive(); + }); +} diff --git a/runtime/parachains/src/initializer.rs b/runtime/parachains/src/initializer.rs index 123cfad2de0a..cbfdd84e58a5 100644 --- a/runtime/parachains/src/initializer.rs +++ b/runtime/parachains/src/initializer.rs @@ -34,6 +34,9 @@ use primitives::v1::{BlockNumber, ConsensusLog, SessionIndex, ValidatorId}; use scale_info::TypeInfo; use sp_std::prelude::*; +#[cfg(test)] +mod tests; + #[cfg(feature = "runtime-benchmarks")] mod benchmarking; @@ -328,138 +331,3 @@ impl OneSessionHandler for Pal fn on_disabled(_i: u32) {} } - -#[cfg(test)] -mod tests { - use super::*; - use crate::mock::{ - new_test_ext, Configuration, Dmp, Initializer, MockGenesisConfig, Paras, SessionInfo, - System, - }; - use primitives::v1::{HeadData, Id as ParaId}; - use test_helpers::dummy_validation_code; - - use frame_support::{ - assert_ok, - traits::{OnFinalize, OnInitialize}, - }; - - #[test] - fn session_0_is_instantly_applied() { - new_test_ext(Default::default()).execute_with(|| { - Initializer::on_new_session( - false, - 0, - Vec::new().into_iter(), - Some(Vec::new().into_iter()), - ); - - let v = ::BufferedSessionChanges::get(); - assert!(v.is_empty()); - - assert_eq!(SessionInfo::earliest_stored_session(), 0); - assert!(SessionInfo::session_info(0).is_some()); - }); - } - - #[test] - fn session_change_before_initialize_is_still_buffered_after() { - new_test_ext(Default::default()).execute_with(|| { - Initializer::on_new_session( - false, - 1, - Vec::new().into_iter(), - Some(Vec::new().into_iter()), - ); - - let now = System::block_number(); - Initializer::on_initialize(now); - - let v = ::BufferedSessionChanges::get(); - assert_eq!(v.len(), 1); - }); - } - - #[test] - fn session_change_applied_on_finalize() { - new_test_ext(Default::default()).execute_with(|| { - Initializer::on_initialize(1); - Initializer::on_new_session( - false, - 1, - Vec::new().into_iter(), - Some(Vec::new().into_iter()), - ); - - Initializer::on_finalize(1); - - assert!(::BufferedSessionChanges::get().is_empty()); - }); - } - - #[test] - fn sets_flag_on_initialize() { - new_test_ext(Default::default()).execute_with(|| { - Initializer::on_initialize(1); - - assert!(::HasInitialized::get().is_some()); - }) - } - - #[test] - fn clears_flag_on_finalize() { - new_test_ext(Default::default()).execute_with(|| { - Initializer::on_initialize(1); - Initializer::on_finalize(1); - - assert!(::HasInitialized::get().is_none()); - }) - } - - #[test] - fn scheduled_cleanup_performed() { - let a = ParaId::from(1312); - let b = ParaId::from(228); - let c = ParaId::from(123); - - let mock_genesis = crate::paras::ParaGenesisArgs { - parachain: true, - genesis_head: HeadData(vec![4, 5, 6]), - validation_code: dummy_validation_code(), - }; - - new_test_ext(MockGenesisConfig { - configuration: crate::configuration::GenesisConfig { - config: crate::configuration::HostConfiguration { - max_downward_message_size: 1024, - ..Default::default() - }, - }, - paras: crate::paras::GenesisConfig { - paras: vec![ - (a, mock_genesis.clone()), - (b, mock_genesis.clone()), - (c, mock_genesis.clone()), - ], - ..Default::default() - }, - ..Default::default() - }) - .execute_with(|| { - // enqueue downward messages to A, B and C. - assert_ok!(Dmp::queue_downward_message(&Configuration::config(), a, vec![1, 2, 3])); - assert_ok!(Dmp::queue_downward_message(&Configuration::config(), b, vec![4, 5, 6])); - assert_ok!(Dmp::queue_downward_message(&Configuration::config(), c, vec![7, 8, 9])); - - assert_ok!(Paras::schedule_para_cleanup(a)); - assert_ok!(Paras::schedule_para_cleanup(b)); - - // Apply session 2 in the future - Initializer::apply_new_session(2, vec![], vec![]); - - assert!(Dmp::dmq_contents(a).is_empty()); - assert!(Dmp::dmq_contents(b).is_empty()); - assert!(!Dmp::dmq_contents(c).is_empty()); - }); - } -} diff --git a/runtime/parachains/src/initializer/tests.rs b/runtime/parachains/src/initializer/tests.rs new file mode 100644 index 000000000000..6085e5f47168 --- /dev/null +++ b/runtime/parachains/src/initializer/tests.rs @@ -0,0 +1,131 @@ +// 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 super::*; +use crate::mock::{ + new_test_ext, Configuration, Dmp, Initializer, MockGenesisConfig, Paras, SessionInfo, System, +}; +use primitives::v1::{HeadData, Id as ParaId}; +use test_helpers::dummy_validation_code; + +use frame_support::{ + assert_ok, + traits::{OnFinalize, OnInitialize}, +}; + +#[test] +fn session_0_is_instantly_applied() { + new_test_ext(Default::default()).execute_with(|| { + Initializer::on_new_session(false, 0, Vec::new().into_iter(), Some(Vec::new().into_iter())); + + let v = ::BufferedSessionChanges::get(); + assert!(v.is_empty()); + + assert_eq!(SessionInfo::earliest_stored_session(), 0); + assert!(SessionInfo::session_info(0).is_some()); + }); +} + +#[test] +fn session_change_before_initialize_is_still_buffered_after() { + new_test_ext(Default::default()).execute_with(|| { + Initializer::on_new_session(false, 1, Vec::new().into_iter(), Some(Vec::new().into_iter())); + + let now = System::block_number(); + Initializer::on_initialize(now); + + let v = ::BufferedSessionChanges::get(); + assert_eq!(v.len(), 1); + }); +} + +#[test] +fn session_change_applied_on_finalize() { + new_test_ext(Default::default()).execute_with(|| { + Initializer::on_initialize(1); + Initializer::on_new_session(false, 1, Vec::new().into_iter(), Some(Vec::new().into_iter())); + + Initializer::on_finalize(1); + + assert!(::BufferedSessionChanges::get().is_empty()); + }); +} + +#[test] +fn sets_flag_on_initialize() { + new_test_ext(Default::default()).execute_with(|| { + Initializer::on_initialize(1); + + assert!(::HasInitialized::get().is_some()); + }) +} + +#[test] +fn clears_flag_on_finalize() { + new_test_ext(Default::default()).execute_with(|| { + Initializer::on_initialize(1); + Initializer::on_finalize(1); + + assert!(::HasInitialized::get().is_none()); + }) +} + +#[test] +fn scheduled_cleanup_performed() { + let a = ParaId::from(1312); + let b = ParaId::from(228); + let c = ParaId::from(123); + + let mock_genesis = crate::paras::ParaGenesisArgs { + parachain: true, + genesis_head: HeadData(vec![4, 5, 6]), + validation_code: dummy_validation_code(), + }; + + new_test_ext(MockGenesisConfig { + configuration: crate::configuration::GenesisConfig { + config: crate::configuration::HostConfiguration { + max_downward_message_size: 1024, + ..Default::default() + }, + }, + paras: crate::paras::GenesisConfig { + paras: vec![ + (a, mock_genesis.clone()), + (b, mock_genesis.clone()), + (c, mock_genesis.clone()), + ], + ..Default::default() + }, + ..Default::default() + }) + .execute_with(|| { + // enqueue downward messages to A, B and C. + assert_ok!(Dmp::queue_downward_message(&Configuration::config(), a, vec![1, 2, 3])); + assert_ok!(Dmp::queue_downward_message(&Configuration::config(), b, vec![4, 5, 6])); + assert_ok!(Dmp::queue_downward_message(&Configuration::config(), c, vec![7, 8, 9])); + + assert_ok!(Paras::schedule_para_cleanup(a)); + assert_ok!(Paras::schedule_para_cleanup(b)); + + // Apply session 2 in the future + Initializer::apply_new_session(2, vec![], vec![]); + + assert!(Dmp::dmq_contents(a).is_empty()); + assert!(Dmp::dmq_contents(b).is_empty()); + assert!(!Dmp::dmq_contents(c).is_empty()); + }); +} diff --git a/runtime/parachains/src/scheduler.rs b/runtime/parachains/src/scheduler.rs index 7b362322b04c..2753fe4e111b 100644 --- a/runtime/parachains/src/scheduler.rs +++ b/runtime/parachains/src/scheduler.rs @@ -48,6 +48,9 @@ use crate::{configuration, initializer::SessionChangeNotification, paras}; pub use pallet::*; +#[cfg(test)] +mod tests; + /// A queued parathread entry, pre-assigned to a core. #[derive(Encode, Decode, TypeInfo)] #[cfg_attr(test, derive(PartialEq, Debug))] @@ -760,1459 +763,3 @@ impl Pallet { }); } } - -#[cfg(test)] -mod tests { - use super::*; - - use frame_support::assert_ok; - use keyring::Sr25519Keyring; - use primitives::v1::{BlockNumber, CollatorId, SessionIndex, ValidatorId}; - - use crate::{ - configuration::HostConfiguration, - initializer::SessionChangeNotification, - mock::{ - new_test_ext, Configuration, MockGenesisConfig, Paras, ParasShared, Scheduler, System, - Test, - }, - paras::ParaGenesisArgs, - }; - - fn schedule_blank_para(id: ParaId, is_chain: bool) { - assert_ok!(Paras::schedule_para_initialize( - id, - ParaGenesisArgs { - genesis_head: Vec::new().into(), - validation_code: vec![1, 2, 3].into(), - parachain: is_chain, - } - )); - } - - fn run_to_block( - to: BlockNumber, - new_session: impl Fn(BlockNumber) -> Option>, - ) { - while System::block_number() < to { - let b = System::block_number(); - - Scheduler::initializer_finalize(); - Paras::initializer_finalize(b); - - if let Some(notification) = new_session(b + 1) { - let mut notification_with_session_index = notification; - // We will make every session change trigger an action queue. Normally this may require 2 or more session changes. - if notification_with_session_index.session_index == SessionIndex::default() { - notification_with_session_index.session_index = - ParasShared::scheduled_session(); - } - Paras::initializer_on_new_session(¬ification_with_session_index); - Scheduler::initializer_on_new_session(¬ification_with_session_index); - } - - System::on_finalize(b); - - System::on_initialize(b + 1); - System::set_block_number(b + 1); - - Paras::initializer_initialize(b + 1); - Scheduler::initializer_initialize(b + 1); - - // In the real runtime this is expected to be called by the `InclusionInherent` pallet. - Scheduler::clear(); - Scheduler::schedule(Vec::new(), b + 1); - } - } - - fn run_to_end_of_block( - to: BlockNumber, - new_session: impl Fn(BlockNumber) -> Option>, - ) { - run_to_block(to, &new_session); - - Scheduler::initializer_finalize(); - Paras::initializer_finalize(to); - - if let Some(notification) = new_session(to + 1) { - Paras::initializer_on_new_session(¬ification); - Scheduler::initializer_on_new_session(¬ification); - } - - System::on_finalize(to); - } - - fn default_config() -> HostConfiguration { - HostConfiguration { - parathread_cores: 3, - group_rotation_frequency: 10, - chain_availability_period: 3, - thread_availability_period: 5, - scheduling_lookahead: 2, - parathread_retries: 1, - pvf_checking_enabled: false, - // This field does not affect anything that scheduler does. However, `HostConfiguration` - // is still a subject to consistency test. It requires that `minimum_validation_upgrade_delay` - // is greater than `chain_availability_period` and `thread_availability_period`. - minimum_validation_upgrade_delay: 6, - ..Default::default() - } - } - - #[test] - fn add_parathread_claim_works() { - let genesis_config = MockGenesisConfig { - configuration: crate::configuration::GenesisConfig { - config: default_config(), - ..Default::default() - }, - ..Default::default() - }; - - let thread_id = ParaId::from(10); - let collator = CollatorId::from(Sr25519Keyring::Alice.public()); - - new_test_ext(genesis_config).execute_with(|| { - schedule_blank_para(thread_id, false); - - assert!(!Paras::is_parathread(thread_id)); - - run_to_block(10, |n| if n == 10 { Some(Default::default()) } else { None }); - - assert!(Paras::is_parathread(thread_id)); - - { - Scheduler::add_parathread_claim(ParathreadClaim(thread_id, collator.clone())); - let queue = ParathreadQueue::::get(); - assert_eq!(queue.next_core_offset, 1); - assert_eq!(queue.queue.len(), 1); - assert_eq!( - queue.queue[0], - QueuedParathread { - claim: ParathreadEntry { - claim: ParathreadClaim(thread_id, collator.clone()), - retries: 0, - }, - core_offset: 0, - } - ); - } - - // due to the index, completing claims are not allowed. - { - let collator2 = CollatorId::from(Sr25519Keyring::Bob.public()); - Scheduler::add_parathread_claim(ParathreadClaim(thread_id, collator2.clone())); - let queue = ParathreadQueue::::get(); - assert_eq!(queue.next_core_offset, 1); - assert_eq!(queue.queue.len(), 1); - assert_eq!( - queue.queue[0], - QueuedParathread { - claim: ParathreadEntry { - claim: ParathreadClaim(thread_id, collator.clone()), - retries: 0, - }, - core_offset: 0, - } - ); - } - - // claims on non-live parathreads have no effect. - { - let thread_id2 = ParaId::from(11); - Scheduler::add_parathread_claim(ParathreadClaim(thread_id2, collator.clone())); - let queue = ParathreadQueue::::get(); - assert_eq!(queue.next_core_offset, 1); - assert_eq!(queue.queue.len(), 1); - assert_eq!( - queue.queue[0], - QueuedParathread { - claim: ParathreadEntry { - claim: ParathreadClaim(thread_id, collator.clone()), - retries: 0, - }, - core_offset: 0, - } - ); - } - }) - } - - #[test] - fn cannot_add_claim_when_no_parathread_cores() { - let config = { - let mut config = default_config(); - config.parathread_cores = 0; - config - }; - let genesis_config = MockGenesisConfig { - configuration: crate::configuration::GenesisConfig { config, ..Default::default() }, - ..Default::default() - }; - - let thread_id = ParaId::from(10); - let collator = CollatorId::from(Sr25519Keyring::Alice.public()); - - new_test_ext(genesis_config).execute_with(|| { - schedule_blank_para(thread_id, false); - - assert!(!Paras::is_parathread(thread_id)); - - run_to_block(10, |n| if n == 10 { Some(Default::default()) } else { None }); - - assert!(Paras::is_parathread(thread_id)); - - Scheduler::add_parathread_claim(ParathreadClaim(thread_id, collator.clone())); - assert_eq!(ParathreadQueue::::get(), Default::default()); - }); - } - - #[test] - fn session_change_prunes_cores_beyond_retries_and_those_from_non_live_parathreads() { - let genesis_config = MockGenesisConfig { - configuration: crate::configuration::GenesisConfig { - config: default_config(), - ..Default::default() - }, - ..Default::default() - }; - let max_parathread_retries = default_config().parathread_retries; - - let thread_a = ParaId::from(1); - let thread_b = ParaId::from(2); - let thread_c = ParaId::from(3); - let thread_d = ParaId::from(4); - - let collator = CollatorId::from(Sr25519Keyring::Alice.public()); - - new_test_ext(genesis_config).execute_with(|| { - assert_eq!(Configuration::config(), default_config()); - - // threads a, b, and c will be live in next session, but not d. - { - schedule_blank_para(thread_a, false); - schedule_blank_para(thread_b, false); - schedule_blank_para(thread_c, false); - } - - // set up a queue as if `n_cores` was 4 and with some with many retries. - ParathreadQueue::::put({ - let mut queue = ParathreadClaimQueue::default(); - - // Will be pruned: too many retries. - queue.enqueue_entry( - ParathreadEntry { - claim: ParathreadClaim(thread_a, collator.clone()), - retries: max_parathread_retries + 1, - }, - 4, - ); - - // Will not be pruned. - queue.enqueue_entry( - ParathreadEntry { - claim: ParathreadClaim(thread_b, collator.clone()), - retries: max_parathread_retries, - }, - 4, - ); - - // Will not be pruned. - queue.enqueue_entry( - ParathreadEntry { - claim: ParathreadClaim(thread_c, collator.clone()), - retries: 0, - }, - 4, - ); - - // Will be pruned: not a live parathread. - queue.enqueue_entry( - ParathreadEntry { - claim: ParathreadClaim(thread_d, collator.clone()), - retries: 0, - }, - 4, - ); - - queue - }); - - ParathreadClaimIndex::::put(vec![thread_a, thread_b, thread_c, thread_d]); - - run_to_block(10, |b| match b { - 10 => Some(SessionChangeNotification { - new_config: Configuration::config(), - ..Default::default() - }), - _ => None, - }); - assert_eq!(Configuration::config(), default_config()); - - let queue = ParathreadQueue::::get(); - assert_eq!( - queue.queue, - vec![ - QueuedParathread { - claim: ParathreadEntry { - claim: ParathreadClaim(thread_b, collator.clone()), - retries: max_parathread_retries, - }, - core_offset: 0, - }, - QueuedParathread { - claim: ParathreadEntry { - claim: ParathreadClaim(thread_c, collator.clone()), - retries: 0, - }, - core_offset: 1, - }, - ] - ); - assert_eq!(queue.next_core_offset, 2); - - assert_eq!(ParathreadClaimIndex::::get(), vec![thread_b, thread_c]); - }) - } - - #[test] - fn session_change_shuffles_validators() { - let genesis_config = MockGenesisConfig { - configuration: crate::configuration::GenesisConfig { - config: default_config(), - ..Default::default() - }, - ..Default::default() - }; - - assert_eq!(default_config().parathread_cores, 3); - new_test_ext(genesis_config).execute_with(|| { - let chain_a = ParaId::from(1); - let chain_b = ParaId::from(2); - - // ensure that we have 5 groups by registering 2 parachains. - schedule_blank_para(chain_a, true); - schedule_blank_para(chain_b, true); - - run_to_block(1, |number| match number { - 1 => Some(SessionChangeNotification { - new_config: default_config(), - validators: vec![ - ValidatorId::from(Sr25519Keyring::Alice.public()), - ValidatorId::from(Sr25519Keyring::Bob.public()), - ValidatorId::from(Sr25519Keyring::Charlie.public()), - ValidatorId::from(Sr25519Keyring::Dave.public()), - ValidatorId::from(Sr25519Keyring::Eve.public()), - ValidatorId::from(Sr25519Keyring::Ferdie.public()), - ValidatorId::from(Sr25519Keyring::One.public()), - ], - random_seed: [99; 32], - ..Default::default() - }), - _ => None, - }); - - let groups = ValidatorGroups::::get(); - assert_eq!(groups.len(), 5); - - // first two groups have the overflow. - for i in 0..2 { - assert_eq!(groups[i].len(), 2); - } - - for i in 2..5 { - assert_eq!(groups[i].len(), 1); - } - }); - } - - #[test] - fn session_change_takes_only_max_per_core() { - let config = { - let mut config = default_config(); - config.parathread_cores = 0; - config.max_validators_per_core = Some(1); - config - }; - - let genesis_config = MockGenesisConfig { - configuration: crate::configuration::GenesisConfig { - config: config.clone(), - ..Default::default() - }, - ..Default::default() - }; - - new_test_ext(genesis_config).execute_with(|| { - let chain_a = ParaId::from(1); - let chain_b = ParaId::from(2); - let chain_c = ParaId::from(3); - - // ensure that we have 5 groups by registering 2 parachains. - schedule_blank_para(chain_a, true); - schedule_blank_para(chain_b, true); - schedule_blank_para(chain_c, false); - - run_to_block(1, |number| match number { - 1 => Some(SessionChangeNotification { - new_config: config.clone(), - validators: vec![ - ValidatorId::from(Sr25519Keyring::Alice.public()), - ValidatorId::from(Sr25519Keyring::Bob.public()), - ValidatorId::from(Sr25519Keyring::Charlie.public()), - ValidatorId::from(Sr25519Keyring::Dave.public()), - ValidatorId::from(Sr25519Keyring::Eve.public()), - ValidatorId::from(Sr25519Keyring::Ferdie.public()), - ValidatorId::from(Sr25519Keyring::One.public()), - ], - random_seed: [99; 32], - ..Default::default() - }), - _ => None, - }); - - let groups = ValidatorGroups::::get(); - assert_eq!(groups.len(), 7); - - // Every validator gets its own group, even though there are 2 paras. - for i in 0..7 { - assert_eq!(groups[i].len(), 1); - } - }); - } - - #[test] - fn schedule_schedules() { - let genesis_config = MockGenesisConfig { - configuration: crate::configuration::GenesisConfig { - config: default_config(), - ..Default::default() - }, - ..Default::default() - }; - - let chain_a = ParaId::from(1); - let chain_b = ParaId::from(2); - - let thread_a = ParaId::from(3); - let thread_b = ParaId::from(4); - let thread_c = ParaId::from(5); - - let collator = CollatorId::from(Sr25519Keyring::Alice.public()); - - new_test_ext(genesis_config).execute_with(|| { - assert_eq!(default_config().parathread_cores, 3); - - // register 2 parachains - schedule_blank_para(chain_a, true); - schedule_blank_para(chain_b, true); - - // and 3 parathreads - schedule_blank_para(thread_a, false); - schedule_blank_para(thread_b, false); - schedule_blank_para(thread_c, false); - - // start a new session to activate, 5 validators for 5 cores. - run_to_block(1, |number| match number { - 1 => Some(SessionChangeNotification { - new_config: default_config(), - validators: vec![ - ValidatorId::from(Sr25519Keyring::Alice.public()), - ValidatorId::from(Sr25519Keyring::Bob.public()), - ValidatorId::from(Sr25519Keyring::Charlie.public()), - ValidatorId::from(Sr25519Keyring::Dave.public()), - ValidatorId::from(Sr25519Keyring::Eve.public()), - ], - ..Default::default() - }), - _ => None, - }); - - { - let scheduled = Scheduler::scheduled(); - assert_eq!(scheduled.len(), 2); - - assert_eq!( - scheduled[0], - CoreAssignment { - core: CoreIndex(0), - para_id: chain_a, - kind: AssignmentKind::Parachain, - group_idx: GroupIndex(0), - } - ); - - assert_eq!( - scheduled[1], - CoreAssignment { - core: CoreIndex(1), - para_id: chain_b, - kind: AssignmentKind::Parachain, - group_idx: GroupIndex(1), - } - ); - } - - // add a couple of parathread claims. - Scheduler::add_parathread_claim(ParathreadClaim(thread_a, collator.clone())); - Scheduler::add_parathread_claim(ParathreadClaim(thread_c, collator.clone())); - - run_to_block(2, |_| None); - - { - let scheduled = Scheduler::scheduled(); - assert_eq!(scheduled.len(), 4); - - assert_eq!( - scheduled[0], - CoreAssignment { - core: CoreIndex(0), - para_id: chain_a, - kind: AssignmentKind::Parachain, - group_idx: GroupIndex(0), - } - ); - - assert_eq!( - scheduled[1], - CoreAssignment { - core: CoreIndex(1), - para_id: chain_b, - kind: AssignmentKind::Parachain, - group_idx: GroupIndex(1), - } - ); - - assert_eq!( - scheduled[2], - CoreAssignment { - core: CoreIndex(2), - para_id: thread_a, - kind: AssignmentKind::Parathread(collator.clone(), 0), - group_idx: GroupIndex(2), - } - ); - - assert_eq!( - scheduled[3], - CoreAssignment { - core: CoreIndex(3), - para_id: thread_c, - kind: AssignmentKind::Parathread(collator.clone(), 0), - group_idx: GroupIndex(3), - } - ); - } - }); - } - - #[test] - fn schedule_schedules_including_just_freed() { - let genesis_config = MockGenesisConfig { - configuration: crate::configuration::GenesisConfig { - config: default_config(), - ..Default::default() - }, - ..Default::default() - }; - - let chain_a = ParaId::from(1); - let chain_b = ParaId::from(2); - - let thread_a = ParaId::from(3); - let thread_b = ParaId::from(4); - let thread_c = ParaId::from(5); - let thread_d = ParaId::from(6); - let thread_e = ParaId::from(7); - - let collator = CollatorId::from(Sr25519Keyring::Alice.public()); - - new_test_ext(genesis_config).execute_with(|| { - assert_eq!(default_config().parathread_cores, 3); - - // register 2 parachains - schedule_blank_para(chain_a, true); - schedule_blank_para(chain_b, true); - - // and 5 parathreads - schedule_blank_para(thread_a, false); - schedule_blank_para(thread_b, false); - schedule_blank_para(thread_c, false); - schedule_blank_para(thread_d, false); - schedule_blank_para(thread_e, false); - - // start a new session to activate, 5 validators for 5 cores. - run_to_block(1, |number| match number { - 1 => Some(SessionChangeNotification { - new_config: default_config(), - validators: vec![ - ValidatorId::from(Sr25519Keyring::Alice.public()), - ValidatorId::from(Sr25519Keyring::Bob.public()), - ValidatorId::from(Sr25519Keyring::Charlie.public()), - ValidatorId::from(Sr25519Keyring::Dave.public()), - ValidatorId::from(Sr25519Keyring::Eve.public()), - ], - ..Default::default() - }), - _ => None, - }); - - // add a couple of parathread claims now that the parathreads are live. - Scheduler::add_parathread_claim(ParathreadClaim(thread_a, collator.clone())); - Scheduler::add_parathread_claim(ParathreadClaim(thread_c, collator.clone())); - - run_to_block(2, |_| None); - - assert_eq!(Scheduler::scheduled().len(), 4); - - // cores 0, 1, 2, and 3 should be occupied. mark them as such. - Scheduler::occupied(&[CoreIndex(0), CoreIndex(1), CoreIndex(2), CoreIndex(3)]); - - { - let cores = AvailabilityCores::::get(); - - assert!(cores[0].is_some()); - assert!(cores[1].is_some()); - assert!(cores[2].is_some()); - assert!(cores[3].is_some()); - assert!(cores[4].is_none()); - - assert!(Scheduler::scheduled().is_empty()); - } - - // add a couple more parathread claims - the claim on `b` will go to the 3rd parathread core (4) - // and the claim on `d` will go back to the 1st parathread core (2). The claim on `e` then - // will go for core `3`. - Scheduler::add_parathread_claim(ParathreadClaim(thread_b, collator.clone())); - Scheduler::add_parathread_claim(ParathreadClaim(thread_d, collator.clone())); - Scheduler::add_parathread_claim(ParathreadClaim(thread_e, collator.clone())); - - run_to_block(3, |_| None); - - { - let scheduled = Scheduler::scheduled(); - - // cores 0 and 1 are occupied by parachains. cores 2 and 3 are occupied by parathread - // claims. core 4 was free. - assert_eq!(scheduled.len(), 1); - assert_eq!( - scheduled[0], - CoreAssignment { - core: CoreIndex(4), - para_id: thread_b, - kind: AssignmentKind::Parathread(collator.clone(), 0), - group_idx: GroupIndex(4), - } - ); - } - - // now note that cores 0, 2, and 3 were freed. - Scheduler::schedule( - vec![ - (CoreIndex(0), FreedReason::Concluded), - (CoreIndex(2), FreedReason::Concluded), - (CoreIndex(3), FreedReason::TimedOut), // should go back on queue. - ], - 3, - ); - - { - let scheduled = Scheduler::scheduled(); - - // 1 thing scheduled before, + 3 cores freed. - assert_eq!(scheduled.len(), 4); - assert_eq!( - scheduled[0], - CoreAssignment { - core: CoreIndex(0), - para_id: chain_a, - kind: AssignmentKind::Parachain, - group_idx: GroupIndex(0), - } - ); - assert_eq!( - scheduled[1], - CoreAssignment { - core: CoreIndex(2), - para_id: thread_d, - kind: AssignmentKind::Parathread(collator.clone(), 0), - group_idx: GroupIndex(2), - } - ); - assert_eq!( - scheduled[2], - CoreAssignment { - core: CoreIndex(3), - para_id: thread_e, - kind: AssignmentKind::Parathread(collator.clone(), 0), - group_idx: GroupIndex(3), - } - ); - assert_eq!( - scheduled[3], - CoreAssignment { - core: CoreIndex(4), - para_id: thread_b, - kind: AssignmentKind::Parathread(collator.clone(), 0), - group_idx: GroupIndex(4), - } - ); - - // the prior claim on thread A concluded, but the claim on thread C was marked as - // timed out. - let index = ParathreadClaimIndex::::get(); - let parathread_queue = ParathreadQueue::::get(); - - // thread A claim should have been wiped, but thread C claim should remain. - assert_eq!(index, vec![thread_b, thread_c, thread_d, thread_e]); - - // Although C was descheduled, the core `4` was occupied so C goes back on the queue. - assert_eq!(parathread_queue.queue.len(), 1); - assert_eq!( - parathread_queue.queue[0], - QueuedParathread { - claim: ParathreadEntry { - claim: ParathreadClaim(thread_c, collator.clone()), - retries: 0, // retries not incremented by timeout - validators' fault. - }, - core_offset: 2, // reassigned to next core. thread_e claim was on offset 1. - } - ); - } - }); - } - - #[test] - fn schedule_clears_availability_cores() { - let genesis_config = MockGenesisConfig { - configuration: crate::configuration::GenesisConfig { - config: default_config(), - ..Default::default() - }, - ..Default::default() - }; - - let chain_a = ParaId::from(1); - let chain_b = ParaId::from(2); - let chain_c = ParaId::from(3); - - new_test_ext(genesis_config).execute_with(|| { - assert_eq!(default_config().parathread_cores, 3); - - // register 3 parachains - schedule_blank_para(chain_a, true); - schedule_blank_para(chain_b, true); - schedule_blank_para(chain_c, true); - - // start a new session to activate, 5 validators for 5 cores. - run_to_block(1, |number| match number { - 1 => Some(SessionChangeNotification { - new_config: default_config(), - validators: vec![ - ValidatorId::from(Sr25519Keyring::Alice.public()), - ValidatorId::from(Sr25519Keyring::Bob.public()), - ValidatorId::from(Sr25519Keyring::Charlie.public()), - ValidatorId::from(Sr25519Keyring::Dave.public()), - ValidatorId::from(Sr25519Keyring::Eve.public()), - ], - ..Default::default() - }), - _ => None, - }); - - run_to_block(2, |_| None); - - assert_eq!(Scheduler::scheduled().len(), 3); - - // cores 0, 1, and 2 should be occupied. mark them as such. - Scheduler::occupied(&[CoreIndex(0), CoreIndex(1), CoreIndex(2)]); - - { - let cores = AvailabilityCores::::get(); - - assert!(cores[0].is_some()); - assert!(cores[1].is_some()); - assert!(cores[2].is_some()); - - assert!(Scheduler::scheduled().is_empty()); - } - - run_to_block(3, |_| None); - - // now note that cores 0 and 2 were freed. - Scheduler::schedule( - vec![ - (CoreIndex(0), FreedReason::Concluded), - (CoreIndex(2), FreedReason::Concluded), - ], - 3, - ); - - { - let scheduled = Scheduler::scheduled(); - - assert_eq!(scheduled.len(), 2); - assert_eq!( - scheduled[0], - CoreAssignment { - core: CoreIndex(0), - para_id: chain_a, - kind: AssignmentKind::Parachain, - group_idx: GroupIndex(0), - } - ); - assert_eq!( - scheduled[1], - CoreAssignment { - core: CoreIndex(2), - para_id: chain_c, - kind: AssignmentKind::Parachain, - group_idx: GroupIndex(2), - } - ); - - // The freed cores should be `None` in `AvailabilityCores`. - let cores = AvailabilityCores::::get(); - assert!(cores[0].is_none()); - assert!(cores[2].is_none()); - } - }); - } - - #[test] - fn schedule_rotates_groups() { - let config = { - let mut config = default_config(); - - // make sure parathread requests don't retry-out - config.parathread_retries = config.group_rotation_frequency * 3; - config.parathread_cores = 2; - config - }; - - let rotation_frequency = config.group_rotation_frequency; - let parathread_cores = config.parathread_cores; - - let genesis_config = MockGenesisConfig { - configuration: crate::configuration::GenesisConfig { - config: config.clone(), - ..Default::default() - }, - ..Default::default() - }; - - let thread_a = ParaId::from(1); - let thread_b = ParaId::from(2); - - let collator = CollatorId::from(Sr25519Keyring::Alice.public()); - - new_test_ext(genesis_config).execute_with(|| { - assert_eq!(default_config().parathread_cores, 3); - - schedule_blank_para(thread_a, false); - schedule_blank_para(thread_b, false); - - // start a new session to activate, 5 validators for 5 cores. - run_to_block(1, |number| match number { - 1 => Some(SessionChangeNotification { - new_config: config.clone(), - validators: vec![ - ValidatorId::from(Sr25519Keyring::Alice.public()), - ValidatorId::from(Sr25519Keyring::Eve.public()), - ], - ..Default::default() - }), - _ => None, - }); - - let session_start_block = ::SessionStartBlock::get(); - assert_eq!(session_start_block, 1); - - Scheduler::add_parathread_claim(ParathreadClaim(thread_a, collator.clone())); - Scheduler::add_parathread_claim(ParathreadClaim(thread_b, collator.clone())); - - run_to_block(2, |_| None); - - let assert_groups_rotated = |rotations: u32| { - let scheduled = Scheduler::scheduled(); - assert_eq!(scheduled.len(), 2); - assert_eq!( - scheduled[0].group_idx, - GroupIndex((0u32 + rotations) % parathread_cores) - ); - assert_eq!( - scheduled[1].group_idx, - GroupIndex((1u32 + rotations) % parathread_cores) - ); - }; - - assert_groups_rotated(0); - - // one block before first rotation. - run_to_block(rotation_frequency, |_| None); - - assert_groups_rotated(0); - - // first rotation. - run_to_block(rotation_frequency + 1, |_| None); - assert_groups_rotated(1); - - // one block before second rotation. - run_to_block(rotation_frequency * 2, |_| None); - assert_groups_rotated(1); - - // second rotation. - run_to_block(rotation_frequency * 2 + 1, |_| None); - assert_groups_rotated(2); - }); - } - - #[test] - fn parathread_claims_are_pruned_after_retries() { - let max_retries = default_config().parathread_retries; - - let genesis_config = MockGenesisConfig { - configuration: crate::configuration::GenesisConfig { - config: default_config(), - ..Default::default() - }, - ..Default::default() - }; - - let thread_a = ParaId::from(1); - let thread_b = ParaId::from(2); - - let collator = CollatorId::from(Sr25519Keyring::Alice.public()); - - new_test_ext(genesis_config).execute_with(|| { - assert_eq!(default_config().parathread_cores, 3); - - schedule_blank_para(thread_a, false); - schedule_blank_para(thread_b, false); - - // start a new session to activate, 5 validators for 5 cores. - run_to_block(1, |number| match number { - 1 => Some(SessionChangeNotification { - new_config: default_config(), - validators: vec![ - ValidatorId::from(Sr25519Keyring::Alice.public()), - ValidatorId::from(Sr25519Keyring::Eve.public()), - ], - ..Default::default() - }), - _ => None, - }); - - Scheduler::add_parathread_claim(ParathreadClaim(thread_a, collator.clone())); - Scheduler::add_parathread_claim(ParathreadClaim(thread_b, collator.clone())); - - run_to_block(2, |_| None); - assert_eq!(Scheduler::scheduled().len(), 2); - - run_to_block(2 + max_retries, |_| None); - assert_eq!(Scheduler::scheduled().len(), 2); - - run_to_block(2 + max_retries + 1, |_| None); - assert_eq!(Scheduler::scheduled().len(), 0); - }); - } - - #[test] - fn availability_predicate_works() { - let genesis_config = MockGenesisConfig { - configuration: crate::configuration::GenesisConfig { - config: default_config(), - ..Default::default() - }, - ..Default::default() - }; - - let HostConfiguration { - group_rotation_frequency, - chain_availability_period, - thread_availability_period, - .. - } = default_config(); - let collator = CollatorId::from(Sr25519Keyring::Alice.public()); - - assert!( - chain_availability_period < thread_availability_period && - thread_availability_period < group_rotation_frequency - ); - - let chain_a = ParaId::from(1); - let thread_a = ParaId::from(2); - - new_test_ext(genesis_config).execute_with(|| { - schedule_blank_para(chain_a, true); - schedule_blank_para(thread_a, false); - - // start a new session with our chain & thread registered. - run_to_block(1, |number| match number { - 1 => Some(SessionChangeNotification { - new_config: default_config(), - validators: vec![ - ValidatorId::from(Sr25519Keyring::Alice.public()), - ValidatorId::from(Sr25519Keyring::Bob.public()), - ValidatorId::from(Sr25519Keyring::Charlie.public()), - ValidatorId::from(Sr25519Keyring::Dave.public()), - ValidatorId::from(Sr25519Keyring::Eve.public()), - ], - ..Default::default() - }), - _ => None, - }); - - // assign some availability cores. - { - AvailabilityCores::::mutate(|cores| { - cores[0] = Some(CoreOccupied::Parachain); - cores[1] = Some(CoreOccupied::Parathread(ParathreadEntry { - claim: ParathreadClaim(thread_a, collator), - retries: 0, - })) - }); - } - - run_to_block(1 + thread_availability_period, |_| None); - assert!(Scheduler::availability_timeout_predicate().is_none()); - - run_to_block(1 + group_rotation_frequency, |_| None); - - { - let pred = Scheduler::availability_timeout_predicate() - .expect("predicate exists recently after rotation"); - - let now = System::block_number(); - let would_be_timed_out = now - thread_availability_period; - for i in 0..AvailabilityCores::::get().len() { - // returns true for unoccupied cores. - // And can time out both threads and chains at this stage. - assert!(pred(CoreIndex(i as u32), would_be_timed_out)); - } - - assert!(!pred(CoreIndex(0), now)); // assigned: chain - assert!(!pred(CoreIndex(1), now)); // assigned: thread - assert!(pred(CoreIndex(2), now)); - - // check the tighter bound on chains vs threads. - assert!(pred(CoreIndex(0), now - chain_availability_period)); - assert!(!pred(CoreIndex(1), now - chain_availability_period)); - - // check the threshold is exact. - assert!(!pred(CoreIndex(0), now - chain_availability_period + 1)); - assert!(!pred(CoreIndex(1), now - thread_availability_period + 1)); - } - - run_to_block(1 + group_rotation_frequency + chain_availability_period, |_| None); - - { - let pred = Scheduler::availability_timeout_predicate() - .expect("predicate exists recently after rotation"); - - let would_be_timed_out = System::block_number() - thread_availability_period; - - assert!(!pred(CoreIndex(0), would_be_timed_out)); // chains can't be timed out now. - assert!(pred(CoreIndex(1), would_be_timed_out)); // but threads can. - } - - run_to_block(1 + group_rotation_frequency + thread_availability_period, |_| None); - - assert!(Scheduler::availability_timeout_predicate().is_none()); - }); - } - - #[test] - fn next_up_on_available_uses_next_scheduled_or_none_for_thread() { - let mut config = default_config(); - config.parathread_cores = 1; - - let genesis_config = MockGenesisConfig { - configuration: crate::configuration::GenesisConfig { - config: config.clone(), - ..Default::default() - }, - ..Default::default() - }; - - let thread_a = ParaId::from(1); - let thread_b = ParaId::from(2); - - let collator = CollatorId::from(Sr25519Keyring::Alice.public()); - - new_test_ext(genesis_config).execute_with(|| { - schedule_blank_para(thread_a, false); - schedule_blank_para(thread_b, false); - - // start a new session to activate, 5 validators for 5 cores. - run_to_block(1, |number| match number { - 1 => Some(SessionChangeNotification { - new_config: config.clone(), - validators: vec![ - ValidatorId::from(Sr25519Keyring::Alice.public()), - ValidatorId::from(Sr25519Keyring::Eve.public()), - ], - ..Default::default() - }), - _ => None, - }); - - let thread_claim_a = ParathreadClaim(thread_a, collator.clone()); - let thread_claim_b = ParathreadClaim(thread_b, collator.clone()); - - Scheduler::add_parathread_claim(thread_claim_a.clone()); - - run_to_block(2, |_| None); - - { - assert_eq!(Scheduler::scheduled().len(), 1); - assert_eq!(Scheduler::availability_cores().len(), 1); - - Scheduler::occupied(&[CoreIndex(0)]); - - let cores = Scheduler::availability_cores(); - match cores[0].as_ref().unwrap() { - CoreOccupied::Parathread(entry) => assert_eq!(entry.claim, thread_claim_a), - _ => panic!("with no chains, only core should be a thread core"), - } - - assert!(Scheduler::next_up_on_available(CoreIndex(0)).is_none()); - - Scheduler::add_parathread_claim(thread_claim_b); - - let queue = ParathreadQueue::::get(); - assert_eq!( - queue.get_next_on_core(0).unwrap().claim, - ParathreadClaim(thread_b, collator.clone()), - ); - - assert_eq!( - Scheduler::next_up_on_available(CoreIndex(0)).unwrap(), - ScheduledCore { para_id: thread_b, collator: Some(collator.clone()) } - ); - } - }); - } - - #[test] - fn next_up_on_time_out_reuses_claim_if_nothing_queued() { - let mut config = default_config(); - config.parathread_cores = 1; - - let genesis_config = MockGenesisConfig { - configuration: crate::configuration::GenesisConfig { - config: config.clone(), - ..Default::default() - }, - ..Default::default() - }; - - let thread_a = ParaId::from(1); - let thread_b = ParaId::from(2); - - let collator = CollatorId::from(Sr25519Keyring::Alice.public()); - - new_test_ext(genesis_config).execute_with(|| { - schedule_blank_para(thread_a, false); - schedule_blank_para(thread_b, false); - - // start a new session to activate, 5 validators for 5 cores. - run_to_block(1, |number| match number { - 1 => Some(SessionChangeNotification { - new_config: config.clone(), - validators: vec![ - ValidatorId::from(Sr25519Keyring::Alice.public()), - ValidatorId::from(Sr25519Keyring::Eve.public()), - ], - ..Default::default() - }), - _ => None, - }); - - let thread_claim_a = ParathreadClaim(thread_a, collator.clone()); - let thread_claim_b = ParathreadClaim(thread_b, collator.clone()); - - Scheduler::add_parathread_claim(thread_claim_a.clone()); - - run_to_block(2, |_| None); - - { - assert_eq!(Scheduler::scheduled().len(), 1); - assert_eq!(Scheduler::availability_cores().len(), 1); - - Scheduler::occupied(&[CoreIndex(0)]); - - let cores = Scheduler::availability_cores(); - match cores[0].as_ref().unwrap() { - CoreOccupied::Parathread(entry) => assert_eq!(entry.claim, thread_claim_a), - _ => panic!("with no chains, only core should be a thread core"), - } - - let queue = ParathreadQueue::::get(); - assert!(queue.get_next_on_core(0).is_none()); - assert_eq!( - Scheduler::next_up_on_time_out(CoreIndex(0)).unwrap(), - ScheduledCore { para_id: thread_a, collator: Some(collator.clone()) } - ); - - Scheduler::add_parathread_claim(thread_claim_b); - - let queue = ParathreadQueue::::get(); - assert_eq!( - queue.get_next_on_core(0).unwrap().claim, - ParathreadClaim(thread_b, collator.clone()), - ); - - // Now that there is an earlier next-up, we use that. - assert_eq!( - Scheduler::next_up_on_available(CoreIndex(0)).unwrap(), - ScheduledCore { para_id: thread_b, collator: Some(collator.clone()) } - ); - } - }); - } - - #[test] - fn next_up_on_available_is_parachain_always() { - let mut config = default_config(); - config.parathread_cores = 0; - - let genesis_config = MockGenesisConfig { - configuration: crate::configuration::GenesisConfig { - config: config.clone(), - ..Default::default() - }, - ..Default::default() - }; - - let chain_a = ParaId::from(1); - - new_test_ext(genesis_config).execute_with(|| { - schedule_blank_para(chain_a, true); - - // start a new session to activate, 5 validators for 5 cores. - run_to_block(1, |number| match number { - 1 => Some(SessionChangeNotification { - new_config: config.clone(), - validators: vec![ - ValidatorId::from(Sr25519Keyring::Alice.public()), - ValidatorId::from(Sr25519Keyring::Eve.public()), - ], - ..Default::default() - }), - _ => None, - }); - - run_to_block(2, |_| None); - - { - assert_eq!(Scheduler::scheduled().len(), 1); - assert_eq!(Scheduler::availability_cores().len(), 1); - - Scheduler::occupied(&[CoreIndex(0)]); - - let cores = Scheduler::availability_cores(); - match cores[0].as_ref().unwrap() { - CoreOccupied::Parachain => {}, - _ => panic!("with no threads, only core should be a chain core"), - } - - // Now that there is an earlier next-up, we use that. - assert_eq!( - Scheduler::next_up_on_available(CoreIndex(0)).unwrap(), - ScheduledCore { para_id: chain_a, collator: None } - ); - } - }); - } - - #[test] - fn next_up_on_time_out_is_parachain_always() { - let mut config = default_config(); - config.parathread_cores = 0; - - let genesis_config = MockGenesisConfig { - configuration: crate::configuration::GenesisConfig { - config: config.clone(), - ..Default::default() - }, - ..Default::default() - }; - - let chain_a = ParaId::from(1); - - new_test_ext(genesis_config).execute_with(|| { - schedule_blank_para(chain_a, true); - - // start a new session to activate, 5 validators for 5 cores. - run_to_block(1, |number| match number { - 1 => Some(SessionChangeNotification { - new_config: config.clone(), - validators: vec![ - ValidatorId::from(Sr25519Keyring::Alice.public()), - ValidatorId::from(Sr25519Keyring::Eve.public()), - ], - ..Default::default() - }), - _ => None, - }); - - run_to_block(2, |_| None); - - { - assert_eq!(Scheduler::scheduled().len(), 1); - assert_eq!(Scheduler::availability_cores().len(), 1); - - Scheduler::occupied(&[CoreIndex(0)]); - - let cores = Scheduler::availability_cores(); - match cores[0].as_ref().unwrap() { - CoreOccupied::Parachain => {}, - _ => panic!("with no threads, only core should be a chain core"), - } - - // Now that there is an earlier next-up, we use that. - assert_eq!( - Scheduler::next_up_on_available(CoreIndex(0)).unwrap(), - ScheduledCore { para_id: chain_a, collator: None } - ); - } - }); - } - - #[test] - fn session_change_requires_reschedule_dropping_removed_paras() { - let genesis_config = MockGenesisConfig { - configuration: crate::configuration::GenesisConfig { - config: default_config(), - ..Default::default() - }, - ..Default::default() - }; - - assert_eq!(default_config().parathread_cores, 3); - new_test_ext(genesis_config).execute_with(|| { - let chain_a = ParaId::from(1); - let chain_b = ParaId::from(2); - - // ensure that we have 5 groups by registering 2 parachains. - schedule_blank_para(chain_a, true); - schedule_blank_para(chain_b, true); - - run_to_block(1, |number| match number { - 1 => Some(SessionChangeNotification { - new_config: default_config(), - validators: vec![ - ValidatorId::from(Sr25519Keyring::Alice.public()), - ValidatorId::from(Sr25519Keyring::Bob.public()), - ValidatorId::from(Sr25519Keyring::Charlie.public()), - ValidatorId::from(Sr25519Keyring::Dave.public()), - ValidatorId::from(Sr25519Keyring::Eve.public()), - ValidatorId::from(Sr25519Keyring::Ferdie.public()), - ValidatorId::from(Sr25519Keyring::One.public()), - ], - random_seed: [99; 32], - ..Default::default() - }), - _ => None, - }); - - assert_eq!(Scheduler::scheduled().len(), 2); - - let groups = ValidatorGroups::::get(); - assert_eq!(groups.len(), 5); - - assert_ok!(Paras::schedule_para_cleanup(chain_b)); - - run_to_end_of_block(2, |number| match number { - 2 => Some(SessionChangeNotification { - new_config: default_config(), - validators: vec![ - ValidatorId::from(Sr25519Keyring::Alice.public()), - ValidatorId::from(Sr25519Keyring::Bob.public()), - ValidatorId::from(Sr25519Keyring::Charlie.public()), - ValidatorId::from(Sr25519Keyring::Dave.public()), - ValidatorId::from(Sr25519Keyring::Eve.public()), - ValidatorId::from(Sr25519Keyring::Ferdie.public()), - ValidatorId::from(Sr25519Keyring::One.public()), - ], - random_seed: [99; 32], - ..Default::default() - }), - _ => None, - }); - - Scheduler::clear(); - Scheduler::schedule(Vec::new(), 3); - - assert_eq!( - Scheduler::scheduled(), - vec![CoreAssignment { - core: CoreIndex(0), - para_id: chain_a, - kind: AssignmentKind::Parachain, - group_idx: GroupIndex(0), - }], - ); - }); - } - - #[test] - fn parathread_claims_are_pruned_after_deregistration() { - let genesis_config = MockGenesisConfig { - configuration: crate::configuration::GenesisConfig { - config: default_config(), - ..Default::default() - }, - ..Default::default() - }; - - let thread_a = ParaId::from(1); - let thread_b = ParaId::from(2); - - let collator = CollatorId::from(Sr25519Keyring::Alice.public()); - - new_test_ext(genesis_config).execute_with(|| { - assert_eq!(default_config().parathread_cores, 3); - - schedule_blank_para(thread_a, false); - schedule_blank_para(thread_b, false); - - // start a new session to activate, 5 validators for 5 cores. - run_to_block(1, |number| match number { - 1 => Some(SessionChangeNotification { - new_config: default_config(), - validators: vec![ - ValidatorId::from(Sr25519Keyring::Alice.public()), - ValidatorId::from(Sr25519Keyring::Eve.public()), - ], - ..Default::default() - }), - _ => None, - }); - - Scheduler::add_parathread_claim(ParathreadClaim(thread_a, collator.clone())); - Scheduler::add_parathread_claim(ParathreadClaim(thread_b, collator.clone())); - - run_to_block(2, |_| None); - assert_eq!(Scheduler::scheduled().len(), 2); - - assert_ok!(Paras::schedule_para_cleanup(thread_a)); - - // start a new session to activate, 5 validators for 5 cores. - run_to_block(3, |number| match number { - 3 => Some(SessionChangeNotification { - new_config: default_config(), - validators: vec![ - ValidatorId::from(Sr25519Keyring::Alice.public()), - ValidatorId::from(Sr25519Keyring::Eve.public()), - ], - ..Default::default() - }), - _ => None, - }); - - assert_eq!(Scheduler::scheduled().len(), 1); - }); - } -} diff --git a/runtime/parachains/src/scheduler/tests.rs b/runtime/parachains/src/scheduler/tests.rs new file mode 100644 index 000000000000..234c1833d9f0 --- /dev/null +++ b/runtime/parachains/src/scheduler/tests.rs @@ -0,0 +1,1451 @@ +// 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 super::*; + +use frame_support::assert_ok; +use keyring::Sr25519Keyring; +use primitives::v1::{BlockNumber, CollatorId, SessionIndex, ValidatorId}; + +use crate::{ + configuration::HostConfiguration, + initializer::SessionChangeNotification, + mock::{ + new_test_ext, Configuration, MockGenesisConfig, Paras, ParasShared, Scheduler, System, Test, + }, + paras::ParaGenesisArgs, +}; + +fn schedule_blank_para(id: ParaId, is_chain: bool) { + assert_ok!(Paras::schedule_para_initialize( + id, + ParaGenesisArgs { + genesis_head: Vec::new().into(), + validation_code: vec![1, 2, 3].into(), + parachain: is_chain, + } + )); +} + +fn run_to_block( + to: BlockNumber, + new_session: impl Fn(BlockNumber) -> Option>, +) { + while System::block_number() < to { + let b = System::block_number(); + + Scheduler::initializer_finalize(); + Paras::initializer_finalize(b); + + if let Some(notification) = new_session(b + 1) { + let mut notification_with_session_index = notification; + // We will make every session change trigger an action queue. Normally this may require 2 or more session changes. + if notification_with_session_index.session_index == SessionIndex::default() { + notification_with_session_index.session_index = ParasShared::scheduled_session(); + } + Paras::initializer_on_new_session(¬ification_with_session_index); + Scheduler::initializer_on_new_session(¬ification_with_session_index); + } + + System::on_finalize(b); + + System::on_initialize(b + 1); + System::set_block_number(b + 1); + + Paras::initializer_initialize(b + 1); + Scheduler::initializer_initialize(b + 1); + + // In the real runtime this is expected to be called by the `InclusionInherent` pallet. + Scheduler::clear(); + Scheduler::schedule(Vec::new(), b + 1); + } +} + +fn run_to_end_of_block( + to: BlockNumber, + new_session: impl Fn(BlockNumber) -> Option>, +) { + run_to_block(to, &new_session); + + Scheduler::initializer_finalize(); + Paras::initializer_finalize(to); + + if let Some(notification) = new_session(to + 1) { + Paras::initializer_on_new_session(¬ification); + Scheduler::initializer_on_new_session(¬ification); + } + + System::on_finalize(to); +} + +fn default_config() -> HostConfiguration { + HostConfiguration { + parathread_cores: 3, + group_rotation_frequency: 10, + chain_availability_period: 3, + thread_availability_period: 5, + scheduling_lookahead: 2, + parathread_retries: 1, + pvf_checking_enabled: false, + // This field does not affect anything that scheduler does. However, `HostConfiguration` + // is still a subject to consistency test. It requires that `minimum_validation_upgrade_delay` + // is greater than `chain_availability_period` and `thread_availability_period`. + minimum_validation_upgrade_delay: 6, + ..Default::default() + } +} + +#[test] +fn add_parathread_claim_works() { + let genesis_config = MockGenesisConfig { + configuration: crate::configuration::GenesisConfig { + config: default_config(), + ..Default::default() + }, + ..Default::default() + }; + + let thread_id = ParaId::from(10); + let collator = CollatorId::from(Sr25519Keyring::Alice.public()); + + new_test_ext(genesis_config).execute_with(|| { + schedule_blank_para(thread_id, false); + + assert!(!Paras::is_parathread(thread_id)); + + run_to_block(10, |n| if n == 10 { Some(Default::default()) } else { None }); + + assert!(Paras::is_parathread(thread_id)); + + { + Scheduler::add_parathread_claim(ParathreadClaim(thread_id, collator.clone())); + let queue = ParathreadQueue::::get(); + assert_eq!(queue.next_core_offset, 1); + assert_eq!(queue.queue.len(), 1); + assert_eq!( + queue.queue[0], + QueuedParathread { + claim: ParathreadEntry { + claim: ParathreadClaim(thread_id, collator.clone()), + retries: 0, + }, + core_offset: 0, + } + ); + } + + // due to the index, completing claims are not allowed. + { + let collator2 = CollatorId::from(Sr25519Keyring::Bob.public()); + Scheduler::add_parathread_claim(ParathreadClaim(thread_id, collator2.clone())); + let queue = ParathreadQueue::::get(); + assert_eq!(queue.next_core_offset, 1); + assert_eq!(queue.queue.len(), 1); + assert_eq!( + queue.queue[0], + QueuedParathread { + claim: ParathreadEntry { + claim: ParathreadClaim(thread_id, collator.clone()), + retries: 0, + }, + core_offset: 0, + } + ); + } + + // claims on non-live parathreads have no effect. + { + let thread_id2 = ParaId::from(11); + Scheduler::add_parathread_claim(ParathreadClaim(thread_id2, collator.clone())); + let queue = ParathreadQueue::::get(); + assert_eq!(queue.next_core_offset, 1); + assert_eq!(queue.queue.len(), 1); + assert_eq!( + queue.queue[0], + QueuedParathread { + claim: ParathreadEntry { + claim: ParathreadClaim(thread_id, collator.clone()), + retries: 0, + }, + core_offset: 0, + } + ); + } + }) +} + +#[test] +fn cannot_add_claim_when_no_parathread_cores() { + let config = { + let mut config = default_config(); + config.parathread_cores = 0; + config + }; + let genesis_config = MockGenesisConfig { + configuration: crate::configuration::GenesisConfig { config, ..Default::default() }, + ..Default::default() + }; + + let thread_id = ParaId::from(10); + let collator = CollatorId::from(Sr25519Keyring::Alice.public()); + + new_test_ext(genesis_config).execute_with(|| { + schedule_blank_para(thread_id, false); + + assert!(!Paras::is_parathread(thread_id)); + + run_to_block(10, |n| if n == 10 { Some(Default::default()) } else { None }); + + assert!(Paras::is_parathread(thread_id)); + + Scheduler::add_parathread_claim(ParathreadClaim(thread_id, collator.clone())); + assert_eq!(ParathreadQueue::::get(), Default::default()); + }); +} + +#[test] +fn session_change_prunes_cores_beyond_retries_and_those_from_non_live_parathreads() { + let genesis_config = MockGenesisConfig { + configuration: crate::configuration::GenesisConfig { + config: default_config(), + ..Default::default() + }, + ..Default::default() + }; + let max_parathread_retries = default_config().parathread_retries; + + let thread_a = ParaId::from(1); + let thread_b = ParaId::from(2); + let thread_c = ParaId::from(3); + let thread_d = ParaId::from(4); + + let collator = CollatorId::from(Sr25519Keyring::Alice.public()); + + new_test_ext(genesis_config).execute_with(|| { + assert_eq!(Configuration::config(), default_config()); + + // threads a, b, and c will be live in next session, but not d. + { + schedule_blank_para(thread_a, false); + schedule_blank_para(thread_b, false); + schedule_blank_para(thread_c, false); + } + + // set up a queue as if `n_cores` was 4 and with some with many retries. + ParathreadQueue::::put({ + let mut queue = ParathreadClaimQueue::default(); + + // Will be pruned: too many retries. + queue.enqueue_entry( + ParathreadEntry { + claim: ParathreadClaim(thread_a, collator.clone()), + retries: max_parathread_retries + 1, + }, + 4, + ); + + // Will not be pruned. + queue.enqueue_entry( + ParathreadEntry { + claim: ParathreadClaim(thread_b, collator.clone()), + retries: max_parathread_retries, + }, + 4, + ); + + // Will not be pruned. + queue.enqueue_entry( + ParathreadEntry { claim: ParathreadClaim(thread_c, collator.clone()), retries: 0 }, + 4, + ); + + // Will be pruned: not a live parathread. + queue.enqueue_entry( + ParathreadEntry { claim: ParathreadClaim(thread_d, collator.clone()), retries: 0 }, + 4, + ); + + queue + }); + + ParathreadClaimIndex::::put(vec![thread_a, thread_b, thread_c, thread_d]); + + run_to_block(10, |b| match b { + 10 => Some(SessionChangeNotification { + new_config: Configuration::config(), + ..Default::default() + }), + _ => None, + }); + assert_eq!(Configuration::config(), default_config()); + + let queue = ParathreadQueue::::get(); + assert_eq!( + queue.queue, + vec![ + QueuedParathread { + claim: ParathreadEntry { + claim: ParathreadClaim(thread_b, collator.clone()), + retries: max_parathread_retries, + }, + core_offset: 0, + }, + QueuedParathread { + claim: ParathreadEntry { + claim: ParathreadClaim(thread_c, collator.clone()), + retries: 0, + }, + core_offset: 1, + }, + ] + ); + assert_eq!(queue.next_core_offset, 2); + + assert_eq!(ParathreadClaimIndex::::get(), vec![thread_b, thread_c]); + }) +} + +#[test] +fn session_change_shuffles_validators() { + let genesis_config = MockGenesisConfig { + configuration: crate::configuration::GenesisConfig { + config: default_config(), + ..Default::default() + }, + ..Default::default() + }; + + assert_eq!(default_config().parathread_cores, 3); + new_test_ext(genesis_config).execute_with(|| { + let chain_a = ParaId::from(1); + let chain_b = ParaId::from(2); + + // ensure that we have 5 groups by registering 2 parachains. + schedule_blank_para(chain_a, true); + schedule_blank_para(chain_b, true); + + run_to_block(1, |number| match number { + 1 => Some(SessionChangeNotification { + new_config: default_config(), + validators: vec![ + ValidatorId::from(Sr25519Keyring::Alice.public()), + ValidatorId::from(Sr25519Keyring::Bob.public()), + ValidatorId::from(Sr25519Keyring::Charlie.public()), + ValidatorId::from(Sr25519Keyring::Dave.public()), + ValidatorId::from(Sr25519Keyring::Eve.public()), + ValidatorId::from(Sr25519Keyring::Ferdie.public()), + ValidatorId::from(Sr25519Keyring::One.public()), + ], + random_seed: [99; 32], + ..Default::default() + }), + _ => None, + }); + + let groups = ValidatorGroups::::get(); + assert_eq!(groups.len(), 5); + + // first two groups have the overflow. + for i in 0..2 { + assert_eq!(groups[i].len(), 2); + } + + for i in 2..5 { + assert_eq!(groups[i].len(), 1); + } + }); +} + +#[test] +fn session_change_takes_only_max_per_core() { + let config = { + let mut config = default_config(); + config.parathread_cores = 0; + config.max_validators_per_core = Some(1); + config + }; + + let genesis_config = MockGenesisConfig { + configuration: crate::configuration::GenesisConfig { + config: config.clone(), + ..Default::default() + }, + ..Default::default() + }; + + new_test_ext(genesis_config).execute_with(|| { + let chain_a = ParaId::from(1); + let chain_b = ParaId::from(2); + let chain_c = ParaId::from(3); + + // ensure that we have 5 groups by registering 2 parachains. + schedule_blank_para(chain_a, true); + schedule_blank_para(chain_b, true); + schedule_blank_para(chain_c, false); + + run_to_block(1, |number| match number { + 1 => Some(SessionChangeNotification { + new_config: config.clone(), + validators: vec![ + ValidatorId::from(Sr25519Keyring::Alice.public()), + ValidatorId::from(Sr25519Keyring::Bob.public()), + ValidatorId::from(Sr25519Keyring::Charlie.public()), + ValidatorId::from(Sr25519Keyring::Dave.public()), + ValidatorId::from(Sr25519Keyring::Eve.public()), + ValidatorId::from(Sr25519Keyring::Ferdie.public()), + ValidatorId::from(Sr25519Keyring::One.public()), + ], + random_seed: [99; 32], + ..Default::default() + }), + _ => None, + }); + + let groups = ValidatorGroups::::get(); + assert_eq!(groups.len(), 7); + + // Every validator gets its own group, even though there are 2 paras. + for i in 0..7 { + assert_eq!(groups[i].len(), 1); + } + }); +} + +#[test] +fn schedule_schedules() { + let genesis_config = MockGenesisConfig { + configuration: crate::configuration::GenesisConfig { + config: default_config(), + ..Default::default() + }, + ..Default::default() + }; + + let chain_a = ParaId::from(1); + let chain_b = ParaId::from(2); + + let thread_a = ParaId::from(3); + let thread_b = ParaId::from(4); + let thread_c = ParaId::from(5); + + let collator = CollatorId::from(Sr25519Keyring::Alice.public()); + + new_test_ext(genesis_config).execute_with(|| { + assert_eq!(default_config().parathread_cores, 3); + + // register 2 parachains + schedule_blank_para(chain_a, true); + schedule_blank_para(chain_b, true); + + // and 3 parathreads + schedule_blank_para(thread_a, false); + schedule_blank_para(thread_b, false); + schedule_blank_para(thread_c, false); + + // start a new session to activate, 5 validators for 5 cores. + run_to_block(1, |number| match number { + 1 => Some(SessionChangeNotification { + new_config: default_config(), + validators: vec![ + ValidatorId::from(Sr25519Keyring::Alice.public()), + ValidatorId::from(Sr25519Keyring::Bob.public()), + ValidatorId::from(Sr25519Keyring::Charlie.public()), + ValidatorId::from(Sr25519Keyring::Dave.public()), + ValidatorId::from(Sr25519Keyring::Eve.public()), + ], + ..Default::default() + }), + _ => None, + }); + + { + let scheduled = Scheduler::scheduled(); + assert_eq!(scheduled.len(), 2); + + assert_eq!( + scheduled[0], + CoreAssignment { + core: CoreIndex(0), + para_id: chain_a, + kind: AssignmentKind::Parachain, + group_idx: GroupIndex(0), + } + ); + + assert_eq!( + scheduled[1], + CoreAssignment { + core: CoreIndex(1), + para_id: chain_b, + kind: AssignmentKind::Parachain, + group_idx: GroupIndex(1), + } + ); + } + + // add a couple of parathread claims. + Scheduler::add_parathread_claim(ParathreadClaim(thread_a, collator.clone())); + Scheduler::add_parathread_claim(ParathreadClaim(thread_c, collator.clone())); + + run_to_block(2, |_| None); + + { + let scheduled = Scheduler::scheduled(); + assert_eq!(scheduled.len(), 4); + + assert_eq!( + scheduled[0], + CoreAssignment { + core: CoreIndex(0), + para_id: chain_a, + kind: AssignmentKind::Parachain, + group_idx: GroupIndex(0), + } + ); + + assert_eq!( + scheduled[1], + CoreAssignment { + core: CoreIndex(1), + para_id: chain_b, + kind: AssignmentKind::Parachain, + group_idx: GroupIndex(1), + } + ); + + assert_eq!( + scheduled[2], + CoreAssignment { + core: CoreIndex(2), + para_id: thread_a, + kind: AssignmentKind::Parathread(collator.clone(), 0), + group_idx: GroupIndex(2), + } + ); + + assert_eq!( + scheduled[3], + CoreAssignment { + core: CoreIndex(3), + para_id: thread_c, + kind: AssignmentKind::Parathread(collator.clone(), 0), + group_idx: GroupIndex(3), + } + ); + } + }); +} + +#[test] +fn schedule_schedules_including_just_freed() { + let genesis_config = MockGenesisConfig { + configuration: crate::configuration::GenesisConfig { + config: default_config(), + ..Default::default() + }, + ..Default::default() + }; + + let chain_a = ParaId::from(1); + let chain_b = ParaId::from(2); + + let thread_a = ParaId::from(3); + let thread_b = ParaId::from(4); + let thread_c = ParaId::from(5); + let thread_d = ParaId::from(6); + let thread_e = ParaId::from(7); + + let collator = CollatorId::from(Sr25519Keyring::Alice.public()); + + new_test_ext(genesis_config).execute_with(|| { + assert_eq!(default_config().parathread_cores, 3); + + // register 2 parachains + schedule_blank_para(chain_a, true); + schedule_blank_para(chain_b, true); + + // and 5 parathreads + schedule_blank_para(thread_a, false); + schedule_blank_para(thread_b, false); + schedule_blank_para(thread_c, false); + schedule_blank_para(thread_d, false); + schedule_blank_para(thread_e, false); + + // start a new session to activate, 5 validators for 5 cores. + run_to_block(1, |number| match number { + 1 => Some(SessionChangeNotification { + new_config: default_config(), + validators: vec![ + ValidatorId::from(Sr25519Keyring::Alice.public()), + ValidatorId::from(Sr25519Keyring::Bob.public()), + ValidatorId::from(Sr25519Keyring::Charlie.public()), + ValidatorId::from(Sr25519Keyring::Dave.public()), + ValidatorId::from(Sr25519Keyring::Eve.public()), + ], + ..Default::default() + }), + _ => None, + }); + + // add a couple of parathread claims now that the parathreads are live. + Scheduler::add_parathread_claim(ParathreadClaim(thread_a, collator.clone())); + Scheduler::add_parathread_claim(ParathreadClaim(thread_c, collator.clone())); + + run_to_block(2, |_| None); + + assert_eq!(Scheduler::scheduled().len(), 4); + + // cores 0, 1, 2, and 3 should be occupied. mark them as such. + Scheduler::occupied(&[CoreIndex(0), CoreIndex(1), CoreIndex(2), CoreIndex(3)]); + + { + let cores = AvailabilityCores::::get(); + + assert!(cores[0].is_some()); + assert!(cores[1].is_some()); + assert!(cores[2].is_some()); + assert!(cores[3].is_some()); + assert!(cores[4].is_none()); + + assert!(Scheduler::scheduled().is_empty()); + } + + // add a couple more parathread claims - the claim on `b` will go to the 3rd parathread core (4) + // and the claim on `d` will go back to the 1st parathread core (2). The claim on `e` then + // will go for core `3`. + Scheduler::add_parathread_claim(ParathreadClaim(thread_b, collator.clone())); + Scheduler::add_parathread_claim(ParathreadClaim(thread_d, collator.clone())); + Scheduler::add_parathread_claim(ParathreadClaim(thread_e, collator.clone())); + + run_to_block(3, |_| None); + + { + let scheduled = Scheduler::scheduled(); + + // cores 0 and 1 are occupied by parachains. cores 2 and 3 are occupied by parathread + // claims. core 4 was free. + assert_eq!(scheduled.len(), 1); + assert_eq!( + scheduled[0], + CoreAssignment { + core: CoreIndex(4), + para_id: thread_b, + kind: AssignmentKind::Parathread(collator.clone(), 0), + group_idx: GroupIndex(4), + } + ); + } + + // now note that cores 0, 2, and 3 were freed. + Scheduler::schedule( + vec![ + (CoreIndex(0), FreedReason::Concluded), + (CoreIndex(2), FreedReason::Concluded), + (CoreIndex(3), FreedReason::TimedOut), // should go back on queue. + ], + 3, + ); + + { + let scheduled = Scheduler::scheduled(); + + // 1 thing scheduled before, + 3 cores freed. + assert_eq!(scheduled.len(), 4); + assert_eq!( + scheduled[0], + CoreAssignment { + core: CoreIndex(0), + para_id: chain_a, + kind: AssignmentKind::Parachain, + group_idx: GroupIndex(0), + } + ); + assert_eq!( + scheduled[1], + CoreAssignment { + core: CoreIndex(2), + para_id: thread_d, + kind: AssignmentKind::Parathread(collator.clone(), 0), + group_idx: GroupIndex(2), + } + ); + assert_eq!( + scheduled[2], + CoreAssignment { + core: CoreIndex(3), + para_id: thread_e, + kind: AssignmentKind::Parathread(collator.clone(), 0), + group_idx: GroupIndex(3), + } + ); + assert_eq!( + scheduled[3], + CoreAssignment { + core: CoreIndex(4), + para_id: thread_b, + kind: AssignmentKind::Parathread(collator.clone(), 0), + group_idx: GroupIndex(4), + } + ); + + // the prior claim on thread A concluded, but the claim on thread C was marked as + // timed out. + let index = ParathreadClaimIndex::::get(); + let parathread_queue = ParathreadQueue::::get(); + + // thread A claim should have been wiped, but thread C claim should remain. + assert_eq!(index, vec![thread_b, thread_c, thread_d, thread_e]); + + // Although C was descheduled, the core `4` was occupied so C goes back on the queue. + assert_eq!(parathread_queue.queue.len(), 1); + assert_eq!( + parathread_queue.queue[0], + QueuedParathread { + claim: ParathreadEntry { + claim: ParathreadClaim(thread_c, collator.clone()), + retries: 0, // retries not incremented by timeout - validators' fault. + }, + core_offset: 2, // reassigned to next core. thread_e claim was on offset 1. + } + ); + } + }); +} + +#[test] +fn schedule_clears_availability_cores() { + let genesis_config = MockGenesisConfig { + configuration: crate::configuration::GenesisConfig { + config: default_config(), + ..Default::default() + }, + ..Default::default() + }; + + let chain_a = ParaId::from(1); + let chain_b = ParaId::from(2); + let chain_c = ParaId::from(3); + + new_test_ext(genesis_config).execute_with(|| { + assert_eq!(default_config().parathread_cores, 3); + + // register 3 parachains + schedule_blank_para(chain_a, true); + schedule_blank_para(chain_b, true); + schedule_blank_para(chain_c, true); + + // start a new session to activate, 5 validators for 5 cores. + run_to_block(1, |number| match number { + 1 => Some(SessionChangeNotification { + new_config: default_config(), + validators: vec![ + ValidatorId::from(Sr25519Keyring::Alice.public()), + ValidatorId::from(Sr25519Keyring::Bob.public()), + ValidatorId::from(Sr25519Keyring::Charlie.public()), + ValidatorId::from(Sr25519Keyring::Dave.public()), + ValidatorId::from(Sr25519Keyring::Eve.public()), + ], + ..Default::default() + }), + _ => None, + }); + + run_to_block(2, |_| None); + + assert_eq!(Scheduler::scheduled().len(), 3); + + // cores 0, 1, and 2 should be occupied. mark them as such. + Scheduler::occupied(&[CoreIndex(0), CoreIndex(1), CoreIndex(2)]); + + { + let cores = AvailabilityCores::::get(); + + assert!(cores[0].is_some()); + assert!(cores[1].is_some()); + assert!(cores[2].is_some()); + + assert!(Scheduler::scheduled().is_empty()); + } + + run_to_block(3, |_| None); + + // now note that cores 0 and 2 were freed. + Scheduler::schedule( + vec![(CoreIndex(0), FreedReason::Concluded), (CoreIndex(2), FreedReason::Concluded)], + 3, + ); + + { + let scheduled = Scheduler::scheduled(); + + assert_eq!(scheduled.len(), 2); + assert_eq!( + scheduled[0], + CoreAssignment { + core: CoreIndex(0), + para_id: chain_a, + kind: AssignmentKind::Parachain, + group_idx: GroupIndex(0), + } + ); + assert_eq!( + scheduled[1], + CoreAssignment { + core: CoreIndex(2), + para_id: chain_c, + kind: AssignmentKind::Parachain, + group_idx: GroupIndex(2), + } + ); + + // The freed cores should be `None` in `AvailabilityCores`. + let cores = AvailabilityCores::::get(); + assert!(cores[0].is_none()); + assert!(cores[2].is_none()); + } + }); +} + +#[test] +fn schedule_rotates_groups() { + let config = { + let mut config = default_config(); + + // make sure parathread requests don't retry-out + config.parathread_retries = config.group_rotation_frequency * 3; + config.parathread_cores = 2; + config + }; + + let rotation_frequency = config.group_rotation_frequency; + let parathread_cores = config.parathread_cores; + + let genesis_config = MockGenesisConfig { + configuration: crate::configuration::GenesisConfig { + config: config.clone(), + ..Default::default() + }, + ..Default::default() + }; + + let thread_a = ParaId::from(1); + let thread_b = ParaId::from(2); + + let collator = CollatorId::from(Sr25519Keyring::Alice.public()); + + new_test_ext(genesis_config).execute_with(|| { + assert_eq!(default_config().parathread_cores, 3); + + schedule_blank_para(thread_a, false); + schedule_blank_para(thread_b, false); + + // start a new session to activate, 5 validators for 5 cores. + run_to_block(1, |number| match number { + 1 => Some(SessionChangeNotification { + new_config: config.clone(), + validators: vec![ + ValidatorId::from(Sr25519Keyring::Alice.public()), + ValidatorId::from(Sr25519Keyring::Eve.public()), + ], + ..Default::default() + }), + _ => None, + }); + + let session_start_block = ::SessionStartBlock::get(); + assert_eq!(session_start_block, 1); + + Scheduler::add_parathread_claim(ParathreadClaim(thread_a, collator.clone())); + Scheduler::add_parathread_claim(ParathreadClaim(thread_b, collator.clone())); + + run_to_block(2, |_| None); + + let assert_groups_rotated = |rotations: u32| { + let scheduled = Scheduler::scheduled(); + assert_eq!(scheduled.len(), 2); + assert_eq!(scheduled[0].group_idx, GroupIndex((0u32 + rotations) % parathread_cores)); + assert_eq!(scheduled[1].group_idx, GroupIndex((1u32 + rotations) % parathread_cores)); + }; + + assert_groups_rotated(0); + + // one block before first rotation. + run_to_block(rotation_frequency, |_| None); + + assert_groups_rotated(0); + + // first rotation. + run_to_block(rotation_frequency + 1, |_| None); + assert_groups_rotated(1); + + // one block before second rotation. + run_to_block(rotation_frequency * 2, |_| None); + assert_groups_rotated(1); + + // second rotation. + run_to_block(rotation_frequency * 2 + 1, |_| None); + assert_groups_rotated(2); + }); +} + +#[test] +fn parathread_claims_are_pruned_after_retries() { + let max_retries = default_config().parathread_retries; + + let genesis_config = MockGenesisConfig { + configuration: crate::configuration::GenesisConfig { + config: default_config(), + ..Default::default() + }, + ..Default::default() + }; + + let thread_a = ParaId::from(1); + let thread_b = ParaId::from(2); + + let collator = CollatorId::from(Sr25519Keyring::Alice.public()); + + new_test_ext(genesis_config).execute_with(|| { + assert_eq!(default_config().parathread_cores, 3); + + schedule_blank_para(thread_a, false); + schedule_blank_para(thread_b, false); + + // start a new session to activate, 5 validators for 5 cores. + run_to_block(1, |number| match number { + 1 => Some(SessionChangeNotification { + new_config: default_config(), + validators: vec![ + ValidatorId::from(Sr25519Keyring::Alice.public()), + ValidatorId::from(Sr25519Keyring::Eve.public()), + ], + ..Default::default() + }), + _ => None, + }); + + Scheduler::add_parathread_claim(ParathreadClaim(thread_a, collator.clone())); + Scheduler::add_parathread_claim(ParathreadClaim(thread_b, collator.clone())); + + run_to_block(2, |_| None); + assert_eq!(Scheduler::scheduled().len(), 2); + + run_to_block(2 + max_retries, |_| None); + assert_eq!(Scheduler::scheduled().len(), 2); + + run_to_block(2 + max_retries + 1, |_| None); + assert_eq!(Scheduler::scheduled().len(), 0); + }); +} + +#[test] +fn availability_predicate_works() { + let genesis_config = MockGenesisConfig { + configuration: crate::configuration::GenesisConfig { + config: default_config(), + ..Default::default() + }, + ..Default::default() + }; + + let HostConfiguration { + group_rotation_frequency, + chain_availability_period, + thread_availability_period, + .. + } = default_config(); + let collator = CollatorId::from(Sr25519Keyring::Alice.public()); + + assert!( + chain_availability_period < thread_availability_period && + thread_availability_period < group_rotation_frequency + ); + + let chain_a = ParaId::from(1); + let thread_a = ParaId::from(2); + + new_test_ext(genesis_config).execute_with(|| { + schedule_blank_para(chain_a, true); + schedule_blank_para(thread_a, false); + + // start a new session with our chain & thread registered. + run_to_block(1, |number| match number { + 1 => Some(SessionChangeNotification { + new_config: default_config(), + validators: vec![ + ValidatorId::from(Sr25519Keyring::Alice.public()), + ValidatorId::from(Sr25519Keyring::Bob.public()), + ValidatorId::from(Sr25519Keyring::Charlie.public()), + ValidatorId::from(Sr25519Keyring::Dave.public()), + ValidatorId::from(Sr25519Keyring::Eve.public()), + ], + ..Default::default() + }), + _ => None, + }); + + // assign some availability cores. + { + AvailabilityCores::::mutate(|cores| { + cores[0] = Some(CoreOccupied::Parachain); + cores[1] = Some(CoreOccupied::Parathread(ParathreadEntry { + claim: ParathreadClaim(thread_a, collator), + retries: 0, + })) + }); + } + + run_to_block(1 + thread_availability_period, |_| None); + assert!(Scheduler::availability_timeout_predicate().is_none()); + + run_to_block(1 + group_rotation_frequency, |_| None); + + { + let pred = Scheduler::availability_timeout_predicate() + .expect("predicate exists recently after rotation"); + + let now = System::block_number(); + let would_be_timed_out = now - thread_availability_period; + for i in 0..AvailabilityCores::::get().len() { + // returns true for unoccupied cores. + // And can time out both threads and chains at this stage. + assert!(pred(CoreIndex(i as u32), would_be_timed_out)); + } + + assert!(!pred(CoreIndex(0), now)); // assigned: chain + assert!(!pred(CoreIndex(1), now)); // assigned: thread + assert!(pred(CoreIndex(2), now)); + + // check the tighter bound on chains vs threads. + assert!(pred(CoreIndex(0), now - chain_availability_period)); + assert!(!pred(CoreIndex(1), now - chain_availability_period)); + + // check the threshold is exact. + assert!(!pred(CoreIndex(0), now - chain_availability_period + 1)); + assert!(!pred(CoreIndex(1), now - thread_availability_period + 1)); + } + + run_to_block(1 + group_rotation_frequency + chain_availability_period, |_| None); + + { + let pred = Scheduler::availability_timeout_predicate() + .expect("predicate exists recently after rotation"); + + let would_be_timed_out = System::block_number() - thread_availability_period; + + assert!(!pred(CoreIndex(0), would_be_timed_out)); // chains can't be timed out now. + assert!(pred(CoreIndex(1), would_be_timed_out)); // but threads can. + } + + run_to_block(1 + group_rotation_frequency + thread_availability_period, |_| None); + + assert!(Scheduler::availability_timeout_predicate().is_none()); + }); +} + +#[test] +fn next_up_on_available_uses_next_scheduled_or_none_for_thread() { + let mut config = default_config(); + config.parathread_cores = 1; + + let genesis_config = MockGenesisConfig { + configuration: crate::configuration::GenesisConfig { + config: config.clone(), + ..Default::default() + }, + ..Default::default() + }; + + let thread_a = ParaId::from(1); + let thread_b = ParaId::from(2); + + let collator = CollatorId::from(Sr25519Keyring::Alice.public()); + + new_test_ext(genesis_config).execute_with(|| { + schedule_blank_para(thread_a, false); + schedule_blank_para(thread_b, false); + + // start a new session to activate, 5 validators for 5 cores. + run_to_block(1, |number| match number { + 1 => Some(SessionChangeNotification { + new_config: config.clone(), + validators: vec![ + ValidatorId::from(Sr25519Keyring::Alice.public()), + ValidatorId::from(Sr25519Keyring::Eve.public()), + ], + ..Default::default() + }), + _ => None, + }); + + let thread_claim_a = ParathreadClaim(thread_a, collator.clone()); + let thread_claim_b = ParathreadClaim(thread_b, collator.clone()); + + Scheduler::add_parathread_claim(thread_claim_a.clone()); + + run_to_block(2, |_| None); + + { + assert_eq!(Scheduler::scheduled().len(), 1); + assert_eq!(Scheduler::availability_cores().len(), 1); + + Scheduler::occupied(&[CoreIndex(0)]); + + let cores = Scheduler::availability_cores(); + match cores[0].as_ref().unwrap() { + CoreOccupied::Parathread(entry) => assert_eq!(entry.claim, thread_claim_a), + _ => panic!("with no chains, only core should be a thread core"), + } + + assert!(Scheduler::next_up_on_available(CoreIndex(0)).is_none()); + + Scheduler::add_parathread_claim(thread_claim_b); + + let queue = ParathreadQueue::::get(); + assert_eq!( + queue.get_next_on_core(0).unwrap().claim, + ParathreadClaim(thread_b, collator.clone()), + ); + + assert_eq!( + Scheduler::next_up_on_available(CoreIndex(0)).unwrap(), + ScheduledCore { para_id: thread_b, collator: Some(collator.clone()) } + ); + } + }); +} + +#[test] +fn next_up_on_time_out_reuses_claim_if_nothing_queued() { + let mut config = default_config(); + config.parathread_cores = 1; + + let genesis_config = MockGenesisConfig { + configuration: crate::configuration::GenesisConfig { + config: config.clone(), + ..Default::default() + }, + ..Default::default() + }; + + let thread_a = ParaId::from(1); + let thread_b = ParaId::from(2); + + let collator = CollatorId::from(Sr25519Keyring::Alice.public()); + + new_test_ext(genesis_config).execute_with(|| { + schedule_blank_para(thread_a, false); + schedule_blank_para(thread_b, false); + + // start a new session to activate, 5 validators for 5 cores. + run_to_block(1, |number| match number { + 1 => Some(SessionChangeNotification { + new_config: config.clone(), + validators: vec![ + ValidatorId::from(Sr25519Keyring::Alice.public()), + ValidatorId::from(Sr25519Keyring::Eve.public()), + ], + ..Default::default() + }), + _ => None, + }); + + let thread_claim_a = ParathreadClaim(thread_a, collator.clone()); + let thread_claim_b = ParathreadClaim(thread_b, collator.clone()); + + Scheduler::add_parathread_claim(thread_claim_a.clone()); + + run_to_block(2, |_| None); + + { + assert_eq!(Scheduler::scheduled().len(), 1); + assert_eq!(Scheduler::availability_cores().len(), 1); + + Scheduler::occupied(&[CoreIndex(0)]); + + let cores = Scheduler::availability_cores(); + match cores[0].as_ref().unwrap() { + CoreOccupied::Parathread(entry) => assert_eq!(entry.claim, thread_claim_a), + _ => panic!("with no chains, only core should be a thread core"), + } + + let queue = ParathreadQueue::::get(); + assert!(queue.get_next_on_core(0).is_none()); + assert_eq!( + Scheduler::next_up_on_time_out(CoreIndex(0)).unwrap(), + ScheduledCore { para_id: thread_a, collator: Some(collator.clone()) } + ); + + Scheduler::add_parathread_claim(thread_claim_b); + + let queue = ParathreadQueue::::get(); + assert_eq!( + queue.get_next_on_core(0).unwrap().claim, + ParathreadClaim(thread_b, collator.clone()), + ); + + // Now that there is an earlier next-up, we use that. + assert_eq!( + Scheduler::next_up_on_available(CoreIndex(0)).unwrap(), + ScheduledCore { para_id: thread_b, collator: Some(collator.clone()) } + ); + } + }); +} + +#[test] +fn next_up_on_available_is_parachain_always() { + let mut config = default_config(); + config.parathread_cores = 0; + + let genesis_config = MockGenesisConfig { + configuration: crate::configuration::GenesisConfig { + config: config.clone(), + ..Default::default() + }, + ..Default::default() + }; + + let chain_a = ParaId::from(1); + + new_test_ext(genesis_config).execute_with(|| { + schedule_blank_para(chain_a, true); + + // start a new session to activate, 5 validators for 5 cores. + run_to_block(1, |number| match number { + 1 => Some(SessionChangeNotification { + new_config: config.clone(), + validators: vec![ + ValidatorId::from(Sr25519Keyring::Alice.public()), + ValidatorId::from(Sr25519Keyring::Eve.public()), + ], + ..Default::default() + }), + _ => None, + }); + + run_to_block(2, |_| None); + + { + assert_eq!(Scheduler::scheduled().len(), 1); + assert_eq!(Scheduler::availability_cores().len(), 1); + + Scheduler::occupied(&[CoreIndex(0)]); + + let cores = Scheduler::availability_cores(); + match cores[0].as_ref().unwrap() { + CoreOccupied::Parachain => {}, + _ => panic!("with no threads, only core should be a chain core"), + } + + // Now that there is an earlier next-up, we use that. + assert_eq!( + Scheduler::next_up_on_available(CoreIndex(0)).unwrap(), + ScheduledCore { para_id: chain_a, collator: None } + ); + } + }); +} + +#[test] +fn next_up_on_time_out_is_parachain_always() { + let mut config = default_config(); + config.parathread_cores = 0; + + let genesis_config = MockGenesisConfig { + configuration: crate::configuration::GenesisConfig { + config: config.clone(), + ..Default::default() + }, + ..Default::default() + }; + + let chain_a = ParaId::from(1); + + new_test_ext(genesis_config).execute_with(|| { + schedule_blank_para(chain_a, true); + + // start a new session to activate, 5 validators for 5 cores. + run_to_block(1, |number| match number { + 1 => Some(SessionChangeNotification { + new_config: config.clone(), + validators: vec![ + ValidatorId::from(Sr25519Keyring::Alice.public()), + ValidatorId::from(Sr25519Keyring::Eve.public()), + ], + ..Default::default() + }), + _ => None, + }); + + run_to_block(2, |_| None); + + { + assert_eq!(Scheduler::scheduled().len(), 1); + assert_eq!(Scheduler::availability_cores().len(), 1); + + Scheduler::occupied(&[CoreIndex(0)]); + + let cores = Scheduler::availability_cores(); + match cores[0].as_ref().unwrap() { + CoreOccupied::Parachain => {}, + _ => panic!("with no threads, only core should be a chain core"), + } + + // Now that there is an earlier next-up, we use that. + assert_eq!( + Scheduler::next_up_on_available(CoreIndex(0)).unwrap(), + ScheduledCore { para_id: chain_a, collator: None } + ); + } + }); +} + +#[test] +fn session_change_requires_reschedule_dropping_removed_paras() { + let genesis_config = MockGenesisConfig { + configuration: crate::configuration::GenesisConfig { + config: default_config(), + ..Default::default() + }, + ..Default::default() + }; + + assert_eq!(default_config().parathread_cores, 3); + new_test_ext(genesis_config).execute_with(|| { + let chain_a = ParaId::from(1); + let chain_b = ParaId::from(2); + + // ensure that we have 5 groups by registering 2 parachains. + schedule_blank_para(chain_a, true); + schedule_blank_para(chain_b, true); + + run_to_block(1, |number| match number { + 1 => Some(SessionChangeNotification { + new_config: default_config(), + validators: vec![ + ValidatorId::from(Sr25519Keyring::Alice.public()), + ValidatorId::from(Sr25519Keyring::Bob.public()), + ValidatorId::from(Sr25519Keyring::Charlie.public()), + ValidatorId::from(Sr25519Keyring::Dave.public()), + ValidatorId::from(Sr25519Keyring::Eve.public()), + ValidatorId::from(Sr25519Keyring::Ferdie.public()), + ValidatorId::from(Sr25519Keyring::One.public()), + ], + random_seed: [99; 32], + ..Default::default() + }), + _ => None, + }); + + assert_eq!(Scheduler::scheduled().len(), 2); + + let groups = ValidatorGroups::::get(); + assert_eq!(groups.len(), 5); + + assert_ok!(Paras::schedule_para_cleanup(chain_b)); + + run_to_end_of_block(2, |number| match number { + 2 => Some(SessionChangeNotification { + new_config: default_config(), + validators: vec![ + ValidatorId::from(Sr25519Keyring::Alice.public()), + ValidatorId::from(Sr25519Keyring::Bob.public()), + ValidatorId::from(Sr25519Keyring::Charlie.public()), + ValidatorId::from(Sr25519Keyring::Dave.public()), + ValidatorId::from(Sr25519Keyring::Eve.public()), + ValidatorId::from(Sr25519Keyring::Ferdie.public()), + ValidatorId::from(Sr25519Keyring::One.public()), + ], + random_seed: [99; 32], + ..Default::default() + }), + _ => None, + }); + + Scheduler::clear(); + Scheduler::schedule(Vec::new(), 3); + + assert_eq!( + Scheduler::scheduled(), + vec![CoreAssignment { + core: CoreIndex(0), + para_id: chain_a, + kind: AssignmentKind::Parachain, + group_idx: GroupIndex(0), + }], + ); + }); +} + +#[test] +fn parathread_claims_are_pruned_after_deregistration() { + let genesis_config = MockGenesisConfig { + configuration: crate::configuration::GenesisConfig { + config: default_config(), + ..Default::default() + }, + ..Default::default() + }; + + let thread_a = ParaId::from(1); + let thread_b = ParaId::from(2); + + let collator = CollatorId::from(Sr25519Keyring::Alice.public()); + + new_test_ext(genesis_config).execute_with(|| { + assert_eq!(default_config().parathread_cores, 3); + + schedule_blank_para(thread_a, false); + schedule_blank_para(thread_b, false); + + // start a new session to activate, 5 validators for 5 cores. + run_to_block(1, |number| match number { + 1 => Some(SessionChangeNotification { + new_config: default_config(), + validators: vec![ + ValidatorId::from(Sr25519Keyring::Alice.public()), + ValidatorId::from(Sr25519Keyring::Eve.public()), + ], + ..Default::default() + }), + _ => None, + }); + + Scheduler::add_parathread_claim(ParathreadClaim(thread_a, collator.clone())); + Scheduler::add_parathread_claim(ParathreadClaim(thread_b, collator.clone())); + + run_to_block(2, |_| None); + assert_eq!(Scheduler::scheduled().len(), 2); + + assert_ok!(Paras::schedule_para_cleanup(thread_a)); + + // start a new session to activate, 5 validators for 5 cores. + run_to_block(3, |number| match number { + 3 => Some(SessionChangeNotification { + new_config: default_config(), + validators: vec![ + ValidatorId::from(Sr25519Keyring::Alice.public()), + ValidatorId::from(Sr25519Keyring::Eve.public()), + ], + ..Default::default() + }), + _ => None, + }); + + assert_eq!(Scheduler::scheduled().len(), 1); + }); +} diff --git a/runtime/parachains/src/session_info.rs b/runtime/parachains/src/session_info.rs index 4e0171b3168b..904d46260b8d 100644 --- a/runtime/parachains/src/session_info.rs +++ b/runtime/parachains/src/session_info.rs @@ -34,6 +34,9 @@ pub use pallet::*; pub mod migration; +#[cfg(test)] +mod tests; + #[frame_support::pallet] pub mod pallet { use super::*; @@ -187,205 +190,3 @@ impl OneSessionHandler for Pal fn on_disabled(_i: u32) {} } - -#[cfg(test)] -mod tests { - use super::*; - use crate::{ - configuration::HostConfiguration, - initializer::SessionChangeNotification, - mock::{ - new_test_ext, Configuration, MockGenesisConfig, Origin, ParasShared, SessionInfo, - System, Test, - }, - util::take_active_subset, - }; - use keyring::Sr25519Keyring; - use primitives::v1::{BlockNumber, ValidatorId, ValidatorIndex}; - - fn run_to_block( - to: BlockNumber, - new_session: impl Fn(BlockNumber) -> Option>, - ) { - while System::block_number() < to { - let b = System::block_number(); - - SessionInfo::initializer_finalize(); - ParasShared::initializer_finalize(); - Configuration::initializer_finalize(); - - if let Some(notification) = new_session(b + 1) { - Configuration::initializer_on_new_session(¬ification.session_index); - ParasShared::initializer_on_new_session( - notification.session_index, - notification.random_seed, - ¬ification.new_config, - notification.validators.clone(), - ); - SessionInfo::initializer_on_new_session(¬ification); - } - - System::on_finalize(b); - - System::on_initialize(b + 1); - System::set_block_number(b + 1); - - Configuration::initializer_initialize(b + 1); - ParasShared::initializer_initialize(b + 1); - SessionInfo::initializer_initialize(b + 1); - } - } - - fn default_config() -> HostConfiguration { - HostConfiguration { - parathread_cores: 1, - dispute_period: 2, - needed_approvals: 3, - ..Default::default() - } - } - - fn genesis_config() -> MockGenesisConfig { - MockGenesisConfig { - configuration: configuration::GenesisConfig { - config: default_config(), - ..Default::default() - }, - ..Default::default() - } - } - - fn session_changes(n: BlockNumber) -> Option> { - if n % 10 == 0 { - Some(SessionChangeNotification { session_index: n / 10, ..Default::default() }) - } else { - None - } - } - - fn new_session_every_block(n: BlockNumber) -> Option> { - Some(SessionChangeNotification { session_index: n, ..Default::default() }) - } - - #[test] - fn session_pruning_is_based_on_dispute_period() { - new_test_ext(genesis_config()).execute_with(|| { - // Dispute period starts at 2 - let config = Configuration::config(); - assert_eq!(config.dispute_period, 2); - - // Move to session 10 - run_to_block(100, session_changes); - // Earliest stored session is 10 - 2 = 8 - assert_eq!(EarliestStoredSession::::get(), 8); - // Pruning works as expected - assert!(Sessions::::get(7).is_none()); - assert!(Sessions::::get(8).is_some()); - assert!(Sessions::::get(9).is_some()); - - // changing `dispute_period` works - let dispute_period = 5; - Configuration::set_dispute_period(Origin::root(), dispute_period).unwrap(); - - // Dispute period does not automatically change - let config = Configuration::config(); - assert_eq!(config.dispute_period, 2); - // Two sessions later it will though - run_to_block(120, session_changes); - let config = Configuration::config(); - assert_eq!(config.dispute_period, 5); - - run_to_block(200, session_changes); - assert_eq!(EarliestStoredSession::::get(), 20 - dispute_period); - - // Increase dispute period even more - let new_dispute_period = 16; - Configuration::set_dispute_period(Origin::root(), new_dispute_period).unwrap(); - - run_to_block(210, session_changes); - assert_eq!(EarliestStoredSession::::get(), 21 - dispute_period); - - // Two sessions later it kicks in - run_to_block(220, session_changes); - let config = Configuration::config(); - assert_eq!(config.dispute_period, 16); - // Earliest session stays the same - assert_eq!(EarliestStoredSession::::get(), 21 - dispute_period); - - // We still don't have enough stored sessions to start pruning - run_to_block(300, session_changes); - assert_eq!(EarliestStoredSession::::get(), 21 - dispute_period); - - // now we do - run_to_block(420, session_changes); - assert_eq!(EarliestStoredSession::::get(), 42 - new_dispute_period); - }) - } - - #[test] - fn session_info_is_based_on_config() { - new_test_ext(genesis_config()).execute_with(|| { - run_to_block(1, new_session_every_block); - let session = Sessions::::get(&1).unwrap(); - assert_eq!(session.needed_approvals, 3); - - // change some param - Configuration::set_needed_approvals(Origin::root(), 42).unwrap(); - // 2 sessions later - run_to_block(3, new_session_every_block); - let session = Sessions::::get(&3).unwrap(); - assert_eq!(session.needed_approvals, 42); - }) - } - - #[test] - fn session_info_active_subsets() { - let unscrambled = vec![ - Sr25519Keyring::Alice, - Sr25519Keyring::Bob, - Sr25519Keyring::Charlie, - Sr25519Keyring::Dave, - Sr25519Keyring::Eve, - ]; - - let active_set = vec![ValidatorIndex(4), ValidatorIndex(0), ValidatorIndex(2)]; - - let unscrambled_validators: Vec = - unscrambled.iter().map(|v| v.public().into()).collect(); - let unscrambled_discovery: Vec = - unscrambled.iter().map(|v| v.public().into()).collect(); - let unscrambled_assignment: Vec = - unscrambled.iter().map(|v| v.public().into()).collect(); - - let validators = take_active_subset(&active_set, &unscrambled_validators); - - new_test_ext(genesis_config()).execute_with(|| { - ParasShared::set_active_validators_with_indices(active_set.clone(), validators.clone()); - - assert_eq!(ParasShared::active_validator_indices(), active_set); - - AssignmentKeysUnsafe::::set(unscrambled_assignment.clone()); - crate::mock::set_discovery_authorities(unscrambled_discovery.clone()); - assert_eq!(::authorities(), unscrambled_discovery); - - // invoke directly, because `run_to_block` will invoke `Shared` and clobber our - // values. - SessionInfo::initializer_on_new_session(&SessionChangeNotification { - session_index: 1, - validators: validators.clone(), - ..Default::default() - }); - let session = Sessions::::get(&1).unwrap(); - - assert_eq!(session.validators, validators); - assert_eq!( - session.discovery_keys, - take_active_subset_and_inactive(&active_set, &unscrambled_discovery), - ); - assert_eq!( - session.assignment_keys, - take_active_subset(&active_set, &unscrambled_assignment), - ); - }) - } -} diff --git a/runtime/parachains/src/session_info/tests.rs b/runtime/parachains/src/session_info/tests.rs new file mode 100644 index 000000000000..e35007289958 --- /dev/null +++ b/runtime/parachains/src/session_info/tests.rs @@ -0,0 +1,214 @@ +// 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 super::*; +use crate::{ + configuration::HostConfiguration, + initializer::SessionChangeNotification, + mock::{ + new_test_ext, Configuration, MockGenesisConfig, Origin, ParasShared, SessionInfo, System, + Test, + }, + util::take_active_subset, +}; +use keyring::Sr25519Keyring; +use primitives::v1::{BlockNumber, ValidatorId, ValidatorIndex}; + +fn run_to_block( + to: BlockNumber, + new_session: impl Fn(BlockNumber) -> Option>, +) { + while System::block_number() < to { + let b = System::block_number(); + + SessionInfo::initializer_finalize(); + ParasShared::initializer_finalize(); + Configuration::initializer_finalize(); + + if let Some(notification) = new_session(b + 1) { + Configuration::initializer_on_new_session(¬ification.session_index); + ParasShared::initializer_on_new_session( + notification.session_index, + notification.random_seed, + ¬ification.new_config, + notification.validators.clone(), + ); + SessionInfo::initializer_on_new_session(¬ification); + } + + System::on_finalize(b); + + System::on_initialize(b + 1); + System::set_block_number(b + 1); + + Configuration::initializer_initialize(b + 1); + ParasShared::initializer_initialize(b + 1); + SessionInfo::initializer_initialize(b + 1); + } +} + +fn default_config() -> HostConfiguration { + HostConfiguration { + parathread_cores: 1, + dispute_period: 2, + needed_approvals: 3, + ..Default::default() + } +} + +fn genesis_config() -> MockGenesisConfig { + MockGenesisConfig { + configuration: configuration::GenesisConfig { + config: default_config(), + ..Default::default() + }, + ..Default::default() + } +} + +fn session_changes(n: BlockNumber) -> Option> { + if n % 10 == 0 { + Some(SessionChangeNotification { session_index: n / 10, ..Default::default() }) + } else { + None + } +} + +fn new_session_every_block(n: BlockNumber) -> Option> { + Some(SessionChangeNotification { session_index: n, ..Default::default() }) +} + +#[test] +fn session_pruning_is_based_on_dispute_period() { + new_test_ext(genesis_config()).execute_with(|| { + // Dispute period starts at 2 + let config = Configuration::config(); + assert_eq!(config.dispute_period, 2); + + // Move to session 10 + run_to_block(100, session_changes); + // Earliest stored session is 10 - 2 = 8 + assert_eq!(EarliestStoredSession::::get(), 8); + // Pruning works as expected + assert!(Sessions::::get(7).is_none()); + assert!(Sessions::::get(8).is_some()); + assert!(Sessions::::get(9).is_some()); + + // changing `dispute_period` works + let dispute_period = 5; + Configuration::set_dispute_period(Origin::root(), dispute_period).unwrap(); + + // Dispute period does not automatically change + let config = Configuration::config(); + assert_eq!(config.dispute_period, 2); + // Two sessions later it will though + run_to_block(120, session_changes); + let config = Configuration::config(); + assert_eq!(config.dispute_period, 5); + + run_to_block(200, session_changes); + assert_eq!(EarliestStoredSession::::get(), 20 - dispute_period); + + // Increase dispute period even more + let new_dispute_period = 16; + Configuration::set_dispute_period(Origin::root(), new_dispute_period).unwrap(); + + run_to_block(210, session_changes); + assert_eq!(EarliestStoredSession::::get(), 21 - dispute_period); + + // Two sessions later it kicks in + run_to_block(220, session_changes); + let config = Configuration::config(); + assert_eq!(config.dispute_period, 16); + // Earliest session stays the same + assert_eq!(EarliestStoredSession::::get(), 21 - dispute_period); + + // We still don't have enough stored sessions to start pruning + run_to_block(300, session_changes); + assert_eq!(EarliestStoredSession::::get(), 21 - dispute_period); + + // now we do + run_to_block(420, session_changes); + assert_eq!(EarliestStoredSession::::get(), 42 - new_dispute_period); + }) +} + +#[test] +fn session_info_is_based_on_config() { + new_test_ext(genesis_config()).execute_with(|| { + run_to_block(1, new_session_every_block); + let session = Sessions::::get(&1).unwrap(); + assert_eq!(session.needed_approvals, 3); + + // change some param + Configuration::set_needed_approvals(Origin::root(), 42).unwrap(); + // 2 sessions later + run_to_block(3, new_session_every_block); + let session = Sessions::::get(&3).unwrap(); + assert_eq!(session.needed_approvals, 42); + }) +} + +#[test] +fn session_info_active_subsets() { + let unscrambled = vec![ + Sr25519Keyring::Alice, + Sr25519Keyring::Bob, + Sr25519Keyring::Charlie, + Sr25519Keyring::Dave, + Sr25519Keyring::Eve, + ]; + + let active_set = vec![ValidatorIndex(4), ValidatorIndex(0), ValidatorIndex(2)]; + + let unscrambled_validators: Vec = + unscrambled.iter().map(|v| v.public().into()).collect(); + let unscrambled_discovery: Vec = + unscrambled.iter().map(|v| v.public().into()).collect(); + let unscrambled_assignment: Vec = + unscrambled.iter().map(|v| v.public().into()).collect(); + + let validators = take_active_subset(&active_set, &unscrambled_validators); + + new_test_ext(genesis_config()).execute_with(|| { + ParasShared::set_active_validators_with_indices(active_set.clone(), validators.clone()); + + assert_eq!(ParasShared::active_validator_indices(), active_set); + + AssignmentKeysUnsafe::::set(unscrambled_assignment.clone()); + crate::mock::set_discovery_authorities(unscrambled_discovery.clone()); + assert_eq!(::authorities(), unscrambled_discovery); + + // invoke directly, because `run_to_block` will invoke `Shared` and clobber our + // values. + SessionInfo::initializer_on_new_session(&SessionChangeNotification { + session_index: 1, + validators: validators.clone(), + ..Default::default() + }); + let session = Sessions::::get(&1).unwrap(); + + assert_eq!(session.validators, validators); + assert_eq!( + session.discovery_keys, + take_active_subset_and_inactive(&active_set, &unscrambled_discovery), + ); + assert_eq!( + session.assignment_keys, + take_active_subset(&active_set, &unscrambled_assignment), + ); + }) +} diff --git a/runtime/parachains/src/shared.rs b/runtime/parachains/src/shared.rs index f05866043327..7bd33c503c63 100644 --- a/runtime/parachains/src/shared.rs +++ b/runtime/parachains/src/shared.rs @@ -35,6 +35,9 @@ pub use pallet::*; // which guarantees that at least one full session has passed before any changes are applied. pub(crate) const SESSION_DELAY: SessionIndex = 2; +#[cfg(test)] +mod tests; + #[frame_support::pallet] pub mod pallet { use super::*; @@ -139,93 +142,3 @@ impl Pallet { ActiveValidatorKeys::::set(keys); } } - -#[cfg(test)] -mod tests { - use super::*; - use crate::{ - configuration::HostConfiguration, - mock::{new_test_ext, MockGenesisConfig, ParasShared}, - }; - use keyring::Sr25519Keyring; - - fn validator_pubkeys(val_ids: &[Sr25519Keyring]) -> Vec { - val_ids.iter().map(|v| v.public().into()).collect() - } - - #[test] - fn sets_and_shuffles_validators() { - let validators = vec![ - Sr25519Keyring::Alice, - Sr25519Keyring::Bob, - Sr25519Keyring::Charlie, - Sr25519Keyring::Dave, - Sr25519Keyring::Ferdie, - ]; - - let mut config = HostConfiguration::default(); - config.max_validators = None; - - let pubkeys = validator_pubkeys(&validators); - - new_test_ext(MockGenesisConfig::default()).execute_with(|| { - let validators = ParasShared::initializer_on_new_session(1, [1; 32], &config, pubkeys); - - assert_eq!( - validators, - validator_pubkeys(&[ - Sr25519Keyring::Ferdie, - Sr25519Keyring::Bob, - Sr25519Keyring::Charlie, - Sr25519Keyring::Dave, - Sr25519Keyring::Alice, - ]) - ); - - assert_eq!(ParasShared::active_validator_keys(), validators); - - assert_eq!( - ParasShared::active_validator_indices(), - vec![ - ValidatorIndex(4), - ValidatorIndex(1), - ValidatorIndex(2), - ValidatorIndex(3), - ValidatorIndex(0), - ] - ); - }); - } - - #[test] - fn sets_truncates_and_shuffles_validators() { - let validators = vec![ - Sr25519Keyring::Alice, - Sr25519Keyring::Bob, - Sr25519Keyring::Charlie, - Sr25519Keyring::Dave, - Sr25519Keyring::Ferdie, - ]; - - let mut config = HostConfiguration::default(); - config.max_validators = Some(2); - - let pubkeys = validator_pubkeys(&validators); - - new_test_ext(MockGenesisConfig::default()).execute_with(|| { - let validators = ParasShared::initializer_on_new_session(1, [1; 32], &config, pubkeys); - - assert_eq!( - validators, - validator_pubkeys(&[Sr25519Keyring::Ferdie, Sr25519Keyring::Bob,]) - ); - - assert_eq!(ParasShared::active_validator_keys(), validators); - - assert_eq!( - ParasShared::active_validator_indices(), - vec![ValidatorIndex(4), ValidatorIndex(1),] - ); - }); - } -} diff --git a/runtime/parachains/src/shared/tests.rs b/runtime/parachains/src/shared/tests.rs new file mode 100644 index 000000000000..0113c3539d9a --- /dev/null +++ b/runtime/parachains/src/shared/tests.rs @@ -0,0 +1,99 @@ +// 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 super::*; +use crate::{ + configuration::HostConfiguration, + mock::{new_test_ext, MockGenesisConfig, ParasShared}, +}; +use keyring::Sr25519Keyring; + +fn validator_pubkeys(val_ids: &[Sr25519Keyring]) -> Vec { + val_ids.iter().map(|v| v.public().into()).collect() +} + +#[test] +fn sets_and_shuffles_validators() { + let validators = vec![ + Sr25519Keyring::Alice, + Sr25519Keyring::Bob, + Sr25519Keyring::Charlie, + Sr25519Keyring::Dave, + Sr25519Keyring::Ferdie, + ]; + + let mut config = HostConfiguration::default(); + config.max_validators = None; + + let pubkeys = validator_pubkeys(&validators); + + new_test_ext(MockGenesisConfig::default()).execute_with(|| { + let validators = ParasShared::initializer_on_new_session(1, [1; 32], &config, pubkeys); + + assert_eq!( + validators, + validator_pubkeys(&[ + Sr25519Keyring::Ferdie, + Sr25519Keyring::Bob, + Sr25519Keyring::Charlie, + Sr25519Keyring::Dave, + Sr25519Keyring::Alice, + ]) + ); + + assert_eq!(ParasShared::active_validator_keys(), validators); + + assert_eq!( + ParasShared::active_validator_indices(), + vec![ + ValidatorIndex(4), + ValidatorIndex(1), + ValidatorIndex(2), + ValidatorIndex(3), + ValidatorIndex(0), + ] + ); + }); +} + +#[test] +fn sets_truncates_and_shuffles_validators() { + let validators = vec![ + Sr25519Keyring::Alice, + Sr25519Keyring::Bob, + Sr25519Keyring::Charlie, + Sr25519Keyring::Dave, + Sr25519Keyring::Ferdie, + ]; + + let mut config = HostConfiguration::default(); + config.max_validators = Some(2); + + let pubkeys = validator_pubkeys(&validators); + + new_test_ext(MockGenesisConfig::default()).execute_with(|| { + let validators = ParasShared::initializer_on_new_session(1, [1; 32], &config, pubkeys); + + assert_eq!(validators, validator_pubkeys(&[Sr25519Keyring::Ferdie, Sr25519Keyring::Bob,])); + + assert_eq!(ParasShared::active_validator_keys(), validators); + + assert_eq!( + ParasShared::active_validator_indices(), + vec![ValidatorIndex(4), ValidatorIndex(1),] + ); + }); +} diff --git a/runtime/parachains/src/ump.rs b/runtime/parachains/src/ump.rs index 302937af4a3d..344b0f7d439f 100644 --- a/runtime/parachains/src/ump.rs +++ b/runtime/parachains/src/ump.rs @@ -28,6 +28,9 @@ use xcm::latest::Outcome; pub use pallet::*; +#[cfg(test)] +pub(crate) mod tests; + /// All upward messages coming from parachains will be funneled into an implementation of this trait. /// /// The message is opaque from the perspective of UMP. The message size can range from 0 to @@ -703,342 +706,3 @@ impl NeedsDispatchCursor { as Store>::NeedsDispatch::put(self.needs_dispatch); } } - -#[cfg(test)] -pub(crate) mod tests { - use super::*; - use crate::mock::{ - assert_last_event, new_test_ext, take_processed, Configuration, MockGenesisConfig, Origin, - System, Test, Ump, - }; - use frame_support::{assert_noop, assert_ok, weights::Weight}; - use std::collections::HashSet; - - struct GenesisConfigBuilder { - max_upward_message_size: u32, - max_upward_message_num_per_candidate: u32, - max_upward_queue_count: u32, - max_upward_queue_size: u32, - ump_service_total_weight: Weight, - ump_max_individual_weight: Weight, - } - - impl Default for GenesisConfigBuilder { - fn default() -> Self { - Self { - max_upward_message_size: 16, - max_upward_message_num_per_candidate: 2, - max_upward_queue_count: 4, - max_upward_queue_size: 64, - ump_service_total_weight: 1000, - ump_max_individual_weight: 100, - } - } - } - - impl GenesisConfigBuilder { - fn build(self) -> crate::mock::MockGenesisConfig { - let mut genesis = default_genesis_config(); - let config = &mut genesis.configuration.config; - - config.max_upward_message_size = self.max_upward_message_size; - config.max_upward_message_num_per_candidate = self.max_upward_message_num_per_candidate; - config.max_upward_queue_count = self.max_upward_queue_count; - config.max_upward_queue_size = self.max_upward_queue_size; - config.ump_service_total_weight = self.ump_service_total_weight; - config.ump_max_individual_weight = self.ump_max_individual_weight; - genesis - } - } - - fn default_genesis_config() -> MockGenesisConfig { - MockGenesisConfig { - configuration: crate::configuration::GenesisConfig { - config: crate::configuration::HostConfiguration { - max_downward_message_size: 1024, - ..Default::default() - }, - }, - ..Default::default() - } - } - - fn queue_upward_msg(para: ParaId, msg: UpwardMessage) { - let msgs = vec![msg]; - assert!(Ump::check_upward_messages(&Configuration::config(), para, &msgs).is_ok()); - let _ = Ump::receive_upward_messages(para, msgs); - } - - fn assert_storage_consistency_exhaustive() { - // check that empty queues don't clutter the storage. - for (_para, queue) in ::RelayDispatchQueues::iter() { - assert!(!queue.is_empty()); - } - - // actually count the counts and sizes in queues and compare them to the bookkept version. - for (para, queue) in ::RelayDispatchQueues::iter() { - let (expected_count, expected_size) = ::RelayDispatchQueueSize::get(para); - let (actual_count, actual_size) = - queue.into_iter().fold((0, 0), |(acc_count, acc_size), x| { - (acc_count + 1, acc_size + x.len() as u32) - }); - - assert_eq!(expected_count, actual_count); - assert_eq!(expected_size, actual_size); - } - - // since we wipe the empty queues the sets of paras in queue contents, queue sizes and - // need dispatch set should all be equal. - let queue_contents_set = ::RelayDispatchQueues::iter() - .map(|(k, _)| k) - .collect::>(); - let queue_sizes_set = ::RelayDispatchQueueSize::iter() - .map(|(k, _)| k) - .collect::>(); - let needs_dispatch_set = - ::NeedsDispatch::get().into_iter().collect::>(); - assert_eq!(queue_contents_set, queue_sizes_set); - assert_eq!(queue_contents_set, needs_dispatch_set); - - // `NextDispatchRoundStartWith` should point into a para that is tracked. - if let Some(para) = ::NextDispatchRoundStartWith::get() { - assert!(queue_contents_set.contains(¶)); - } - - // `NeedsDispatch` is always sorted. - assert!(::NeedsDispatch::get().windows(2).all(|xs| xs[0] <= xs[1])); - } - - #[test] - fn dispatch_empty() { - new_test_ext(default_genesis_config()).execute_with(|| { - assert_storage_consistency_exhaustive(); - - // make sure that the case with empty queues is handled properly - Ump::process_pending_upward_messages(); - - assert_storage_consistency_exhaustive(); - }); - } - - #[test] - fn dispatch_single_message() { - let a = ParaId::from(228); - let msg = 1000u32.encode(); - - new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| { - queue_upward_msg(a, msg.clone()); - Ump::process_pending_upward_messages(); - assert_eq!(take_processed(), vec![(a, msg)]); - - assert_storage_consistency_exhaustive(); - }); - } - - #[test] - fn dispatch_resume_after_exceeding_dispatch_stage_weight() { - let a = ParaId::from(128); - let c = ParaId::from(228); - let q = ParaId::from(911); - - let a_msg_1 = (200u32, "a_msg_1").encode(); - let a_msg_2 = (100u32, "a_msg_2").encode(); - let c_msg_1 = (300u32, "c_msg_1").encode(); - let c_msg_2 = (100u32, "c_msg_2").encode(); - let q_msg = (500u32, "q_msg").encode(); - - new_test_ext( - GenesisConfigBuilder { ump_service_total_weight: 500, ..Default::default() }.build(), - ) - .execute_with(|| { - queue_upward_msg(q, q_msg.clone()); - queue_upward_msg(c, c_msg_1.clone()); - queue_upward_msg(a, a_msg_1.clone()); - queue_upward_msg(a, a_msg_2.clone()); - - assert_storage_consistency_exhaustive(); - - // we expect only two first messages to fit in the first iteration. - Ump::process_pending_upward_messages(); - assert_eq!(take_processed(), vec![(a, a_msg_1), (c, c_msg_1)]); - assert_storage_consistency_exhaustive(); - - queue_upward_msg(c, c_msg_2.clone()); - assert_storage_consistency_exhaustive(); - - // second iteration should process the second message. - Ump::process_pending_upward_messages(); - assert_eq!(take_processed(), vec![(q, q_msg)]); - assert_storage_consistency_exhaustive(); - - // 3rd iteration. - Ump::process_pending_upward_messages(); - assert_eq!(take_processed(), vec![(a, a_msg_2), (c, c_msg_2)]); - assert_storage_consistency_exhaustive(); - - // finally, make sure that the queue is empty. - Ump::process_pending_upward_messages(); - assert_eq!(take_processed(), vec![]); - assert_storage_consistency_exhaustive(); - }); - } - - #[test] - fn dispatch_keeps_message_after_weight_exhausted() { - let a = ParaId::from(128); - - let a_msg_1 = (300u32, "a_msg_1").encode(); - let a_msg_2 = (300u32, "a_msg_2").encode(); - - new_test_ext( - GenesisConfigBuilder { - ump_service_total_weight: 500, - ump_max_individual_weight: 300, - ..Default::default() - } - .build(), - ) - .execute_with(|| { - queue_upward_msg(a, a_msg_1.clone()); - queue_upward_msg(a, a_msg_2.clone()); - - assert_storage_consistency_exhaustive(); - - // we expect only one message to fit in the first iteration. - Ump::process_pending_upward_messages(); - assert_eq!(take_processed(), vec![(a, a_msg_1)]); - assert_storage_consistency_exhaustive(); - - // second iteration should process the remaining message. - Ump::process_pending_upward_messages(); - assert_eq!(take_processed(), vec![(a, a_msg_2)]); - assert_storage_consistency_exhaustive(); - - // finally, make sure that the queue is empty. - Ump::process_pending_upward_messages(); - assert_eq!(take_processed(), vec![]); - assert_storage_consistency_exhaustive(); - }); - } - - #[test] - fn dispatch_correctly_handle_remove_of_latest() { - let a = ParaId::from(1991); - let b = ParaId::from(1999); - - let a_msg_1 = (300u32, "a_msg_1").encode(); - let a_msg_2 = (300u32, "a_msg_2").encode(); - let b_msg_1 = (300u32, "b_msg_1").encode(); - - new_test_ext( - GenesisConfigBuilder { ump_service_total_weight: 900, ..Default::default() }.build(), - ) - .execute_with(|| { - // We want to test here an edge case, where we remove the queue with the highest - // para id (i.e. last in the `needs_dispatch` order). - // - // If the last entry was removed we should proceed execution, assuming we still have - // weight available. - - queue_upward_msg(a, a_msg_1.clone()); - queue_upward_msg(a, a_msg_2.clone()); - queue_upward_msg(b, b_msg_1.clone()); - Ump::process_pending_upward_messages(); - assert_eq!(take_processed(), vec![(a, a_msg_1), (b, b_msg_1), (a, a_msg_2)]); - }); - } - - #[test] - fn verify_relay_dispatch_queue_size_is_externally_accessible() { - // Make sure that the relay dispatch queue size storage entry is accessible via well known - // keys and is decodable into a (u32, u32). - - use parity_scale_codec::Decode as _; - use primitives::v1::well_known_keys; - - let a = ParaId::from(228); - let msg = vec![1, 2, 3]; - - new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| { - queue_upward_msg(a, msg); - - let raw_queue_size = - sp_io::storage::get(&well_known_keys::relay_dispatch_queue_size(a)).expect( - "enqueing a message should create the dispatch queue\ - and it should be accessible via the well known keys", - ); - let (cnt, size) = <(u32, u32)>::decode(&mut &raw_queue_size[..]) - .expect("the dispatch queue size should be decodable into (u32, u32)"); - - assert_eq!(cnt, 1); - assert_eq!(size, 3); - }); - } - - #[test] - fn service_overweight_unknown() { - // This test just makes sure that 0 is not a valid index and we can use it not worrying in - // the next test. - new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| { - assert_noop!( - Ump::service_overweight(Origin::root(), 0, 1000), - Error::::UnknownMessageIndex - ); - }); - } - - #[test] - fn overweight_queue_works() { - let para_a = ParaId::from(2021); - - let a_msg_1 = (301u32, "a_msg_1").encode(); - let a_msg_2 = (500u32, "a_msg_2").encode(); - let a_msg_3 = (500u32, "a_msg_3").encode(); - - new_test_ext( - GenesisConfigBuilder { - ump_service_total_weight: 900, - ump_max_individual_weight: 300, - ..Default::default() - } - .build(), - ) - .execute_with(|| { - // HACK: Start with the block number 1. This is needed because should an event be - // emitted during the genesis block they will be implicitly wiped. - System::set_block_number(1); - - // This one is overweight. However, the weight is plenty and we can afford to execute - // this message, thus expect it. - queue_upward_msg(para_a, a_msg_1.clone()); - Ump::process_pending_upward_messages(); - assert_eq!(take_processed(), vec![(para_a, a_msg_1)]); - - // This is overweight and this message cannot fit into the total weight budget. - queue_upward_msg(para_a, a_msg_2.clone()); - queue_upward_msg(para_a, a_msg_3.clone()); - Ump::process_pending_upward_messages(); - assert_last_event( - Event::OverweightEnqueued(para_a, upward_message_id(&a_msg_3[..]), 0, 500).into(), - ); - - // Now verify that if we wanted to service this overweight message with less than enough - // weight it will fail. - assert_noop!( - Ump::service_overweight(Origin::root(), 0, 499), - Error::::WeightOverLimit - ); - - // ... and if we try to service it with just enough weight it will succeed as well. - assert_ok!(Ump::service_overweight(Origin::root(), 0, 500)); - assert_last_event(Event::OverweightServiced(0, 500).into()); - - // ... and if we try to service a message with index that doesn't exist it will error - // out. - assert_noop!( - Ump::service_overweight(Origin::root(), 1, 1000), - Error::::UnknownMessageIndex - ); - }); - } -} diff --git a/runtime/parachains/src/ump/tests.rs b/runtime/parachains/src/ump/tests.rs new file mode 100644 index 000000000000..8a45e7bbbb44 --- /dev/null +++ b/runtime/parachains/src/ump/tests.rs @@ -0,0 +1,350 @@ +// 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 super::*; +use crate::mock::{ + assert_last_event, new_test_ext, take_processed, Configuration, MockGenesisConfig, Origin, + System, Test, Ump, +}; +use frame_support::{assert_noop, assert_ok, weights::Weight}; +use std::collections::HashSet; + +struct GenesisConfigBuilder { + max_upward_message_size: u32, + max_upward_message_num_per_candidate: u32, + max_upward_queue_count: u32, + max_upward_queue_size: u32, + ump_service_total_weight: Weight, + ump_max_individual_weight: Weight, +} + +impl Default for GenesisConfigBuilder { + fn default() -> Self { + Self { + max_upward_message_size: 16, + max_upward_message_num_per_candidate: 2, + max_upward_queue_count: 4, + max_upward_queue_size: 64, + ump_service_total_weight: 1000, + ump_max_individual_weight: 100, + } + } +} + +impl GenesisConfigBuilder { + fn build(self) -> crate::mock::MockGenesisConfig { + let mut genesis = default_genesis_config(); + let config = &mut genesis.configuration.config; + + config.max_upward_message_size = self.max_upward_message_size; + config.max_upward_message_num_per_candidate = self.max_upward_message_num_per_candidate; + config.max_upward_queue_count = self.max_upward_queue_count; + config.max_upward_queue_size = self.max_upward_queue_size; + config.ump_service_total_weight = self.ump_service_total_weight; + config.ump_max_individual_weight = self.ump_max_individual_weight; + genesis + } +} + +fn default_genesis_config() -> MockGenesisConfig { + MockGenesisConfig { + configuration: crate::configuration::GenesisConfig { + config: crate::configuration::HostConfiguration { + max_downward_message_size: 1024, + ..Default::default() + }, + }, + ..Default::default() + } +} + +fn queue_upward_msg(para: ParaId, msg: UpwardMessage) { + let msgs = vec![msg]; + assert!(Ump::check_upward_messages(&Configuration::config(), para, &msgs).is_ok()); + let _ = Ump::receive_upward_messages(para, msgs); +} + +fn assert_storage_consistency_exhaustive() { + // check that empty queues don't clutter the storage. + for (_para, queue) in ::RelayDispatchQueues::iter() { + assert!(!queue.is_empty()); + } + + // actually count the counts and sizes in queues and compare them to the bookkept version. + for (para, queue) in ::RelayDispatchQueues::iter() { + let (expected_count, expected_size) = ::RelayDispatchQueueSize::get(para); + let (actual_count, actual_size) = queue + .into_iter() + .fold((0, 0), |(acc_count, acc_size), x| (acc_count + 1, acc_size + x.len() as u32)); + + assert_eq!(expected_count, actual_count); + assert_eq!(expected_size, actual_size); + } + + // since we wipe the empty queues the sets of paras in queue contents, queue sizes and + // need dispatch set should all be equal. + let queue_contents_set = ::RelayDispatchQueues::iter() + .map(|(k, _)| k) + .collect::>(); + let queue_sizes_set = ::RelayDispatchQueueSize::iter() + .map(|(k, _)| k) + .collect::>(); + let needs_dispatch_set = + ::NeedsDispatch::get().into_iter().collect::>(); + assert_eq!(queue_contents_set, queue_sizes_set); + assert_eq!(queue_contents_set, needs_dispatch_set); + + // `NextDispatchRoundStartWith` should point into a para that is tracked. + if let Some(para) = ::NextDispatchRoundStartWith::get() { + assert!(queue_contents_set.contains(¶)); + } + + // `NeedsDispatch` is always sorted. + assert!(::NeedsDispatch::get().windows(2).all(|xs| xs[0] <= xs[1])); +} + +#[test] +fn dispatch_empty() { + new_test_ext(default_genesis_config()).execute_with(|| { + assert_storage_consistency_exhaustive(); + + // make sure that the case with empty queues is handled properly + Ump::process_pending_upward_messages(); + + assert_storage_consistency_exhaustive(); + }); +} + +#[test] +fn dispatch_single_message() { + let a = ParaId::from(228); + let msg = 1000u32.encode(); + + new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| { + queue_upward_msg(a, msg.clone()); + Ump::process_pending_upward_messages(); + assert_eq!(take_processed(), vec![(a, msg)]); + + assert_storage_consistency_exhaustive(); + }); +} + +#[test] +fn dispatch_resume_after_exceeding_dispatch_stage_weight() { + let a = ParaId::from(128); + let c = ParaId::from(228); + let q = ParaId::from(911); + + let a_msg_1 = (200u32, "a_msg_1").encode(); + let a_msg_2 = (100u32, "a_msg_2").encode(); + let c_msg_1 = (300u32, "c_msg_1").encode(); + let c_msg_2 = (100u32, "c_msg_2").encode(); + let q_msg = (500u32, "q_msg").encode(); + + new_test_ext( + GenesisConfigBuilder { ump_service_total_weight: 500, ..Default::default() }.build(), + ) + .execute_with(|| { + queue_upward_msg(q, q_msg.clone()); + queue_upward_msg(c, c_msg_1.clone()); + queue_upward_msg(a, a_msg_1.clone()); + queue_upward_msg(a, a_msg_2.clone()); + + assert_storage_consistency_exhaustive(); + + // we expect only two first messages to fit in the first iteration. + Ump::process_pending_upward_messages(); + assert_eq!(take_processed(), vec![(a, a_msg_1), (c, c_msg_1)]); + assert_storage_consistency_exhaustive(); + + queue_upward_msg(c, c_msg_2.clone()); + assert_storage_consistency_exhaustive(); + + // second iteration should process the second message. + Ump::process_pending_upward_messages(); + assert_eq!(take_processed(), vec![(q, q_msg)]); + assert_storage_consistency_exhaustive(); + + // 3rd iteration. + Ump::process_pending_upward_messages(); + assert_eq!(take_processed(), vec![(a, a_msg_2), (c, c_msg_2)]); + assert_storage_consistency_exhaustive(); + + // finally, make sure that the queue is empty. + Ump::process_pending_upward_messages(); + assert_eq!(take_processed(), vec![]); + assert_storage_consistency_exhaustive(); + }); +} + +#[test] +fn dispatch_keeps_message_after_weight_exhausted() { + let a = ParaId::from(128); + + let a_msg_1 = (300u32, "a_msg_1").encode(); + let a_msg_2 = (300u32, "a_msg_2").encode(); + + new_test_ext( + GenesisConfigBuilder { + ump_service_total_weight: 500, + ump_max_individual_weight: 300, + ..Default::default() + } + .build(), + ) + .execute_with(|| { + queue_upward_msg(a, a_msg_1.clone()); + queue_upward_msg(a, a_msg_2.clone()); + + assert_storage_consistency_exhaustive(); + + // we expect only one message to fit in the first iteration. + Ump::process_pending_upward_messages(); + assert_eq!(take_processed(), vec![(a, a_msg_1)]); + assert_storage_consistency_exhaustive(); + + // second iteration should process the remaining message. + Ump::process_pending_upward_messages(); + assert_eq!(take_processed(), vec![(a, a_msg_2)]); + assert_storage_consistency_exhaustive(); + + // finally, make sure that the queue is empty. + Ump::process_pending_upward_messages(); + assert_eq!(take_processed(), vec![]); + assert_storage_consistency_exhaustive(); + }); +} + +#[test] +fn dispatch_correctly_handle_remove_of_latest() { + let a = ParaId::from(1991); + let b = ParaId::from(1999); + + let a_msg_1 = (300u32, "a_msg_1").encode(); + let a_msg_2 = (300u32, "a_msg_2").encode(); + let b_msg_1 = (300u32, "b_msg_1").encode(); + + new_test_ext( + GenesisConfigBuilder { ump_service_total_weight: 900, ..Default::default() }.build(), + ) + .execute_with(|| { + // We want to test here an edge case, where we remove the queue with the highest + // para id (i.e. last in the `needs_dispatch` order). + // + // If the last entry was removed we should proceed execution, assuming we still have + // weight available. + + queue_upward_msg(a, a_msg_1.clone()); + queue_upward_msg(a, a_msg_2.clone()); + queue_upward_msg(b, b_msg_1.clone()); + Ump::process_pending_upward_messages(); + assert_eq!(take_processed(), vec![(a, a_msg_1), (b, b_msg_1), (a, a_msg_2)]); + }); +} + +#[test] +fn verify_relay_dispatch_queue_size_is_externally_accessible() { + // Make sure that the relay dispatch queue size storage entry is accessible via well known + // keys and is decodable into a (u32, u32). + + use parity_scale_codec::Decode as _; + use primitives::v1::well_known_keys; + + let a = ParaId::from(228); + let msg = vec![1, 2, 3]; + + new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| { + queue_upward_msg(a, msg); + + let raw_queue_size = sp_io::storage::get(&well_known_keys::relay_dispatch_queue_size(a)) + .expect( + "enqueing a message should create the dispatch queue\ + and it should be accessible via the well known keys", + ); + let (cnt, size) = <(u32, u32)>::decode(&mut &raw_queue_size[..]) + .expect("the dispatch queue size should be decodable into (u32, u32)"); + + assert_eq!(cnt, 1); + assert_eq!(size, 3); + }); +} + +#[test] +fn service_overweight_unknown() { + // This test just makes sure that 0 is not a valid index and we can use it not worrying in + // the next test. + new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| { + assert_noop!( + Ump::service_overweight(Origin::root(), 0, 1000), + Error::::UnknownMessageIndex + ); + }); +} + +#[test] +fn overweight_queue_works() { + let para_a = ParaId::from(2021); + + let a_msg_1 = (301u32, "a_msg_1").encode(); + let a_msg_2 = (500u32, "a_msg_2").encode(); + let a_msg_3 = (500u32, "a_msg_3").encode(); + + new_test_ext( + GenesisConfigBuilder { + ump_service_total_weight: 900, + ump_max_individual_weight: 300, + ..Default::default() + } + .build(), + ) + .execute_with(|| { + // HACK: Start with the block number 1. This is needed because should an event be + // emitted during the genesis block they will be implicitly wiped. + System::set_block_number(1); + + // This one is overweight. However, the weight is plenty and we can afford to execute + // this message, thus expect it. + queue_upward_msg(para_a, a_msg_1.clone()); + Ump::process_pending_upward_messages(); + assert_eq!(take_processed(), vec![(para_a, a_msg_1)]); + + // This is overweight and this message cannot fit into the total weight budget. + queue_upward_msg(para_a, a_msg_2.clone()); + queue_upward_msg(para_a, a_msg_3.clone()); + Ump::process_pending_upward_messages(); + assert_last_event( + Event::OverweightEnqueued(para_a, upward_message_id(&a_msg_3[..]), 0, 500).into(), + ); + + // Now verify that if we wanted to service this overweight message with less than enough + // weight it will fail. + assert_noop!( + Ump::service_overweight(Origin::root(), 0, 499), + Error::::WeightOverLimit + ); + + // ... and if we try to service it with just enough weight it will succeed as well. + assert_ok!(Ump::service_overweight(Origin::root(), 0, 500)); + assert_last_event(Event::OverweightServiced(0, 500).into()); + + // ... and if we try to service a message with index that doesn't exist it will error + // out. + assert_noop!( + Ump::service_overweight(Origin::root(), 1, 1000), + Error::::UnknownMessageIndex + ); + }); +} From b74a2c04b0b326c33fbd0c213ca712e31580e1f1 Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Thu, 3 Feb 2022 16:24:45 +0100 Subject: [PATCH 09/15] [ci] revert #4779 (#4843) --- .gitlab-ci.yml | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ff60e5bdcc0b..0b6e75134abe 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -104,6 +104,12 @@ default: #### Vault secrets .vault-secrets: &vault-secrets secrets: + AWS_ACCESS_KEY_ID: + vault: cicd/gitlab/$CI_PROJECT_PATH/AWS_ACCESS_KEY_ID@kv + file: false + AWS_SECRET_ACCESS_KEY: + vault: cicd/gitlab/$CI_PROJECT_PATH/AWS_SECRET_ACCESS_KEY@kv + file: false GITHUB_PR_TOKEN: vault: cicd/gitlab/parity/GITHUB_PR_TOKEN@kv file: false @@ -497,6 +503,47 @@ update_westend_weights: #### stage: publish +publish-s3-release: &publish-s3 + stage: publish + needs: + - job: test-build-linux-stable + artifacts: true + <<: *kubernetes-env + <<: *vault-secrets + image: paritytech/awscli:latest + variables: + GIT_STRATEGY: none + PREFIX: "builds/polkadot/${ARCH}-${DOCKER_OS}" + rules: + - if: $CI_PIPELINE_SOURCE == "pipeline" + when: never + # publishing binaries nightly + - if: $CI_PIPELINE_SOURCE == "schedule" + before_script: + - *check-versions + script: + - echo "uploading objects to https://releases.parity.io/${PREFIX}/${VERSION}" + - aws s3 sync --acl public-read ./artifacts/ s3://${AWS_BUCKET}/${PREFIX}/${VERSION}/ + - echo "update objects at https://releases.parity.io/${PREFIX}/${EXTRATAG}" + - find ./artifacts -type f | while read file; do + name="${file#./artifacts/}"; + aws s3api copy-object + --copy-source ${AWS_BUCKET}/${PREFIX}/${VERSION}/${name} + --bucket ${AWS_BUCKET} --key ${PREFIX}/${EXTRATAG}/${name}; + done + - | + cat <<-EOM + | + | polkadot binary paths: + | + | - https://releases.parity.io/${PREFIX}/${EXTRATAG}/polkadot + | - https://releases.parity.io/${PREFIX}/${VERSION}/polkadot + | + EOM + after_script: + - aws s3 ls s3://${AWS_BUCKET}/${PREFIX}/${EXTRATAG}/ + --recursive --human-readable --summarize + publish-rustdoc: stage: publish <<: *kubernetes-env From 3b68869e14f84b043aa65bd83f9fe44359e4d626 Mon Sep 17 00:00:00 2001 From: Chevdor Date: Thu, 3 Feb 2022 18:27:49 +0100 Subject: [PATCH 10/15] Add a few items to the release checklist and move the doc away (#4844) --- .github/ISSUE_TEMPLATE/release.md | 122 ++++-------------------------- doc/release-checklist.md | 98 ++++++++++++++++++++++++ 2 files changed, 111 insertions(+), 109 deletions(-) create mode 100644 doc/release-checklist.md diff --git a/.github/ISSUE_TEMPLATE/release.md b/.github/ISSUE_TEMPLATE/release.md index 30cd1f39e853..cbeb7b21d64b 100644 --- a/.github/ISSUE_TEMPLATE/release.md +++ b/.github/ISSUE_TEMPLATE/release.md @@ -15,133 +15,37 @@ checked out with `git checkout release-{{ env.VERSION }}` These checks should be performed on the codebase prior to forking to a release- candidate branch. -- [ ] Verify [`spec_version`](#spec-version) has been incremented since the +- [ ] Verify [`spec_version`](https://github.com/paritytech/polkadot/blob/master/doc/release-checklist.md#spec-version) has been incremented since the last release for any native runtimes from any existing use on public (non-private/test) networks. If the runtime was published (release or pre-release), either the `spec_version` or `impl` must be bumped. -- [ ] Verify previously [completed migrations](#old-migrations-removed) are +- [ ] Verify previously [completed migrations](https://github.com/paritytech/polkadot/blob/master/doc/release-checklist.md#old-migrations-removed) are removed for any public (non-private/test) networks. -- [ ] Verify pallet and [extrinsic ordering](#extrinsic-ordering) has stayed +- [ ] Verify pallet and [extrinsic ordering](https://github.com/paritytech/polkadot/blob/master/doc/release-checklist.md#extrinsic-ordering) has stayed the same. Bump `transaction_version` if not. - [ ] Verify new extrinsics have been correctly whitelisted/blacklisted for - [proxy filters](#proxy-filtering). -- [ ] Verify [benchmarks](#benchmarks) have been updated for any modified + [proxy filters](https://github.com/paritytech/polkadot/blob/master/doc/release-checklist.md#proxy-filtering). +- [ ] Verify [benchmarks](https://github.com/paritytech/polkadot/blob/master/doc/release-checklist.md#benchmarks) have been updated for any modified runtime logic. The following checks can be performed after we have forked off to the release- candidate branch or started an additional release candidate branch (rc-2, rc-3, etc) -- [ ] Verify [new migrations](#new-migrations) complete successfully, and the +- [ ] Verify [new migrations](https://github.com/paritytech/polkadot/blob/master/doc/release-checklist.md#new-migrations) complete successfully, and the runtime state is correctly updated for any public (non-private/test) networks. -- [ ] Verify [Polkadot JS API](#polkadot-js) are up to date with the latest +- [ ] Verify [Polkadot JS API](https://github.com/paritytech/polkadot/blob/master/doc/release-checklist.md#polkadot-js) are up to date with the latest runtime changes. +- [ ] Check with the Signer's team to make sure metadata update QR are lined up - [ ] Push runtime upgrade to Westend and verify network stability. ### All Releases -- [ ] Check that the new client versions have [run on the network](#burn-in) - without issue for 12 hours. +- [ ] Check that the new client versions have [run on the network](https://github.com/paritytech/polkadot/blob/master/doc/release-checklist.md#burn-in) + without issue for 12+ hours on >75% of our validator nodes. - [ ] Check that a draft release has been created at https://github.com/paritytech/polkadot/releases with relevant [release - notes](#release-notes) -- [ ] Check that [build artifacts](#build-artifacts) have been added to the + notes](https://github.com/paritytech/polkadot/blob/master/doc/release-checklist.md#release-notes) +- [ ] Check that [build artifacts](https://github.com/paritytech/polkadot/blob/master/doc/release-checklist.md#build-artifacts) have been added to the draft-release - -## Notes - -### Burn In - -Ensure that Parity DevOps has run the new release on Westend, Kusama, and -Polkadot validators for at least 12 hours prior to publishing the release. - -### Build Artifacts - -Add any necessary assets to the release. They should include: - -- Linux binary -- GPG signature of the Linux binary -- SHA256 of binary -- Source code -- Wasm binaries of any runtimes - -### Release notes - -The release notes should list: - -- The priority of the release (i.e., how quickly users should upgrade) - this is - based on the max priority of any *client* changes. -- Which native runtimes and their versions are included -- The proposal hashes of the runtimes as built with - [srtool](https://gitlab.com/chevdor/srtool) -- Any changes in this release that are still awaiting audit - -The release notes may also list: - -- Free text at the beginning of the notes mentioning anything important - regarding this release -- Notable changes (those labelled with B[1-9]-* labels) separated into sections - -### Spec Version - -A runtime upgrade must bump the spec number. This may follow a pattern with the -client release (e.g. runtime v12 corresponds to v0.8.12, even if the current -runtime is not v11). - -### Old Migrations Removed - -Any previous `on_runtime_upgrade` functions from old upgrades must be removed -to prevent them from executing a second time. The `on_runtime_upgrade` function -can be found in `runtime//src/lib.rs`. - -### New Migrations - -Ensure that any migrations that are required due to storage or logic changes -are included in the `on_runtime_upgrade` function of the appropriate pallets. - -### Extrinsic Ordering - -Offline signing libraries depend on a consistent ordering of call indices and -functions. Compare the metadata of the current and new runtimes and ensure that -the `module index, call index` tuples map to the same set of functions. In case -of a breaking change, increase `transaction_version`. - -To verify the order has not changed, you may manually start the following [Github Action](https://github.com/paritytech/polkadot/actions/workflows/extrinsic-ordering-check-from-bin.yml). It takes around a minute to run and will produce the report as artifact you need to manually check. - -The things to look for in the output are lines like: - - `[Identity] idx 28 -> 25 (calls 15)` - indicates the index for `Identity` has changed - - `[+] Society, Recovery` - indicates the new version includes 2 additional modules/pallets. - - If no indices have changed, every modules line should look something like `[Identity] idx 25 (calls 15)` - -Note: Adding new functions to the runtime does not constitute a breaking change -as long as the indexes did not change. - -### Proxy Filtering - -The runtime contains proxy filters that map proxy types to allowable calls. If -the new runtime contains any new calls, verify that the proxy filters are up to -date to include them. - -### Benchmarks - -There are three benchmarking machines reserved for updating the weights at -release-time. To initialise a benchmark run for each production runtime -(westend, kusama, polkadot): -* Go to https://gitlab.parity.io/parity/polkadot/-/pipelines?page=1&scope=branches&ref=master -* Click the link to the last pipeline run for master -* Start each of the manual jobs: - * 'update_westend_weights' - * 'update_polkadot_weights' - * 'update_kusama_weights' -* When these jobs have completed (it takes a few hours), a git PATCH file will - be available to download as an artifact. -* On your local machine, branch off master -* Download the patch file and apply it to your branch with `git patch patchfile.patch` -* Commit the changes to your branch and submit a PR against master -* The weights should be (Currently manually) checked to make sure there are no - big outliers (i.e., twice or half the weight). - -### Polkadot JS - -Ensure that a release of [Polkadot JS API]() contains any new types or -interfaces necessary to interact with the new runtime. +- [ ] Check that all items listed in the [milestone](https://github.com/paritytech/polkadot/milestones) are included in the release. \ No newline at end of file diff --git a/doc/release-checklist.md b/doc/release-checklist.md new file mode 100644 index 000000000000..4be7c9bcd5df --- /dev/null +++ b/doc/release-checklist.md @@ -0,0 +1,98 @@ + +## Notes + +### Burn In + +Ensure that Parity DevOps has run the new release on Westend, Kusama, and +Polkadot validators for at least 12 hours prior to publishing the release. + +### Build Artifacts + +Add any necessary assets to the release. They should include: + +- Linux binary +- GPG signature of the Linux binary +- SHA256 of binary +- Source code +- Wasm binaries of any runtimes + +### Release notes + +The release notes should list: + +- The priority of the release (i.e., how quickly users should upgrade) - this is + based on the max priority of any *client* changes. +- Which native runtimes and their versions are included +- The proposal hashes of the runtimes as built with + [srtool](https://gitlab.com/chevdor/srtool) +- Any changes in this release that are still awaiting audit + +The release notes may also list: + +- Free text at the beginning of the notes mentioning anything important + regarding this release +- Notable changes (those labelled with B[1-9]-* labels) separated into sections + +### Spec Version + +A runtime upgrade must bump the spec number. This may follow a pattern with the +client release (e.g. runtime v12 corresponds to v0.8.12, even if the current +runtime is not v11). + +### Old Migrations Removed + +Any previous `on_runtime_upgrade` functions from old upgrades must be removed +to prevent them from executing a second time. The `on_runtime_upgrade` function +can be found in `runtime//src/lib.rs`. + +### New Migrations + +Ensure that any migrations that are required due to storage or logic changes +are included in the `on_runtime_upgrade` function of the appropriate pallets. + +### Extrinsic Ordering + +Offline signing libraries depend on a consistent ordering of call indices and +functions. Compare the metadata of the current and new runtimes and ensure that +the `module index, call index` tuples map to the same set of functions. In case +of a breaking change, increase `transaction_version`. + +To verify the order has not changed, you may manually start the following [Github Action](https://github.com/paritytech/polkadot/actions/workflows/extrinsic-ordering-check-from-bin.yml). It takes around a minute to run and will produce the report as artifact you need to manually check. + +The things to look for in the output are lines like: + - `[Identity] idx 28 -> 25 (calls 15)` - indicates the index for `Identity` has changed + - `[+] Society, Recovery` - indicates the new version includes 2 additional modules/pallets. + - If no indices have changed, every modules line should look something like `[Identity] idx 25 (calls 15)` + +Note: Adding new functions to the runtime does not constitute a breaking change +as long as the indexes did not change. + +### Proxy Filtering + +The runtime contains proxy filters that map proxy types to allowable calls. If +the new runtime contains any new calls, verify that the proxy filters are up to +date to include them. + +### Benchmarks + +There are three benchmarking machines reserved for updating the weights at +release-time. To initialise a benchmark run for each production runtime +(westend, kusama, polkadot): +* Go to https://gitlab.parity.io/parity/polkadot/-/pipelines?page=1&scope=branches&ref=master +* Click the link to the last pipeline run for master +* Start each of the manual jobs: + * 'update_westend_weights' + * 'update_polkadot_weights' + * 'update_kusama_weights' +* When these jobs have completed (it takes a few hours), a git PATCH file will + be available to download as an artifact. +* On your local machine, branch off master +* Download the patch file and apply it to your branch with `git patch patchfile.patch` +* Commit the changes to your branch and submit a PR against master +* The weights should be (Currently manually) checked to make sure there are no + big outliers (i.e., twice or half the weight). + +### Polkadot JS + +Ensure that a release of [Polkadot JS API]() contains any new types or +interfaces necessary to interact with the new runtime. From c81bd36e30df081ce3baa4fe38cbd488d8eb49e4 Mon Sep 17 00:00:00 2001 From: Bernhard Schuster Date: Mon, 7 Feb 2022 10:46:27 +0100 Subject: [PATCH 11/15] allow overseer to be enabled anyways (#4840) Closes #4763 --- node/service/src/lib.rs | 13 +++++++++++-- node/test/service/src/lib.rs | 1 + 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/node/service/src/lib.rs b/node/service/src/lib.rs index f7b172442410..6c9d4b4510bd 100644 --- a/node/service/src/lib.rs +++ b/node/service/src/lib.rs @@ -665,6 +665,10 @@ where /// /// This is an advanced feature and not recommended for general use. Generally, `build_full` is /// a better choice. +/// +/// `overseer_enable_anyways` always enables the overseer, based on the provided `OverseerGenerator`, +/// regardless of the role the node has. The relay chain selection (longest or disputes-aware) is +/// still determined based on the role of the node. Likewise for authority discovery. #[cfg(feature = "full-node")] pub fn new_full( mut config: Configuration, @@ -674,6 +678,7 @@ pub fn new_full( jaeger_agent: Option, telemetry_worker_handle: Option, program_path: Option, + overseer_enable_anyways: bool, overseer_gen: OverseerGenerator, ) -> Result>>, Error> where @@ -909,14 +914,14 @@ where let active_leaves = futures::executor::block_on(active_leaves(select_chain.as_longest_chain(), &*client))?; - let authority_discovery_service = if auth_or_collator { + let authority_discovery_service = if auth_or_collator || overseer_enable_anyways { use futures::StreamExt; use sc_network::Event; let authority_discovery_role = if role.is_authority() { sc_authority_discovery::Role::PublishAndDiscover(keystore_container.keystore()) } else { - // don't publish our addresses when we're only a collator + // don't publish our addresses when we're not an authority (collator, cumulus, ..) sc_authority_discovery::Role::Discover }; let dht_event_stream = @@ -1275,6 +1280,7 @@ pub fn build_full( jaeger_agent, telemetry_worker_handle, None, + false, overseer_gen, ) .map(|full| full.with_client(Client::Rococo)) @@ -1290,6 +1296,7 @@ pub fn build_full( jaeger_agent, telemetry_worker_handle, None, + false, overseer_gen, ) .map(|full| full.with_client(Client::Kusama)) @@ -1305,6 +1312,7 @@ pub fn build_full( jaeger_agent, telemetry_worker_handle, None, + false, overseer_gen, ) .map(|full| full.with_client(Client::Westend)) @@ -1320,6 +1328,7 @@ pub fn build_full( jaeger_agent, telemetry_worker_handle, None, + false, overseer_gen, ) .map(|full| full.with_client(Client::Polkadot)) diff --git a/node/test/service/src/lib.rs b/node/test/service/src/lib.rs index 8a6e6912a8f8..01cc6acda485 100644 --- a/node/test/service/src/lib.rs +++ b/node/test/service/src/lib.rs @@ -95,6 +95,7 @@ pub fn new_full( None, None, worker_program_path, + false, polkadot_service::RealOverseerGen, ) } From 666f31719b9a8178c8092d3682c7647c798adc5a Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Mon, 7 Feb 2022 11:21:56 +0100 Subject: [PATCH 12/15] staking miner: spawn separate task for each block (#4716) * staking miner: use config for emergency solution Fixes #4678 * bump jsonrpsee * run `monitor_cmd_for` until the connection is closed * new tokio task for submit_and_watch xt * re-use header subscription * update jsonrpsee + simplify code * revert polkadot runtime changes * fix grumbles * Update utils/staking-miner/src/monitor.rs * grumbles: fix logs + nits --- Cargo.lock | 2 +- utils/staking-miner/Cargo.toml | 12 +- utils/staking-miner/README.md | 7 + utils/staking-miner/src/main.rs | 4 +- utils/staking-miner/src/monitor.rs | 298 ++++++++++++++++++------- utils/staking-miner/src/rpc_helpers.rs | 6 +- 6 files changed, 232 insertions(+), 97 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 311a648fd0a1..4b7f0e217703 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10401,7 +10401,7 @@ dependencies = [ "frame-election-provider-support", "frame-support", "frame-system", - "jsonrpsee 0.4.1", + "jsonrpsee 0.8.0", "kusama-runtime", "log", "pallet-balances", diff --git a/utils/staking-miner/Cargo.toml b/utils/staking-miner/Cargo.toml index 21e08f84ba7a..6a2700f66ad8 100644 --- a/utils/staking-miner/Cargo.toml +++ b/utils/staking-miner/Cargo.toml @@ -5,16 +5,16 @@ authors = ["Parity Technologies "] edition = "2018" [dependencies] +clap = { version = "3.0", features = ["derive", "env"] } codec = { package = "parity-scale-codec", version = "2.0.0" } -tokio = { version = "1.15", features = ["macros"] } -log = "0.4.11" env_logger = "0.9.0" -clap = { version = "3.0", features = ["derive", "env"] } -jsonrpsee = { version = "0.4.1", default-features = false, features = ["ws-client"] } -serde_json = "1.0" -serde = "1.0.132" +jsonrpsee = { version = "0.8", features = ["ws-client"] } +log = "0.4.11" paste = "1.0.6" +serde = "1.0.132" +serde_json = "1.0" thiserror = "1.0.30" +tokio = { version = "1.15", features = ["macros", "rt-multi-thread", "sync"] } remote-externalities = { git = "https://github.com/paritytech/substrate", branch = "master" } diff --git a/utils/staking-miner/README.md b/utils/staking-miner/README.md index 944f870d6dfc..6355395b1ab1 100644 --- a/utils/staking-miner/README.md +++ b/utils/staking-miner/README.md @@ -59,3 +59,10 @@ docker run --rm -it \ -e URI=wss://your-node:9944 \ staking-miner dry-run ``` + +### Test locally + +1. Modify `EPOCH_DURATION_IN_SLOTS` and `SessionsPerEra` to force an election + more often than once per day. +2. $ polkadot --chain polkadot-dev --tmp --alice --execution Native -lruntime=debug --offchain-worker=Always --ws-port 9999 +3. $ staking-miner --uri ws://localhost:9999 --seed //Alice monitor phrag-mms diff --git a/utils/staking-miner/src/main.rs b/utils/staking-miner/src/main.rs index e38c81f602ef..daf29d8c2809 100644 --- a/utils/staking-miner/src/main.rs +++ b/utils/staking-miner/src/main.rs @@ -228,7 +228,7 @@ macro_rules! any_runtime_unit { #[derive(frame_support::DebugNoBound, thiserror::Error)] enum Error { Io(#[from] std::io::Error), - JsonRpsee(#[from] jsonrpsee::types::Error), + JsonRpsee(#[from] jsonrpsee::core::Error), RpcHelperError(#[from] rpc_helpers::RpcHelperError), Codec(#[from] codec::Error), Crypto(sp_core::crypto::SecretStringError), @@ -602,7 +602,7 @@ async fn main() { let outcome = any_runtime! { match command.clone() { - Command::Monitor(c) => monitor_cmd(&client, shared, c, signer_account).await + Command::Monitor(c) => monitor_cmd(client, shared, c, signer_account).await .map_err(|e| { log::error!(target: LOG_TARGET, "Monitor error: {:?}", e); }), diff --git a/utils/staking-miner/src/monitor.rs b/utils/staking-miner/src/monitor.rs index 19259098df53..8d71b242a411 100644 --- a/utils/staking-miner/src/monitor.rs +++ b/utils/staking-miner/src/monitor.rs @@ -19,13 +19,17 @@ use crate::{prelude::*, rpc_helpers::*, signer::Signer, Error, MonitorConfig, SharedConfig}; use codec::Encode; use jsonrpsee::{ + core::{ + client::{Subscription, SubscriptionClientT}, + Error as RpcError, + }, rpc_params, - types::{traits::SubscriptionClient, Subscription}, ws_client::WsClient, }; - use sc_transaction_pool_api::TransactionStatus; use sp_core::storage::StorageKey; +use std::sync::Arc; +use tokio::sync::mpsc; /// Ensure that now is the signed phase. async fn ensure_signed_phase( @@ -64,14 +68,16 @@ async fn ensure_no_previous_solution< } macro_rules! monitor_cmd_for { ($runtime:tt) => { paste::paste! { + /// The monitor command. pub(crate) async fn []( - client: &WsClient, + client: WsClient, shared: SharedConfig, config: MonitorConfig, signer: Signer, ) -> Result<(), Error<$crate::[<$runtime _runtime_exports>]::Runtime>> { use $crate::[<$runtime _runtime_exports>]::*; + type StakingMinerError = Error<$crate::[<$runtime _runtime_exports>]::Runtime>; let (sub, unsub) = if config.listen == "head" { ("chain_subscribeNewHeads", "chain_unsubscribeNewHeads") @@ -79,66 +85,143 @@ macro_rules! monitor_cmd_for { ($runtime:tt) => { paste::paste! { ("chain_subscribeFinalizedHeads", "chain_unsubscribeFinalizedHeads") }; + let mut subscription: Subscription
= client.subscribe(&sub, None, &unsub).await?; + + let client = Arc::new(client); + let (tx, mut rx) = mpsc::unbounded_channel::(); + loop { - log::info!(target: LOG_TARGET, "subscribing to {:?} / {:?}", sub, unsub); - let mut subscription: Subscription
= client - .subscribe(&sub, None, &unsub) - .await - .unwrap(); - - while let Some(now) = subscription.next().await? { - let hash = now.hash(); - log::trace!(target: LOG_TARGET, "new event at #{:?} ({:?})", now.number, hash); - - // if the runtime version has changed, terminate. - crate::check_versions::(client).await?; - - // we prefer doing this check before fetching anything into a remote-ext. - if ensure_signed_phase::(client, hash).await.is_err() { - log::debug!(target: LOG_TARGET, "phase closed, not interested in this block at all."); - continue; - }; + let at = tokio::select! { + maybe_rp = subscription.next() => { + match maybe_rp { + Some(Ok(r)) => r, + // Custom `jsonrpsee` message sent by the server if the subscription was closed on the server side. + Some(Err(RpcError::SubscriptionClosed(reason))) => { + log::warn!(target: LOG_TARGET, "subscription to {} terminated: {:?}. Retrying..", sub, reason); + subscription = client.subscribe(&sub, None, &unsub).await?; + continue; + } + Some(Err(e)) => { + log::error!(target: LOG_TARGET, "subscription failed to decode Header {:?}, this is bug please file an issue", e); + return Err(e.into()); + } + // The subscription was dropped, should only happen if: + // - the connection was closed. + // - the subscription could not keep up with the server. + None => { + log::warn!(target: LOG_TARGET, "subscription to {} terminated. Retrying..", sub); + subscription = client.subscribe(&sub, None, &unsub).await?; + continue + } + } + }, + maybe_err = rx.recv() => { + match maybe_err { + Some(err) => return Err(err), + None => unreachable!("at least one sender kept in the main loop should always return Some; qed"), + } + } + }; + + // Spawn task and non-recoverable errors are sent back to the main task + // such as if the connection has been closed. + tokio::spawn( + send_and_watch_extrinsic(client.clone(), tx.clone(), at, signer.clone(), shared.clone(), config.clone()) + ); + } + + /// Construct extrinsic at given block and watch it. + async fn send_and_watch_extrinsic( + client: Arc, + tx: mpsc::UnboundedSender, + at: Header, + signer: Signer, + shared: SharedConfig, + config: MonitorConfig, + ) { + + let hash = at.hash(); + log::trace!(target: LOG_TARGET, "new event at #{:?} ({:?})", at.number, hash); - // grab an externalities without staking, just the election snapshot. - let mut ext = crate::create_election_ext::( - shared.uri.clone(), - Some(hash), - vec![], - ).await?; + // if the runtime version has changed, terminate. + if let Err(err) = crate::check_versions::(&*client).await { + let _ = tx.send(err.into()); + return; + } + + // we prefer doing this check before fetching anything into a remote-ext. + if ensure_signed_phase::(&*client, hash).await.is_err() { + log::debug!(target: LOG_TARGET, "phase closed, not interested in this block at all."); + return; + } - if ensure_no_previous_solution::(&mut ext, &signer.account).await.is_err() { - log::debug!(target: LOG_TARGET, "We already have a solution in this phase, skipping."); - continue; + // grab an externalities without staking, just the election snapshot. + let mut ext = match crate::create_election_ext::( + shared.uri.clone(), + Some(hash), + vec![], + ).await { + Ok(ext) => ext, + Err(err) => { + let _ = tx.send(err); + return; } + }; + + if ensure_no_previous_solution::(&mut ext, &signer.account).await.is_err() { + log::debug!(target: LOG_TARGET, "We already have a solution in this phase, skipping."); + return; + } - // mine a solution, and run feasibility check on it as well. - let (raw_solution, witness) = crate::mine_with::(&config.solver, &mut ext, true)?; - log::info!(target: LOG_TARGET, "mined solution with {:?}", &raw_solution.score); - - let nonce = crate::get_account_info::(client, &signer.account, Some(hash)) - .await? - .map(|i| i.nonce) - .expect(crate::signer::SIGNER_ACCOUNT_WILL_EXIST); - let tip = 0 as Balance; - let period = ::BlockHashCount::get() / 2; - let current_block = now.number.saturating_sub(1); - let era = sp_runtime::generic::Era::mortal(period.into(), current_block.into()); - log::trace!( - target: LOG_TARGET, "transaction mortality: {:?} -> {:?}", - era.birth(current_block.into()), - era.death(current_block.into()), - ); - let extrinsic = ext.execute_with(|| create_uxt(raw_solution, witness, signer.clone(), nonce, tip, era)); - let bytes = sp_core::Bytes(extrinsic.encode()); - - let mut tx_subscription: Subscription< + // mine a solution, and run feasibility check on it as well. + let (raw_solution, witness) = match crate::mine_with::(&config.solver, &mut ext, true) { + Ok(r) => r, + Err(err) => { + let _ = tx.send(err.into()); + return; + } + }; + + log::info!(target: LOG_TARGET, "mined solution with {:?}", &raw_solution.score); + + let nonce = match crate::get_account_info::(&*client, &signer.account, Some(hash)).await { + Ok(maybe_account) => { + let acc = maybe_account.expect(crate::signer::SIGNER_ACCOUNT_WILL_EXIST); + acc.nonce + } + Err(err) => { + let _ = tx.send(err); + return; + } + }; + + let tip = 0 as Balance; + let period = ::BlockHashCount::get() / 2; + let current_block = at.number.saturating_sub(1); + let era = sp_runtime::generic::Era::mortal(period.into(), current_block.into()); + + log::trace!( + target: LOG_TARGET, "transaction mortality: {:?} -> {:?}", + era.birth(current_block.into()), + era.death(current_block.into()), + ); + + let extrinsic = ext.execute_with(|| create_uxt(raw_solution, witness, signer.clone(), nonce, tip, era)); + let bytes = sp_core::Bytes(extrinsic.encode()); + + let mut tx_subscription: Subscription< TransactionStatus<::Hash, ::Hash> - > = match client - .subscribe(&"author_submitAndWatchExtrinsic", rpc_params! { bytes }, "author_unwatchExtrinsic") - .await - { - Ok(sub) => sub, - Err(why) => { + > = match client.subscribe( + "author_submitAndWatchExtrinsic", + rpc_params! { bytes }, + "author_unwatchExtrinsic" + ).await { + Ok(sub) => sub, + Err(RpcError::RestartNeeded(e)) => { + let _ = tx.send(RpcError::RestartNeeded(e).into()); + return + }, + Err(why) => { // This usually happens when we've been busy with mining for a few blocks, and // now we're receiving the subscriptions of blocks in which we were busy. In // these blocks, we still don't have a solution, so we re-compute a new solution @@ -146,38 +229,83 @@ macro_rules! monitor_cmd_for { ($runtime:tt) => { paste::paste! { // error. NOTE: to improve this overall, and to be able to introduce an array of // other fancy features, we should make this multi-threaded and do the // computation outside of this callback. - log::warn!(target: LOG_TARGET, "failing to submit a transaction {:?}. continuing...", why); - continue - } + log::warn!( + target: LOG_TARGET, + "failing to submit a transaction {:?}. ignore block: {}", + why, at.number + ); + return; + }, + }; + + while let Some(rp) = tx_subscription.next().await { + let status_update = match rp { + Ok(r) => r, + // Custom `jsonrpsee` message sent by the server if the subscription was closed on the server side. + Err(RpcError::SubscriptionClosed(reason)) => { + log::warn!( + target: LOG_TARGET, + "tx subscription closed by the server: {:?}; skip block: {}", + reason, at.number + ); + return; + }, + Err(e) => { + log::error!(target: LOG_TARGET, "subscription failed to decode TransactionStatus {:?}, this is a bug please file an issue", e); + let _ = tx.send(e.into()); + return; + }, }; - while let Some(status_update) = tx_subscription.next().await? { - log::trace!(target: LOG_TARGET, "status update {:?}", status_update); - match status_update { - TransactionStatus::Ready | TransactionStatus::Broadcast(_) | TransactionStatus::Future => continue, - TransactionStatus::InBlock(hash) => { - log::info!(target: LOG_TARGET, "included at {:?}", hash); - let key = StorageKey(frame_support::storage::storage_prefix(b"System",b"Events").to_vec()); - let events = get_storage::::Hash>>, - >(client, rpc_params!{ key, hash }).await?.unwrap_or_default(); - log::info!(target: LOG_TARGET, "events at inclusion {:?}", events); - } - TransactionStatus::Retracted(hash) => { - log::info!(target: LOG_TARGET, "Retracted at {:?}", hash); - } - TransactionStatus::Finalized(hash) => { - log::info!(target: LOG_TARGET, "Finalized at {:?}", hash); - break - } - _ => { - log::warn!(target: LOG_TARGET, "Stopping listen due to other status {:?}", status_update); - break - } - } + log::trace!(target: LOG_TARGET, "status update {:?}", status_update); + match status_update { + TransactionStatus::Ready | + TransactionStatus::Broadcast(_) | + TransactionStatus::Future => continue, + TransactionStatus::InBlock(hash) => { + log::info!(target: LOG_TARGET, "included at {:?}", hash); + let key = StorageKey( + frame_support::storage::storage_prefix(b"System", b"Events").to_vec(), + ); + let key2 = key.clone(); + + let events = match get_storage::< + Vec::Hash>>, + >(&*client, rpc_params! { key, hash }) + .await { + Ok(rp) => rp.unwrap_or_default(), + Err(RpcHelperError::JsonRpsee(RpcError::RestartNeeded(e))) => { + let _ = tx.send(RpcError::RestartNeeded(e).into()); + return; + } + // Decoding or other RPC error => just terminate the task. + Err(e) => { + log::warn!(target: LOG_TARGET, "get_storage [key: {:?}, hash: {:?}] failed: {:?}; skip block: {}", + key2, hash, e, at.number + ); + return; + } + }; + + log::info!(target: LOG_TARGET, "events at inclusion {:?}", events); + }, + TransactionStatus::Retracted(hash) => { + log::info!(target: LOG_TARGET, "Retracted at {:?}", hash); + }, + TransactionStatus::Finalized(hash) => { + log::info!(target: LOG_TARGET, "Finalized at {:?}", hash); + break + }, + _ => { + log::warn!( + target: LOG_TARGET, + "Stopping listen due to other status {:?}", + status_update + ); + break + }, }; } - - log::warn!(target: LOG_TARGET, "subscription to {} terminated. Retrying..", sub) } } }}} diff --git a/utils/staking-miner/src/rpc_helpers.rs b/utils/staking-miner/src/rpc_helpers.rs index 1277564ebd93..153ca0e65c03 100644 --- a/utils/staking-miner/src/rpc_helpers.rs +++ b/utils/staking-miner/src/rpc_helpers.rs @@ -17,12 +17,12 @@ //! Helper method for RPC. use super::*; -use jsonrpsee::types::traits::Client; -pub(crate) use jsonrpsee::types::v2::ParamsSer; +use jsonrpsee::core::client::ClientT; +pub(crate) use jsonrpsee::types::ParamsSer; #[derive(frame_support::DebugNoBound, thiserror::Error)] pub(crate) enum RpcHelperError { - JsonRpsee(#[from] jsonrpsee::types::Error), + JsonRpsee(#[from] jsonrpsee::core::Error), Codec(#[from] codec::Error), } From 0d76dc7eed7a81cd24ce59eb06234a72c498d570 Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Mon, 7 Feb 2022 11:48:56 +0100 Subject: [PATCH 13/15] [ci] Fix scheduled pipeline (#4855) * [ci] Fix scheduled pipeline * empty commit for pipeline rerun --- .gitlab-ci.yml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 0b6e75134abe..0768f26937a5 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -91,6 +91,7 @@ default: - if: $CI_PIPELINE_SOURCE == "pipeline" when: never - if: $CI_PIPELINE_SOURCE == "schedule" + when: never - if: $CI_COMMIT_REF_NAME == "master" - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs @@ -638,11 +639,7 @@ zombienet-test-parachains-upgrade-smoke-test: stage: deploy image: "${ZOMBIENET_IMAGE}" <<: *kubernetes-env - rules: - - if: $CI_PIPELINE_SOURCE == "schedule" - - if: $CI_COMMIT_REF_NAME == "master" - - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs - - if: $CI_COMMIT_REF_NAME == "rococo-v1" + <<: *zombienet-refs needs: - job: publish-polkadot-image - job: publish-malus-image From 6f81bff3e7588684099e928cb49767f8d6222e13 Mon Sep 17 00:00:00 2001 From: Bernhard Schuster Date: Mon, 7 Feb 2022 11:50:06 +0100 Subject: [PATCH 14/15] make it 2 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index da63014e59fa..fc3b0c3679a1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -134,7 +134,7 @@ codegen-units = 1 [profile.testnet] inherits = "release" -debug = 1 # debug symbols are useful for profilers +debug = 2 # debug symbols are useful for profilers debug-assertions = true overflow-checks = true From 43b390f289fbe2054fbc86dd91f79dee314dc689 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Mon, 7 Feb 2022 17:05:53 +0100 Subject: [PATCH 15/15] Forward `enable_overseer_always` (#4858) Cumulus actually uses the `build_full` function. I missed that. --- cli/src/command.rs | 1 + node/service/src/lib.rs | 17 +++++++++++++---- .../test-parachains/adder/collator/src/main.rs | 1 + 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/cli/src/command.rs b/cli/src/command.rs index 10acbb1d7c01..0d6efefbb816 100644 --- a/cli/src/command.rs +++ b/cli/src/command.rs @@ -280,6 +280,7 @@ where cli.run.beefy, jaeger_agent, None, + false, overseer_gen, ) .map(|full| full.task_manager) diff --git a/node/service/src/lib.rs b/node/service/src/lib.rs index 6c9d4b4510bd..693513c3964d 100644 --- a/node/service/src/lib.rs +++ b/node/service/src/lib.rs @@ -1257,6 +1257,14 @@ pub fn new_chain_ops( Err(Error::NoRuntime) } +/// Build a full node. +/// +/// The actual "flavor", aka if it will use `Polkadot`, `Rococo` or `Kusama` is determined based on +/// [`IdentifyVariant`] using the chain spec. +/// +/// `overseer_enable_anyways` always enables the overseer, based on the provided `OverseerGenerator`, +/// regardless of the role the node has. The relay chain selection (longest or disputes-aware) is +/// still determined based on the role of the node. Likewise for authority discovery. #[cfg(feature = "full-node")] pub fn build_full( config: Configuration, @@ -1265,6 +1273,7 @@ pub fn build_full( enable_beefy: bool, jaeger_agent: Option, telemetry_worker_handle: Option, + overseer_enable_anyways: bool, overseer_gen: impl OverseerGen, ) -> Result, Error> { #[cfg(feature = "rococo-native")] @@ -1280,7 +1289,7 @@ pub fn build_full( jaeger_agent, telemetry_worker_handle, None, - false, + overseer_enable_anyways, overseer_gen, ) .map(|full| full.with_client(Client::Rococo)) @@ -1296,7 +1305,7 @@ pub fn build_full( jaeger_agent, telemetry_worker_handle, None, - false, + overseer_enable_anyways, overseer_gen, ) .map(|full| full.with_client(Client::Kusama)) @@ -1312,7 +1321,7 @@ pub fn build_full( jaeger_agent, telemetry_worker_handle, None, - false, + overseer_enable_anyways, overseer_gen, ) .map(|full| full.with_client(Client::Westend)) @@ -1328,7 +1337,7 @@ pub fn build_full( jaeger_agent, telemetry_worker_handle, None, - false, + overseer_enable_anyways, overseer_gen, ) .map(|full| full.with_client(Client::Polkadot)) diff --git a/parachain/test-parachains/adder/collator/src/main.rs b/parachain/test-parachains/adder/collator/src/main.rs index b1366abccb9d..09f307e6fb75 100644 --- a/parachain/test-parachains/adder/collator/src/main.rs +++ b/parachain/test-parachains/adder/collator/src/main.rs @@ -68,6 +68,7 @@ fn main() -> Result<()> { true, None, None, + false, polkadot_service::RealOverseerGen, ) .map_err(|e| e.to_string())?;